Chiamata di strumenti

Le chiamate di strumenti, note anche come chiamate di funzioni, sono un modo strutturato per consentire agli LLM di inviare richieste all'applicazione che li ha chiamati. Tu definisci gli strumenti che vuoi rendere disponibili al modello, che farà richieste di strumenti alla tua app in base alle necessità per soddisfare i prompt che gli fornisci.

I casi d'uso delle chiamate allo strumento rientrano generalmente in alcuni temi:

Fornire a un LLM l'accesso a informazioni con cui non è stato addestrato

  • Informazioni che cambiano di frequente, ad esempio il prezzo di un'azione o il meteo corrente.
  • Informazioni specifiche per il dominio della tua app, ad esempio informazioni sui prodotti o profili degli utenti.

Tieni presente la sovrapposizione con la retrieval augmented generation (RAG), che è anche un modo per consentire a un LLM di integrare informazioni oggettive nelle sue generazioni. La RAG è una soluzione più complessa, più adatta quando hai una grande quantità di informazioni o quando le informazioni più pertinenti per un prompt sono ambigue. D'altra parte, se il recupero delle informazioni di cui ha bisogno l'LLM è una semplice chiamata di funzione o una ricerca nel database, la chiamata dello strumento è più appropriata.

Introduzione di un grado di determinismo in un flusso di lavoro LLM

  • Eseguire calcoli che l'LLM non è in grado di completare in modo affidabile.
  • Forzare un LLM a generare un testo letterale in determinate circostanze, ad esempio quando si risponde a una domanda sui termini di servizio di un'app.

Eseguire un'azione quando viene avviata da un modello LLM

  • Accendere e spegnere le luci in un'assistente domestica basata su LLM
  • Prenotazione di tavoli in un agente di ristoranti basato su LLM

Prima di iniziare

Se vuoi eseguire gli esempi di codice in questa pagina, completa prima i passaggi descritti nella guida Introduzione. Tutti gli esempi presuppongono che tu abbia già configurato un progetto con le dipendenze Genkit installate.

Questa pagina illustra una delle funzionalità avanzate dell'astrazione del modello di Genkit, quindi, prima di addentrarti troppo in profondità, devi conoscere i contenuti della pagina Generare contenuti con modelli di IA. Inoltre, devi conoscere il sistema di Genkit per la definizione degli schemi di input e output, descritto nella pagina Fluidi.

Panoramica delle chiamate allo strumento

A livello generale, un'interazione di chiamata dello strumento con un LLM è simile alla seguente:

  1. L'applicazione chiamante presenta all'LLM una richiesta e include anche nel prompt un elenco di strumenti che l'LLM può utilizzare per generare una risposta.
  2. L'LLM genera una risposta completa o una richiesta di chiamata allo strumento in un formato specifico.
  3. Se chi chiama riceve una risposta completa, la richiesta viene soddisfatta e l'interazione termina. Se invece chi chiama riceve una chiamata dello strumento, esegue la logica appropriata e invia una nuova richiesta all'LLM contenente il prompt originale o una sua variante, nonché il risultato della chiamata dello strumento.
  4. L'LLM gestisce il nuovo prompt come indicato nel passaggio 2.

Affinché questa operazione funzioni, devono essere soddisfatti diversi requisiti:

  • Il modello deve essere addestrato a effettuare richieste di strumenti quando è necessario per completare un prompt. La maggior parte dei modelli più grandi forniti tramite API web, come Gemini e Claude, può farlo, ma spesso i modelli più piccoli e specializzati non possono. Genkit genera un errore se provi a fornire strumenti a un modello che non li supporta.
  • L'applicazione chiamante deve fornire al modello le definizioni degli strumenti nel formato che prevede.
  • L'applicazione chiamante deve chiedere al modello di generare richieste di chiamata allo strumento nel formato previsto dall'applicazione.

Chiamate di strumenti con Genkit

Genkit fornisce un'unica interfaccia per le chiamate allo strumento con i modelli che lo supportano. Ogni plug-in del modello garantisce che gli ultimi due dei criteri sopra indicati siano soddisfatti e la funzione generate() dell'istanza Genkit esegue automaticamente il loop di chiamata dello strumento descritto in precedenza.

Supporto dei modelli

Il supporto delle chiamate allo strumento dipende dal modello, dall'API del modello e dal plug-in Genkit. Consulta la documentazione pertinente per stabilire se è probabile che le chiamate allo strumento siano supportate. Inoltre:

  • Genkit genera un errore se provi a fornire strumenti a un modello che non li supporta.
  • Se il plug-in esporta i riferimenti ai modelli, la proprietà info.supports.tools indicarà se supporta le chiamate allo strumento.

