Nota: Esta biblioteca está en desuso, ahora se divide en ZOD-GPT y LLM-API.

El control de herramientas de ingeniería de TypeScript-First Sement para trabajar con modelos de idiomas grandes basados en chat (LLMS).
LlamaFlow es la capa de middleware que se encuentra entre su software y el modelo AI, agrega las siguientes capacidades además de la API estándar de finalización de chat:
Con LlamaFlow, simplemente puede consultar el modelo de chatgpt de OpenAI como así:
import { OpenAI } from 'llama-flow' ;
const model = new OpenAI ( { apiKey : 'YOUR_OPENAI_KEY' } ) ;
const chat = model . chat ( {
systemMessage :
"You are a smart and honest AI assistant. Follow the user's requirements carefully & to the letter, minimize any other prose." ,
} ) ;
const response = await chat . request (
prompt . json ( {
message :
'What are some good names for childrens book about the renaissance? Respond as a JSON array' ,
schema : z . array ( z . string ( ) . max ( 200 ) ) ,
} ) ,
) ;
console . log ( response . content ) ; // content will be typed as string[]; Este paquete está alojado en NPM:
npm i llama-flow
yarn add llama-flow
Para configurar su base de código, inicialice una nueva instancia con el modelo que desea (solo OpenAI se supera por ahora). Tenga en cuenta que también puede agregar modelo predeterminado y configuración de chat (como temperatura, tiempo de espera, reintentos) al inicializar. Estos son solo valores predeterminados, y siempre se pueden sobrescribir más tarde por chat o por requisito.
import { OpenAI } from 'llama-flow' ;
const model = new OpenAI (
{ apiKey : 'YOUR_OPENAI_KEY' } ,
{ model : 'gpt-3.5-turbo' } ,
) ;Un chat es una conversación entre el "usuario" (su software) y el agente de IA. LlamaFlow se encargará de administrar la memoria de chat, por lo que simplemente puede continuar la conversación enviando otra solicitud. Tenga en cuenta que se agregarán diferentes estrategias de gestión de memoria en el futuro, como podar la memoria según sea necesario para que se ajuste a la ventana de contexto.
const chat = model . chat ( {
systemMessage : 'You are an AI writer.' ,
retainMemory : true ,
} ) ;
// You can ask the AI model with a simple string, or a dedicated `Prompt` object.
const response = await chat . request (
prompt . text (
'Write a script for a tiktok video that talks about the artistic contribution of the renaissance.' ,
) ,
) ;
// The results, as well as any usage stats, will be returned.
console . log (
`The AI writer's response is: ${ response . content } . Token used: ${ response . usage . totalTokens } .` ,
) ;
// You can follow up on this chat by prompting further, using the `bulletPrompt` object that was created earlier.
const bulletPoints = await chat . request ( bulletPrompt ) ;
// `bulletPoints.content` will be automatically casted in the correct type as defined in the schema field of `bulletPrompt`
console . log (
`The structured version of this response is: ${ JSON . stringify (
bulletPoints . content ,
) } ` ,
) ;Un aviso es un mensaje para un chat de IA con una expectativa de un formato de respuesta específico. Los mensajes de tipo de solicitud se validan para garantizar que el formateado definido se devuelva exactamente, o se equivocará. Hay diferentes tipos de indicaciones para diferentes formatos. Aquí hay un ejemplo de un mensaje JSON.
import { prompt } from 'llama-flow' ;
import { z } from 'zod' ; // JSON prompt uses Zod for schema validation.
const bulletPrompt = prompt . json ( {
message :
'Please rewrite this in a list of bullet points. Respond as a JSON array, where each element in the array is one bullet point. Keep each bullet point to be 200 characters max. For example: ["bullet point 1", "bullet point 2"]' ,
schema : z . array ( z . string ( ) . max ( 200 ) ) ,
} ) ; Tenga en cuenta que el objeto Prompt separa el message principal y formatMessage . Esto se usa para reintentos. Cuando LlamaFlow usa este aviso, le preguntará al modelo con el mensaje principal y de formato. Si el modelo regresa con una respuesta formateada incorrectamente, le pedirá al modelo que corrija la salida anterior, utilizando solo el formatMessage .
También puede construir sus propios objetos rápidos con validadores personalizados. LlamaFlow proporciona una forma fácil y extensible de construir cualquier tipo de validador. Aquí hay algunos ejemplos de validadores personalizados:
Tomando el pronta ejemplo de arriba, pero esta vez, le pedirá al modelo que solo responda en puntos de bala reales en lugar de matrices JSON. Esto es útil porque a veces el modelo (ESP <GPT-4) no es el mejor para seguir instrucciones de formato específicas, especialmente cuando se trata de estructuras de datos complicadas.
import { prompt } from 'llama-flow' ;
const bulletPrompt = prompt . json ( {
message :
'Please rewrite this in a list of bullet points. Respond as a list of bullet points, where each bullet point begins with the "-" character. Each bullet point should be less than 200 characters. Put each bullet point on a new line.' ,
// parse the response from the model so it can be fed into the schema validator
parseResponse : ( res ) => res . split ( 'n' ) . map ( ( s ) => s . replace ( '-' , '' ) . trim ( ) ) ,
// it's useful to define custom error messages, any schema parse errors will be automatically fed back into the model on retry, so the model knows exactly what to correct.
schema : z . array (
z . string ( ) . max ( 200 , {
message : 'This bullet point should be less than 200 characters.' ,
} ) ,
) ,
} ) ; Ahora, llevemos esto aún más lejos. Puede crear un aviso que use el modelo (o alguna otra fuente externa) para validar su propia salida. Puede hacer esto pasando un método validate Async personalizado. Tenga en cuenta que este método anulará otras propiedades relacionadas con la validación, como formatMessage , parseResponse , schema .. etc.
import { prompt , Chat } from 'llama-flow' ;
const factCheckerChat = model . chat ( {
systemMessage :
'You are a fact checker that responds to if the user's messages are true or not, with just the word "true" or "false". Do not add punctuations or any other text. If the user asks a question, request, or anything that cannot be fact checked, ignore the user's request and just say "null".' ,
// The fact checker is designed to fulfill each request independently (e.g. the current request does not depend on the content of the previous request). So no need to keep message memory to save on tokens.
retainMemory : false ,
} ) ;
const buildFactCheckedPrompt = ( article : string ) =>
prompt . text ( {
message : `Please write a summary about the following article: ${ article } ` ,
// Because LLM driven validation can get expensive, set a lower retry count.
promptRetries : 2 ,
parse : async ( response ) => {
// Check if this summary is true or not
const { response } = await factCheckerChat . request (
prompt . boolean ( {
message : response . content ,
} ) ,
) ;
if ( response . content === true ) {
return { success : true , data : response . content } ;
} else {
// if `retryPrompt` is set, LLamaFlow will automatically retry with the text in this property.
return {
success : false ,
retryPrompt :
'This summary is not true, please rewrite with only true facts.' ,
} ;
}
} ,
} ) ;
// now, every content generated by this chat will be fact checked by the LLM itself, and this request will throw an error if the content can't be fixed (once the maximum number of retries has been reached).
const factCheckedContent = await chat . request (
buildFactCheckedPrompt (
'Write a script for a tiktok video that talks about the artistic contribution of the renaissance.' ,
) ,
) ;Debido a que esta es una API, a menudo es útil seguir solicitando el mismo chat. A menudo, el historial de mensajes servirá como contexto para la próxima solicitud. Un buen caso de uso es un aviso para escribir primero algún contenido, luego extraer entidades y, por último, dar algunas opciones para el título.
// You can reset chat history anytime with `reset()`, however, this is an anti-pattern, as it is prone to mistakes. It's much safer to just initialize a new chat.
chat . reset ( ) ;
const article = await chat . request (
prompt . text ( 'Write a blog post about the financial crisis of 2008' ) ,
) ;
const entities = await chat . request (
prompt . json ( {
message :
'What are the different entities in the above blog post? Respond in a JSON array, where the items in the array are just the names of the entities.' ,
schema : z . array ( z . string ( ) ) ,
} ) ,
) ;
const titles = await chat . request (
prompt . bulletPoints ( {
message : 'Write a good title for this post' ,
amount : 10 ,
} ) ,
) ; Un error común con las API de LLM es el uso de token: solo se le permite ajustar una cierta cantidad de datos en la ventana de contexto. En el caso de LlamaFlow, esto significa que está limitado en el número total de mensajes que puede enviar (si retainMemory está configurado en true ) y la longitud del contenido de los mensajes.
LlamaFlow determinará automáticamente si la solicitud incumplirá el límite del token antes de enviar la solicitud real al proveedor del modelo (por ejemplo, OpenAI). Esto guardará una llamada de ida y vuelta de red y le permitirá manejar este tipo de errores de manera receptiva. La forma típica de manejar estos errores es eliminar los mensajes en el historial de mensajes (si está utilizando el chat con el set retainMemory ), o dividir su contenido en clústeres más pequeños y procesarlos en múltiples solicitudes.
Aquí hay un ejemplo de captura del error de desbordamiento del token. Tenga en cuenta que minimumResponseTokens se establece en un valor alto para activar explícitamente este error ( gpt-3.5-turbo tiene un límite de contexto máximo de 4096, por lo que establecer el límite mínimo en 4095 significa que solo queda 1 token para la solicitud real, lo que no es suficiente para el ejemplo a continuación).
try {
// make sure to set the `contextSize` to enable automatic token checking
const model = new OpenAI (
{ apiKey : 'YOUR_OPENAI_KEY' } ,
{ model : 'gpt-3.5-turbo' , contextSize : 4096 } ,
) ;
const chat = model . chat ( {
systemMessage : 'You are an AI assistant' ,
} ) ;
await chat . request (
{ message : 'hello world, testing overflow logic' } ,
{ minimumResponseTokens : 4095 } ,
) ;
} catch ( e ) {
if ( e instanceof TokenError ) {
console . info (
`Caught token overflow, overflowed tokens: ${ e . overflowTokens } ` ,
) ;
}
} Una forma común de manejar los problemas de límite de tokens es dividir su contenido. LlamaFlow proporciona un método útil útil que envuelve el método chat.request y dividirá automáticamente su texto en función de una configuración de fragmento de entrada. Es lo suficientemente inteligente como para dividir su texto si determina que está por encima del límite de token, e intentará preservar la mayor cantidad posible del texto original.
const response = await chat . requestWithSplit (
'hello world, testing overflow logic' ,
( text ) =>
prompt . text ( {
message : `Add other required prompts first, then add your content: ${ text } ` ,
} ) ,
) ; Tenga en cuenta que ahora, el contenido principal del aviso se envía primero. Este es el contenido que será dividido por el divisor de texto (a lo largo del n . , y personajes primero, para fragmentarlo). Puede agregar cualquier indicación requerida adicional y combinarlo con el mensaje de contenido en el parámetro responseFn .
LlamaFlow Usese El módulo debug para mensajes de registro y error. Para ejecutarse en modo de depuración, establezca la variable ENV DEBUG :
DEBUG=llamaflow:* yarn playground
También puede especificar diferentes tipos de registro a través de:
DEBUG=llamaflow:error yarn playground DEBUG=llamaflow:log yarn playground
LlamaFlow también viene con apoyo para los modelos OpenAI de Azure. La versión de Azure suele ser mucho más rápida y más confiable que los puntos finales de API de Openai. Para usar los puntos finales de Azure, debe incluir 2 opciones específicas de Azure al inicializar el modelo OpenAI, azureDeployment y azureEndpoint . El campo apiKey también se utilizará para la tecla Azure API.
Puede encontrar la tecla API Azure y el punto final en el portal de Azure. La implementación de Azure debe crearse bajo el portal Azure AI.
Tenga en cuenta que el parámetro model en ModelConfig se ignorará cuando use Azure. Esto se debe a que en el sistema Azure, el model se selecciona en la creación de implementación, no en tiempo de ejecución.
const model = new OpenAI ( {
apiKey : 'AZURE_OPENAI_KEY' ,
azureDeployment : 'AZURE_DEPLOYMENT_NAME' ,
azureEndpoint : 'AZURE_ENDPOINT' ,
} ) ; El único modelo de que LlamaFlow admite actualmente son los modelos basados en chat de OpenAI.
const model = new OpenAI ( openAiConfig , modelConfig ) ; interface OpenAIConfig {
apiKey : string ;
} Este mapa de configuración del modelo a la configuración de OpenAI directamente, consulte Doc: https://platform.openai.com/docs/api-reference/chat/create
interface ModelConfig {
model ?: string ;
maxTokens ?: number ;
temperature ?: number ;
topP ?: number ;
stop ?: string | string [ ] ;
presencePenalty ?: number ;
frequencyPenalty ?: number ;
logitBias ?: Record < string , number > ;
user ?: string ;
stream ?: boolean ;
} Cuando stream se establece en true , puede acceder a salidas parciales de las solicitudes del modelo pasando un emisor de eventos a ChatRequestOptions al hacer solicitudes. Las salidas parciales se enviarán como una cadena a través del evento data .
Para hacer una solicitud al modelo, primero debe construir el objeto de inmediato. Las indicaciones proporcionan una forma de agregar validación y volver a intentar la lógica a cada solicitud.
import { prompt } from 'llama-flow' ;
prompt . text ( prompt : string ) ;
prompt . text ( prompt : RawPrompt ) ;
prompt . json ( prompt : JSONPrompt ) ;
prompt . bulletPoints ( prompt : BulletPointsPrompt ) ;
prompt . boolean ( prompt : BooleanPrompt ) ; Puede solicitar una cadena o como RawPrompt .
interface RawPrompt < T = string > {
message : string ;
parse ?: (
response : ChatResponse < string > ,
) => MaybePromise <
{ success : false ; retryPrompt ?: string } | { success : true ; data : T }
> ;
promptRetries ?: number ;
}Mensaje Este es el texto que se envía al modelo.
PARSE Puede implementar un analizador personalizado definiendo un método parse de su propio.
Al definir un método parse personalizado que devuelve un tipo de datos personalizado, puede agregar un tipo genérico a RawPrompt , que lanzará automáticamente el tipo de retorno de parse al genérico. También propagará el tipo hasta el método chat.request .
Si los datos devueltos por el modelo están malformados, puede devolver una cadena retryPrompt personalizada, lo que hará que LlamaFlow vuelva a hacer el modelo.
PrompTretries define cuántas veces volver a hacer el modelo antes de que la solicitud arroje un error. El valor predeterminado a 3. Tenga en cuenta que parse tiene que devolver un retryPrompt válido para cualquier reintento que se intente.
interface BooleanPrompt {
message : string ;
promptRetries ?: number ;
} Use este aviso si desea hacerle al modelo una pregunta en la que solo espera una respuesta true o false .
Envíe el mensaje la consulta para enviar al modelo. Este aviso agregará automáticamente las instrucciones de formato al mensaje que se envía al modelo que le indica al modelo que formatea su respuesta como booleana, por lo que puede incluir la consulta en message , sin escribir ninguna declaración de formato adicional.
interface BulletPointsPrompt {
message : string ;
amount ?: number ;
length ?: number ;
promptRetries ?: number ;
}Use este aviso si desea que el modelo devuelva una lista de cadenas.
Envíe el mensaje la consulta para enviar al modelo. Este aviso agregará automáticamente las instrucciones de formateo del mensaje que le indique al modelo cómo formatear la respuesta.
cantidad el número de puntos de bala que deben devolverse.
Longitud El número máximo de caracteres que deberían estar en cada punto de bala.
interface JSONPrompt < T extends z . ZodType > {
message : string ;
schema : T ;
parseResponse ?: ( res : string ) => MaybePromise < z . infer < T > > ;
retryMessage ?: string ;
promptRetries ?: number ;
}Enviar el mensaje para enviar al modelo. A diferencia de las indicaciones booleanas o de bala, este mensaje no genera automáticamente instrucciones de formación para el modelo. Entonces, como parte de su mensaje al modelo, debe incluir instrucciones de formato para devolver datos en formato JSON, así como la forma del JSON.
Esquema Este es el esquema Zod que se utilizará para analizar y escribir la respuesta del modelo.
Parseresponse Si le pide al modelo que no devuelva los datos en formato JSON, puede definir un analizador personalizado para analizar la cadena de retorno a JSON, antes de enviarlo a schema para la validación.
Ritrymessage Si falla el análisis de esquema, esto se usará como parte del mensaje enviado al modelo para reask para una respuesta formateada correctamente. Tenga en cuenta que este aviso generará automáticamente el mensaje de Realk dependiendo de los errores de análisis de esquemas (por ejemplo, si falta una clave específica, LlamaFlow le pedirá al modelo que incluya esa clave específica). Por lo tanto, este campo es puramente dar contexto adicional al modelo en Realk.
El objeto de chat almacena una sesión de chat con el modelo. La sesión se encargará de almacenar el historial de mensajes, por lo que simplemente puede continuar la conversación con el modelo haciendo otra solicitud.
const chat = model . chat ( config : ChatConfig ) ;Opciones Puede establecer el comportamiento de retención de memoria, así como las opciones de solicitud predeterminadas para cada solicitud enviada en este chat.
export interface ChatConfig {
// the message injected at the start of every chat to steer the agent
systemMessage : string ;
// if chat memory should be retained after every request. when enabled, the chat's behavior will be similar to a normal user chat room, and model can have access to history when making inferences. defaults to false
retainMemory ?: boolean ;
// set default request options. note that this can be overridden on a per-request basis
options ?: ChatRequestOptions ;
} Para enviar una solicitud a una sesión de chat:
const res : ChatResponse = await chat . request ( prompt , options : ChatRequestOptions ) ;Opciones Puede anular las opciones de solicitud predeterminadas a través de este parámetro. Una solicitud se volverá automáticamente si hay un error de ratelimit o servidor.
Tenga en cuenta que un reintento en la solicitud no cuenta para un aviso de reask definido en la sección de solicitud anterior.
type ChatRequestOptions = {
// the number of time to retry this request due to rate limit or recoverable API errors
retries ?: number ;
retryInterval ?: number ;
timeout ?: number ;
// the minimum amount of tokens to allocate for the response. if the request is predicted to not have enough tokens, it will automatically throw a 'TokenError' without sending the request
minimumResponseTokens ?: number ;
// override the messages used for completion, only use this if you understand the API well
messages ?: Message [ ] ;
// pass in an event emitter to receive message stream events
events ?: EventEmitter ;
} ; Las respuestas de chat están en el siguiente formato:
interface ChatResponse < T = string > {
content : T ;
model : string ;
// set to true if this content was streamed. note to actually access the stream, you have to pass in an event emitter via ChatRequestOptions
isStream : boolean ;
usage : {
promptTokens : number ;
completionTokens : number ;
totalTokens : number ;
} ;
}Contenido analizado y typastado Contenido desde el aviso. Los tipos se establecerán automáticamente dependiendo de la solicitud que haya usado.
Modelo El modelo específico utilizado para la finalización (por ejemplo gpt-3.5-turbo-0301 )
Datos de uso del token de uso , esto mapea directamente la respuesta de uso de OpenAI.
Si desea restablecer el historial de mensajes en un historial de chat, hay un método de ayuda simple:
chat . reset ( ) ;Tenga en cuenta que este método es una escotilla de escape. Es mejor instanciar una nueva sesión de chat si desea hacer una nueva solicitud con una pizarra limpia. La lógica compleja en la que está restableciendo una sesión de chat varias veces puede ser difícil de rastrear y difícil de depurar.
Tenga en cuenta que si desea evitar la lógica de administración de chat de LlamaFlow y enviar una solicitud al modelo de subrayado directamente, puede enviar una solicitud al modelo directamente sin instancias de un chat:
const model = new OpenAI ( openAiConfig , modelConfig ) ;
const res = await model . request ( messages : Message [ ] , options : ChatRequestOptions ) ; Esto omitirá cualquier gestión del historial de chat, formato rápido y análisis, así como lógica de personalidad. Todavía puede utilizar la función API reintentos a través de ChatRequestOptions .