Tools in Legion
Tools are powerful functions that agents can use to interact with external systems and perform specific tasks. Learn how to create and use tools effectively in your Legion applications.
What are Tools?
Tools in Legion are decorated functions that:
- Have well-defined inputs and outputs
- Can be shared between agents
- Support parameter injection
- Can be async or sync
- Include built-in validation
Creating Basic Tools
Here's how to create and use tools:
from typing import Annotated, List from datetime import datetime from pydantic import Field from legion import agent, tool # Standalone tool that can be shared between agents @tool def get_current_time( format: Annotated[str, Field(description="Format string for the datetime")] = ( "%Y-%m-%d %H:%M:%S" ) ) -> str: """Get the current time in a specified format.""" return datetime.now().strftime(format) @tool def add_numbers( numbers: Annotated[List[float], Field(description="List of numbers to add together")] ) -> float: """Add a list of numbers together and return the sum.""" return sum(numbers) # Create an agent with tools @agent( model="openai:gpt-4o-mini", temperature=0.2, tools=[get_current_time, add_numbers] # Bind external tools ) class NoteTaker: """An agent that helps with taking and formatting notes.""" # Agent-specific tool @tool def create_note( self, title: Annotated[str, Field(description="Title of the note")], content: Annotated[str, Field(description="Content of the note")], add_timestamp: Annotated[bool, Field( description="Whether to add a timestamp" )] = True ) -> str: """Create a formatted note with an optional timestamp.""" timestamp = ( f" Created at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" if add_timestamp else "" ) return f"# {title} {content}{timestamp}"
Tool Features
- Type Safety: Tools use Pydantic annotations for input/output validation
- Documentation: Tools inherit descriptions from docstrings
- Flexibility: Tools can be standalone or agent-specific
- Reusability: Standalone tools can be shared across agents
Parameter Injection
Tools support parameter injection for sensitive data:
@tool( inject=["api_key", "endpoint"], # Mark these as injectable defaults={ # Default values for injectable parameters "api_key": "sk_test_default_key", "endpoint": "https://api.example.com/v1" } ) def process_api_query( query: Annotated[str, Field(description="The query to process")], api_key: Annotated[str, Field(description="API key for the service")], endpoint: Annotated[str, Field(description="API endpoint")] ) -> str: """Process a query using an external API with injected credentials.""" # In a real application, you would make an actual API call here return f"Processed '{query}' using API at {endpoint}" # When using the tool, you can inject parameters per message response = await agent.aprocess( "Process the query 'test message'", injected_parameters=[ { "tool": process_api_query, "parameters": { "api_key": "sk_prod_key_123", "endpoint": "https://api.prod.example.com/v1" } } ] )
Best Practices
- Use descriptive docstrings for tools
- Leverage type annotations for clear interfaces
- Keep tools focused on single responsibilities
- Use meaningful parameter descriptions
- Consider making tools reusable when possible
- Use parameter injection for sensitive data
Check out Parameter Injection for more advanced tool features.