Chamada de ferramenta

A chamada de ferramenta, também conhecida como chamada de função, é uma maneira estruturada de dar aos LLMs a capacidade de fazer solicitações de volta ao aplicativo que os chamou. Você define as ferramentas que quer disponibilizar para o modelo, e ele vai fazer solicitações de ferramentas para o app conforme necessário para atender às solicitações.

Os casos de uso de chamadas de ferramentas geralmente se enquadram em alguns temas:

Dar acesso a um LLM a informações com as quais ele não foi treinado

  • Informações que mudam com frequência, como o preço de uma ação ou a previsão do tempo.
  • Informações específicas do domínio do app, como informações do produto ou perfis de usuário.

Observe a sobreposição com a geração aumentada de recuperação (RAG, na sigla em inglês), que também é uma maneira de permitir que um LLM integre informações factuais nas gerações. A RAG é uma solução mais pesada que é mais adequada quando você tem uma grande quantidade de informações ou quando as informações mais relevantes para uma solicitação são ambíguas. Por outro lado, se a recuperação das informações necessárias para o LLM for uma chamada de função simples ou pesquisa de banco de dados, a chamada de ferramenta será mais apropriada.

Como introduzir um grau de determinismo em um fluxo de trabalho de LLM

  • Fazer cálculos que o LLM não consegue concluir de forma confiável.
  • Forçar um LLM a gerar texto literal em determinadas circunstâncias, como ao responder a uma pergunta sobre os termos de serviço de um app.

Realizar uma ação quando iniciada por um LLM

  • Acender e apagar luzes em um assistente doméstico com LLM
  • Reservar mesas em um agente de restaurante com LLM

Antes de começar

Se você quiser executar os exemplos de código nesta página, primeiro conclua as etapas do guia Primeiros passos. Todos os exemplos pressupõem que você já tenha configurado um projeto com as dependências do Genkit instaladas.

Esta página discute um dos recursos avançados da abstração de modelo do Genkit. Portanto, antes de se aprofundar demais, você precisa conhecer o conteúdo da página Como gerar conteúdo com modelos de IA. Você também precisa conhecer o sistema do Genkit para definir esquemas de entrada e saída, que é discutido na página Fluxos.

Visão geral da chamada de ferramentas

De modo geral, esta é a aparência de uma interação típica de chamada de ferramenta com um LLM:

  1. O aplicativo que faz a chamada solicita o LLM com uma solicitação e também inclui uma lista de ferramentas que o LLM pode usar para gerar uma resposta.
  2. O LLM gera uma resposta completa ou uma solicitação de chamada de ferramenta em um formato específico.
  3. Se o autor da chamada receber uma resposta completa, a solicitação será atendida e a interação será encerrada. No entanto, se o autor da chamada receber uma chamada de ferramenta, ele executará a lógica apropriada e enviará uma nova solicitação para o LLM contendo o comando original ou alguma variação dele, além do resultado da chamada da ferramenta.
  4. O LLM processa a nova solicitação, como na etapa 2.

Para que isso funcione, vários requisitos precisam ser atendidos:

  • O modelo precisa ser treinado para fazer solicitações de ferramentas quando necessário para concluir uma instrução. A maioria dos modelos maiores fornecidos por APIs da Web, como Gemini e Claude, podem fazer isso, mas modelos menores e mais especializados geralmente não podem. O Genkit vai gerar um erro se você tentar fornecer ferramentas a um modelo que não oferece suporte a elas.
  • O aplicativo de chamada precisa fornecer definições de ferramentas para o modelo no formato esperado.
  • O aplicativo de chamada precisa solicitar que o modelo gere solicitações de chamada de ferramenta no formato esperado pelo aplicativo.

Chamada de ferramentas com o Genkit

O Genkit oferece uma única interface para chamadas de ferramentas com modelos compatíveis. Cada plug-in de modelo garante que os dois últimos critérios acima sejam atendidos, e a função generate() da instância do Genkit executa automaticamente o loop de chamada de ferramentas descrito anteriormente.

Suporte a modelos

O suporte a chamadas de ferramentas depende do modelo, da API do modelo e do plug-in do Genkit. Consulte a documentação relevante para determinar se a chamada de ferramentas tem suporte. Além disso:

  • O Genkit vai gerar um erro se você tentar fornecer ferramentas a um modelo que não oferece suporte a elas.
  • Se o plug-in exporta referências de modelo, a propriedade info.supports.tools vai indicar se ele oferece suporte à chamada de ferramentas.

Como definir ferramentas

Use a função defineTool() da instância do Genkit para escrever definições de ferramentas:

import { genkit, z } from 'genkit';
import { googleAI, gemini15Flash } from '@genkit-ai/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.';
  }
);

A sintaxe aqui é semelhante à sintaxe defineFlow(). No entanto, todos os quatro parâmetros name, description, inputSchema e outputSchema são necessários. Ao escrever uma definição de ferramenta, tenha cuidado especial com a redação e a descrição desses parâmetros, já que eles são essenciais para que o LLM use as ferramentas disponíveis.

Como usar ferramentas

Inclua ferramentas definidas nos comandos para gerar conteúdo.

Gerar

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' });

Arquivo de comando

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

What is the weather in {{location}}?

Em seguida, execute o comando no código da seguinte maneira:

// 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],
});

O Genkit processará automaticamente a chamada de ferramenta se o LLM precisar usar a ferramenta getWeather para responder ao comando.

Processar explicitamente chamadas de ferramentas

Por padrão, o Genkit chama o LLM repetidamente até que todas as chamadas de ferramentas sejam resolução. Se você quiser ter mais controle sobre esse loop de chamada de ferramenta, por exemplo, para aplicar uma lógica mais complicada, defina o parâmetro returnToolRequests como true. Agora, é sua responsabilidade garantir que todas as solicitações de ferramentas sejam atendidas:

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;
}