API.md 21 KB

Agent Execution API - 前端对接文档

版本:v4.0 更新日期:2026-02-04


概览

本 API 提供 Agent 执行过程的实时可视化能力:

  • REST API - 查询 Trace 和 GoalTree
  • WebSocket - 实时推送 Goal/Message 更新(支持断线续传)

核心概念

  • Trace - 一次完整的 Agent 执行(主 Agent 和 Sub-Agent 都是 Trace)
  • GoalTree - 每个 Trace 的目标树
  • Goal - 一个目标节点,包含 self_stats(自身统计)和 cumulative_stats(含后代统计)
  • Message - 执行消息,对应 LLM API 的 assistant/tool 消息
  • Sub-Trace - 子 Agent(通过 explore/delegate 工具启动)

统一的 Trace 模型

主 Trace 和 Sub-Trace 使用相同的数据结构:
- 每个 Trace 有独立的 GoalTree
- 每个 Trace 有独立的 Message List
- Sub-Trace 通过 parent_trace_id 和 parent_goal_id 关联父 Trace
- Trace ID 采用层级命名(abc123, abc123.A, abc123.A.1)

数据结构

后端存储:
1. 每个 Trace 独立存储(主 Trace 和 Sub-Traces)
2. GoalTree - 目标树结构 + 聚合统计
3. Messages - 执行记录,通过 goal_id 关联 Goal

关系:
- Goal.stats 从关联的 Messages 聚合计算
- Sub-Trace 通过 parent_trace_id 关联
- Goal 通过 sub_trace_ids 关联启动的 Sub-Traces

DAG 可视化(前端负责):

  • 从 GoalTree 生成 DAG 视图
  • 节点 = Goal 完成后的里程碑
  • 边 = 相邻节点之间的执行过程
  • Sub-Trace 可以折叠(显示为单个节点)或展开(显示内部 Goals)
  • 边的统计数据从 target Goal 的 stats 获取

REST API

基础信息

  • Base URL: http://localhost:8000
  • Content-Type: application/json

1. 列出 Traces

GET /api/traces?status=running&limit=20

查询参数: | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | status | string | 否 | 过滤状态:running / completed / failed | | mode | string | 否 | 过滤模式:call / agent | | limit | int | 否 | 返回数量(默认 50,最大 100)|

响应示例

{
  "traces": [
    {
      "trace_id": "abc123",
      "mode": "agent",
      "task": "实现用户认证功能",
      "status": "running",
      "total_messages": 15,
      "total_tokens": 5000,
      "total_cost": 0.05,
      "current_goal_id": "2.1",
      "created_at": "2026-02-04T15:30:00"
    }
  ],
  "total": 1
}

2. 获取 Trace + GoalTree

GET /api/traces/{trace_id}

响应示例(主 Trace):

{
  "trace_id": "abc123",
  "mode": "agent",
  "task": "实现用户认证功能",
  "status": "running",
  "parent_trace_id": null,
  "parent_goal_id": null,
  "agent_type": "main",
  "total_messages": 15,
  "total_tokens": 5000,
  "total_cost": 0.05,
  "created_at": "2026-02-04T15:30:00",
  "completed_at": null,
  "goal_tree": {
    "mission": "实现用户认证功能",
    "current_id": "2",
    "goals": [
      {
        "id": "1",
        "parent_id": null,
        "type": "normal",
        "description": "分析代码",
        "reason": "了解现有结构",
        "status": "completed",
        "summary": "用户模型在 models/user.py",
        "self_stats": { "message_count": 5, "total_tokens": 2300, "total_cost": 0.03, "preview": "glob → read × 2" },
        "cumulative_stats": { "message_count": 5, "total_tokens": 2300, "total_cost": 0.03, "preview": "glob → read × 2" }
      },
      {
        "id": "2",
        "parent_id": null,
        "type": "agent_call",
        "description": "并行探索认证方案",
        "reason": "评估不同技术选型",
        "status": "in_progress",
        "agent_call_mode": "explore",
        "sub_trace_ids": ["abc123.A", "abc123.B"],
        "self_stats": { "message_count": 0, "total_tokens": 0, "total_cost": 0.0, "preview": null },
        "cumulative_stats": { "message_count": 0, "total_tokens": 0, "total_cost": 0.0, "preview": null }
      },
      {
        "id": "3",
        "parent_id": null,
        "type": "normal",
        "description": "完善实现",
        "reason": "基于选定方案完成实现",
        "status": "pending"
      }
    ]
  },
  "sub_traces": {
    "abc123.A": {
      "trace_id": "abc123.A",
      "parent_trace_id": "abc123",
      "parent_goal_id": "2",
      "agent_type": "explore",
      "task": "JWT 方案",
      "status": "completed",
      "total_messages": 8,
      "total_tokens": 4000,
      "total_cost": 0.05,
      "created_at": "2026-02-04T15:31:00",
      "completed_at": "2026-02-04T15:35:00"
    },
    "abc123.B": {
      "trace_id": "abc123.B",
      "parent_trace_id": "abc123",
      "parent_goal_id": "2",
      "agent_type": "explore",
      "task": "Session 方案",
      "status": "completed",
      "total_messages": 10,
      "total_tokens": 5000,
      "total_cost": 0.06
    }
  }
}

