Building Your Own Framework
Master designing and building custom agentic AI frameworks from scratch
Your Progress
0 / 5 completedTool Registry & Integration
Tools are the actions your agent can take. A robust tool registry handles registration, validation, and safe execution of functions.
Tool Registry Implementation
Complete Tool Registry
from typing import Dict, Any, Callable, Optional
from pydantic import BaseModel
import inspect
class ToolRegistry:
def __init__(self):
self.tools: Dict[str, Dict] = {}
def register(
self,
name: str,
func: Callable,
description: str,
schema: Optional[BaseModel] = None
):
"""Register a tool with metadata"""
# Extract function signature
sig = inspect.signature(func)
parameters = {
param.name: {
"type": param.annotation.__name__ if param.annotation != inspect.Parameter.empty else "any",
"required": param.default == inspect.Parameter.empty
}
for param in sig.parameters.values()
}
self.tools[name] = {
"function": func,
"description": description,
"parameters": parameters,
"schema": schema,
"is_async": inspect.iscoroutinefunction(func)
}
def execute(self, name: str, args: Dict[str, Any]) -> Any:
"""Execute a tool with validation"""
if name not in self.tools:
raise ValueError(f"Tool '{name}' not found")
tool = self.tools[name]
# Validate with schema if provided
if tool["schema"]:
try:
validated_args = tool["schema"](**args)
args = validated_args.dict()
except Exception as e:
return {"error": f"Validation failed: {str(e)}"}
# Execute tool
try:
if tool["is_async"]:
import asyncio
return asyncio.run(tool["function"](**args))
else:
return tool["function"](**args)
except Exception as e:
return {"error": f"Execution failed: {str(e)}"}
def get_tool_descriptions(self) -> str:
"""Generate tool descriptions for LLM"""
descriptions = []
for name, tool in self.tools.items():
params = ", ".join([
f"{p}:{info['type']}" for p, info in tool["parameters"].items()
])
descriptions.append(
f"- {name}({params}): {tool['description']}"
)
return "\n".join(descriptions)Interactive: Tool Patterns
Simple Tool
Basic synchronous function with no validation
def calculator(operation: str, a: float, b: float) -> float:
"""Simple calculator tool"""
if operation == "add":
return a + b
elif operation == "subtract":
return a - b
elif operation == "multiply":
return a * b
elif operation == "divide":
return a / b if b != 0 else "Error: Division by zero"
# Register with agent
agent.register_tool(
name="calculator",
func=calculator,
description="Performs basic math operations: add, subtract, multiply, divide"
)Pros:
- ✓Fast and simple
- ✓No overhead
- ✓Easy to debug
Cons:
- ✗No input validation
- ✗Blocking execution
- ✗Poor error handling
Tool Discovery for LLM
Generate Tool Prompt
def generate_tool_prompt(tools: Dict) -> str:
"""Create prompt describing available tools for LLM"""
prompt = """You are an AI agent with access to the following tools:
"""
for name, tool in tools.items():
prompt += f"**{name}**\n"
prompt += f"Description: {tool['description']}\n"
prompt += f"Parameters:\n"
for param, info in tool['parameters'].items():
required = " (required)" if info['required'] else " (optional)"
prompt += f" - {param}: {info['type']}{required}\n"
prompt += "\n"
prompt += """
To use a tool, respond with JSON:
{
"tool": "tool_name",
"args": {"param1": "value1", "param2": "value2"}
}
To provide final answer:
{
"final_answer": "your answer here"
}
"""
return prompt🎯 Tool Integration Best Practices
- •Clear descriptions: Help LLM understand when and how to use each tool
- •Schema validation: Use Pydantic or similar for input type checking
- •Error handling: Return structured errors, don't crash the agent
- •Timeout protection: Set execution time limits for long-running tools