Strumenti di definizione

Utilizza la funzione defineTool() dell'istanza Genkit per scrivere le definizioni degli strumenti:

import { genkit, z } from 'genkit';
import { googleAI, gemini15Flash } from '@genkitai/google-ai';

const ai = genkit({
  plugins: [googleAI()],
  model: gemini15Flash,
});

const getWeather = ai.defineTool(
  {
    name: 'getWeather',
    description: 'Gets the current weather in a given location',
    inputSchema: z.object({ 
      location: z.string().describe('The location to get the current weather for')
    }),
    outputSchema: z.string(),
  },
  async (input) => {
    // Here, we would typically make an API call or database query. For this
    // example, we just return a fixed value.
    return 'The current weather in ${input.location} is 63°F and sunny.';
  }
);

La sintassi è simile a quella di defineFlow(), ma i parametri name, description e inputSchema sono obbligatori. Quando scrivi una definizione dello strumento, presta particolare attenzione alla formulazione e alla descrittività di questi parametri. Sono fondamentali per consentire all'LLM di utilizzare in modo efficace gli strumenti disponibili.

Utilizzare gli strumenti

Includi strumenti definiti nei prompt per generare contenuti.

Genera

const response = await ai.generate({
  prompt: 'What is the weather in Baltimore?',
  tools: [getWeather],
});

definePrompt

const weatherPrompt = ai.definePrompt(
  {
    name: 'weatherPrompt',
    tools: [getWeather],
  },
  'What is the weather in {{location}}?'
);

const response = await weatherPrompt({ location: 'Baltimore' });

File dei prompt

---
system: "Answer questions using the tools you have."
tools: [getWeather]
input:
  schema:
    location: string
---

What is the weather in {{location}}?

Poi puoi eseguire il prompt nel codice come segue:

// assuming prompt file is named weatherPrompt.prompt
const weatherPrompt = ai.prompt('weatherPrompt');

const response = await weatherPrompt({ location: 'Baltimore' });

Chat

const chat = ai.chat({
  system: 'Answer questions using the tools you have.',
  tools: [getWeather],
});

const response = await chat.send('What is the weather in Baltimore?');

// Or, specify tools that are message-specific 
const response = await chat.send({
  prompt: 'What is the weather in Baltimore?',
  tools: [getWeather],
});

Genkit gestirà automaticamente la chiamata allo strumento se l'LLM deve utilizzare lo strumentogetWeather per rispondere al prompt.

Metti in pausa il loop dello strumento utilizzando le interruzioni

Per impostazione predefinita, Genkit chiama ripetutamente l'LLM finché ogni chiamata allo strumento non è stata risolta. Puoi mettere in pausa l'esecuzione in modo condizionale nelle situazioni in cui vuoi, ad esempio:

  • Chiedi all'utente una domanda o mostra l'interfaccia utente.
  • Conferma un'azione potenzialmente rischiosa con l'utente.
  • Richiedi l'approvazione out-of-band per un'azione.

Le interruzioni sono strumenti speciali che possono interrompere il loop e restituire il controllo al codice in modo da gestire scenari più avanzati. Consulta la guida alle interruzioni per scoprire come utilizzarle.

Gestire esplicitamente le chiamate allo strumento

Se vuoi avere il controllo completo su questo ciclo di chiamata dello strumento, ad esempio per applicare una logica più complessa, imposta il parametro returnToolRequests su true. Ora è tua responsabilità assicurarti che tutte le richieste di strumenti vengano soddisfatte:

const getWeather = ai.defineTool(
  {
    // ... tool definition ...
  },
  async ({ location }) => {
    // ... tool implementation ...
  },
);

const generateOptions: GenerateOptions = {
  prompt: "What's the weather like in Baltimore?",
  tools: [getWeather],
  returnToolRequests: true,
};

let llmResponse;
while (true) {
  llmResponse = await ai.generate(generateOptions);
  const toolRequests = llmResponse.toolRequests;
  if (toolRequests.length < 1) {
    break;
  }
  const toolResponses: ToolResponsePart[] = await Promise.all(
    toolRequests.map(async (part) => {
      switch (part.toolRequest.name) {
        case 'specialTool':
          return {
            toolResponse: {
              name: part.toolRequest.name,
              ref: part.toolRequest.ref,
              output: await getWeather(part.toolRequest.input),
            },
          };
        default:
          throw Error('Tool not found');
      }
    })
  );
  generateOptions.messages = llmResponse.messages;
  generateOptions.prompt = toolResponses;
}