OpenClaw 时间旅行调试与执行回放

更新时间:2026-04-24 | 预计阅读:15分钟

凌晨4点,Agent莫名其妙崩溃了——它调用了一个不存在的API,然后陷入了死循环。日志里只有"Error: timeout",鬼知道它当时脑子里装了什么。于是我打开了执行回放——像看监控录像一样,一帧一帧地看它当时在干什么、看到了什么、怎么做的决定。然后我找到了问题的根源:一个变量的值在某个时间点被覆盖了,而它被卡在了错误的状态。

什么是时间旅行调试

时间旅行调试(Time Travel Debugging)允许你:

  • 记录执行轨迹:每一步工具调用、状态变化、模型输出都记录下来
  • 回放任意时刻:跳转到任意时间点,查看当时的状态
  • 单步调试:像IDE一样逐帧执行,定位问题发生的瞬间
  • 反向追踪:从错误发生点反向查找根因

启用执行记录

配置执行追踪

# openclaw.config.yaml
execution_trace:
  enabled: true
  
  # 记录内容
  capture:
    - messages        # 所有对话消息
    - tool_calls      # 工具调用(包括参数和返回值)
    - state_changes   # 状态变更
    - llm_outputs     # LLM生成内容
    - errors          # 错误和异常

  # 存储配置
  storage:
    backend: file     # file | memory | database
    path: ~/.openclaw/traces/
    max_size: 100MB   # 单个trace文件最大100MB
    retention: 7d     # 保留7天

  # 采样配置(可选,减少开销)
  sampling:
    rate: 1.0         # 1.0 = 100%记录
    # 生产环境可以设置为0.1 (10%采样)

运行时启用追踪

// 为特定会话启用追踪
const session = await sessions_spawn({
  task: "分析用户数据",
  runtime: "acp",
  trace: true  // 启用执行追踪
});

// 会话ID即为trace ID
const traceId = session.sessionId;
console.log(`执行追踪ID: ${traceId}`);

回放执行轨迹

查看Trace概览

# CLI查看trace
openclaw trace list                    # 列出最近的trace
openclaw trace show          # 查看trace概览
openclaw trace show  --detail # 详细视图

# 输出示例
Trace ID: session_abc123
Duration: 45.2s
Steps: 23
Status: failed

Timeline:
├── [00:00] 开始任务: 分析用户数据
├── [00:05] 工具调用: web_search
├── [00:08] 搜索结果返回 (12条)
├── [00:10] 工具调用: web_fetch
├── [00:15] 解析网页内容
├── [00:20] ⚠️  模型输出警告...
├── [00:35] 工具调用: exec (失败)
└── [00:45] ❌ 任务失败: timeout

时间点跳转

// API方式回放
// 跳转到特定时间点
const snapshot = await getTracePoint(traceId, {
  timestamp: '00:20',  // 跳转到20秒时的状态
  // 或使用step索引
  step: 12
});

// snapshot 包含当时的完整状态
console.log(snapshot.state);      // Agent当时的状态
console.log(snapshot.context);    // 当时的上下文内容
console.log(snapshot.toolCalls);  // 正在进行的工具调用
console.log(snapshot.messages);   // 当时的对话历史

可视化回放

# 在浏览器中可视化回放
openclaw trace view 

# 打开 http://localhost:3000/trace/
# 特性:
# - 时间轴拖动
# - 消息流展示
# - 工具调用详情
# - 状态变化高亮
# - 错误点标记

问题定位实战

场景1:无限循环调试

// Trace中发现循环点
Steps 15-18 重复执行了5次:
├── [00:30] 工具调用: check_status
├── [00:31] 结果: "pending"
├── [00:32] Agent判断继续等待
├── [00:33] 工具调用: check_status
├── [00:34] 结果: "pending"
└── ... (重复)

// 根因:状态一直没有变成"completed"
// 原因:检查的API端点错误,永返回"pending"
// 修复:添加超时限制或检查正确的端点

场景2:错误消息追踪

// 从错误点反向追踪
Error at step 23: "Failed to parse JSON"

// 回到step 23
查看工具输出:
{
  "data": "<html>...</html>"  // 竟然返回了HTML
}

// 继续回到step 22
工具调用:web_fetch("https://api.example.com/data")
// 应该返回JSON的API,却返回了HTML错误页面

// 再回到step 21
查看Agent的决策:
"我决定从 https://api.example.com/data 获取数据"
// URL是动态拼接的,拼接逻辑有误

// 根因:URL拼接错误,使用了undefined变量

场景3:状态污染分析

// 对比不同时间点的状态
Step 10:
state.currentTask = "process_data"

Step 15:
state.currentTask = null  // 什么时候被清空的?

// 追踪state变更
Step 12:
  Action: setState
  Change: currentTask: null
  Trigger: 某个工具调用的清理逻辑

// 根因:工具调用后错误地清理了状态

高级功能

差异对比

// 对比两个时间点的状态差异
const diff = compareTracePoints(traceId, {
  from: 10,   // step 10
  to: 20      // step 20
});

// 输出差异
{
  "added": {
    "searchResults": [...]  // 新增的数据
  },
  "removed": {
    "tempCache": null  // 被清理的缓存
  },
  "changed": {
    "step": "analyzing → complete"
  }
}

搜索与过滤

# 在trace中搜索
openclaw trace search  "error"
openclaw trace search  "tool:web_fetch"

# 过滤显示
openclaw trace show  \
  --filter "tool_calls" \
  --filter "errors"

导出分析

# 导出trace为JSON
openclaw trace export  > trace.json

# 分析报告
openclaw trace analyze 

# 输出分析报告
Analysis Report
===============
Total Steps: 45
Tool Calls: 23
Errors: 2

Time Distribution:
- LLM Calls: 60% (27s)
- Tool Calls: 30% (13.5s)
- Other: 10% (4.5s)

Bottleneck Analysis:
1. web_fetch (step 15): 8.2s - 慢!建议添加超时
2. llm_generate (step 30): 3.1x平均时长 - 可能context过长

Recommendations:
1. 为web_fetch添加30s超时
2. 压缩第30步前的上下文

性能开销

  • 内存开销:约10-20%(取决于记录内容)
  • 存储空间:每次执行约100KB-10MB(取决于复杂度)
  • 延迟影响:约5%(可以接受)
  • 建议:生产环境开启10%采样,开发环境全量记录

最佳实践

  1. 始终保留最近7天的trace——问题往往几天后才发现
  2. 关键任务全量记录——尤其是审批流程、数据迁移
  3. 定期清理trace——占用的空间不小
  4. 结合告警——错误发生时自动保存trace
  5. 不要看所有细节——聚焦错误点附近的步骤

相关资源