3. 获取 Sub-Trace 详情

获取 Sub-Trace 的完整信息(包括 GoalTree)。

GET /api/traces/abc123.A

响应示例

{
  "trace_id": "abc123.A",
  "parent_trace_id": "abc123",
  "parent_goal_id": "2",
  "agent_type": "explore",
  "task": "JWT 方案",
  "status": "completed",
  "total_messages": 8,
  "total_tokens": 4000,
  "total_cost": 0.05,
  "created_at": "2026-02-04T15:31:00",
  "completed_at": "2026-02-04T15:35:00",
  "goal_tree": {
    "mission": "JWT 方案",
    "current_id": null,
    "goals": [
      {
        "id": "1",
        "parent_id": null,
        "type": "normal",
        "description": "JWT 设计",
        "status": "completed",
        "summary": "设计完成",
        "self_stats": { "message_count": 3, "total_tokens": 1500, "total_cost": 0.02, "preview": "read → edit" },
        "cumulative_stats": { "message_count": 3, "total_tokens": 1500, "total_cost": 0.02, "preview": "read → edit" }
      },
      {
        "id": "2",
        "parent_id": null,
        "type": "normal",
        "description": "JWT 实现",
        "status": "completed",
        "summary": "实现完成",
        "self_stats": { "message_count": 5, "total_tokens": 2500, "total_cost": 0.03, "preview": "edit × 3 → bash" },
        "cumulative_stats": { "message_count": 5, "total_tokens": 2500, "total_cost": 0.03, "preview": "edit × 3 → bash" }
      }
    ]
  },
  "sub_traces": {}
}

4. 获取 Messages(边详情)

查询指定 Trace 的 Messages(用于查看边的详细执行内容)。

GET /api/traces/abc123/messages?goal_id=1
GET /api/traces/abc123.A/messages?goal_id=2

查询参数: | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | goal_id | string | 否 | 过滤指定 Goal 的 Messages(内部 ID,如 "1", "2")|

响应示例

{
  "trace_id": "abc123",
  "messages": [
    {
      "message_id": "msg-001",
      "trace_id": "abc123",
      "role": "assistant",
      "sequence": 1,
      "goal_id": "1",
      "content": {
        "text": "让我先读取现有的 API 设计...",
        "tool_calls": [
          {
            "id": "call_abc",
            "name": "read_file",
            "arguments": { "path": "api/routes.py" }
          }
        ]
      },
      "description": "让我先读取现有的 API 设计...",
      "tokens": 150,
      "cost": 0.002,
      "created_at": "2026-02-04T15:31:00"
    },
    {
      "message_id": "msg-002",
      "trace_id": "abc123",
      "role": "tool",
      "sequence": 2,
      "goal_id": "1",
      "tool_call_id": "call_abc",
      "content": "# API Routes\n...",
      "description": "read_file",
      "tokens": null,
      "cost": null,
      "created_at": "2026-02-04T15:31:01"
    }
  ],
  "total": 2
}

WebSocket API

连接

const ws = new WebSocket(
  'ws://localhost:8000/api/traces/{trace_id}/watch?since_event_id=0'
)

查询参数: | 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | since_event_id | int | 0 | 从哪个事件 ID 开始。0 = 补发所有历史 |


事件类型

1. connected(连接成功)

连接后推送完整 Trace 信息,前端据此初始化 DAG。

{
  "event": "connected",
  "trace_id": "abc123",
  "current_event_id": 15,
  "trace": {
    "trace_id": "abc123",
    "status": "running",
    "goal_tree": {
      "mission": "实现用户认证功能",
      "current_id": "2",
      "goals": [...]
    },
    "sub_traces": {}
  }
}

