aster的Agent遵循清晰的生命周期模型,从创建到销毁经历多个阶段。理解生命周期对于正确使用和扩展aster至关重要。
┌──────────────┐
│ Create │ 创建Agent实例
│ (准备阶段) │
└──────┬───────┘
│
▼
┌──────────────┐
│ Start │ 启动Agent(可选显式调用)
│ (初始化) │
└──────┬───────┘
│
▼
┌──────────────┐
│ Running │ 执行对话
│ (Chat/Send) │ ◄─────┐
└──────┬───────┘ │
│ │ 循环
│ ┌──────────────┘
│ │
│ ▼
│ ┌─────────────┐
│ │ Processing │ 处理消息
│ │ (内部循环) │
│ └─────────────┘
│ │
│ ▼
│ ┌─────────────┐
│ │Tool Execute │ 执行工具
│ │(可选) │
│ └─────────────┘
▼
┌──────────────┐
│ Close │ 关闭Agent
│ (清理资源) │
└──────────────┘
ag, err := agent.Create(context.Background(), &types.AgentConfig{
TemplateID: "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",
},
}, deps)
type AgentConfig struct {
// Agent标识
ID string // 可选,自动生成UUID
TemplateID string // 模板ID
// 模型配置
ModelConfig *ModelConfig
// 沙箱配置
Sandbox *SandboxConfig
// 中间件列表
Middlewares []string
// 系统提示词(可选,覆盖模板)
SystemPrompt string
// 工具配置
Tools []interface{} // 工具名称或工具实例
}
type Dependencies struct {
// 必需
Store Store // 持久化存储
SandboxFactory SandboxFactory // 沙箱工厂
ToolRegistry ToolRegistry // 工具注册表
ProviderFactory ProviderFactory // Provider工厂
TemplateRegistry TemplateRegistry // 模板注册表
// 可选
MiddlewareRegistry MiddlewareRegistry // 中间件注册表
}
虽然Start通常不需要显式调用(Chat会自动调用),但理解它很重要。
// 通常由Chat自动调用,但也可以显式启动
ag.Start(ctx)
for _, m := range middlewares {
m.OnAgentStart(ctx, agentID)
}
这是Agent的主要工作阶段,包含两种交互模式。
阻塞等待完整响应:
result, err := ag.Chat(ctx, "你好,请介绍一下Go语言")
if err != nil {
log.Fatal(err)
}
fmt.Println(result.Text)
Chat流程:
1. 发送用户消息 → Send()
2. 订阅Progress通道
3. 循环处理事件直到完成
4. 返回最终结果
非阻塞,实时处理事件:
// 1. 订阅事件
eventCh := ag.Subscribe([]types.AgentChannel{
types.ChannelProgress,
}, nil)
// 2. 启动事件处理
go func() {
for envelope := range eventCh {
switch e := envelope.Event.(type) {
case *types.ProgressTextChunkEvent:
fmt.Print(e.Delta)
case *types.ProgressToolStartEvent:
fmt.Printf("\n[Tool] %s\n", e.Call.Name)
}
}
}()
// 3. 发送消息
ag.Send(ctx, "你好,请介绍一下Go语言")
User Message
│
▼
┌────────────────┐
│ processMessages│ 主处理循环
└────┬───────────┘
│
▼
┌────────────────┐
│ runModelStep │ 调用模型
└────┬───────────┘
│
├─► Text Chunk → ProgressTextChunkEvent
│
├─► Tool Call
│ │
│ ▼
│ ┌──────────────┐
│ │ executeTools │ 执行工具
│ └──────┬───────┘
│ │
│ ▼
│ ┌──────────────┐
│ │ Tool Result │
│ └──────┬───────┘
│ │
│ └─────► 继续循环
│
└─► Stop Reason = "end_turn"
│
▼
结束循环,返回结果
ag.Send(ctx, "请创建一个hello.txt文件")
ag.SendSystemMessage(ctx, "当前时间是 2024-01-15 10:30")
工具执行完成后自动添加到历史。
工具执行是Agent运行时的关键环节。
1. 模型返回tool_use块
│
▼
2. 提取工具调用参数
│
▼
3. 查找工具定义
│
▼
4. 通过中间件栈执行
│ (WrapToolCall洋葱模型)
▼
5. 工具Execute方法
│
▼
6. 返回结果
│
▼
7. 构造tool_result消息
│
▼
8. 继续模型调用
// 模型请求
{
"type": "tool_use",
"id": "toolu_123",
"name": "Write",
"input": {
"path": "/hello.txt",
"content": "Hello World"
}
}
// 工具执行
tool := registry.GetTool("Write")
result, err := tool.Execute(ctx, input)
// 构造响应
{
"type": "tool_result",
"tool_use_id": "toolu_123",
"content": "{\"ok\": true, \"path\": \"/hello.txt\"}"
}
// 工具应返回结构化错误,而不是Go error
if err != nil {
return map[string]interface{}{
"ok": false,
"error": "文件不存在",
"path": path,
}, nil // 注意:返回nil error
}
这样LLM可以看到错误信息并尝试恢复。
Agent在运行时发布各种事件。
// 文本流
&types.ProgressTextChunkEvent{
Delta: "部分文本",
}
// 工具开始
&types.ProgressToolStartEvent{
Call: ToolCall{
ID: "toolu_123",
Name: "Write",
Input: map[string]interface{}{...},
},
}
// 工具结束
&types.ProgressToolEndEvent{
CallID: "toolu_123",
Result: map[string]interface{}{...},
}
// 错误事件
&types.MonitorErrorEvent{
Error: err,
Context: "模型调用失败",
}
// 工具执行审计
&types.MonitorToolExecutionEvent{
ToolName: "Write",
Duration: 15 * time.Millisecond,
Success: true,
}
// 工具审批请求
&types.ControlToolApprovalRequest{
ToolCall: call,
Reason: "需要审批写操作",
}
结束Agent生命周期,清理资源。
defer ag.Close()
// 或显式调用
ag.Close()
for _, m := range middlewares {
m.OnAgentStop(ctx, agentID)
}
// 使用context控制超时
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// 等待当前操作完成
result, err := ag.Chat(ctx, "最后一个问题")
// 关闭
ag.Close()
type AgentState int
const (
StateCreated AgentState = iota // 已创建
StateStarted // 已启动
StateRunning // 运行中
StateStopped // 已停止
StateClosed // 已关闭
)
Created → Started → Running ⟷ Running → Stopped → Closed
↑ │
└────────────────────┘
(循环对话)
state := ag.GetState()
if state == agent.StateRunning {
log.Println("Agent正在处理消息")
}
ag, err := agent.Create(ctx, config, deps)
if err != nil {
log.Fatal(err)
}
defer ag.Close() // ✅ 确保资源释放
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
result, err := ag.Chat(ctx, message)
// ✅ 推荐
eventCh := ag.Subscribe(channels, nil)
go func() {
for event := range eventCh {
// 处理事件
}
}()
// ❌ 不推荐(阻塞主线程)
result, _ := ag.Chat(ctx, longRunningTask)
result, err := ag.Chat(ctx, message)
if err != nil {
// 检查具体错误类型
if errors.Is(err, context.DeadlineExceeded) {
log.Println("超时")
} else {
log.Printf("错误: %v", err)
}
return
}
// ✅ 推荐:一个Agent处理多轮对话
ag, _ := agent.Create(ctx, config, deps)
defer ag.Close()
ag.Chat(ctx, "第一个问题")
ag.Chat(ctx, "第二个问题") // 保留上下文
// ❌ 不推荐:每次都创建新Agent(丢失上下文)
for _, question := range questions {
ag, _ := agent.Create(ctx, config, deps)
ag.Chat(ctx, question)
ag.Close()
}