0Pricing
AI Engineering Academy · Lezione

Elaborare le chiamate agli strumenti nell'applicazione

Rilevi finish_reason tool_calls nella risposta dell'API, estragga i nomi e gli argomenti delle funzioni, esegua la funzione Python corrispondente e invii il risultato al modello.

Elaborare le chiamate agli strumenti nell'applicazione è una lezione AI Engineering Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento AI Engineering Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso AI Engineering Academy include 4 lezioni in totale.

L'oggetto di risposta alla chiamata dello strumento

Quando il modello decide di chiamare una funzione, la risposta dell'API contiene un elenco tool_calls nell'oggetto del messaggio. Ogni chiamata allo strumento ha un id univoco, il function.name da chiamare e function.arguments, ovvero una stringa JSON contenente gli argomenti che il modello desidera passare. Spetta al codice della Sua applicazione analizzare questi dati ed eseguire la funzione.

from openai import OpenAI
import json

client = OpenAI()

response = client.chat.completions.create(
    model='gpt-4o',
    messages=[{'role': 'user', 'content': 'What is the weather in Paris?'}],
    tools=tools  # defined previously
)

message = response.choices[0].message

if response.choices[0].finish_reason == 'tool_calls':
    for tool_call in message.tool_calls:
        print('Call ID:', tool_call.id)
        print('Function name:', tool_call.function.name)
        print('Arguments (JSON string):', tool_call.function.arguments)

Analizzare gli argomenti delle funzioni

Il campo function.arguments è una stringa codificata in JSON, non un dizionario Python. Deve analizzarlo con json.loads(). Racchiuda sempre questa operazione in un blocco try/except: nonostante le indicazioni dello schema, talvolta il modello produce JSON non valido e occorre gestire la situazione in modo appropriato.

import json

def parse_tool_call(tool_call) -> dict:
    '''Parse a tool call's arguments from JSON string to dict.'''
    try:
        args = json.loads(tool_call.function.arguments)
        return args
    except json.JSONDecodeError as e:
        print(f'Failed to parse arguments for {tool_call.function.name}: {e}')
        print(f'Raw arguments: {tool_call.function.arguments}')
        return {}

# Usage
tool_call = message.tool_calls[0]
args = parse_tool_call(tool_call)
print('Parsed args:', args)  # {'location': 'Paris', 'unit': 'celsius'}

Inviare alla funzione corretta

Utilizzi function.name per inviare la richiesta alla funzione Python corretta. Un approccio ordinato consiste nel mantenere le funzioni in un dizionario che associa ogni nome al relativo callable. In questo modo evita catene fragili di if/elif e può aggiungere facilmente nuovi strumenti in seguito.

def get_current_weather(location: str, unit: str = 'celsius') -> str:
    # Real implementation calls a weather API
    return f'{location}: 18{chr(176)}C, partly cloudy'

def create_calendar_event(title: str, start_time: str, duration_minutes: int, **kwargs) -> str:
    return f'Event created: {title} at {start_time} for {duration_minutes} minutes'

# Tool registry: maps function names to callables
TOOL_REGISTRY = {
    'get_current_weather': get_current_weather,
    'create_calendar_event': create_calendar_event
}

def execute_tool_call(tool_call) -> str:
    name = tool_call.function.name
    args = parse_tool_call(tool_call)

    if name not in TOOL_REGISTRY:
        return f'Unknown function: {name}'

    try:
        result = TOOL_REGISTRY[name](**args)
        return str(result)
    except Exception as e:
        return f'Function {name} raised an error: {str(e)}'

Inviare i risultati al modello

Dopo aver eseguito la funzione, deve inviare il risultato al modello in una chiamata API successiva. Aggiunga alla conversazione il messaggio dell'assistente, che contiene le tool_calls, quindi aggiunga un nuovo messaggio con role='tool', il tool_call_id e il risultato della funzione come contenuto. Infine, chiami nuovamente l'API.