前端处理

if (data.event === 'connected') {
  initDAG(data.goal_tree)
  localStorage.setItem('last_event_id', data.current_event_id)
}

2. goal_added(新增 Goal)

{
  "event": "goal_added",
  "event_id": 16,
  "goal": {
    "id": "6",
    "parent_id": "2",
    "branch_id": null,
    "type": "normal",
    "description": "编写测试",
    "reason": "确保代码质量",
    "status": "pending",
    "summary": null,
    "self_stats": { "message_count": 0, "total_tokens": 0, "total_cost": 0.0, "preview": null },
    "cumulative_stats": { "message_count": 0, "total_tokens": 0, "total_cost": 0.0, "preview": null }
  },
  "parent_id": "2"
}

前端处理

if (data.event === 'goal_added') {
  insertGoal(data.goal, data.parent_id)
  regenerateDAG()
}

3. goal_updated(Goal 状态变化)

包含级联完成场景:当所有子 Goal 完成时,父 Goal 自动 completed。

{
  "event": "goal_updated",
  "event_id": 17,
  "goal_id": "3",
  "updates": {
    "status": "completed",
    "summary": "接口设计完成"
  },
  "affected_goals": [
    {
      "goal_id": "3",
      "cumulative_stats": { "message_count": 3, "total_tokens": 1500, "total_cost": 0.02, "preview": "read → edit" }
    },
    {
      "goal_id": "2",
      "status": "completed",
      "summary": "功能实现完成",
      "cumulative_stats": { "message_count": 8, "total_tokens": 4200, "total_cost": 0.05, "preview": "..." }
    }
  ]
}

前端处理

if (data.event === 'goal_updated') {
  updateGoal(data.goal_id, data.updates)
  for (const g of data.affected_goals) {
    updateGoalStats(g.goal_id, g)
  }
  regenerateDAG()
}

4. message_added(新 Message)

后端更新统计后推送,包含受影响的所有 Goals。

{
  "event": "message_added",
  "event_id": 18,
  "message": {
    "message_id": "msg-018",
    "role": "assistant",
    "goal_id": "4",
    "branch_id": null,
    "content": { "text": "...", "tool_calls": [...] },
    "tokens": 500,
    "cost": 0.005
  },
  "affected_goals": [
    {
      "goal_id": "4",
      "self_stats": { "message_count": 6, "total_tokens": 3200, "total_cost": 0.035, "preview": "edit × 3 → bash × 2" },
      "cumulative_stats": { "message_count": 6, "total_tokens": 3200, "total_cost": 0.035, "preview": "edit × 3 → bash × 2" }
    },
    {
      "goal_id": "2",
      "cumulative_stats": { "message_count": 9, "total_tokens": 4700, "total_cost": 0.055, "preview": "read → edit × 4 → bash × 2" }
    }
  ]
}

说明

  • affected_goals[0] 是直接关联的 Goal,更新 self_stats + cumulative_stats
  • 后续是所有祖先 Goal,仅更新 cumulative_stats

前端处理

if (data.event === 'message_added') {
  for (const g of data.affected_goals) {
    updateGoalStats(g.goal_id, g)
  }
  // 根据当前展开状态更新对应边
  rerenderEdge(data.message.goal_id)
}

5. trace_completed(任务完成)

{
  "event": "trace_completed",
  "event_id": 50,
  "trace_id": "abc123",
  "total_messages": 50,
  "total_tokens": 25000,
  "total_cost": 0.25
}

前端处理

if (data.event === 'trace_completed') {
  markTraceCompleted()
  ws.close()
}

6. sub_trace_started(Sub-Trace 开始)

explore 或 delegate 工具启动 Sub-Trace 时触发。

{
  "event": "sub_trace_started",
  "event_id": 20,
  "parent_trace_id": "abc123",
  "parent_goal_id": "2",
  "sub_trace": {
    "trace_id": "abc123.A",
    "parent_trace_id": "abc123",
    "parent_goal_id": "2",
    "agent_type": "explore",
    "task": "JWT 方案",
    "status": "running",
    "total_messages": 0,
    "total_tokens": 0,
    "total_cost": 0.0
  }
}

前端处理

if (data.event === 'sub_trace_started') {
  insertSubTrace(data.parent_trace_id, data.sub_trace)
  regenerateDAG()
}

7. sub_trace_completed(Sub-Trace 完成)

Sub-Trace 执行完成后触发。

