"""
Pattern 91: Tool-Using Agent Pattern
Agents that can use external tools to extend their capabilities.
Integrates with LangChain's tool system for dynamic tool selection and execution.
"""
from typing import Dict, Any, List, Optional, Callable
from dataclasses import dataclass, field
from datetime import datetime
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_core.tools import Tool, StructuredTool
from langchain.tools import tool
@dataclass
class ToolExecution:
"""Record of tool execution."""
tool_name: str
input_data: Any
output: Any
success: bool
timestamp: datetime = field(default_factory=datetime.now)
error: Optional[str] = None
# Define some example tools
@tool
def calculator(expression: str) -> str:
"""Evaluate a mathematical expression. Input should be a valid Python expression."""
try:
result = eval(expression)
return f"Result: {result}"
except Exception as e:
return f"Error: {str(e)}"
@tool
def web_search(query: str) -> str:
"""Search the web for information. Returns simulated search results."""
# In real implementation, would call actual search API
return f"Search results for '{query}': [Simulated] Found 3 relevant articles about {query}."
@tool
def get_weather(location: str) -> str:
"""Get current weather for a location."""
# Simulated weather data
return f"Weather in {location}: Sunny, 72°F (22°C), Light breeze"
@tool
def text_analyzer(text: str) -> str:
"""Analyze text and return statistics."""
words = text.split()
chars = len(text)
return f"Analysis: {len(words)} words, {chars} characters, avg word length: {chars/len(words):.1f}"
class ToolUsingAgent:
"""Agent that can use tools to accomplish tasks."""
def __init__(self, name: str, tools: List[Tool], model_name: str = "gpt-4"):
self.name = name
self.tools = tools
self.llm = ChatOpenAI(model=model_name, temperature=0)
self.execution_history: List[ToolExecution] = []
# Create prompt for tool-using agent
self.prompt = ChatPromptTemplate.from_messages([
("system", f"You are {name}, an AI assistant with access to tools. "
f"Use the available tools to help answer questions accurately. "
f"Available tools: {', '.join([t.name for t in tools])}"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}")
])
# Create agent
self.agent = create_openai_tools_agent(self.llm, self.tools, self.prompt)
self.agent_executor = AgentExecutor(
agent=self.agent,
tools=self.tools,
verbose=False,
max_iterations=5
)
def execute_task(self, task: str) -> Dict[str, Any]:
"""Execute task using available tools."""
try:
result = self.agent_executor.invoke({"input": task})
# Record execution
execution = ToolExecution(
tool_name="agent_executor",
input_data=task,
output=result.get("output", ""),
success=True
)
self.execution_history.append(execution)
return {
"success": True,
"agent": self.name,
"task": task,
"result": result.get("output", ""),
"tools_used": self._extract_tools_used(result)
}
except Exception as e:
execution = ToolExecution(
tool_name="agent_executor",
input_data=task,
output=None,
success=False,
error=str(e)
)
self.execution_history.append(execution)
return {
"success": False,
"agent": self.name,
"task": task,
"error": str(e)
}
def _extract_tools_used(self, result: Dict) -> List[str]:
"""Extract which tools were used from result."""
# Simplified - in real implementation would parse intermediate steps
tools_mentioned = []
output = str(result.get("output", ""))
for tool in self.tools:
if tool.name.lower() in output.lower():
tools_mentioned.append(tool.name)
return tools_mentioned
class ToolUsingAgentPattern:
"""
Tool-Using Agent Pattern - Extend agent capabilities with tools.
Agents can dynamically select and use tools based on task requirements.
Integrates with LangChain's tool system for seamless tool calling.
"""
def __init__(self):
self.agents: Dict[str, ToolUsingAgent] = {}
self.available_tools: List[Tool] = []
def register_tool(self, tool: Tool):
"""Register a tool for agents to use."""
self.available_tools.append(tool)
def create_agent(self, name: str, tool_names: Optional[List[str]] = None) -> ToolUsingAgent:
"""Create agent with specified tools."""
# Select tools
if tool_names:
agent_tools = [t for t in self.available_tools if t.name in tool_names]
else:
agent_tools = self.available_tools.copy()
agent = ToolUsingAgent(name, agent_tools)
self.agents[name] = agent
return agent
def execute_with_agent(self, agent_name: str, task: str) -> Dict[str, Any]:
"""Execute task with specific agent."""
if agent_name not in self.agents:
return {"success": False, "error": "Agent not found"}
agent = self.agents[agent_name]
result = agent.execute_task(task)
if result["success"]:
print(f"\n ✓ {agent_name}: {task[:60]}...")
print(f" Result: {result['result'][:100]}...")
if result.get("tools_used"):
print(f" Tools used: {', '.join(result['tools_used'])}")
else:
print(f"\n ✗ {agent_name}: {result.get('error', 'Unknown error')}")
return result
def run(self, scenario: str) -> Dict[str, Any]:
"""Execute tool-using agent pattern."""
total_executions = sum(len(agent.execution_history) for agent in self.agents.values())
successful_executions = sum(
sum(1 for e in agent.execution_history if e.success)
for agent in self.agents.values()
)
return {
"pattern": "ToolUsingAgent",
"total_agents": len(self.agents),
"available_tools": len(self.available_tools),
"total_executions": total_executions,
"successful_executions": successful_executions,
"scenario": scenario
}
# Example usage
if __name__ == "__main__":
print("=== Tool-Using Agent Pattern Demo ===\n")
# Create pattern
pattern = ToolUsingAgentPattern()
# Register tools
print("1. Registering tools...")
pattern.register_tool(calculator)
pattern.register_tool(web_search)
pattern.register_tool(get_weather)
pattern.register_tool(text_analyzer)
print(f" Registered {len(pattern.available_tools)} tools")
# Create agents with different tool sets
print("\n2. Creating tool-using agents...")
# General agent with all tools
general_agent = pattern.create_agent("GeneralAssistant")
print(f" - GeneralAssistant: {len(general_agent.tools)} tools")
# Math specialist with calculator
math_agent = pattern.create_agent("MathSpecialist", ["calculator"])
print(f" - MathSpecialist: {len(math_agent.tools)} tools")
# Research agent with search
research_agent = pattern.create_agent("ResearchAssistant", ["web_search", "text_analyzer"])
print(f" - ResearchAssistant: {len(research_agent.tools)} tools")
# Execute tasks
print("\n3. Executing tasks with tool-using agents...")
# Math task
pattern.execute_with_agent(
"MathSpecialist",
"Calculate the result of (123 + 456) * 2"
)
# Weather task
pattern.execute_with_agent(
"GeneralAssistant",
"What's the weather like in San Francisco?"
)
# Research task
pattern.execute_with_agent(
"ResearchAssistant",
"Search for information about artificial intelligence and analyze the query"
)
# Complex task requiring multiple tools
pattern.execute_with_agent(
"GeneralAssistant",
"Calculate 15% tip on a $85 dinner bill, then tell me the weather in New York"
)
# Summary
print("\n4. Pattern Summary:")
summary = pattern.run("Multi-agent tool-using system")
print(f" Total Agents: {summary['total_agents']}")
print(f" Available Tools: {summary['available_tools']}")
print(f" Total Executions: {summary['total_executions']}")
print(f" Successful: {summary['successful_executions']}")
print("\n✓ Tool-using agents successfully extended capabilities with tools!")
Agentic Architecture Pattern: Tool Using Agent
Pattern 91: 91 Tool Using Agent – Line-by-Line Explanation
Overview
Pattern 91: Tool-Using Agent Pattern
Agents that can use external tools to extend their capabilities. Integrates with LangChain’s tool system for dynamic tool selection and execution.
Code Structure Analysis
File Information
- Pattern Number: 91
- Pattern Name: 91 Tool Using Agent
- File Path:
patterns\tool_resource\91_tool_using_agent.py - Total Lines: 271
Detailed Code Explanation
Module Docstring
"""
Pattern 91: Tool-Using Agent Pattern
Agents that can use external tools to extend their capabilities.
Integrates with LangChain's tool system for dynamic tool selection and execution.
"""
Explanation: This module docstring describes the purpose and key features of the 91 Tool Using Agent pattern.
Imports Section
from typing import Dict, Any, List, Optional, Callable
from dataclasses import dataclass, field
from datetime import datetime
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_core.tools import Tool, StructuredTool
from langchain.tools import tool # First 20 imports shown
Explanation: The module imports necessary dependencies:
– from typing import Dict, Any, List, Optional, Callable: Type hints for better code documentation
– from dataclasses import dataclass, field: Data class decorators for clean data structures
– from datetime import datetime: Date and time utilities
– from langchain_core.prompts import ChatPromptTemplate: LangChain framework integration
– from langchain_openai import ChatOpenAI: LangChain framework integration
– from langchain.agents import AgentExecutor, create_openai_tools_agent: LangChain framework integration
– from langchain_core.tools import Tool, StructuredTool: LangChain framework integration
– from langchain.tools import tool: LangChain framework integration
Classes
ToolExecution (Line 19)
Description: Record of tool execution.
ToolUsingAgent (Line 62)
Description: Agent that can use tools to accomplish tasks.
Methods:
__init__ (Line 65)
def __init__(self, name, tools, model_name):
"""No method docstring."""
Purpose: No method docstring.
Parameters:
– self: Instance reference
– name: Identifier or label
– tools: Parameter for tools
– model_name: LLM model to use (e.g., “gpt-4”)
execute_task (Line 89)
def execute_task(self, task):
"""Execute task using available tools."""
Purpose: Execute task using available tools.
Parameters:
– self: Instance reference
– task: Parameter for task
_extract_tools_used (Line 128)
def _extract_tools_used(self, result):
"""Extract which tools were used from result."""
Purpose: Extract which tools were used from result.
Parameters:
– self: Instance reference
– result: Parameter for result
ToolUsingAgentPattern (Line 139)
Description: Tool-Using Agent Pattern – Extend agent capabilities with tools.
Agents can dynamically select and use tools based on task requirements. Integrates with LangChain’s tool system for seamless tool calling.
Methods:
__init__ (Line 147)
def __init__(self):
"""No method docstring."""
Purpose: No method docstring.
Parameters:
– self: Instance reference
register_tool (Line 151)
def register_tool(self, tool):
"""Register a tool for agents to use."""
Purpose: Register a tool for agents to use.
Parameters:
– self: Instance reference
– tool: Parameter for tool
create_agent (Line 155)
def create_agent(self, name, tool_names):
"""Create agent with specified tools."""
Purpose: Create agent with specified tools.
Parameters:
– self: Instance reference
– name: Identifier or label
– tool_names: Parameter for tool_names
execute_with_agent (Line 168)
def execute_with_agent(self, agent_name, task):
"""Execute task with specific agent."""
Purpose: Execute task with specific agent.
Parameters:
– self: Instance reference
– agent_name: Parameter for agent_name
– task: Parameter for task
run (Line 186)
def run(self, scenario):
"""Execute tool-using agent pattern."""
Purpose: Execute tool-using agent pattern.
Parameters:
– self: Instance reference
– scenario: Parameter for scenario
Functions
calculator (Line 31)
def calculator(expression):
"""Evaluate a mathematical expression. Input should be a valid Python expression."""
Purpose: Evaluate a mathematical expression. Input should be a valid Python expression.
web_search (Line 41)
def web_search(query):
"""Search the web for information. Returns simulated search results."""
Purpose: Search the web for information. Returns simulated search results.
get_weather (Line 48)
def get_weather(location):
"""Get current weather for a location."""
Purpose: Get current weather for a location.
text_analyzer (Line 55)
def text_analyzer(text):
"""Analyze text and return statistics."""
Purpose: Analyze text and return statistics.
Design Patterns Used
- Strategy Pattern: Different execution strategies for various scenarios
- State Pattern: Managing different states in the workflow
- Chain of Responsibility: Sequential processing through workflow nodes
- Observer Pattern: Tracking and monitoring pattern execution
- Factory Pattern: Creating instances with proper configuration
Usage Example
# Initialize the pattern
pattern = ToolExecution(name="example", model_name="gpt-4")
# Configure and execute
result = pattern.execute(data={"key": "value"})
# Check results
print(result)
Key Concepts
- LLM Integration: Uses LangChain/OpenAI for intelligent decision-making
- Workflow Orchestration: LangGraph manages execution flow through nodes
- State Management: TypedDict defines workflow state structure
- Error Handling: Comprehensive error handling and fallback mechanisms
- Extensibility: Designed for easy customization and extension
Extension Points
This pattern can be extended by: 1. Adding custom workflow nodes 2. Implementing additional validation logic 3. Integrating with external services 4. Customizing LLM prompts and responses 5. Adding monitoring and logging capabilities
Leave a Reply