Initial commit
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
# Phase 2: Multi-Tool Agent Implementation
|
||||
|
||||
**Objective**: Implement agent with multiple validated tools
|
||||
|
||||
## Python Implementation
|
||||
|
||||
```python
|
||||
from anthropic import Anthropic
|
||||
from typing import Dict, Any, List
|
||||
|
||||
client = Anthropic()
|
||||
|
||||
# Define tools
|
||||
TOOLS = [
|
||||
{
|
||||
"name": "search_flights",
|
||||
"description": "Search for available flights",
|
||||
"strict": True,
|
||||
"input_schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"origin": {"type": "string", "description": "Departure city"},
|
||||
"destination": {"type": "string", "description": "Arrival city"},
|
||||
"departure_date": {"type": "string", "format": "date"},
|
||||
"travelers": {"type": "integer", "enum": [1, 2, 3, 4, 5, 6]}
|
||||
},
|
||||
"required": ["origin", "destination", "departure_date", "travelers"],
|
||||
"additionalProperties": False
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "book_flight",
|
||||
"description": "Book a selected flight",
|
||||
"strict": True,
|
||||
"input_schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"flight_id": {"type": "string", "description": "Flight identifier"},
|
||||
"passengers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"passport": {"type": "string"}
|
||||
},
|
||||
"required": ["name", "passport"],
|
||||
"additionalProperties": False
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["flight_id", "passengers"],
|
||||
"additionalProperties": False
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "search_hotels",
|
||||
"description": "Search for hotels in a city",
|
||||
"strict": True,
|
||||
"input_schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"city": {"type": "string", "description": "City name"},
|
||||
"check_in": {"type": "string", "format": "date"},
|
||||
"check_out": {"type": "string", "format": "date"},
|
||||
"guests": {"type": "integer", "enum": [1, 2, 3, 4]}
|
||||
},
|
||||
"required": ["city", "check_in", "check_out", "guests"],
|
||||
"additionalProperties": False
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
# Tool execution functions
|
||||
def search_flights(origin: str, destination: str, departure_date: str, travelers: int) -> Dict:
|
||||
"""Execute flight search - calls actual API."""
|
||||
# Implementation here
|
||||
return {"flights": [...]}
|
||||
|
||||
def book_flight(flight_id: str, passengers: List[Dict]) -> Dict:
|
||||
"""Book the flight - calls actual API."""
|
||||
# Implementation here
|
||||
return {"confirmation": "ABC123", "status": "confirmed"}
|
||||
|
||||
def search_hotels(city: str, check_in: str, check_out: str, guests: int) -> Dict:
|
||||
"""Search hotels - calls actual API."""
|
||||
# Implementation here
|
||||
return {"hotels": [...]}
|
||||
|
||||
# Tool registry
|
||||
TOOL_FUNCTIONS = {
|
||||
"search_flights": search_flights,
|
||||
"book_flight": book_flight,
|
||||
"search_hotels": search_hotels,
|
||||
}
|
||||
|
||||
# Agent loop
|
||||
def run_agent(user_request: str, max_turns: int = 10):
|
||||
"""Run agent with tool validation."""
|
||||
messages = [{"role": "user", "content": user_request}]
|
||||
|
||||
for turn in range(max_turns):
|
||||
response = client.beta.messages.create(
|
||||
model="claude-sonnet-4-5",
|
||||
max_tokens=2048,
|
||||
betas=["structured-outputs-2025-11-13"],
|
||||
messages=messages,
|
||||
tools=TOOLS,
|
||||
)
|
||||
|
||||
# Process response
|
||||
if response.stop_reason == "end_turn":
|
||||
# Agent finished
|
||||
return extract_final_answer(response)
|
||||
|
||||
if response.stop_reason == "tool_use":
|
||||
# Execute tools
|
||||
tool_results = []
|
||||
|
||||
for block in response.content:
|
||||
if block.type == "tool_use":
|
||||
# Tool input is GUARANTEED to match schema
|
||||
tool_name = block.name
|
||||
tool_input = block.input # Already validated!
|
||||
|
||||
# Execute tool
|
||||
tool_function = TOOL_FUNCTIONS[tool_name]
|
||||
result = tool_function(**tool_input) # Type-safe!
|
||||
|
||||
tool_results.append({
|
||||
"type": "tool_result",
|
||||
"tool_use_id": block.id,
|
||||
"content": str(result)
|
||||
})
|
||||
|
||||
# Add assistant response and tool results to conversation
|
||||
messages.append({"role": "assistant", "content": response.content})
|
||||
messages.append({"role": "user", "content": tool_results})
|
||||
|
||||
else:
|
||||
raise Exception(f"Unexpected stop reason: {response.stop_reason}")
|
||||
|
||||
raise Exception("Max turns reached")
|
||||
|
||||
# Usage
|
||||
result = run_agent("Book a flight from SF to Paris for 2 people, departing May 15")
|
||||
print(result)
|
||||
```
|
||||
|
||||
## TypeScript Implementation
|
||||
|
||||
```typescript
|
||||
import Anthropic from '@anthropic-ai/sdk';
|
||||
|
||||
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
|
||||
|
||||
const TOOLS: Anthropic.Tool[] = [
|
||||
{
|
||||
name: "search_flights",
|
||||
description: "Search for available flights",
|
||||
strict: true,
|
||||
input_schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
origin: { type: "string", description: "Departure city" },
|
||||
destination: { type: "string", description: "Arrival city" },
|
||||
departure_date: { type: "string", format: "date" },
|
||||
travelers: { type: "integer", enum: [1, 2, 3, 4, 5, 6] }
|
||||
},
|
||||
required: ["origin", "destination", "departure_date", "travelers"],
|
||||
additionalProperties: false
|
||||
}
|
||||
},
|
||||
// ... other tools
|
||||
];
|
||||
|
||||
async function runAgent(userRequest: string, maxTurns: number = 10) {
|
||||
const messages: Anthropic.MessageParam[] = [
|
||||
{ role: "user", content: userRequest }
|
||||
];
|
||||
|
||||
for (let turn = 0; turn < maxTurns; turn++) {
|
||||
const response = await client.beta.messages.create({
|
||||
model: "claude-sonnet-4-5",
|
||||
max_tokens: 2048,
|
||||
betas: ["structured-outputs-2025-11-13"],
|
||||
messages,
|
||||
tools: TOOLS,
|
||||
});
|
||||
|
||||
if (response.stop_reason === "end_turn") {
|
||||
return extractFinalAnswer(response);
|
||||
}
|
||||
|
||||
if (response.stop_reason === "tool_use") {
|
||||
const toolResults: Anthropic.ToolResultBlockParam[] = [];
|
||||
|
||||
for (const block of response.content) {
|
||||
if (block.type === "tool_use") {
|
||||
// Input guaranteed to match schema!
|
||||
const result = await executeTool(block.name, block.input);
|
||||
|
||||
toolResults.push({
|
||||
type: "tool_result",
|
||||
tool_use_id: block.id,
|
||||
content: JSON.stringify(result)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
messages.push({ role: "assistant", content: response.content });
|
||||
messages.push({ role: "user", content: toolResults });
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error("Max turns reached");
|
||||
}
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
Working multi-tool agent with validated tool schemas.
|
||||
Reference in New Issue
Block a user