def run_tool_call_loop(messages: list, tools: list) -> str:
    response = client.chat.completions.create(
        model='gpt-4o',
        messages=messages,
        tools=tools
    )
    message = response.choices[0].message
    messages.append(message)  # Add assistant's tool_calls message

    # Execute all tool calls and collect results
    for tool_call in (message.tool_calls or []):
        result = execute_tool_call(tool_call)
        # Add each tool result as a 'tool' role message
        messages.append({
            'role': 'tool',
            'tool_call_id': tool_call.id,
            'content': result
        })

    # Second API call with results appended
    final_response = client.chat.completions.create(
        model='gpt-4o',
        messages=messages,
        tools=tools
    )
    return final_response.choices[0].message.content

Il ciclo completo della conversazione

Un'interazione completa con una chiamata allo strumento coinvolge quattro messaggi nella cronologia della conversazione: il messaggio dell'utente, il messaggio dell'assistente che richiede una chiamata allo strumento, il messaggio con il risultato dello strumento e la risposta finale dell'assistente che integra il risultato. Comprendere questa struttura è essenziale per creare assistenti capaci di utilizzare strumenti in conversazioni su più turni.

# The full message history for a tool-calling conversation:
conversation = [
    {'role': 'user', 'content': 'What is the weather in Tokyo?'},

    # Model requests a tool call (added by run_tool_call_loop)
    # {'role': 'assistant', 'content': None, 'tool_calls': [...]},

    # Application sends tool result back
    # {'role': 'tool', 'tool_call_id': 'call_abc123', 'content': 'Tokyo: 22C, sunny'},

    # Model produces final human-readable response
    # {'role': 'assistant', 'content': 'The weather in Tokyo is 22 degrees Celsius and sunny.'}
]

final_answer = run_tool_call_loop(
    [{'role': 'user', 'content': 'What is the weather in Tokyo?'}],
    tools
)
print(final_answer)

Gestire il caso in cui non viene chiamato alcuno strumento

Talvolta il modello risponde direttamente senza chiamare alcuno strumento: finish_reason sarà 'stop' anziché 'tool_calls'. Verifichi sempre questo caso prima di tentare di elaborare le chiamate agli strumenti. Un'implementazione robusta gestisce in modo chiaro entrambi i rami.

def smart_complete(user_message: str) -> str:
    messages = [{'role': 'user', 'content': user_message}]
    response = client.chat.completions.create(
        model='gpt-4o',
        messages=messages,
        tools=tools
    )
    choice = response.choices[0]

    if choice.finish_reason == 'stop':
        # Model answered directly without calling a tool
        return choice.message.content

    elif choice.finish_reason == 'tool_calls':
        # Process tool calls
        messages.append(choice.message)
        for tc in choice.message.tool_calls:
            result = execute_tool_call(tc)
            messages.append({'role': 'tool', 'tool_call_id': tc.id, 'content': result})
        # Get final answer
        final = client.chat.completions.create(model='gpt-4o', messages=messages)
        return final.choices[0].message.content

    return 'Unexpected finish reason: ' + choice.finish_reason

Convalidare gli argomenti prima dell'esecuzione

Talvolta il modello può passare argomenti che non superano la convalida della logica aziendale: una durata negativa, un indirizzo email non valido o una data passata. Convalidi gli argomenti prima di chiamare la funzione reale e restituisca una stringa di errore descrittiva se la convalida non riesce. Il modello potrà quindi correggere gli argomenti nel turno successivo.

from pydantic import BaseModel, ValidationError
from datetime import datetime

class CreateEventArgs(BaseModel):
    title: str
    start_time: str  # ISO 8601
    duration_minutes: int

def safe_create_event(tool_call) -> str:
    try:
        raw_args = json.loads(tool_call.function.arguments)
        validated = CreateEventArgs(**raw_args)
        # Additional business rule
        event_time = datetime.fromisoformat(validated.start_time)
        if event_time < datetime.now():
            return 'Error: start_time must be in the future.'
        return create_calendar_event(**validated.dict())
    except ValidationError as e:
        return f'Invalid arguments: {e}'

Registrare le interazioni con le chiamate agli strumenti

Registri sempre le interazioni con le chiamate agli strumenti per il debugging e l'analisi. Registri il nome della funzione, gli argomenti, il risultato e il tempo di esecuzione. Questi dati aiutano a identificare quali strumenti vengono chiamati più spesso, quali falliscono e quali schemi di argomenti produce il modello: informazioni preziose per migliorare gli schemi e le implementazioni delle funzioni.

import time
import logging

logger = logging.getLogger('tool_calls')

