Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Annotazioni
L'API di esposizione progressiva dello strumento (FunctionInvocationContext.add_tools / remove_tools) è attualmente solo Python.
Questa pagina illustra tre tecniche complementari per controllare quali strumenti un modello può chiamare e in quale ordine, tutti all'interno di un'esecuzione di un singolo agente, senza richiedere un flusso di lavoro:
- Esposizione progressiva degli strumenti : aggiungere o rimuovere strumenti in fase di esecuzione dall'interno di uno strumento o un middleware di funzione, quindi il modello vede solo gli strumenti che è pronto per l'uso.
- Filtro middleware — utilizzare un middleware di funzione per convalidare gli argomenti della chiamata e restituire un feedback correttivo senza eseguire la funzione sottostante.
-
Prima chiamata forzata : usare
tool_choiceper richiedere al modello di chiamare uno strumento specifico prima di qualsiasi altro.
Annotazioni
I vincoli di ordinamento pairwise, ad esempio "chiamare get_record sempre prima update_record" non richiedono un flusso di lavoro. Le tecniche su questa pagina gestiscono tale schema in un'unica esecuzione. I flussi di lavoro servono per una vera orchestrazione in più fasi tra esecuzioni diverse o rami paralleli.
Esposizione progressiva degli strumenti
L'esposizione progressiva degli strumenti consente di avviare un'esecuzione con un piccolo set di strumenti e aggiungere o rimuovere strumenti in risposta ai risultati degli strumenti precedenti, tutti all'interno della stessa esecuzione. Il modello vede solo il set aggiornato nella successiva iterazione del ciclo di chiamata di funzione; le chiamate agli strumenti già richieste nel batch in anteprima vengono comunque eseguite prima che la modifica venga applicata.
L'API è sperimentale e vive su FunctionInvocationContext:
| Membro | Descrizione |
|---|---|
ctx.tools |
L'insieme attivo e modificabile list degli strumenti per l'esecuzione corrente.
None quando la funzione viene richiamata all'esterno di un ciclo di chiamata di funzione. |
ctx.add_tools(tools) |
Aggiungere uno o più strumenti. I callable vengono incapsulati come FunctionTool. Aggiungere nuovamente lo stesso oggetto è un no-op; un oggetto diverso con un nome duplicato provoca ValueError. Tutto o niente: se uno strumento nel batch genera un aumento, non viene aggiunto alcuno. |
ctx.remove_tools(tools) |
Rimuovi per nome, oggetto tool o oggetto invocabile. I nomi non presenti nell'elenco vengono ignorati automaticamente. |
Entrambi gli helper emettono ExperimentalWarning la prima volta che vengono chiamati in un processo (ID della funzionalità PROGRESSIVE_TOOLS). La chiamata di uno degli helper all'esterno di un ciclo di chiamata di funzione genera RuntimeError.
Importante
L'elenco degli strumenti viene reimpostato sul set originale in ogni nuova agent.run() chiamata, quindi tutti i cancelli riaccendono automaticamente per ogni turno.
Annotazioni
L'esposizione progressiva degli strumenti si applica solo al ciclo di chiamata a funzioni standard. Non è disponibile per i provider CodeAct (agent-framework-monty, agent-framework-hyperlight), in cui il modello vede una singola superficie di esecuzione del codice anziché singoli schemi degli strumenti. La chiamata add_tools o remove_tools dall'interno di una sandbox CodeAct genera RuntimeError. Per modificare il set di strumenti per un agente CodeAct, usare i metodi del provider tra add_tools / remove_tool / clear_tools le esecuzioni.
Modello dello strumento di caricamento
Registrare preventivamente un piccolo insieme di strumenti "loader" e consentire al modello di caricare strumenti aggiuntivi su richiesta. In questo modo lo schema iniziale viene ridotto, migliorando l'accuratezza della selezione degli strumenti e riducendo i costi.
import asyncio
import warnings
from typing import Annotated
from agent_framework import Agent, FunctionInvocationContext, tool
from agent_framework.openai import OpenAIChatClient
from pydantic import Field
warnings.filterwarnings("ignore", category=UserWarning) # suppress ExperimentalWarning for brevity
@tool(approval_mode="never_require")
def factorial(n: Annotated[int, Field(description="A non-negative integer.")]) -> str:
"""Compute the factorial of n."""
if n < 0:
return "Error: n must be a non-negative integer."
result = 1
for value in range(2, n + 1):
result *= value
return f"{n}! = {result}"
@tool(approval_mode="never_require")
def fibonacci(n: Annotated[int, Field(description="The 0-based index in the Fibonacci sequence.")]) -> str:
"""Compute the n-th Fibonacci number."""
if n < 0:
return "Error: n must be a non-negative integer."
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return f"fib({n}) = {a}"
# The ctx parameter is injected by the framework and is NOT visible to the model.
@tool(approval_mode="never_require")
def load_math_tools(ctx: FunctionInvocationContext) -> str:
"""Load additional math tools (factorial, fibonacci) so they can be used."""
ctx.add_tools([factorial, fibonacci])
return "Loaded math tools: factorial, fibonacci. You can now call them."
async def main() -> None:
agent = Agent(
client=OpenAIChatClient(),
name="MathAgent",
instructions=(
"You are a math assistant. "
"If you need math capabilities that are not yet available, call load_math_tools first."
),
tools=[load_math_tools], # agent starts with only the loader
)
print(await agent.run("What is 5 factorial?"))
asyncio.run(main())
L'esempio eseguibile completo si trova in python/samples/02-agents/tools/dynamic_tool_exposure.py.
Modello di controllo
Registrare inizialmente solo lo strumento di lettura. Lo strumento di lettura aggiunge lo strumento di scrittura dopo un recupero riuscito, quindi il modello non può chiamare lo strumento di scrittura prima dell'esecuzione dello strumento di lettura.
from agent_framework import Agent, FunctionInvocationContext, tool
from agent_framework.openai import OpenAIChatClient
_last_fetched_id: str | None = None
@tool(approval_mode="never_require")
def get_record(record_id: str, ctx: FunctionInvocationContext) -> str:
"""Fetch a record. Unlocks update_record for the same record."""
global _last_fetched_id
_last_fetched_id = record_id
ctx.add_tools(update_record) # gate: expose the write tool now
return f"Record {record_id}: title='Example record', status='open'"
@tool(approval_mode="never_require")
def update_record(record_id: str, status: str) -> str:
"""Update the status of a record."""
return f"Updated record {record_id} to status '{status}'."
agent = Agent(
client=OpenAIChatClient(),
name="RecordAgent",
instructions="You help manage records. Fetch a record before updating it.",
tools=[get_record], # update_record is hidden until get_record runs
)
Poiché ctx.tools si reimposta su [get_record] all'inizio di ogni esecuzione, il gate si riarma automaticamente a ogni turno di conversazione.
Controllo del middleware
Il middleware della funzione può esaminare gli argomenti di una chiamata allo strumento in sospeso e rifiutarlo prima dell'esecuzione della funzione sottostante impostando context.result senza chiamare call_next(). La stringa assegnata a context.result viene restituita al modello come risultato della funzione, fornendo un feedback correttivo.
Ciò è utile per i controlli a livello di argomento che richiedono informazioni non disponibili in fase di definizione dello schema, ad esempio verificando che un aggiornamento sia destinato allo stesso elemento recuperato in precedenza nell'esecuzione.
from collections.abc import Awaitable, Callable
from agent_framework import FunctionInvocationContext
_last_fetched_id: str | None = None
async def enforce_read_before_write(
context: FunctionInvocationContext,
call_next: Callable[[], Awaitable[None]],
) -> None:
"""Reject update_record calls that target a different record than the one fetched."""
if context.function.name == "update_record":
requested_id = context.arguments.get("record_id") if hasattr(context.arguments, "get") else None
if requested_id != _last_fetched_id:
# Set result without calling call_next — the function never executes.
context.result = (
f"Error: you must fetch record '{requested_id}' before updating it. "
f"Last fetched record was '{_last_fetched_id}'."
)
return
await call_next()
Aggiungere il middleware all'agente:
agent = Agent(
client=OpenAIChatClient(),
name="RecordAgent",
instructions="Fetch a record before updating it.",
tools=[get_record, update_record],
middleware=[enforce_read_before_write],
)
Per ulteriori informazioni sul middleware di funzione, vedere Definizione del middleware e Override dei risultati.
Forzare una chiamata di strumento con tool_choice
Per fare in modo che il modello richiami uno strumento specifico come prima azione, passa tool_choice con la modalità "required" e required_function_name. Il framework viene reimpostato tool_choiceNone automaticamente dopo la prima iterazione in modo che il modello sia libero nelle iterazioni successive.
result = await agent.run(
"Update record REC-42 to status 'in-progress'.",
tool_choice={"mode": "required", "required_function_name": "get_record"},
)
Il tool_choice campo accetta un ToolMode dict o le stringhe abbreviate "auto", "required"o "none":
from agent_framework import ToolMode
tool_choice: ToolMode = {"mode": "required", "required_function_name": "get_record"}
Semantica e avvertenze
| Behavior | Dettagli |
|---|---|
| Effetto di iterazione successiva |
add_tools
/
remove_tools le mutazioni sono visibili al modello nell'iterazione del ciclo successivo. Le chiamate agli strumenti già inoltrate nel batch corrente vengono comunque completate. |
| Batch in corso | Se il modello richiede più strumenti in un unico batch, tutti vengono eseguiti prima dell'invio dell'elenco degli strumenti aggiornato. |
| Nomi duplicati | L'aggiunta dello stesso oggetto esatto è un no-op. L'aggiunta di un oggetto diverso il cui nome corrisponde a uno strumento esistente genera ValueError. L'intero batch viene convalidato prima di qualsiasi aggiunta, quindi un duplicato a metà di un elenco lascia invariato l'elenco attivo. |
| Errore fuori ciclo | Chiamata add_tools o remove_tools quando ctx.tools is None genera RuntimeError. Ciò si verifica quando la funzione viene richiamata direttamente (ad esempio tramite FunctionTool.invoke) anziché tramite il ciclo dell'agente. |
| Stato sperimentale | Entrambi gli helper emettono ExperimentalWarning alla prima chiamata in ciascun processo. Sopprimi con warnings.filterwarnings("ignore", category=UserWarning) , se desiderato. |
| Ambito di esecuzione | L'elenco degli strumenti live è una nuova copia creata da normalize_tools all'inizio di ogni chiamata a agent.run(). Il contenitore originale tools del chiamante non viene mai modificato. |
| Esclusione CodeAct | Non disponibile per i provider agent-framework-monty o agent-framework-hyperlight CodeAct. |