396 lines
21 KiB
Markdown
396 lines
21 KiB
Markdown
# Agent Loop 流程图对比
|
||
|
||
## 1. Incoming (refactor/agent) 流程
|
||
|
||
### 整体架构
|
||
```
|
||
User Message
|
||
↓
|
||
Message Bus (串行队列)
|
||
↓
|
||
processMessage()
|
||
↓
|
||
runAgentLoop()
|
||
↓
|
||
newTurnState() → 创建 turnState
|
||
↓
|
||
runTurn()
|
||
↓
|
||
registerActiveTurn(ts) ← 设置 al.activeTurn = ts (单例)
|
||
↓
|
||
[Turn 执行循环]
|
||
↓
|
||
clearActiveTurn(ts) ← 清除 al.activeTurn = nil
|
||
```
|
||
|
||
### runTurn() 详细流程
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ runTurn(ctx, turnState) │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 1. 注册 activeTurn (单例) │
|
||
│ al.registerActiveTurn(ts) │
|
||
│ defer al.clearActiveTurn(ts) │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 2. 发送 TurnStart 事件 │
|
||
│ al.emitEvent(EventKindTurnStart) │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 3. 加载 Session History & Summary │
|
||
│ history = Sessions.GetHistory() │
|
||
│ summary = Sessions.GetSummary() │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 4. 构建消息 │
|
||
│ messages = BuildMessages(...) │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 5. 检查 Context Budget │
|
||
│ if isOverContextBudget() { │
|
||
│ forceCompression() │
|
||
│ emitEvent(ContextCompress) │
|
||
│ } │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 6. 保存用户消息到 Session │
|
||
│ Sessions.AddMessage("user", ...) │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 7. Turn Loop (迭代执行) │
|
||
│ for iteration < MaxIterations { │
|
||
│ ┌─────────────────────────────┐ │
|
||
│ │ 7.1 调用 LLM │ │
|
||
│ │ callLLM() │ │
|
||
│ │ emitEvent(LLMStart) │ │
|
||
│ └─────────────────────────────┘ │
|
||
│ ↓ │
|
||
│ ┌─────────────────────────────┐ │
|
||
│ │ 7.2 处理 Tool Calls │ │
|
||
│ │ for each toolCall { │ │
|
||
│ │ emitEvent(ToolStart)│ │
|
||
│ │ executeTool() │ │
|
||
│ │ emitEvent(ToolEnd) │ │
|
||
│ │ } │ │
|
||
│ └─────────────────────────────┘ │
|
||
│ ↓ │
|
||
│ ┌─────────────────────────────┐ │
|
||
│ │ 7.3 检查中断 │ │
|
||
│ │ if gracefulInterrupt { │ │
|
||
│ │ break │ │
|
||
│ │ } │ │
|
||
│ └─────────────────────────────┘ │
|
||
│ ↓ │
|
||
│ ┌─────────────────────────────┐ │
|
||
│ │ 7.4 处理 Steering Messages │ │
|
||
│ │ pollSteering() │ │
|
||
│ └─────────────────────────────┘ │
|
||
│ } │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 8. 保存最终响应到 Session │
|
||
│ Sessions.AddMessage("assistant", ...) │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 9. 发送 TurnEnd 事件 │
|
||
│ al.emitEvent(EventKindTurnEnd) │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 10. 返回 turnResult │
|
||
│ {finalContent, status, followUps} │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
### 关键特点
|
||
- ✅ **事件驱动**: 每个阶段都发送事件到 EventBus
|
||
- ✅ **Hook 集成**: 在 before_llm, after_llm, before_tool, after_tool 触发 Hook
|
||
- ✅ **单 Turn**: 使用 `activeTurn` 单例,同一时间只有一个 turn
|
||
- ❌ **无并发**: 不支持多个 session 同时执行 turn
|
||
|
||
---
|
||
|
||
## 2. HEAD (feat/subturn-poc) 流程
|
||
|
||
### 整体架构
|
||
```
|
||
User Message
|
||
↓
|
||
Message Bus
|
||
↓
|
||
processMessage()
|
||
↓
|
||
runAgentLoop()
|
||
↓
|
||
检查 Context 中是否有 turnState
|
||
├─ 有 → 复用 (SubTurn 场景)
|
||
└─ 无 → 创建新的 rootTS
|
||
↓
|
||
存储到 activeTurnStates[sessionKey]
|
||
↓
|
||
runLLMIteration()
|
||
↓
|
||
[并发 SubTurn 支持]
|
||
```
|
||
|
||
### runAgentLoop() 详细流程
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ runAgentLoop(ctx, agent, opts) │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 1. 检查是否在 SubTurn 中 │
|
||
│ existingTS = turnStateFromContext() │
|
||
│ if existingTS != nil { │
|
||
│ rootTS = existingTS (复用) │
|
||
│ isRootTurn = false │
|
||
│ } else { │
|
||
│ rootTS = new turnState │
|
||
│ isRootTurn = true │
|
||
│ } │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 2. 注册 Turn State (支持并发) │
|
||
│ if isRootTurn { │
|
||
│ al.activeTurnStates.Store( │
|
||
│ sessionKey, rootTS) │
|
||
│ defer activeTurnStates.Delete() │
|
||
│ } │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 3. 记录 Last Channel │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 4. 构建消息 │
|
||
│ messages = BuildMessages(...) │
|
||
│ messages = resolveMediaRefs(...) │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 5. 覆盖 System Prompt (如果需要) │
|
||
│ if opts.SystemPromptOverride != "" { │
|
||
│ // 用于 SubTurn 的特殊 prompt │
|
||
│ } │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 6. 保存用户消息 │
|
||
│ if !opts.SkipAddUserMessage { │
|
||
│ Sessions.AddMessage(...) │
|
||
│ } │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 7. 执行 LLM 迭代 │
|
||
│ finalContent, iteration, err = │
|
||
│ runLLMIteration(ctx, agent, ...) │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 8. 轮询 SubTurn 结果 (如果是根 turn) │
|
||
│ if isRootTurn { │
|
||
│ results = │
|
||
│ dequeuePendingSubTurnResults()│
|
||
│ // 将结果注入到最终响应 │
|
||
│ } │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 9. 处理空响应 │
|
||
│ if finalContent == "" { │
|
||
│ finalContent = DefaultResponse │
|
||
│ } │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 10. 保存助手响应 │
|
||
│ Sessions.AddMessage("assistant"...) │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 11. 发送响应 (如果需要) │
|
||
│ if opts.SendResponse { │
|
||
│ bus.PublishOutbound(...) │
|
||
│ } │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
### SubTurn 执行流程
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ Tool: spawn │
|
||
│ args: {task: "...", label: "..."} │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ SpawnTool.Execute() │
|
||
│ if spawner != nil { │
|
||
│ // 直接 SubTurn 路径 │
|
||
│ } else { │
|
||
│ // SubagentManager 路径 │
|
||
│ } │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ spawner.SpawnSubTurn() │
|
||
│ ┌─────────────────────────────────┐ │
|
||
│ │ 1. 生成 SubTurn ID │ │
|
||
│ │ subTurnID = atomic.Add() │ │
|
||
│ └─────────────────────────────────┘ │
|
||
│ ↓ │
|
||
│ ┌─────────────────────────────────┐ │
|
||
│ │ 2. 创建 SubTurn Context │ │
|
||
│ │ subCtx = withTurnState(...) │ │
|
||
│ │ // 继承父 turnState │ │
|
||
│ └─────────────────────────────────┘ │
|
||
│ ↓ │
|
||
│ ┌─────────────────────────────────┐ │
|
||
│ │ 3. 获取并发信号量 │ │
|
||
│ │ <-rootTS.concurrencySem │ │
|
||
│ │ defer release │ │
|
||
│ └─────────────────────────────────┘ │
|
||
│ ↓ │
|
||
│ ┌─────────────────────────────────┐ │
|
||
│ │ 4. 启动 Goroutine │ │
|
||
│ │ go func() { │ │
|
||
│ │ result = runAgentLoop( │ │
|
||
│ │ subCtx, ...) │ │
|
||
│ │ // 将结果发送到 channel │ │
|
||
│ │ rootTS.pendingResults <- │ │
|
||
│ │ }() │ │
|
||
│ └─────────────────────────────────┘ │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 父 Turn 继续执行 │
|
||
│ - 不等待 SubTurn 完成 │
|
||
│ - SubTurn 异步执行 │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 父 Turn 轮询 SubTurn 结果 │
|
||
│ results = dequeuePendingSubTurnResults│
|
||
│ for each result { │
|
||
│ // 注入到响应或下一次迭代 │
|
||
│ } │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
### SubTurn 层级结构
|
||
```
|
||
Root Turn (Session A)
|
||
├─ turnState (depth=0)
|
||
│ ├─ turnID: "session-a"
|
||
│ ├─ pendingResults: chan
|
||
│ └─ concurrencySem: chan (限制并发数)
|
||
│
|
||
├─ SubTurn 1 (depth=1)
|
||
│ ├─ turnState (继承父 context)
|
||
│ ├─ parentTurnID: "session-a"
|
||
│ └─ 独立的 goroutine
|
||
│
|
||
├─ SubTurn 2 (depth=1)
|
||
│ ├─ turnState (继承父 context)
|
||
│ ├─ parentTurnID: "session-a"
|
||
│ └─ 独立的 goroutine
|
||
│
|
||
└─ SubTurn 3 (depth=1)
|
||
└─ SubTurn 3.1 (depth=2) ← 嵌套 SubTurn
|
||
└─ ...
|
||
|
||
Root Turn (Session B) - 并发执行
|
||
├─ turnState (depth=0)
|
||
└─ ...
|
||
```
|
||
|
||
### 关键特点
|
||
- ✅ **并发支持**: `activeTurnStates` map 支持多个 session 并发
|
||
- ✅ **SubTurn 层级**: 通过 context 传递 turnState,支持嵌套
|
||
- ✅ **并发控制**: `concurrencySem` 限制 SubTurn 并发数
|
||
- ✅ **异步执行**: SubTurn 在独立 goroutine 中执行
|
||
- ✅ **结果回传**: 通过 `pendingResults` channel 传递结果
|
||
- ❌ **无事件系统**: 没有 EventBus 和 Hook 集成
|
||
|
||
---
|
||
|
||
## 3. 对比总结
|
||
|
||
| 特性 | Incoming (refactor/agent) | HEAD (feat/subturn-poc) |
|
||
|------|---------------------------|-------------------------|
|
||
| **并发模型** | 单 Turn (串行) | 多 Turn (并发) |
|
||
| **Turn 管理** | `activeTurn` (单例) | `activeTurnStates` (map) |
|
||
| **事件系统** | ✅ EventBus | ❌ 无 |
|
||
| **Hook 系统** | ✅ HookManager | ❌ 无 |
|
||
| **SubTurn** | ❓ 未实现或不同方式 | ✅ 完整实现 |
|
||
| **并发 Session** | ❌ 不支持 | ✅ 支持 |
|
||
| **嵌套 SubTurn** | ❌ 不支持 | ✅ 支持 |
|
||
| **架构复杂度** | 简单 | 复杂 |
|
||
| **可扩展性** | 高 (Hook) | 低 |
|
||
| **调试难度** | 低 | 高 (并发) |
|
||
|
||
---
|
||
|
||
## 4. 混合方案流程
|
||
|
||
结合两者优点的混合方案:
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ runAgentLoop(ctx, agent, opts) │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 1. 检查 SubTurn Context │
|
||
│ existingTS = turnStateFromContext() │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 2. 创建/复用 turnState │
|
||
│ ts = newTurnState(agent, opts, ...) │
|
||
│ if isRootTurn { │
|
||
│ activeTurnStates.Store(key, ts) │
|
||
│ } │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 3. 执行 Turn (带事件和 Hook) │
|
||
│ result = runTurn(ctx, ts) │
|
||
│ ├─ emitEvent(TurnStart) │
|
||
│ ├─ Hook: before_llm │
|
||
│ ├─ callLLM() │
|
||
│ ├─ Hook: after_llm │
|
||
│ ├─ Hook: before_tool │
|
||
│ ├─ executeTool() │
|
||
│ │ └─ 如果是 spawn → SpawnSubTurn │
|
||
│ ├─ Hook: after_tool │
|
||
│ └─ emitEvent(TurnEnd) │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ 4. 处理 SubTurn 结果 │
|
||
│ if isRootTurn { │
|
||
│ pollSubTurnResults() │
|
||
│ } │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
### 混合方案优势
|
||
- ✅ 保留并发能力 (`activeTurnStates`)
|
||
- ✅ 获得事件系统 (`EventBus`)
|
||
- ✅ 获得扩展能力 (`HookManager`)
|
||
- ✅ 支持 SubTurn 并发
|
||
- ✅ 支持多 Session 并发
|