Module 3 of 10
Module 3Tool Actuation

Function Calling & Tool Use

Empower models to interact with the real world: Master JSON Schema tool definitions, Pydantic validation, runtime error feedback, and safe dynamic dispatch.

1. The Mechanics of LLM Tool Calling

Large Language Models cannot execute code or query APIs on their own. Instead,Function Calling works through a structured protocol:

  1. Schema Declaration: You supply a list of available tools described via JSON Schema(tool names, natural language descriptions, and parameter types).
  2. Model Prediction: When answering a query, the model decides if it needs a tool. Instead of generating plain text, it outputs structured JSON containing the function name and arguments.
  3. Application Execution: Your Python backend intercepts the tool call, executes the underlying Python function, and captures the output.
  4. Observation Injection: The tool output is appended to the message history with role "tool", prompting the model to synthesize the final answer.

2. Pydantic-Driven Tool Schema Definitions

Writing raw JSON Schema manually is tedious and error-prone. In modern Python AI engineering, use Pydantic to enforce strict type checking and auto-generate schema:

from pydantic import BaseModel, Field
from typing import Literal, Optional

# Define the input schema with validation constraints
class SQLQueryInput(BaseModel):
    query: str = Field(
        ..., 
        description="The read-only SELECT SQL query to execute against the PostgreSQL database."
    )
    timeout_seconds: int = Field(
        default=10, 
        ge=1, 
        le=60, 
        description="Query timeout limit in seconds."
    )
    format: Literal["json", "markdown_table"] = Field(
        default="json",
        description="Desired output serialization format."
    )

# LangChain or native tool decorator converts this automatically
from langchain_core.tools import tool

@tool(args_schema=SQLQueryInput)
def execute_sql_query(query: str, timeout_seconds: int = 10, format: str = "json") -> str:
    """Executes a validated read-only SQL query against the enterprise warehouse."""
    # Safety Check: Prevent mutation
    normalized = query.strip().upper()
    if any(keyword in normalized for keyword in ["DROP", "DELETE", "UPDATE", "INSERT", "ALTER"]):
        return "Error: Mutation queries are strictly forbidden. Only SELECT queries are permitted."
    
    # Simulate DB Execution
    return f"Executed successfully! Retrieved 3 rows matching: {query}"

3. Resilient Error Recovery & Self-Healing Loops

When an external API returns a 404 Not Found or a SQL database returns a syntax error,never crash your application. Return the error string back to the model as an observation:

How Self-Healing Tool Use Works

When the model sees: Observation: "psycopg2.errors.UndefinedColumn: column 'usr_mail' does not exist. Available columns: [user_id, email, full_name]", the model automatically self-corrects in the next loop and generates: SELECT email FROM users;.

def safe_tool_executor(func, **kwargs):
    """Wraps any tool call in resilient exception handling."""
    try:
        result = func(**kwargs)
        return {"status": "success", "data": result}
    except Exception as e:
        # Pass exception message directly to the LLM so it can adjust its query
        return {
            "status": "error",
            "error_type": type(e).__name__,
            "message": str(e),
            "hint": "Please review parameters and revise your tool call."
        }

4. Dynamic Multi-Tool Dispatcher

A production agent often has access to dozens of tools. Organize them into a typed registry:

class ToolRegistry:
    def __init__(self):
        self._tools = {}
        
    def register(self, name, func, schema):
        self._tools[name] = {"function": func, "schema": schema}
        
    def get_schemas(self):
        return [t["schema"] for t in self._tools.values()]
        
    def execute(self, name, arguments):
        if name not in self._tools:
            return f"Error: Tool '{name}' is not registered."
        return self._tools[name]["function"](**arguments)

# Registering tools
registry = ToolRegistry()
# registry.register("sql_query", execute_sql_query, sql_tool_schema)
# registry.register("web_search", execute_web_search, search_tool_schema)
Next Chapter

LangGraph StateGraph & Loops

Continue to the next advanced agentic AI engineering module.

Continue Learning →

Explore Related Tools

Hand-picked utilities and calculators related to this tool.

Related Tools