4点45分,Agent删除了错误的文件。我倒带回去,想看看它当时到底在想什么。
行为重放(Behavior Replay)是OpenClaw Agent调试的「时光机」。它记录Agent每一步的决策过程——选择了什么工具、传了什么参数、为什么选择这个工具、中间思考了什么。你可以像看录像回放一样,逐帧分析Agent的行为,找出问题所在。
# 启用详细行为记录
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
# 列出可重放的会话
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%
# 会话性能报告
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 |
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教程请访问 工具教程索引