Integre o poder dos grandes modelos de linguagem (LLM) ao seu aplicativo Go.
Este projeto visa abstrair grande parte do encanamento (texto livre para dados estruturados, memória contextual, agrupamento de ferramentas, lógica de repetição, etc.) para que você possa se concentrar na lógica de negócios do seu agente.
gráfico LR
Entrada de subgrafo
A[Entrada Estruturada] -> B[Tarefa Compilada]
fim
subgrafo Agente baseado em LLM
C[Modelo de Tarefa] -> B[Tarefa Compilada]
B --> D((Agente))
D --"Raciocínio"--> D
D --"Ação"--> E[Meio Ambiente]
E --"Observação"--> D
D --"Resposta"--> G[Validadores de Saída]
G --> D
fim
Saída do subgrafo
G --"Resposta"--> F[Saída Estruturada]
fim
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/natexcvi/go-llm/agents"
"github.com/natexcvi/go-llm/engines"
"github.com/natexcvi/go-llm/memory"
"github.com/natexcvi/go-llm/tools"
)
type CodeBaseRefactorRequest struct {
Dir string
Goal string
}
func ( req CodeBaseRefactorRequest ) Encode () string {
return fmt . Sprintf ( `{"dir": "%s", "goal": "%s"}` , req . Dir , req . Goal )
}
func ( req CodeBaseRefactorRequest ) Schema () string {
return `{"dir": "path to code base", "goal": "refactoring goal"}`
}
type CodeBaseRefactorResponse struct {
RefactoredFiles map [ string ] string `json:"refactored_files"`
}
func ( resp CodeBaseRefactorResponse ) Encode () string {
marshalled , err := json . Marshal ( resp . RefactoredFiles )
if err != nil {
panic ( err )
}
return string ( marshalled )
}
func ( resp CodeBaseRefactorResponse ) Schema () string {
return `{"refactored_files": {"path": "description of changes"}}`
}
func main () {
task := & agents. Task [ CodeBaseRefactorRequest , CodeBaseRefactorResponse ]{
Description : "You will be given access to a code base, and instructions for refactoring." +
"your task is to refactor the code base to meet the given goal." ,
Examples : []agents. Example [ CodeBaseRefactorRequest , CodeBaseRefactorResponse ]{
{
Input : CodeBaseRefactorRequest {
Dir : "/Users/nate/code/base" ,
Goal : "Handle errors gracefully" ,
},
Answer : CodeBaseRefactorResponse {
RefactoredFiles : map [ string ] string {
"/Users/nate/code/base/main.py" : "added try/except block" ,
},
},
IntermediarySteps : [] * engines. ChatMessage {
( & agents. ChainAgentThought {
Content : "I should scan the code base for functions that might error." ,
}). Encode ( engine ),
( & agents. ChainAgentAction {
Tool : tools . NewBashTerminal (),
Args : json . RawMessage ( `{"command": "ls /Users/nate/code/base"}` ),
}). Encode ( engine ),
( & agents. ChainAgentObservation {
Content : "main.py" ,
ToolName : tools . NewBashTerminal (). Name (),
}). Encode ( engine ),
( & agents. ChainAgentThought {
Content : "Now I should read the code file." ,
}). Encode ( engine ),
( & agents. ChainAgentAction {
Tool : tools . NewBashTerminal (),
Args : json . RawMessage ( `{"command": "cat /Users/nate/code/base/main.py"}` ),
}). Encode ( engine ),
( & agents. ChainAgentObservation {
Content : "def main(): n t func_that_might_error()" ,
ToolName : tools . NewBashTerminal (). Name (),
}). Encode ( engine ),
( & agents. ChainAgentThought {
Content : "I should refactor the code to handle errors gracefully." ,
}). Encode ( engine ),
( & agents. ChainAgentAction {
Tool : tools . NewBashTerminal (),
Args : json . RawMessage ( `{"command": "echo 'def main():nttry:nttfunc_that_might_error()ntexcept Exception as e:nttprint("Error: %s", e)' > /Users/nate/code/base/main.py"}` ),
}). Encode ( engine ),
},
},
},
AnswerParser : func ( msg string ) ( CodeBaseRefactorResponse , error ) {
var res CodeBaseRefactorResponse
if err := json . Unmarshal ([] byte ( msg ), & res ); err != nil {
return CodeBaseRefactorResponse {}, err
}
return res , nil
},
}
agent := agents . NewChainAgent ( engines . NewGPTEngine ( os . Getenv ( "OPENAI_TOKEN" ), "gpt-3.5-turbo-0613" ), task , memory . NewBufferedMemory ( 0 )). WithMaxSolutionAttempts ( 12 ). WithTools ( tools . NewPythonREPL (), tools . NewBashTerminal ())
res , err := agent . Run ( CodeBaseRefactorRequest {
Dir : "/Users/nate/Git/go-llm/tools" ,
Goal : "Write unit tests for the bash.go file, following the example of python_repl_test.go." ,
})
...
}
Observação
Curiosidade: o arquivo
tools/bash_test.go
foi escrito por esse mesmo agente e ajudou a encontrar um bug!
Conectores para motores LLM. Atualmente, apenas a API de conclusão de bate-papo GPT da OpenAI é suportada.
Ferramentas que podem fornecer aos agentes a capacidade de realizar ações interagindo com o mundo exterior. As ferramentas atualmente disponíveis são:
PythonREPL
- uma ferramenta que permite aos agentes executar código Python em um REPL.IsolatedPythonREPL
– uma ferramenta que permite aos agentes executar código Python em um REPL, mas em um contêiner Docker.BashTerminal
– uma ferramenta que permite aos agentes executar comandos bash em um terminal.GoogleSearch
- uma ferramenta que permite aos agentes pesquisar no Google.WebpageSummary
– uma ferramenta baseada em LLM que permite aos agentes obter um resumo de uma página da web.WolframAlpha
- uma ferramenta que permite aos agentes consultar a API de resposta curta do WolframAlpha.KeyValueStore
- uma ferramenta para armazenar e recuperar informações. O agente pode usar esta ferramenta para reutilizar longas informações por referência, removendo duplicações e, portanto, reduzindo o tamanho do contexto.AskUser
- uma ferramenta de interatividade que permite ao agente solicitar esclarecimentos a um operador humano quando necessário.JSONAutoFixer
- uma metaferramenta habilitada por padrão. Quando os argumentos para qualquer ferramenta são fornecidos em um formato que não é JSON válido, essa ferramenta tenta corrigir a carga útil usando uma cadeia LLM separada.GenericAgentTool
- permite que um agente execute outro agente, com ferramentas pré-determinadas, fornecendo-lhe dinamicamente sua tarefa e entrada e coletando sua resposta final.Aviso
As ferramentas
BashTerminal
ePythonREPL
regulares permitem que o agente execute comandos arbitrários em sua máquina, use por sua própria conta e risco. Pode ser uma boa ideia usar o suporte integrado para retornos de chamada de confirmação de ação (consulte o métodoWithActionConfirmation
no tipoChainAgent
).
As ferramentas go-llm
suportam a nova interface de chamada de função OpenAI de forma transparente, para variantes de modelo que possuem esse recurso.
Um sistema de memória que permite aos agentes armazenar e recuperar informações. Os sistemas de memória atualmente disponíveis são:
BufferMemory
- que fornece a cada etapa do agente um buffer fixo de mensagens recentes do histórico de conversas.SummarisedMemory
- que fornece a cada etapa do agente um resumo do histórico da conversa, alimentado por um LLM.Os agentes são o principal componente da biblioteca. Os agentes podem realizar tarefas complexas que envolvem interações iterativas com o mundo exterior.
Uma coleção de agentes prontos que podem ser facilmente integrados à sua aplicação.
Uma coleção de ferramentas de avaliação para agentes e mecanismos.
package main
import (
"fmt"
"os"
"github.com/natexcvi/go-llm/engines"
"github.com/natexcvi/go-llm/evaluation"
)
func goodness ( _ * engines. ChatPrompt , _ * engines. ChatMessage , err error ) float64 {
if err != nil {
return 0
}
return 1
}
func main () {
engine := engines . NewGPTEngine ( os . Getenv ( "OPENAI_TOKEN" ), "gpt-3.5-turbo-0613" )
engineRunner := evaluation . NewLLMRunner ( engine )
evaluator := evaluation . NewEvaluator ( engineRunner , & evaluation. Options [ * engines. ChatPrompt , * engines. ChatMessage ]{
GoodnessFunction : goodness ,
Repetitions : 5 ,
})
testPack := [] * engines. ChatPrompt {
{
History : [] * engines. ChatMessage {
{
Text : "Hello, how are you?" ,
},
{
Text : "I'm trying to understand how this works." ,
},
},
},
{
History : [] * engines. ChatMessage {
{
Text : "Could you please explain it to me?" ,
},
},
},
}
results := evaluator . Evaluate ( testPack )
fmt . Println ( "Goodness level of the first prompt:" , results [ 0 ])
fmt . Println ( "Goodness level of the second prompt:" , results [ 1 ])
}