ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Agent 可观测性实战:日志、追踪和 token 账单怎么看(附代码)

Agent 可观测性实战:日志、追踪和 token 账单怎么看(附代码) Agent 可观测性实战日志、追踪和 token 账单怎么看附代码LLM 系列又一篇。安全篇说过「日志是最后防线」成本篇说过「跑完对账单」评测篇说过「指标要回归」——它们背后是同一件事可观测性。这篇把它正面讲透。一、为什么 Agent 比传统应用更需要可观测性传统应用出错看堆栈Agent 出错看什么它一个任务黑盒跑几十步十几次 LLM 调用、一堆工具调用、上下文越滚越大——「答案错了」是检索没召回模型幻觉还是工具返回了脏数据「任务卡住了」死循环工具超时还是上下文爆了「账单超标了」哪一步吃的 token哪个工具被调爆了没有可观测性这三个问题只能靠猜。Agent 的不可复现性温度、模型随机性让「复现一下」失效——日志是唯一每次都留下的证据。安全篇那句话的完整版出事之后只有日志能告诉你 Agent 到底干了什么。二、三根支柱支柱记什么回答什么结构化日志每次 LLM/工具调用的输入输出它到底干了什么调用链追踪一次任务的完整调用树出错的环节在哪指标token 成本、成功率、延迟健不健康、贵不贵三、40 行最小日志中间件不用上重型平台一个装饰器/包装函数就是最小可用的可观测层import json, time, uuid from datetime import datetime class AgentLog: def __init__(self, pathagent-trace.jsonl): self.path path def record(self, trace_id: str, event: str, **fields): entry { ts: datetime.now().isoformat(timespecseconds), trace_id: trace_id, # 一次任务一个 ID event: event, # llm_call / tool_call / final **fields, } with open(self.path, a, encodingutf-8) as f: f.write(json.dumps(entry, ensure_asciiFalse) \n) def traced_tool(log: AgentLog, trace_id: str, name: str, fn): 工具包装记录入参、出参、耗时 def wrapper(**kwargs): start time.time() try: result fn(**kwargs) log.record(trace_id, tool_call, toolname, argskwargs, resultstr(result)[:500], # 长结果截断日志别变黑洞 msint((time.time()-start)*1000)) return result except Exception as e: log.record(trace_id, tool_error, toolname, argskwargs, errorstr(e), msint((time.time()-start)*1000)) return {error: str(e)} # 错误回填agent 自我修正 return wrapper def traced_llm(log: AgentLog, trace_id: str, client, **kw): LLM 调用包装记录 token 用量 resp client.chat.completions.create(**kw) u resp.usage log.record(trace_id, llm_call, modelkw[model], prompt_tokensu.prompt_tokens, completion_tokensu.completion_tokens) return respJSONL 格式每行一个 JSONgrep 友好、流式追加、机器可分析——比纯文本日志强一个量级。工具结果截断到 500 字符日志本身也是磁盘成本别让它变成新的 token 黑洞成本篇的逻辑反转过来用。四、追踪一次任务的调用链trace_id把散落的日志串成一次任务的完整故事。出事时按 ID 捞出来看# 捞出某次任务的全链路 grep trace_abc123 agent-trace.jsonl | jq .{ts:...,trace_id:trace_abc123,event:llm_call,prompt_tokens:3200} {ts:...,trace_id:trace_abc123,event:tool_call,tool:read_file,args:{...},ms:42} {ts:...,trace_id:trace_abc123,event:tool_error,tool:send_email,error:timeout} {ts:...,trace_id:trace_abc123,event:llm_call,prompt_tokens:8900}一次真实排障长这样第二次 LLM 调用 prompt_tokens 从 3200 涨到 8900——某工具返回了 5000 token 的结果塞爆了上下文。没有 trace你只会看到「答案质量突然变差」有了 trace一眼定位到那个工具。这就是可观测性的价值从「猜」变成「查」。五、指标三张账单1. Token 账单接成本篇每次llm_call记录了 token 用量按天聚合就是成本篇说的「对账单」from collections import defaultdict usage defaultdict(lambda: [0, 0]) # model - [prompt_tokens, completion_tokens] for line in open(agent-trace.jsonl, encodingutf-8): e json.loads(line) if e[event] llm_call: usage[e[model]][0] e[prompt_tokens] usage[e[model]][1] e[completion_tokens] for model, (pt, ct) in usage.items(): print(f{model}: 输入 {pt:,} / 输出 {ct:,})哪个模型吃掉多少 token 一目了然——分级路由成本篇第二杠杆该优化哪一步账单说了算。2. 工具成功率接评测篇tool_error的占比就是工具成功率下降就是回归信号。按评测篇的口径成功率掉超过 5% 就查原因。3. 延迟每步的ms字段串起来哪个工具慢、哪轮 LLM 卡一目了然——优化先优化最慢的那步别拍脑袋。六、踩坑提醒日志里别记敏感数据工具参数里可能有密钥、客户数据——日志是文件泄漏就是安全事故安全篇的逻辑反转过来用在日志上。敏感字段脱敏后再落盘日志和 trace_id 要串联没有 trace_id 的日志是一盘散沙出事只能按时间猜别只记成功路径错误和超时才是排障时最需要的信息tool_error必须记日志要有保留策略JSONL 天天涨按天滚动、过期清理——日志系统自己也要可观测总结支柱一句话结构化日志JSONL trace_id出事从「猜」变「查」调用链追踪一次任务一条链token 暴涨一眼定位指标token 账单、工具成功率、延迟三张账单定期看铁律日志是唯一不可复现场景下的证据错误路径必记系列到这里隐形的第四条线也闭环了评测管质量、成本管钱、安全管边界、可观测性管证据——四张网叠在 Agent 循环上才算工程化。黑盒不可怕可怕的是黑盒跑完连它干了什么都不留痕迹。觉得有用点个关注。
返回列表