Although the tool interface is straightforward and simple to use, there are actually quite a few practices and tricks that you can use to get significantly better results.
Use chain-of-thought prompting to allow the agent to think and plan before executing a complex tool.
from agency_swarm.tools import BaseTool
from pydantic import Field
class ComplexAnalysisTool(BaseTool):
"""
Performs complex analysis after planning the approach.
"""
chain_of_thought: str = Field(
...,
description="Think-step-by-step about how to perform the analysis."
)
data: str = Field(..., description="Data to analyze.")
def run(self):
# Analysis logic
return "Analysis complete."
Provide Hints for the Agent
Based on your tool’s logic, you can provide hints for the agent in tool output on what to do next.
class QueryDatabase(BaseTool):
question: str = Field(...)
def run(self):
# query your database here
context = self.query_database(self.question)
# context not found
if context is None:
# tell agent what to do next
raise ValueError("No context found. Please propose to the user to change the topic.")
else:
# return the context to the agent
return context
Use shared_state
to validate previous actions taken by this or other agents, before allowing it to proceed with the next action.
class Action2(BaseTool):
input: str = Field(...)
def run(self):
if self._shared_state.get("action_1_result", None) is "failure":
raise ValueError("Please proceed with the Action1 tool first.")
else:
return "Success. The action has been taken."
Use Special Types
Restrict the agent to only use specific values for a field, instead of letting it wander by itself.
from typing import Literal
class RunCommand(BaseTool):
"""
Execute predefined system commands.
"""
command: Literal["start", "stop"] = Field(..., description="Command to execute: 'start' or 'stop'.")
def run(self):
if self.command == "start":
# Start command logic
pass
elif self.command == "stop":
# Stop command logic
pass
else:
raise ValueError("Invalid command")
or use special Pydantic types like EmailStr
.
from pydantic import EmailStr
class EmailSender(BaseTool):
recipient: EmailStr = Field(..., description="Email recipient's address.")
Combine Multiple Methods
Combine multiple methods to make your execution flow more readable.
class CompositeTool(BaseTool):
"""
A tool that combines several methods to perform a series of actions.
"""
input_data: str = Field(..., description="Input data for the composite operation.")
def run(self):
# Step 1: Process data
processed_data = self.process_data(self.input_data)
# Step 2: Analyze results
analysis = self.analyze_results(processed_data)
# Step 3: Format output
output = self.format_output(analysis)
return output
def process_data(self, data):
# Implement data processing logic
pass
def analyze_results(self, data):
# Implement analysis logic
pass
def format_output(self, data):
# Implement output formatting
pass
Include a Test Case
Include test cases at the bottom of each tool file.
if __name__ == "__main__":
# Test the EmailSender tool
email_sender = EmailSender(
chain_of_thought="Plan to inform the team about the update.",
recipient="user@example.com",
subject="Project Update",
body="The project is on track."
)
assert email_sender.run() == "Email sent successfully."
Next Steps
We highly recommend you explore the resources provided in the Pydantic is all you need section.