本示例展示如何创建一个完整的 Agent,包括:
创建 Agent 需要以下核心依赖:
// 1. 创建工具注册表并注册内置工具
toolRegistry := tools.NewRegistry()
builtin.RegisterAll(toolRegistry)
// 2. 创建Sandbox工厂
sandboxFactory := sandbox.NewFactory()
// 3. 创建Provider工厂
providerFactory := &provider.AnthropicFactory{}
// 4. 创建Store
storePath := ".aster"
jsonStore, err := store.NewJSONStore(storePath)
if err != nil {
log.Fatalf("Failed to create store: %v", err)
}
// 5. 创建模板注册表
templateRegistry := agent.NewTemplateRegistry()
关键点:
ToolRegistry - 管理所有可用工具SandboxFactory - 创建沙箱实例ProviderFactory - 创建 LLM ProviderStore - 持久化存储消息和状态TemplateRegistry - 管理 Agent 模板定义 Agent 的行为和能力:
templateRegistry.Register(&types.AgentTemplateDefinition{
ID: "simple-assistant",
Model: "claude-sonnet-4-5",
SystemPrompt: "You are a helpful assistant that can read and write files. When users ask you to read or write files, use the available tools.",
Tools: []interface{}{"Read", "Write", "Bash"},
})
模板字段说明:
ID - 模板唯一标识Model - 使用的模型名称SystemPrompt - 系统提示词,定义 Agent 角色Tools - 可用工具列表将所有依赖组装到一起:
deps := &agent.Dependencies{
Store: jsonStore,
SandboxFactory: sandboxFactory,
ToolRegistry: toolRegistry,
ProviderFactory: providerFactory,
TemplateRegistry: templateRegistry,
}
config := &types.AgentConfig{
TemplateID: "simple-assistant",
ModelConfig: &types.ModelConfig{
Provider: "anthropic",
Model: "claude-sonnet-4-5",
APIKey: os.Getenv("ANTHROPIC_API_KEY"),
},
Sandbox: &types.SandboxConfig{
Kind: types.SandboxKindLocal,
WorkDir: "./workspace",
},
}
配置说明:
TemplateID - 使用的模板 IDModelConfig - LLM 配置(Provider、模型、API Key)Sandbox - 沙箱配置(类型、工作目录)ag, err := agent.Create(ctx, config, deps)
if err != nil {
log.Fatalf("Failed to create agent: %v", err)
}
defer ag.Close()
fmt.Printf("Agent created: %s\n", ag.ID())
监听 Agent 的实时进度和状态变化:
eventCh := ag.Subscribe([]types.AgentChannel{
types.ChannelProgress, // 进度事件(文本输出、工具调用等)
types.ChannelMonitor, // 监控事件(状态变化、Token使用等)
}, nil)
// 启动事件监听
go func() {
for envelope := range eventCh {
if evt, ok := envelope.Event.(types.EventType); ok {
switch evt.Channel() {
case types.ChannelProgress:
handleProgressEvent(envelope.Event)
case types.ChannelMonitor:
handleMonitorEvent(envelope.Event)
}
}
}
}()
发送消息并获取响应:
// 测试1: 创建文件
result, err := ag.Chat(ctx, "Please create a file called test.txt with content 'Hello World'")
if err != nil {
log.Fatalf("Chat failed: %v", err)
}
fmt.Printf("Assistant: %s\n", result.Text)
// 测试2: 读取文件
result, err = ag.Chat(ctx, "Please read the test.txt file")
if err != nil {
log.Fatalf("Chat failed: %v", err)
}
fmt.Printf("Assistant: %s\n", result.Text)
// 测试3: 执行命令
result, err = ag.Chat(ctx, "Please run 'ls -la' command")
if err != nil {
log.Fatalf("Chat failed: %v", err)
}
fmt.Printf("Assistant: %s\n", result.Text)
根据不同事件类型执行相应逻辑:
func handleProgressEvent(event interface{}) {
switch e := event.(type) {
case *types.ProgressTextChunkEvent:
fmt.Print(e.Delta) // 流式输出文本
case *types.ProgressToolStartEvent:
fmt.Printf("\n[Tool Start] %s\n", e.Call.Name)
case *types.ProgressToolEndEvent:
fmt.Printf("[Tool End] %s - State: %s\n", e.Call.Name, e.Call.State)
case *types.ProgressDoneEvent:
fmt.Printf("\n[Done] Step %d\n", e.Step)
}
}
func handleMonitorEvent(event interface{}) {
switch e := event.(type) {
case *types.MonitorStateChangedEvent:
fmt.Printf("[State] %s\n", e.State)
case *types.MonitorTokenUsageEvent:
fmt.Printf("[Tokens] Input: %d, Output: %d\n",
e.InputTokens, e.OutputTokens)
}
}
export ANTHROPIC_API_KEY=sk-ant-xxxxx
cd examples/agent
go run main.go
Agent created: agt-xxxxxx
--- Test 1: Create a test file ---
[Assistant] I'll create a file called test.txt with the content 'Hello World'.
[Tool Start] Write (ID: toolu_xxxxx)
[Tool End] Write - State: success
The file has been created successfully.
--- Test 2: Read the file back ---
[Assistant] I'll read the test.txt file.
[Tool Start] Read (ID: toolu_xxxxx)
[Tool End] Read - State: success
The content of test.txt is: Hello World
--- Test 3: Run a bash command ---
[Assistant] I'll run the 'ls -la' command.
[Tool Start] Bash (ID: toolu_xxxxx)
[Tool End] Bash - State: success
Here are the files in the directory:
...
Final Status:
Agent ID: agt-xxxxxx
State: idle
Steps: 3
Cursor: 42
aster 使用依赖注入来保持灵活性:
type Dependencies struct {
Store store.Store // 可替换存储
SandboxFactory sandbox.Factory // 可替换沙箱
ToolRegistry tools.Registry // 可扩展工具
ProviderFactory provider.Factory // 可替换 LLM
TemplateRegistry *agent.TemplateRegistry // 可定制模板
}
优势:
Agent 通过事件通道传递实时信息:
graph LR
Agent[Agent] -->|进度事件| Progress[Progress Channel]
Agent -->|监控事件| Monitor[Monitor Channel]
Agent -->|控制事件| Control[Control Channel]
Progress -->|文本输出| UI1[用户界面]
Progress -->|工具调用| UI1
Monitor -->|状态变化| Dashboard[监控面板]
Monitor -->|Token使用| Dashboard
Control -->|工具确认| Handler[业务逻辑]
事件类型:
| 通道 | 事件类型 | 用途 |
|---|---|---|
| Progress | TextChunkEvent | 流式文本输出 |
| Progress | ToolStartEvent | 工具调用开始 |
| Progress | ToolEndEvent | 工具调用结束 |
| Progress | DoneEvent | 步骤完成 |
| Monitor | StateChangedEvent | 状态变化 |
| Monitor | TokenUsageEvent | Token 使用统计 |
| Control | ToolApprovalEvent | 工具调用确认请求 |
// 创建
ag, err := agent.Create(ctx, config, deps)
// 使用
result, err := ag.Chat(ctx, "消息")
// 暂停
ag.Pause()
// 恢复
ag.Resume()
// 关闭
ag.Close()
修改 ModelConfig 即可:
config := &types.AgentConfig{
ModelConfig: &types.ModelConfig{
Provider: "openai", // 改为 openai
Model: "gpt-4o",
APIKey: os.Getenv("OPENAI_API_KEY"),
},
}
修改 SandboxConfig:
config := &types.AgentConfig{
Sandbox: &types.SandboxConfig{
Kind: types.SandboxKindAgentBay, // 阿里云
Config: map[string]interface{}{
"accessKeyID": os.Getenv("ALIYUN_ACCESS_KEY_ID"),
"accessKeySecret": os.Getenv("ALIYUN_ACCESS_KEY_SECRET"),
"endpoint": os.Getenv("AGENTBAY_ENDPOINT"),
},
},
}
aster 自动通过 Store 持久化:
// 创建时会加载历史消息
ag, err := agent.Create(ctx, config, deps)
// 每次 Chat 后自动保存
result, err := ag.Chat(ctx, "消息")
// 下次创建相同 AgentID 的 Agent 时会恢复历史