{
  "event": "sub_trace_completed",
  "event_id": 35,
  "trace_id": "abc123.A",
  "parent_trace_id": "abc123",
  "parent_goal_id": "2",
  "summary": "JWT 方案实现完成,无状态但 token 较大",
  "total_messages": 8,
  "total_tokens": 4000,
  "total_cost": 0.05
}

前端处理

if (data.event === 'sub_trace_completed') {
  updateSubTrace(data.trace_id, {
    status: 'completed',
    summary: data.summary,
    total_messages: data.total_messages,
    total_tokens: data.total_tokens,
    total_cost: data.total_cost
  })
  regenerateDAG()
}

数据模型

Trace

字段 类型 说明
trace_id string 层级化 ID(如 "abc123", "abc123.A", "abc123.A.1")
mode string call - 单次调用 / agent - Agent 模式
task string 任务描述
parent_trace_id string | null 父 Trace ID(Sub-Trace 才有)
parent_goal_id string | null 哪个 Goal 启动的(Sub-Trace 才有)
agent_type string | null "main" / "explore" / "delegate" / "compaction"
status string running / completed / failed
total_messages int Message 总数
total_tokens int Token 总消耗
total_cost float 成本总和
created_at string 创建时间(ISO 8601)
completed_at string | null 完成时间

Trace ID 规则

  • 主 Trace:短随机 ID(如 "abc123")
  • Sub-Trace:父 ID + 后缀(如 "abc123.A", "abc123.task1")
  • 嵌套:继续追加(如 "abc123.A.1")

GoalTree

字段 类型 说明
mission string 总任务描述(来自 Trace.task)
current_id string | null 当前焦点 Goal 的内部 ID
goals Goal[] 顶层目标列表

Goal

字段 类型 说明
id string 内部 ID,每个 Trace 独立编号("1", "2", "3"...)
parent_id string | null 父 Goal ID(层级关系)
type string normal / agent_call
description string 目标描述(做什么)
reason string 创建理由(为什么做)
status string pending / in_progress / completed / abandoned
summary string | null 完成/放弃时的总结
sub_trace_ids string[] | null 启动的 Sub-Trace IDs(仅 agent_call)
agent_call_mode string | null "explore" / "delegate" / "sequential"(仅 agent_call)
self_stats GoalStats 自身统计
cumulative_stats GoalStats 累计统计

ID 设计

  • 每个 Trace 内部独立编号("1", "2", "3")
  • 层级关系通过 parent_id 维护
  • 显示序号由前端/后端动态生成

GoalStats

