🤖 妙趣AI

OpenClaw Agent行为重放与调试

4点45分,Agent删除了错误的文件。我倒带回去,想看看它当时到底在想什么。

📌 功能介绍

行为重放(Behavior Replay)是OpenClaw Agent调试的「时光机」。它记录Agent每一步的决策过程——选择了什么工具、传了什么参数、为什么选择这个工具、中间思考了什么。你可以像看录像回放一样,逐帧分析Agent的行为,找出问题所在。

💡 妙趣提示:行为重放不仅仅是为了调试bug,更是理解Agent「思维方式」的窗口。通过分析Agent的决策链路,你可以优化prompt、调整工具配置、改进Agent架构。

🛠️ 使用方法

1. 启用行为记录

# 启用详细行为记录
openclaw config set tracing.enabled true
openclaw config set tracing.level "verbose"  # minimal | normal | verbose | debug
openclaw config set tracing.export "file"  # file | json | otel

# 指定记录输出
openclaw config set tracing.output "/var/log/openclaw/traces"

# 为特定会话启用
openclaw session trace --session session_abc123 --level verbose

2. 行为重放

# 列出可重放的会话
openclaw replay list --limit 10

# 重放整个会话
openclaw replay session --session-id session_abc123

# 重放特定步骤
openclaw replay step --session-id session_abc123 --step 5

# 带决策分析的重放
openclaw replay analyze --session-id session_abc123 \
  --focus "tool-selection" \
  --format markdown

# 输出示例:
# Step 5 - 工具选择决策分析
# ━━━━━━━━━━━━━━━━━━━━━━━
# 可用工具: [web_search, file_read, code_execute]
# 用户意图: "分析这段Python代码的性能问题"
# 
# 决策过程:
# 1. file_read (score: 0.95) → 读取代码文件 ✓ 已选
# 2. code_execute (score: 0.72) → 执行性能测试
# 3. web_search (score: 0.15) → 搜索相关问题
# 
# 选择理由: 用户要求分析现有代码,需要先读取文件内容
# 置信度: 95%

3. 性能分析

# 会话性能报告
openclaw replay profile --session-id session_abc123

# 输出示例:
# 会话性能分析报告
# ━━━━━━━━━━━━━━━━━
# 总耗时: 3m 42s
# Token消耗: 15,234
# 工具调用: 12次
# 
# 耗时分布:
#   模型推理:    2m 15s (61%)  ████████████░░░░
#   工具执行:      45s  (20%)  ████░░░░░░░░░░░░
#   上下文处理:    22s  (10%)  ██░░░░░░░░░░░░░░
#   等待/空闲:     20s   (9%)  █░░░░░░░░░░░░░░░
#
# 瓶颈分析:
#   ⚠️ 模型推理时间过长 (平均11.25s/call)
#   💡 建议: 考虑使用更快的模型或启用流式输出

🏆 最佳实践

调试策略分层

层级 关注点 工具
L1: 输入输出 Agent说了什么、做了什么 replay session
L2: 决策链路 为什么选择这个工具/参数 replay analyze
L3: 性能瓶颈 时间花在哪里、token如何消耗 replay profile
L4: 模型思维 模型的中间推理过程 replay trace --level debug
⚠️ 性能影响:「verbose」和「debug」级别的追踪会显著增加内存使用和响应延迟。生产环境建议使用「normal」级别,仅在排查问题时临时切换到更高级别。

💻 代码示例

自动化重放测试

const { OpenClawClient, ReplayEngine } = require('@openclaw/sdk');

async function regressionTest(sessionId, goldenOutput) {
  const client = new OpenClawClient();
  const replay = new ReplayEngine(client);
  
  // 1. 加载历史会话记录
  const recording = await replay.load(sessionId);
  
  // 2. 重放会话(可选:修改某些步骤的输入)
  const result = await replay.replay(recording, {
    dryRun: false,
    compareWith: goldenOutput,
    stopOnDiff: true
  });
  
  // 3. 分析差异
  if (result.hasDifferences) {
    console.error('回归测试失败!发现差异:');
    result.differences.forEach((diff, i) => {
      console.error(`\n步骤 ${diff.step}:`);
      console.error(`  期望工具: ${diff.expected.tool}`);
      console.error(`  实际工具: ${diff.actual.tool}`);
      console.error(`  差异原因: ${diff.reason}`);
    });
    
    // 生成详细报告
    await replay.exportReport(result, {
      format: 'html',
      outputPath: `/reports/regression-${Date.now()}.html`
    });
  } else {
    console.log('✅ 回归测试通过!');
  }
  
  return result;
}

决策质量评分

async function scoreDecisions(sessionId) {
  const client = new OpenClawClient();
  const trace = await client.sessions.getTrace(sessionId);
  
  let totalScore = 0;
  const analysis = [];
  
  for (const step of trace.steps) {
    if (step.toolCall) {
      const score = evaluateStep(step);
      totalScore += score;
      
      analysis.push({
        step: step.index,
        tool: step.toolCall.name,
        score: score,
        issues: score < 0.7 ? findIssues(step) : []
      });
    }
  }
  
  const avgScore = analysis.length > 0 
    ? totalScore / analysis.length 
    : 0;
  
  return {
    sessionId,
    avgDecisionScore: avgScore,
    totalSteps: analysis.length,
    lowQualitySteps: analysis.filter(a => a.score < 0.7),
    report: analysis
  };
}

function evaluateStep(step) {
  let score = 1.0;
  
  // 工具选择是否合理
  if (step.toolCall.error) score -= 0.3;
  
  // 参数是否完整
  const requiredParams = step.toolCall.schema?.required || [];
  const missingParams = requiredParams.filter(p => !step.toolCall.params[p]);
  score -= missingParams.length * 0.1;
  
  // 执行时间是否合理
  if (step.duration > 30000) score -= 0.1;
  
  // 重试次数
  score -= (step.retries || 0) * 0.15;
  
  return Math.max(0, score);
}

🔗 相关链接

📅 更新时间:2026-05-11 | 📖 更多OpenClaw教程请访问 工具教程索引