Las interrupciones son un tipo especial de herramienta que puede pausar el bucle de generación y llamada de herramientas de LLM para devolverte el control. Cuando todo esté listo, puedes reanudar la generación enviando respuestas que el LLM procesará para generar más contenido.
Los usos más comunes de las interrupciones se dividen en algunas categorías:
- Human-in-the-Loop: Permite que el usuario de una IA interactiva aclare la información necesaria o confirme la acción del LLM antes de que se complete, lo que proporciona una medida de seguridad y confianza.
- Procesamiento asíncrono: Inicia una tarea asíncrona que solo se puede completar fuera del rango, como enviar una notificación de aprobación a un revisor manual o iniciar un proceso en segundo plano de larga duración.
- Salir de una tarea autónoma: Proporciona al modelo una forma de marcar una tarea como completa, en un flujo de trabajo que podría iterar a través de una larga serie de llamadas a herramientas.
Antes de comenzar
En todos los ejemplos que se documentan aquí, se da por sentado que ya configuraste un proyecto con las dependencias de Genkit instaladas. Si quieres ejecutar los ejemplos de código de esta página, primero completa los pasos de la guía Cómo comenzar.
Antes de profundizar demasiado, también debes familiarizarte con los siguientes conceptos:
- Generar contenido con modelos de IA
- Es el sistema de Genkit para definir esquemas de entrada y salida.
- Métodos generales de llamada a herramientas.
Descripción general de las interrupciones
En un nivel alto, así se ve una interrupción cuando interactúa con un LLM:
- La aplicación que realiza la llamada le envía una solicitud al LLM. La instrucción incluye una lista de herramientas, incluida al menos una para una interrupción que el LLM puede usar para generar una respuesta.
- El LLM genera una respuesta completa o una solicitud de llamada a la herramienta en un formato específico. Para el LLM, una llamada de interrupción se ve como cualquier otra llamada a la herramienta.
- Si el LLM llama a una herramienta de interrupción, la biblioteca de Genkit pausa automáticamente la generación en lugar de pasar las respuestas inmediatamente al modelo para un procesamiento adicional.
- El desarrollador verifica si se realiza una llamada de interrupción y realiza cualquier tarea necesaria para recopilar la información necesaria para la respuesta de interrupción.
- El desarrollador reanuda la generación pasando una respuesta de interrupción al modelo. Esta acción activa un retorno al paso 2.
Define las interrupciones de respuesta manual
El tipo de interrupción más común permite que el LLM le solicite al usuario una aclaración, por ejemplo, haciendo una pregunta de opción múltiple.
Para este caso de uso, usa el método defineInterrupt()
de la instancia de Genkit:
import { genkit, z } from 'genkit';
import { googleAI, gemini15Flash } from '@genkitai/google-ai';
const ai = genkit({
plugins: [googleAI()],
model: gemini15Flash,
});
const askQuestion = ai.defineInterrupt({
name: 'askQuestion',
description: 'use this to ask the user a clarifying question',
inputSchema: z.object({
choices: z.array(z.string()).describe('the choices to display to the user'),
allowOther: z.boolean().optional().describe('when true, allow write-ins')
}),
outputSchema: z.string()
});
Ten en cuenta que el outputSchema
de una interrupción corresponde a los datos de respuesta que proporcionarás, en lugar de algo que una función de herramienta propagará automáticamente.
Usa interrupciones
Las interrupciones se pasan al array tools
cuando se genera contenido, al igual que otros tipos de herramientas. Puedes pasar herramientas normales y de interrupción a la misma llamada a generate
:
generar
const response = await ai.generate({
prompt: 'Ask me a movie trivia question.',
tools: [askQuestion],
});
definePrompt
const triviaPrompt = ai.definePrompt(
{
name: 'triviaPrompt',
tools: [askQuestion],
input: {
schema: z.object({subject: z.string()})
},
prompt: 'Ask me a trivia question about {{subject}}
.',
}
);
const response = await triviaPrompt({ subject: 'computer history' });
Archivo de la instrucción
---
tools: [askQuestion]
input:
schema:
partyType: string
---
{{role "system"}}
Use the askQuestion tool if you need to clarify something.
{{role "user"}}
Help me plan a {{partyType}} party next week.
Luego, puedes ejecutar la instrucción en tu código de la siguiente manera:
```ts
// assuming prompt file is named partyPlanner.prompt
const partyPlanner = ai.prompt('partyPlanner');
const response = await partyPlanner({ partyType: 'birthday' });
```
Chat
const chat = ai.chat({
system: 'Use the askQuestion tool if you need to clarify something.',
tools: [askQuestion],
});
const response = await chat.send('make a plan for my birthday party');
Genkit muestra una respuesta de inmediato cuando recibe una llamada a la herramienta de interrupción.
Cómo responder a las interrupciones
Si pasaste una o más interrupciones a tu llamada de generación, debes verificar la respuesta en busca de interrupciones para poder controlarlas:
// you can check the 'finishReason' of the response
response.finishReason === 'interrupted'
// or you can check to see if any interrupt requests are on the response
response.interrupts.length > 0
Para responder a una interrupción, se usa la opción resume
en una llamada generate
posterior y se debe asegurar de pasar el historial existente. Cada herramienta tiene un método .respond()
para ayudar a construir la respuesta.
Una vez reanudado, el modelo vuelve a ingresar al bucle de generación, incluida la ejecución de la herramienta, hasta que se complete o se active otra interrupción:
let response = await ai.generate({
tools: [askQuestion],
system: 'ask clarifying questions until you have a complete solution',
prompt: 'help me plan a backyard BBQ',
});
while (response.interrupts.length) {
const answers = [];
// multiple interrupts can be called at once, so we handle them all
for (const question in response.interrupts) {
answers.push(
// use the `respond` method on our tool to populate answers
askQuestion.respond(
question,
// send the tool request input to the user to respond
await askUser(question.toolRequest.input)
)
);
}
response = await ai.generate({
tools: [askQuestion],
messages: response.messages,
resume: {
respond: answers
}
})
}
// no more interrupts, we can see the final response
console.log(response.text);
Herramientas con interrupciones reiniciables
Otro patrón común para las interrupciones es la necesidad de confirmar una acción que sugiere el LLM antes de realizarla. Por ejemplo, una app de pagos podría solicitar que el usuario confirme ciertos tipos de transferencias.
Para este caso de uso, puedes usar el método defineTool
estándar para agregar una lógica personalizada sobre cuándo activar una interrupción y qué hacer cuando se reinicia una interrupción con metadatos adicionales.
Define una herramienta que se pueda reiniciar
Cada herramienta tiene acceso a dos ayudantes especiales en el segundo argumento de su definición de implementación:
interrupt
: Cuando se lo llama, este método arroja un tipo especial de excepción que se detecta para pausar el bucle de generación. Puedes proporcionar metadatos adicionales como un objeto.resumed
: Cuando se reinicia una solicitud de una generación interrumpida con la opción{resume: {restart: ...}}
(consulta a continuación), este ayudante contiene los metadatos proporcionados cuando se reinicia.
Por ejemplo, si compilas una app de pagos, te recomendamos que confirmes con el usuario antes de realizar una transferencia que supere un importe determinado:
const transferMoney = ai.defineTool({
name: 'transferMoney',
description: 'Transfers money between accounts.',
inputSchema: z.object({
toAccountId: z.string().describe('the account id of the transfer destination'),
amount: z.number().describe('the amount in integer cents (100 = $1.00)'),
}),
outputSchema: z.object({
status: z.string().describe('the outcome of the transfer'),
message: z.string().optional(),
})
}, async (input, {context, interrupt, resumed})) {
// if the user rejected the transaction
if (resumed?.status === "REJECTED") {
return {status: 'REJECTED', message: 'The user rejected the transaction.'};
}
// trigger an interrupt to confirm if amount > $100
if (resumed?.status !== "APPROVED" && input.amount > 10000) {
interrupt({
message: "Please confirm sending an amount > $100.",
});
}
// complete the transaction if not interrupted
return doTransfer(input);
}
En este ejemplo, en la primera ejecución (cuando resumed
no está definido), la herramienta verifica si el importe supera los USD 100 y, de ser así, activa una interrupción. En la segunda ejecución, busca un estado en los metadatos nuevos proporcionados y realiza la transferencia o muestra una respuesta de rechazo, según se apruebe o se rechace.
Cómo reiniciar herramientas después de una interrupción
Las herramientas de interrupción te brindan control total sobre lo siguiente:
- Cuándo una solicitud de herramienta inicial debe activar una interrupción.
- Cuándo y si se debe reanudar el bucle de generación.
- Qué información adicional se debe proporcionar a la herramienta cuando se reanuda.
En el ejemplo que se muestra en la sección anterior, la aplicación podría pedirle al usuario que confirme la solicitud interrumpida para asegurarse de que el importe de la transferencia sea correcto:
let response = await ai.generate({
tools: [transferMoney],
prompt: "Transfer $1000 to account ABC123",
});
while (response.interrupts.length) {
const confirmations = [];
// multiple interrupts can be called at once, so we handle them all
for (const interrupt in response.interrupts) {
confirmations.push(
// use the 'restart' method on our tool to provide `resumed` metadata
transferMoney.restart(
interrupt,
// send the tool request input to the user to respond. assume that this
// returns `{status: "APPROVED"}` or `{status: "REJECTED"}`
await requestConfirmation(interrupt.toolRequest.input);
)
);
}
response = await ai.generate({
tools: [transferMoney],
messages: response.messages,
resume: {
restart: confirmations,
}
})
}
// no more interrupts, we can see the final response
console.log(response.text);