核心概念

Agent生命周期

深入理解Agent的创建、运行和销毁过程

Agent生命周期

aster的Agent遵循清晰的生命周期模型,从创建到销毁经历多个阶段。理解生命周期对于正确使用和扩展aster至关重要。

🔄 生命周期概览

┌──────────────┐
│   Create     │  创建Agent实例
│  (准备阶段)  │
└──────┬───────┘
       │
       ▼
┌──────────────┐
│   Start      │  启动Agent(可选显式调用)
│  (初始化)    │
└──────┬───────┘
       │
       ▼
┌──────────────┐
│  Running     │  执行对话
│ (Chat/Send)  │  ◄─────┐
└──────┬───────┘         │
       │                 │ 循环
       │  ┌──────────────┘
       │  │
       │  ▼
       │ ┌─────────────┐
       │ │ Processing  │  处理消息
       │ │ (内部循环)  │
       │ └─────────────┘
       │       │
       │       ▼
       │ ┌─────────────┐
       │ │Tool Execute │  执行工具
       │ │(可选)       │
       │ └─────────────┘
       ▼
┌──────────────┐
│    Close     │  关闭Agent
│  (清理资源)  │
└──────────────┘

📝 Create阶段

创建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)

创建时发生了什么?

  1. 验证配置
    • 检查必需字段
    • 验证模板ID
    • 检查模型Provider
  2. 初始化依赖
    • 创建工具注册表
    • 初始化存储后端
    • 配置沙箱工厂
  3. 注册中间件
    • 按配置加载中间件
    • 构建中间件栈(按优先级排序)
    • 收集所有工具
  4. 创建事件系统
    • 初始化三个事件通道
    • 启动事件分发器
  5. 准备Provider
    • 初始化大模型客户端
    • 配置API密钥和参数

配置详解

AgentConfig

type AgentConfig struct {
    // Agent标识
    ID         string  // 可选,自动生成UUID
    TemplateID string  // 模板ID

    // 模型配置
    ModelConfig *ModelConfig

    // 沙箱配置
    Sandbox *SandboxConfig

    // 中间件列表
    Middlewares []string

    // 系统提示词(可选,覆盖模板)
    SystemPrompt string

    // 工具配置
    Tools []interface{}  // 工具名称或工具实例
}

Dependencies

type Dependencies struct {
    // 必需
    Store            Store             // 持久化存储
    SandboxFactory   SandboxFactory    // 沙箱工厂
    ToolRegistry     ToolRegistry      // 工具注册表
    ProviderFactory  ProviderFactory   // Provider工厂
    TemplateRegistry TemplateRegistry  // 模板注册表

    // 可选
    MiddlewareRegistry MiddlewareRegistry  // 中间件注册表
}

🚀 Start阶段

虽然Start通常不需要显式调用(Chat会自动调用),但理解它很重要。

启动流程

// 通常由Chat自动调用,但也可以显式启动
ag.Start(ctx)

Start时发生了什么?

  1. 触发中间件钩子
    for _, m := range middlewares {
        m.OnAgentStart(ctx, agentID)
    }
    
  2. 初始化消息历史
    • 加载系统提示词
    • 如果有持久化状态,恢复历史消息
  3. 启动事件监听
    • 开始监听控制事件
    • 准备接收用户输入

💬 Running阶段

这是Agent的主要工作阶段,包含两种交互模式。

模式1:同步对话(Chat)

阻塞等待完整响应:

result, err := ag.Chat(ctx, "你好,请介绍一下Go语言")
if err != nil {
    log.Fatal(err)
}
fmt.Println(result.Text)

Chat流程

1. 发送用户消息 → Send()
2. 订阅Progress通道
3. 循环处理事件直到完成
4. 返回最终结果

模式2:异步流式(Send + Subscribe)

非阻塞,实时处理事件:

// 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")

工具结果消息(自动)

工具执行完成后自动添加到历史。

🛠️ Tool Execution

工具执行是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在运行时发布各种事件。

Progress事件

// 文本流
&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{}{...},
}

Monitor事件

// 错误事件
&types.MonitorErrorEvent{
    Error:   err,
    Context: "模型调用失败",
}

// 工具执行审计
&types.MonitorToolExecutionEvent{
    ToolName: "Write",
    Duration: 15 * time.Millisecond,
    Success:  true,
}

Control事件

// 工具审批请求
&types.ControlToolApprovalRequest{
    ToolCall: call,
    Reason:   "需要审批写操作",
}

🔚 Close阶段

结束Agent生命周期,清理资源。

关闭Agent

defer ag.Close()

// 或显式调用
ag.Close()

Close时发生了什么?

  1. 触发中间件钩子
    for _, m := range middlewares {
        m.OnAgentStop(ctx, agentID)
    }
    
  2. 关闭事件通道
    • 停止接收新事件
    • 关闭所有订阅通道
  3. 保存状态
    • 如果配置了持久化,保存消息历史
    • 保存Agent状态
  4. 释放资源
    • 关闭沙箱连接
    • 释放Provider资源
    • 清理临时文件

优雅关闭

// 使用context控制超时
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

// 等待当前操作完成
result, err := ag.Chat(ctx, "最后一个问题")

// 关闭
ag.Close()

🔄 状态管理

Agent状态

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正在处理消息")
}

🎯 最佳实践

1. 始终defer Close

ag, err := agent.Create(ctx, config, deps)
if err != nil {
    log.Fatal(err)
}
defer ag.Close()  // ✅ 确保资源释放

2. 使用context控制超时

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()

result, err := ag.Chat(ctx, message)

3. 异步处理长时间运行的任务

// ✅ 推荐
eventCh := ag.Subscribe(channels, nil)
go func() {
    for event := range eventCh {
        // 处理事件
    }
}()

// ❌ 不推荐(阻塞主线程)
result, _ := ag.Chat(ctx, longRunningTask)

4. 正确处理错误

result, err := ag.Chat(ctx, message)
if err != nil {
    // 检查具体错误类型
    if errors.Is(err, context.DeadlineExceeded) {
        log.Println("超时")
    } else {
        log.Printf("错误: %v", err)
    }
    return
}

5. 复用Agent实例

// ✅ 推荐:一个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()
}

📚 下一步

🔗 相关API