Askit es un complemento de lenguaje para TypeScript que le permite aprovechar las capacidades de un modelo de lenguaje grande (LLM), como GPT-4, directamente dentro de su entorno de programación, no se necesitan API complejas. La amplia gama de aplicaciones de Askit incluye:
Construido sobre la API de OpenAI, Askit proporciona una interfaz fácil de usar para incorporar LLM en sus aplicaciones. Puede usar Askit no solo en TypeScript, sino también en JavaScript y Python.
Para integrar Askit con JavaScript, consulte la sección JavaScript correspondiente.
Si Python es su idioma preferido, puede obtener más información sobre cómo utilizar Askit visitando nuestra página de Askit (Pyaskit) dedicada.
Control de salida guiado por tipo: obtenga una respuesta en el tipo especificado.
Definición de función basada en plantillas: Defina funciones utilizando una plantilla de inmediato.
Generación de códigos: genere funciones desde la interfaz unificada. Consulte la generación de código con Askit para obtener más detalles.
Programación por ejemplo (PBE): Defina funciones utilizando ejemplos. Vea la programación por ejemplo con Askit para obtener más detalles.
Antes de comenzar, asegúrese de que Node.js y NPM estén instalados en su sistema. Luego, ejecute el siguiente comando:
npm install ts-askit Este paquete se basa en ts-patch . Para instalar ts-patch , ejecute:
npx ts-patch install Agregue el siguiente fragmento a su tsconfig.json :
"compilerOptions" : {
"plugins" : [{ "transform" : " ts-askit/transform " }]
} Esta modificación permite que el compilador TypeScript admita los parámetros de tipo para las API ask y define en Askit.
El paquete ts-patch es crucial para desatar todo el potencial de Askit, ya que extiende el compilador TypeScript para integrar completamente el sistema de tipos de Askit. Si bien Askit se puede usar sin ts-patch , esta integración ofrece una experiencia más rica en funciones.
Antes de usar Askit , debe configurar su tecla API OpenAI como una variable de entorno OPENAI_API_KEY :
export OPENAI_API_KEY= < your OpenAI API key > <your OpenAI API key> es una cadena que se ve así: sk-<your key> . Puede encontrar su tecla API en el tablero de OpenAI.
También puede especificar el nombre del modelo como una variable de entorno ASKIT_MODEL :
export ASKIT_MODEL= < model name > <model name> es el nombre del modelo que desea usar. El último Askit se prueba con gpt-4 y gpt-3.5-turbo-16k . Puede encontrar la lista de modelos disponibles en la documentación de la API de OpenAI.
Aquí hay algunos ejemplos introductorios:
import { ask } from 'ts-askit' ;
ask < string > ( 'Paraphrase "Hello World!"' ) . then ( ( result ) => {
console . log ( result ) ;
} ) ; En este ejemplo, ask es una función API que permite que su programa plantee consultas a un modelo de lenguaje grande (LLM). El parámetro de tipo representa el tipo de salida esperado del LLM. Aquí, el tipo de salida es string . El aviso se pasa como un argumento en el lenguaje natural, que describe la tarea para que el LLM funcione. ask es asíncrono, devolviendo una Promise del tipo de salida especificado. El fragmento de código anterior debería imprimir algo como esto:
Greetings, Universe!
Para un mensaje con los parámetros, puede usar la API define de la siguiente manera:
import { define } from 'ts-askit' ;
const paraphrase = define < string > ( 'Paraphrase {{text}}' ) ;
paraphrase ( { text : 'Hello World!' } ) . then ( ( result ) => {
console . log ( result ) ;
} ) ; define es una función API que le permite definir una función personalizada. Su parámetro de tipo indica el tipo de salida del LLM y, en consecuencia, el valor de retorno de la función. La función recibe una plantilla de cadena como argumento, sirviendo como el mensaje de la tarea de la LLM. La plantilla puede incluir parámetros encerrados en aparatos ortopédicos dobles. En el ejemplo anterior, text es un parámetro dentro de la plantilla, y puede ser cualquier identificador de JavaScript válido.
Una vez que se define la función, se puede invocar como cualquier otra función. Esta función acepta un objeto como un argumento, que se asigna a los valores de los parámetros de la plantilla. En este caso, text se mapea en la cadena '¡Hola mundo!'.
Askit es experto en generar código a partir de descripciones del lenguaje natural. Aquí hay un ejemplo:
import { define } from 'ts-askit' ;
const sort = define < number [ ] , { numbers : number [ ] } > (
'Sort {{numbers}} in ascending order'
) ; Este ejemplo muestra una función que clasifica una matriz de números en orden ascendente, utilizando la API define para instruir a la LLM para definir la función. Si bien es eficiente en concepto, este método puede parecer computacionalmente pesado ya que cada llamada de función requiere una nueva tarea LLM.
Para optimizar este proceso, podemos aprovechar el LLM para generar el código de la función de clasificación, en lugar de recurrir a la LLM para cada tarea de clasificación. Esto optimiza la función sin requerir ningún cambio en su implementación, gracias a las capacidades de generación de código de Askit .
El código para la función mencionada se puede generar en tres pasos:
tsc . El analizador Askit escanea el código y genera un archivo JSONL que contiene detalles sobre las llamadas de API define y ask .npx askgen < jsonl file >tsc . Esta vez, las llamadas API define y ask son reemplazadas por las referencias y llamadas a la función recién generada, respectivamente, gracias a la función de reemplazo automático de Askit . Askit le permite aprovechar el poder de la programación por ejemplo (PBE). PBE simplifica el proceso de programación al permitirle definir la funcionalidad a través de ejemplos en lugar de lógica codificada. El siguiente ejemplo ilustra esto mostrando cómo agregar dos números binarios usando PBE con Askit .
import { define , Example } from 'ts-askit' ;
const trainingExamples : Example [ ] = [
{ input : { x : '1' , y : '0' } , output : '1' } ,
{ input : { x : '1' , y : '1' } , output : '10' } ,
{ input : { x : '101' , y : '11' } , output : '1000' } ,
{ input : { x : '1001' , y : '110' } , output : '1111' } ,
{ input : { x : '1111' , y : '1' } , output : '10000' } ,
] ;
const testExamples = [
{ input : { x : '0' , y : '1' } , output : '1' } ,
{ input : { x : '10' , y : '0' } , output : '10' } ,
{ input : { x : '110' , y : '10' } , output : '1000' } ,
] ;
const addInBase2 = define < string , { x : string ; y : string } > (
'Add {{x}} and {{y}}' ,
trainingExamples ,
testExamples
) ;
async function doit ( ) {
console . log ( await addInBase2 ( { x : '101' , y : '11' } ) ) ;
}
doit ( ) ; En este ejemplo, definimos una función addInBase2 que toma dos números binarios (representados como cadenas) y los agrega. La función define se invoca con una solicitud y dos conjuntos de ejemplos: ejemplos de capacitación y ejemplos de prueba. Los ejemplos de capacitación se reflejan en el aviso de una manera de aprendizaje de pocos disparos. Por otro lado, los ejemplos de prueba se utilizan para validar la corrección de la función generada. No se requieren ejemplos de pruebas si no genera código para la función.
El resultado es una característica poderosa que le permite instruir a la LLM para realizar operaciones complejas, como la adición binaria, usando nada más que ejemplos. Este enfoque le permite desarrollar una funcionalidad compleja rápidamente y con una lógica menos explícita.
Una vez que se define la función addInBase2 , puede llamarlo con cadenas de números binarios para realizar la adición en la base 2. Al igual que con las llamadas de función tradicionales, la operación ask de Askit devuelve una promesa que se resuelve con el resultado calculado.
Los desarrolladores de JavaScript pueden explotar completamente el potencial del control de salida guiado por tipo ofrecido por Askit . Al igual que su escritor de hermanos, JavaScript incorpora el método API ask esto. La función ask toma dos parámetros: un tipo y un aviso.
Aquí hay una variedad de ejemplos que demuestran su uso:
const ai = require ( 'ts-askit' )
const t = require ( 'ts-askit/types' )
ai . ask ( t . number , 'What is the third prime number?' ) . then ( ( answer ) => { console . log ( answer ) } ) ;
ai . ask ( t . string , "What is the month number of 'January'?" ) . then ( ( answer ) => { console . log ( answer ) } ) ;
ai . ask ( t . array ( t . number ) , "What are the month numbers in the second quarter?" ) ;
const monthType = t . type ( {
name : t . string ,
number : t . number
} )
ai . ask ( monthType , "What is the month number of 'October'?" ) . then ( ( answer ) => { console . log ( answer ) } ) ;
ai . ask ( t . array ( monthType ) , "What are the months in the second quarter?" ) . then ( ( answer ) => { console . log ( answer ) } ) ; En el fragmento de código anterior, la función ask se invoca con un tipo y un mensaje. El parámetro de tipo sirve al propósito de informar a Askit sobre el formato y la estructura de la salida deseada. Esto se vuelve extremadamente útil cuando se trata de estructuras de datos complejas.
Con Askit , los desarrolladores de JavaScript tienen la capacidad de definir funciones utilizando plantillas fáciles de entender. El método define es el héroe detrás de escena aquí, ya que ayuda a crear funciones basadas en la plantilla de tareas proporcionada. Una vez creado, estas funciones pueden llamarse con cualquier objeto que proporcione valores para los marcadores de posición en la plantilla.
Aquí hay un ejemplo de cómo se hace:
const ai = require ( 'ts-askit' )
const t = require ( 'ts-askit/types' )
let f = ai . define ( t . string , 'Translate {{text}} into {{language}}' ) ;
f ( { text : 'Hello' , language : 'French' } ) . then ( ( answer ) => { console . log ( answer ) } ) ; En el código anterior, el método define se emplea para establecer una función f utilizando una plantilla de tarea 'traducir {{text}} en {{lenguaje}}'. La función f se invoca con un objeto que proporciona valores para text y language .
El módulo 'ts-askit/types' es un tesoro de tipos que puede utilizar para guiar la salida de Askit . Aquí hay una tabla para ayudarlo a comprender rápidamente estos tipos:
| Tipo | Descripción | Tipo de ejemplo | Ejemplo de valor |
|---|---|---|---|
NumberType | Tipo numérico | t.number | 123 |
StringType | Tipo de cadena | t.string | "¡Hola Mundo!" |
BooleanType | Tipo booleano | t.boolean | verdadero |
LiteralType | Tipo de valor literal | t.literal(123) | 123 |
ArrayType | Tipo de matriz | t.array(t.number) | [1, 2, 3] |
UnionType | Tipo de unión (múltiples valores posibles) | t.union([t.literal('yes'), t.literal('no')]) | "sí o no" |
InterfaceType | Tipo de interfaz/diccionario | t.type({a: t.number, b: t.number}) | {A: 1, B: 2} |
CodeType | Tipo de código | t.code('python') | "Def hello_world (): imprime ('¡Hola, mundo!')" |
Cada tipo tiene propiedades específicas que utiliza Askit para comprender la tarea en cuestión y formatear correctamente la salida.
Al momento de escribir, la función de generación de código está disponible exclusivamente en TypeScript. Sin embargo, los esfuerzos están en pleno apogeo para extender esta potente característica al ámbito de JavaScript. Si sus requisitos requieren el uso de la generación de código en el ínterin, recomendamos usar TypeScript hasta nuevas actualizaciones.
Para obtener detalles sobre nuestro código de conducta y el proceso para enviar solicitudes de extracción, consulte Contriping.md.
Este proyecto tiene licencia bajo la licencia MIT. Para obtener más información, consulte el archivo de licencia.
@misc { okuda2023askit ,
title = { AskIt: Unified Programming Interface for Programming with Large Language Models } ,
author = { Katsumi Okuda and Saman Amarasinghe } ,
year = { 2023 } ,
eprint = { 2308.15645 } ,
archivePrefix = { arXiv } ,
primaryClass = { cs.PL }
}