Skip to main contentSkip to footer
EsempioscriptadvancedEseguibiletool-agent

Livello 3: Agente con chiamata di strumenti — Autonomia circoscritta

L’agente decide quali strumenti chiamare e in quale ordine, ma solo all’interno di un insieme fisso di capacità ben definite.

Fatti chiave

Livello
advanced
Runtime
Python • Pydantic + Python Dotenv
Pattern
Agent autonomy inside a fixed capability boundary
Interazione
Sandbox live • Script
Aggiornato
14 marzo 2026

Naviga questo esempio

Vista rapida del flusso

Come questo esempio si muove tra input, esecuzione e risultato rivedibile
Livello 3: Agente con chiamata… -> Use bounded tools -> Run the agent task -> Task framing -> Tool trace -> Resolution output

Avvio

Livello 3: Agente con chiamata…

Checkpoint

Use bounded tools

Esito

Run the agent task

Perché esiste questa pagina

Questo esempio è mostrato sia come codice sorgente reale che come pattern di interazione orientato al prodotto, così i discenti possono collegare implementazione, UX e dottrina senza lasciare la libreria.

Flusso visivoCodice realeSandbox o walkthroughAccesso MCP
Come dovrebbe essere usato questo esempio nella piattaforma?

Usa prima la sandbox per comprendere il pattern di esperienza, poi ispeziona il sorgente per vedere come il confine del prodotto, il confine del modello e il confine della dottrina sono effettivamente implementati.

UX pattern: Agent autonomy inside a fixed capability boundary
The agent chooses the tool order
Tools are fixed and inspectable
Structured output summarizes autonomous action
Riferimenti sorgente
Voce di libreria
agents-agent-complexity-3-tool-calling-agent
Percorso sorgente
content/example-library/sources/agents/agent-complexity/3-tool-calling-agent.py
Librerie
pydantic, python-dotenv
Requisiti di runtime
Ambiente del repository locale
Principi correlati
Progettare per la delega piuttosto che per la manipolazione diretta, Sostituire la magia implicita con modelli mentali chiari, Rappresentare il lavoro delegato come un sistema, non solo come una conversazione, Ottimizzare per la guida, non solo per l'inizio

3-tool-calling-agent.py

python
"""
Level 3: Tool-Calling Agent — Scoped Autonomy
The agent decides which tools to call and in what order,
but only within a fixed set of well-defined capabilities.
"""

from dataclasses import dataclass

from pydantic import BaseModel
from pydantic_ai import Agent, RunContext
from dotenv import load_dotenv
from utils import print_agent_trace
import nest_asyncio

load_dotenv()

nest_asyncio.apply()


# --- Dependencies ---


@dataclass
class CustomerDeps:
    customer_id: str
    db: dict  # simplified — in production this would be a real DB client


# --- Output ---


class BillingResolution(BaseModel):
    action_taken: str
    refund_amount: float | None
    follow_up_needed: bool


# --- Agent ---


billing_agent = Agent(
    "anthropic:claude-sonnet-4-6",
    deps_type=CustomerDeps,
    output_type=BillingResolution,
    system_prompt=(
        "You are a billing support agent. Use the available tools to look up "
        "customer data, check policies, and resolve billing issues. "
        "Always verify the charge before issuing a refund."
    ),
)


# --- Tools (the agent decides when and how to use these) ---


@billing_agent.tool
async def get_customer_balance(ctx: RunContext[CustomerDeps]) -> str:
    balance = ctx.deps.db.get("balance", 0)
    return f"Current balance: ${balance:.2f}"


@billing_agent.tool
async def get_recent_charges(ctx: RunContext[CustomerDeps]) -> str:
    charges = ctx.deps.db.get("charges", [])
    return "\n".join(
        f"- ${c['amount']:.2f} on {c['date']}: {c['description']}" for c in charges
    )