字段 类型 说明
message_count int 消息数量
total_tokens int Token 总数
total_cost float 总成本
preview string | null 工具调用摘要(如 "read → edit × 2"

Message

字段 类型 说明
message_id string 唯一 ID
trace_id string 所属 Trace ID(可能是主 Trace 或 Sub-Trace)
role string assistant / tool
sequence int 当前 Trace 内的顺序
goal_id string 关联的 Goal 内部 ID(如 "1", "2")
tool_call_id string | null tool 消息关联的 tool_call ID
content any 消息内容(和 LLM API 格式一致)
description string 消息描述(系统自动生成)
tokens int | null Token 消耗
cost float | null 成本
created_at string 创建时间

DAG 可视化(前端实现)

后端提供 Trace(包含 GoalTree 和 Sub-Traces),前端负责生成 DAG 视图。

核心逻辑

普通 Goal(子目标)

  1. 未展开:显示父 Goal
  2. 已展开:父 Goal 被子 Goal 替代(顺序)

agent_call Goal(Sub-Trace)

  1. 未展开:显示为单个节点(代表整个 Sub-Trace)
  2. 已展开:加载 Sub-Trace 的 GoalTree,显示内部 Goals

边数据

从 target 节点的 stats 获取:

  • 折叠边(父 Goal)→ target.cumulative_stats
  • 展开边(子 Goal)→ target.self_stats
  • Sub-Trace 折叠边 → Sub-Trace 的 total_tokens/total_cost
  • Sub-Trace 展开边 → Sub-Trace 内部 Goal 的 stats

示例:普通展开(子目标)

// GoalTree(扁平列表,通过 parent_id 构建层级)
const goalTree = {
  goals: [
    { id: "1", parent_id: null, description: "分析代码" },
    { id: "2", parent_id: null, description: "实现功能" },
    { id: "3", parent_id: "2", description: "设计接口" },  // 2 的子目标
    { id: "4", parent_id: "2", description: "实现代码" },  // 2 的子目标
    { id: "5", parent_id: null, description: "测试" }
  ]
}

// 构建层级视图
function buildHierarchy(goals) {
  const map = new Map(goals.map(g => [g.id, { ...g, children: [] }]))
  const roots = []
  for (const goal of goals) {
    const node = map.get(goal.id)
    if (goal.parent_id) {
      map.get(goal.parent_id)?.children.push(node)
    } else {
      roots.push(node)
    }
  }
  return roots
}

// 展开状态
const expanded = new Set()  // 空 = 全部折叠

// 生成可见节点序列
function getVisibleGoals(nodes, expanded) {
  const result = []
  for (const node of nodes) {
    if (expanded.has(node.id) && node.children.length > 0) {
      // 展开:递归处理子节点
      result.push(...getVisibleGoals(node.children, expanded))
    } else {
      // 折叠:显示自己
      result.push(node)
    }
  }
  return result
}

// 折叠视图: [1] → [2] → [5]
// 展开 "2" 后: [1] → [3] → [4] → [5]

// 生成边
function generateEdges(visibleGoals) {
  const edges = []
  for (let i = 0; i < visibleGoals.length; i++) {
    const source = i === 0 ? null : visibleGoals[i - 1]
    const target = visibleGoals[i]
    edges.push({
      source: source?.id ?? null,
      target: target.id,
      // 边数据来自 target 的 stats
      // 如果 target 有子节点且未展开,用 cumulative_stats
      // 否则用 self_stats
      stats: hasUnexpandedChildren(target, expanded)
        ? target.cumulative_stats
        : target.self_stats
    })
  }
  return edges
}

示例:Sub-Trace 展开

// 主 Trace 的 GoalTree
const mainTrace = {
  trace_id: "abc123",
  goal_tree: {
    goals: [
      { id: "1", type: "normal", description: "分析问题" },
      { id: "2", type: "agent_call", agent_call_mode: "explore", sub_trace_ids: ["abc123.A", "abc123.B"] },
      { id: "3", type: "normal", description: "完善实现" }
    ]
  },
  sub_traces: {
    "abc123.A": { trace_id: "abc123.A", task: "JWT 方案", status: "completed", total_tokens: 4000 },
    "abc123.B": { trace_id: "abc123.B", task: "Session 方案", status: "completed", total_tokens: 5000 }
  }
}

// 折叠视图:[1] → [2:并行探索] → [3]

// 展开 Sub-Traces 后的视图:
//           ┌→ [abc123.A] ────┐
// [1] ──────┼                 ├──→ [3]
//           └→ [abc123.B] ────┘

// 继续展开 Sub-Trace abc123.A 内部
async function loadSubTrace(traceId) {
  const resp = await fetch(`/api/traces/${traceId}`)
  return await resp.json()  // 返回完整 Trace,含 goal_tree
}

const subTraceA = await loadSubTrace("abc123.A")
// {
//   trace_id: "abc123.A",
//   goal_tree: {
//     goals: [
//       { id: "1", description: "JWT 设计" },
//       { id: "2", description: "JWT 实现" }
//     ]
//   }
// }

// 展开后显示 Sub-Trace 内部 Goals:
//           ┌→ [A.1:JWT设计] → [A.2:JWT实现] ──┐
// [1] ──────┼                                  ├──→ [3]
//           └→ [abc123.B] ─────────────────────┘

// 注意:前端显示为 "A.1",实际查询是 GET /api/traces/abc123.A/messages?goal_id=1

视觉区分

边类型 说明 样式建议
普通边 顺序执行 实线
分叉边 explore 分支开始 虚线或带标记
汇合边 分支合并到 merge 节点 虚线或带标记
废弃边 abandoned 分支 灰色

断线续传

let lastEventId = 0

function connect(traceId) {
  const ws = new WebSocket(
    `ws://localhost:8000/api/traces/${traceId}/watch?since_event_id=${lastEventId}`
  )

  ws.onmessage = (event) => {
    const data = JSON.parse(event.data)
    if (data.event_id) {
      lastEventId = data.event_id
      localStorage.setItem(`trace_${traceId}_event_id`, lastEventId)
    }
    // 处理事件...
  }

  ws.onclose = () => {
    setTimeout(() => connect(traceId), 3000)
  }
}

错误处理

HTTP 错误码

状态码 说明
200 成功
404 Trace 不存在
400 参数错误
500 服务器错误

WebSocket 错误

{
  "event": "error",
  "message": "Too many missed events, please reload via REST API"
}

相关文档