Day 4: Clawdbot 失控现场实录:论 run_id 的重要性
标题备选
- Clawdbot 失控现场实录:论 run_id 的重要性
- 如果你的 AI Agent 没有日志,那你就是在"盲跑"
- 这里的 Bug 没法 Print:如何构建 AI 工作流的可观测性?
正文内容
当你把一个巨大的任务拆解成"微链架构"(Micro-Chain)后,你会面临一个新的挑战:信息碎片化。
以前,程序挂了,你看一眼控制台最后一行报错就行。 现在,你有三个 Agent 在跑,任务 A 传给了 B,B 传给了 C。 用户反馈说"没收到邮件"。 是 A 没抓到数据?是 B 把数据筛空了?还是 C 发送失败了?
如果你的回答是"我得去看看代码/重新跑一遍",那你的工作流还处于"石器时代"。你不能靠猜来调试。
状态管理靠记忆 = 灾难
在 GitHub 上,我看到很多 Clawdbot 用户的脚本里,状态管理基本靠"全局变量"或者"临时文件"。
比如 temp_result.json。
第二次运行的时候,直接覆盖了这个文件。
如果我想知道昨天为什么跑失败了?对不起,证据已经被销毁了。
引入核心概念:Trace ID (或 run_id)
在分布式系统里,有一个概念叫 Trace ID。在 AI Agent 工作流里,我们也需要它。 每一次运行(Run),都必须生成一个唯一的身份证号(UUID)。
所有的日志、中间产物、最终结果,甚至消耗的 Token 数量,都要挂在这个 run_id 下面。
一个理想的日志结构设计
不要只打印 print("Error")。你的日志应该记录完整的上下文。
{
"run_id": "20240127-x8y9z0",
"timestamp": "2024-01-27T10:00:00Z",
"status": "FAILED",
"total_cost_usd": 0.15,
"steps": [
{
"step_name": "Scraper",
"status": "SUCCESS",
"input_url": "https://example.com",
"output_count": 50,
"duration_ms": 1200,
"model": "claude-3-haiku"
},
{
"step_name": "Analyst",
"status": "SUCCESS",
"input_count": 50,
"filtered_count": 0, // <--- 疑点在这里!
"reasoning": "No items price < 10", // Agent 的思考过程
"model": "claude-3-5-sonnet"
},
{
"step_name": "Sender",
"status": "SKIPPED",
"reason": "No data to send"
}
]
}
为什么这对 Clawdbot 至关重要?
-
还原现场: 看到上面的日志,你一眼就能明白:不是系统挂了,而是数据被筛选空了。 为什么空了?看
reasoning字段,原来是价格阈值设置太低。 如果没有这个记录,你会以为是网络问题,傻傻地去重试抓取。 -
计费与成本控制: 挂载
run_id还能让你统计每次运行的成本。 "为什么昨天的 Token 消耗暴涨?" 查一下日志发现,昨天某个网页死循环了,Agent 尝试了 50 次重试。 -
人工介入(Human-in-the-loop): 当任务失败时,你可以设计一个简单的脚本,读取这个
run_id的所有中间文件。你可以手动修正"分析"步骤的结果,然后告诉系统:"从这一步继续往下跑"。
怎么做?(Python 示例)
不需要引入复杂的 APM 工具(如 Datadog)。对于个人或小团队,一个简单的 SQLite 数据库就足够了。
import sqlite3
import uuid
import json
def start_run():
run_id = str(uuid.uuid4())
conn = sqlite3.connect('workflow_logs.db')
cursor = conn.cursor()
cursor.execute('''
INSERT INTO runs (run_id, status, start_time)
VALUES (?, 'STARTED', CURRENT_TIMESTAMP)
''', (run_id,))
conn.commit()
return run_id
def log_step(run_id, step_name, status, details):
conn = sqlite3.connect('workflow_logs.db')
conn.execute('''
INSERT INTO steps (run_id, step_name, status, details_json)
VALUES (?, ?, ?, ?)
''', (run_id, step_name, status, json.dumps(details)))
conn.commit()
记住一句话:Logs are for code; Traces are for Agents. 代码逻辑是确定的,看 Log 就行。但 Agent 的行为是概率性的,只有完整的 Trace 才能让你理解它为什么做出了那个决定。
明天,我们讨论当 Agent 真的发疯(比如开始胡编乱造)时,我们该怎么自动拦截它——容错与熔断机制。
标签:#可观测性 #DevOps #AI调试 #Clawdbot #日志管理