@billing_agent.tool
async def check_refund_policy(
    ctx: RunContext[CustomerDeps], charge_description: str
) -> str:
    return (
        f"Policy for '{charge_description}': "
        "Duplicate charges are eligible for automatic refund within 30 days. "
        "Refunds over $100 require manager approval."
    )


@billing_agent.tool
async def issue_refund(
    ctx: RunContext[CustomerDeps], amount: float, reason: str
) -> str:
    return f"Refund of ${amount:.2f} issued successfully. Reason: {reason}"


# --- Run ---


if __name__ == "__main__":
    import asyncio

    deps = CustomerDeps(
        customer_id="cust_12345",
        db={
            "balance": 149.97,
            "charges": [
                {
                    "amount": 49.99,
                    "date": "2025-02-01",
                    "description": "Monthly subscription",
                },
                {
                    "amount": 49.99,
                    "date": "2025-02-01",
                    "description": "Monthly subscription",
                },
                {
                    "amount": 49.99,
                    "date": "2025-01-01",
                    "description": "Monthly subscription",
                },
            ],
        },
    )

    result = asyncio.run(
        billing_agent.run(
            "I was charged twice on Feb 1st for my subscription. Please fix this.",
            deps=deps,
        )
    )

    print_agent_trace(result)

    print(f"\nAction: {result.output.action_taken}")
    print(f"Refund: ${result.output.refund_amount}")
    print(f"Follow-up needed: {result.output.follow_up_needed}")
Cosa dovrebbe ispezionare il discente nel codice?

Cerca il punto esatto in cui lo scope del sistema è delimitato: definizioni di schema, impostazione del prompt, configurazione di runtime e il punto di chiamata che trasforma l'intenzione dell'utente in un'azione concreta del modello o del workflow.

@billing_agent.tool
async def get_recent_charges
async def issue_refund
billing_agent.run(
Come si relaziona la sandbox al sorgente?

La sandbox dovrebbe rendere leggibile l'UX: cosa vede l'utente, cosa sta decidendo il sistema e come il risultato diventa revisionabile. Il sorgente mostra poi come quel comportamento è effettivamente implementato.

Choose a billing scenario.
Run the investigation and inspect the tool trace.
Review the structured billing resolution before accepting the outcome.
SandboxAgent autonomy inside a fixed capability boundary
Scoped autonomy with visible tool use

This example turns the sandbox into a tool-using support workflow where the agent can investigate and act, but only through a bounded toolset.

Spiegazione UX

The user asks for an outcome, not a sequence of steps. The experience should still make it clear which tools the system consulted and when the agent crossed from reasoning into action.

Spiegazione AI Design

The model is allowed to choose tools and ordering, but only from a curated set. That creates useful autonomy without handing over the entire runtime or hiding all intermediate work.

Guida all'interazione

  1. 1Choose a billing scenario.
  2. 2Run the investigation and inspect the tool trace.
  3. 3Review the structured billing resolution before accepting the outcome.

User request

I was charged twice on Feb 1st for my subscription. Please fix this.

Allowed tools onlyAgent chooses orderStructured resolution

Tool trace

The trace appears as the agent decides which tool to call next.

Resolution

The final output should summarize what the agent did, not leave the action implicit.

Autonomy boundary

  • The agent chooses the tool order
  • Tools are fixed and inspectable
  • Structured output summarizes autonomous action
Usato in corsi e percorsi

Questo esempio attualmente è indipendente nella libreria, ma si connette comunque al sistema dei principi e alla famiglia di esempi più ampia.

Principi correlati

Runtime architecture

Usa questo esempio nei tuoi agenti

Questo esempio è disponibile anche tramite il layer agent-ready del blueprint. Usa la pagina Per agenti per recuperare MCP pubblico, export deterministici e setup per Claude o Cursor.

Definisci trigger, contesto e confini prima di aumentare l'autonomia
Rendi espliciti controllo, osservabilita e recovery nel runtime
Scegli i pattern operativi giusti prima di delegare ai workflow