No description
- Go 100%
| docs | ||
| examples | ||
| .env.example | ||
| .gitignore | ||
| agent.go | ||
| agent_integration_test.go | ||
| agent_unit_test.go | ||
| context.go | ||
| coverage.out | ||
| errors.go | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| message.go | ||
| message_test.go | ||
| options.go | ||
| README.md | ||
| tool.go | ||
| tool_test.go | ||
go-simple-agent
Легковесный Go-пакет для создания LLM-агентов. Работает поверх llm-simple-api.
Установка
go get git.ymnuktech.ru/ymnuk/go-simple-agent
Быстрый старт
package main
import (
"context"
"fmt"
"log"
llmsdk "git.ymnuktech.ru/ymnuk/llm-simple-api"
"git.ymnuktech.ru/ymnuk/go-simple-agent"
)
func main() {
api := llmsdk.NewLLMSimpleAPI(&llmsdk.LLMOpts{
BaseUrl: "http://localhost:11434/v1",
Model: "gpt-3.5-turbo",
MaxTokens: 4096,
NotContinue: true,
})
ag, err := agent.NewAgent(api, agent.WithMaxIterations(5))
if err != nil {
log.Fatal(err)
}
output, _, err := ag.Run(context.Background(), "What is 2+2?", nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(output)
}
Tool
type Tool interface {
Name() string
Description() string
Schema() json.RawMessage
Call(ctx context.Context, args json.RawMessage) (json.RawMessage, error)
}
Регистрация тула в llm-simple-api (отдельно от агента):
type WeatherArgs struct {
Location string `json:"location"`
}
tool := &myWeatherTool{}
api.RegisterTool(tool.Name(), tool.Description(), agent.WrapTool[WeatherArgs](tool))
Subagent (агент как Tool)
Любой Agent может быть обёрнут в Tool и вызван другим агентом. Для этого не нужно менять библиотеку — достаточно реализовать Tool, внутри Call которого запускается subagent.
type SubagentTool struct {
name string
subAgent *agent.Agent
}
func (s *SubagentTool) Name() string { return s.name }
func (s *SubagentTool) Description() string { return "..." }
func (s *SubagentTool) Schema() json.RawMessage { return nil }
func (s *SubagentTool) Call(ctx context.Context, args json.RawMessage) (json.RawMessage, error) {
var params struct{ Task string `json:"task"` }
json.Unmarshal(args, ¶ms)
output, _, err := s.subAgent.Run(ctx, params.Task, nil)
if err != nil {
return nil, err
}
return json.RawMessage(`{"result": "` + output + `"}`), nil
}
Subagent использует отдельный llm-simple-api со своими тулами и настройками:
subAPI := llmsdk.NewLLMSimpleAPI(...)
subAgent, _ := agent.NewAgent(subAPI, agent.WithMaxIterations(3))
subAgent.SetSystemPrompt("You are a maths expert.")
subTool := &SubagentTool{name: "math_expert", subAgent: subAgent}
api.RegisterTool(subTool.Name(), subTool.Description(),
agent.WrapTool[struct{Task string `json:"task"`}](subTool))
Сжатие контекста (OnLimitHandler)
Агент предоставляет callback для HistoryOpts.OnLimit в llm-simple-api:
ag, _ := agent.NewAgent(api,
agent.WithMaxIterations(20),
agent.WithContextStrategy(myCompressStrategy),
)
api.SetOpts(llmsdk.LLMOpts{
History: llmsdk.HistoryOpts{
Threshold: 3000,
OnLimit: ag.OnLimitHandler(),
},
})
Сигнатура стратегии:
type ContextStrategy func(history []llmsdk.Message, promptTokens, totalTokens int) ([]llmsdk.Message, error)
Стратегия получает историю (включая system prompt), сжимает и возвращает. Агент подставляет [system] + compressed обратно. Если стратегия не задана — история возвращается без изменений.
Архитектура
Agent.Run(ctx, input, history)
│
├─ SetHistory(system + history)
├─ ChatCompletions(input) // 1 раунд: запрос → tool_calls → выполнение
├─ for IsNeedContinue() && ... // пока есть tool_calls
│ Continue()
├─ GetHistory()
└─ return (output, newHistory)
- Цикл tool_calls —
llm-simple-api(конкурентно черезMaxParallelTools) - Тулы регистрируются в
llm-simple-apiнапрямую, агенту не нужны - Сжатие контекста — через
OnLimitHandler()+ внешняяContextStrategy - Статус —
IsNeedContinue()определяет, нужно ли продолжать
API
func NewAgent(api *llmsdk.LLMSimpleAPI, opts ...AgentOption) (*Agent, error)
func (a *Agent) Run(ctx context.Context, input string, history []Message) (string, []Message, error)
func (a *Agent) SetSystemPrompt(prompt string)
func (a *Agent) OnLimitHandler() llmsdk.HistoryLimitCallback
func WithMaxIterations(n int) AgentOption
func WithContextStrategy(s ContextStrategy) AgentOption
Лицензия
MIT