def logged_execute(tool_call) -> str:
    name = tool_call.function.name
    args_str = tool_call.function.arguments
    start = time.time()
    result = execute_tool_call(tool_call)
    elapsed = time.time() - start

    logger.info(
        'Tool call executed',
        extra={
            'function': name,
            'arguments': args_str,
            'result_length': len(result),
            'elapsed_ms': round(elapsed * 1000)
        }
    )
    return result

Considerazioni sulla sicurezza delle chiamate agli strumenti

Non esegua mai funzioni arbitrarie basandosi sull'output del modello senza una convalida. Inserisca sempre nella whitelist i nomi esatti delle funzioni in TOOL_REGISTRY, convalidi tutti gli argomenti e verifichi l'autorizzazione prima di eseguire le azioni. Il modello è un chiamante non attendibile: un prompt malevolo potrebbe tentare di invocare funzioni distruttive se la logica di dispatch è troppo permissiva.

  • Consenta solo le funzioni elencate esplicitamente in TOOL_REGISTRY
  • Convalidi gli input con Pydantic prima dell'esecuzione
  • Richieda l'autorizzazione per le operazioni di scrittura/eliminazione

Restituire risultati strutturati e dettagliati

I risultati degli strumenti non devono essere necessariamente stringhe semplici. Può restituire dati in formato JSON, tabelle o riepiloghi. Restituire dati strutturati come JSON consente al modello di analizzare e citare campi specifici nella risposta finale. Per risultati di grandi dimensioni, restituisca un riepilogo con i fatti principali invece di riversare tutti i dati grezzi nel contesto.

def get_order_status(order_id: str) -> str:
    # Fetch from real database
    order = {'id': order_id, 'status': 'shipped', 'estimated_delivery': '2024-03-15', 'carrier': 'FedEx', 'tracking': 'FX123456'}
    # Return concise summary, not raw DB record
    return (
        f'Order {order_id}: Status={order["status"]}, '
        f'Estimated delivery: {order["estimated_delivery"]}, '
        f'Carrier: {order["carrier"]}, Tracking: {order["tracking"]}'
    )

Conversazioni su più turni con utilizzo di strumenti

Un modello efficace consiste in una conversazione su più turni in cui il modello chiama gli strumenti attraverso diversi messaggi dell'utente, accumulando contesto. Mantenga sempre l'intera cronologia della conversazione, comprese le chiamate agli strumenti e i risultati precedenti, in modo che il modello possa fare riferimento alle risposte già fornite senza chiamare nuovamente gli strumenti inutilmente.

Verifica rapida

Verifichi la Sua comprensione della gestione delle chiamate agli strumenti nella Sua applicazione.

Riepilogo della lezione

In questa lezione ha imparato che: gli argomenti delle chiamate agli strumenti arrivano come stringa JSON e devono essere analizzati con json.loads(), un dizionario TOOL_REGISTRY associa i nomi delle funzioni ai callable per un dispatch ordinato e i risultati tornano al modello come messaggi con role='tool' e tool_call_ids corrispondenti. Ora gestirà il caso in cui il modello chiami più funzioni contemporaneamente tramite il function calling parallelo.

Domande Frequenti

La lezione «Elaborare le chiamate agli strumenti nell'applicazione» è gratuita?

Sì — il testo completo di «Elaborare le chiamate agli strumenti nell'applicazione» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso AI Engineering Academy, passa a CoddyKit PRO. Il corso AI Engineering Academy include 4 lezioni in totale.

Cosa imparerò in «Elaborare le chiamate agli strumenti nell'applicazione»?

Rilevi finish_reason tool_calls nella risposta dell'API, estragga i nomi e gli argomenti delle funzioni, esegua la funzione Python corrispondente e invii il risultato al modello. Eserciti AI Engineering Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare AI Engineering Academy?

Non è richiesta alcuna esperienza precedente. AI Engineering Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «Elaborare le chiamate agli strumenti nell'applicazione»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione AI Engineering Academy?

Sì. Ogni lezione AI Engineering Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Definire gli schemi delle funzioni per l'API
  2. Elaborare le chiamate agli strumenti nell'applicazione
  3. Chiamate di funzioni in parallelo
  4. Creare un'interfaccia al database in linguaggio naturale
← Torna a AI Engineering Academy