Askit é um plug-in de idioma para o TypeScript que permite aproveitar os recursos de um grande modelo de idioma (LLM), como o GPT-4, diretamente em seu ambiente de programação, nenhuma API complexa necessária. A extensa gama de aplicações da Askit inclui:
Construído sobre a API OpenAI, o Askit fornece uma interface amigável para incorporar LLMs em seus aplicativos. Você pode usar o Askit não apenas no TypeScript, mas também em JavaScript e Python.
Para integrar o Askit ao JavaScript, consulte a seção JavaScript correspondente.
Se o Python for o seu idioma preferido, você poderá aprender mais sobre como utilizar askit visitando nossa página Dedicated Askit (Pyaskit).
Controle de saída guiado por tipo: Obtenha uma resposta no tipo especificado.
Definição da função baseada em modelo: defina funções usando um modelo de prompt.
Geração de código: gerar funções a partir da interface unificada. Consulte a geração de código com as solicitação de mais detalhes.
Programação por exemplo (PBE): defina funções usando exemplos. Consulte Programação por exemplo com o Autit para obter mais detalhes.
Antes de iniciar, verifique se o Node.js e o NPM estão instalados no seu sistema. Em seguida, execute o seguinte comando:
npm install ts-askit Este pacote depende do ts-patch . Para instalar ts-patch , execute:
npx ts-patch install Adicione o seguinte snippet ao seu tsconfig.json :
"compilerOptions" : {
"plugins" : [{ "transform" : " ts-askit/transform " }]
} Essa modificação permite que o compilador do TypeScript suportasse parâmetros de tipo para as APIs ask e define no ASKIT.
O pacote ts-patch é crucial para liberar todo o potencial do ASKIT, pois estende o compilador do TypeScript para integrar totalmente o sistema de tipo de Askit. Embora o ASKIT possa ser usado sem ts-patch , essa integração oferece uma experiência mais rica em recursos.
Antes de usar askit , você precisa definir sua chave de API do OpenAI como uma variável de ambiente OPENAI_API_KEY :
export OPENAI_API_KEY= < your OpenAI API key > <your OpenAI API key> é uma string que se parece com a seguinte: sk-<your key> . Você pode encontrar sua chave da API no painel do Openai.
Você também pode especificar o nome do modelo como uma variável de ambiente ASKIT_MODEL :
export ASKIT_MODEL= < model name > <model name> é o nome do modelo que você deseja usar. O último askit é testado com gpt-4 e gpt-3.5-turbo-16k . Você pode encontrar a lista de modelos disponíveis na documentação da API do OpenAI.
Aqui estão alguns exemplos introdutórios:
import { ask } from 'ts-askit' ;
ask < string > ( 'Paraphrase "Hello World!"' ) . then ( ( result ) => {
console . log ( result ) ;
} ) ; Neste exemplo, ask é uma função de API que permite que seu programa represente consultas para um grande modelo de idioma (LLM). O parâmetro de tipo representa o tipo de saída esperado do LLM. Aqui, o tipo de saída é string . O prompt é aprovado como um argumento na linguagem natural, descrevendo a tarefa para o LLM executar. ask é assíncrono, retornando uma Promise do tipo de saída especificado. O trecho de código acima deve imprimir algo assim:
Greetings, Universe!
Para um prompt com parâmetros, você pode usar a API define da seguinte maneira:
import { define } from 'ts-askit' ;
const paraphrase = define < string > ( 'Paraphrase {{text}}' ) ;
paraphrase ( { text : 'Hello World!' } ) . then ( ( result ) => {
console . log ( result ) ;
} ) ; define é uma função API que permite definir uma função personalizada. Seu parâmetro de tipo indica o tipo de saída do LLM e, consequentemente, o valor de retorno da função. A função recebe um modelo de string como argumento, servindo como o prompt de tarefa do LLM. O modelo pode incluir parâmetros envolvidos em aparelhos duplos encaracolados. No exemplo acima, text é um parâmetro dentro do modelo e pode ser qualquer identificador JavaScript válido.
Depois que a função é definida, ela pode ser invocada como qualquer outra função. Esta função aceita um objeto como um argumento, que mapeia os valores dos parâmetros do modelo. Nesse caso, text mapeia a string 'Hello World!'.
Askit é adepto de gerar código a partir de descrições de linguagem natural. Aqui está um exemplo:
import { define } from 'ts-askit' ;
const sort = define < number [ ] , { numbers : number [ ] } > (
'Sort {{numbers}} in ascending order'
) ; Este exemplo mostra uma função que classifica uma matriz de números em ordem ascendente, utilizando a API define para instruir o LLM a definir a função. Embora seja eficiente em conceito, esse método pode parecer computacionalmente pesado, pois cada chamada de função requer uma nova tarefa LLM.
Para otimizar esse processo, podemos aproveitar o LLM para gerar o código da função de classificação, em vez de recorrer ao LLM para todas as tarefas de classificação. Isso otimiza a função sem exigir quaisquer alterações em sua implementação, graças aos recursos de geração de código da Askit .
O código para a função acima mencionada pode ser gerado em três etapas:
tsc . O analisador AKIT digitaliza o código e gera um arquivo JSONL contendo detalhes sobre as chamadas de API define e ask .npx askgen < jsonl file >tsc . Desta vez, as chamadas de API define e ask são substituídas pelas referências e chamadas para a função recém-gerada, respectivamente, graças ao recurso de substituição automática da Askit . Askit permite que você aproveite o poder da programação pelo exemplo (PBE). O PBE simplifica o processo de programação, permitindo que você defina a funcionalidade por meio de exemplos, em vez de lógica codificada. O exemplo a seguir ilustra isso mostrando como adicionar dois números binários usando o PBE com 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 ( ) ; Neste exemplo, definimos uma função addInBase2 que leva dois números binários (representados como strings) e os adiciona. A função define é invocada com um prompt e duas matrizes de exemplos: exemplos de treinamento e exemplos de teste. Os exemplos de treinamento são refletidos no aviso de alguma maneira de aprendizado. Por outro lado, os exemplos de teste são usados para validar a correção da função gerada. Exemplos de teste não são necessários se você não gerar código para a função.
O resultado é um recurso poderoso, permitindo que você instrua o LLM a executar operações complexas, como adição binária, usando nada além de exemplos. Essa abordagem permite que você desenvolva funcionalidade complexa rapidamente e com lógica menos explícita.
Depois que a função addInBase2 for definida, você pode chamá -lo com strings de número binário para executar a adição na base 2. Como nas chamadas de função tradicionais, a Operação ask Askit retorna uma promessa que resolve com o resultado calculado.
Os desenvolvedores JavaScript podem explorar completamente o potencial do controle de saída guiado por tipo oferecido pela ASKIT . Assim como o seu tipógrafo de irmãos, o JavaScript incorpora o método da API ask isso para conseguir isso. A função ask leva dois parâmetros: um tipo e um prompt.
Aqui está uma variedade de exemplos demonstrando seu 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 ) } ) ; No trecho de código acima, a função ask é invocada com um tipo e um prompt. O parâmetro de tipo serve ao objetivo de informar o Askit sobre o formato e a estrutura da saída desejada. Isso se torna extremamente útil quando você está lidando com estruturas de dados complexas.
Com o Askit , os desenvolvedores JavaScript têm a capacidade de definir funções usando modelos fáceis de entender. O método define é o herói nos bastidores aqui, pois ajuda a criar funções com base no modelo de tarefa fornecido. Uma vez criado, essas funções podem ser chamadas com qualquer objeto que forneça valores para os espaços reservados no modelo.
Aqui está um exemplo de como é feito:
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 ) } ) ; No código acima, o método define é empregado para estabelecer uma função f usando um modelo de tarefa 'tradução {{text}} em {{idioma}}'. A função f é então invocada com um objeto que fornece valores para text e language .
O módulo 'ts-askit/types' é um tesouro de tipos que você pode utilizar para orientar a saída do Askit . Aqui está uma tabela para ajudá -lo a entender rapidamente estes tipos:
| Tipo | Descrição | Exemplo de tipo | Exemplo de valor |
|---|---|---|---|
NumberType | Tipo numérico | t.number | 123 |
StringType | Tipo de string | t.string | "Olá, mundo!" |
BooleanType | Tipo booleano | t.boolean | verdadeiro |
LiteralType | Tipo de valor literal | t.literal(123) | 123 |
ArrayType | Tipo de matriz | t.array(t.number) | [1, 2, 3] |
UnionType | Tipo de união (múltiplos valores possíveis) | t.union([t.literal('yes'), t.literal('no')]) | "Sim" ou "Não" |
InterfaceType | Tipo de interface/dicionário | t.type({a: t.number, b: t.number}) | {a: 1, b: 2} |
CodeType | Tipo de código | t.code('python') | "Def hello_world (): print ('Olá, mundo!')" |
Cada tipo possui propriedades específicas que askit usa para compreender a tarefa em questão e formatar corretamente a saída.
Até o momento da redação deste artigo, o recurso de geração de código está disponível exclusivamente no TypeScript. No entanto, os esforços estão em pleno andamento para estender esse recurso poderoso ao reino do JavaScript. Se seus requisitos solicitarem o uso da geração de código nesse meio tempo, recomendamos o uso do TypeScript até mais atualizações.
Para obter detalhes sobre o nosso código de conduta e o processo para enviar solicitações de tração, consulte contribuindo.md.
Este projeto está licenciado sob a licença do MIT. Para mais informações, consulte o arquivo de licença.
@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 }
}