Python结构化日志实战:5 个让AI Agent 输出可调试的工程技巧
读完你能直接把“turn_id / tokens / tool / latency”这些关键字段写进 JSON 日志并用一段 Python 在 10 秒内定位最费 token 的轮次。你可能遇到过Agent 一开始很稳过一阵子开始不稳定你去查原因日志只有Turn 1 ok这种信息。问题不在“日志写得少”而在日志没有结构。你没法查询、没法聚合、没法做回归对比。本文给 5 个工程技巧全部配可运行代码并带一个真实本地小实验结果文件在experiment/results.json/experiment/results_advanced.json。0. 什么叫“可调试”的 Agent 日志至少满足三点每轮都有稳定字段turn、tokens、tool、latency_ms输出可查询能快速找异常轮次/失败率输出可治理长字段截断、敏感字段脱敏1) 技巧 1固定字段先立起来推荐最小字段trace_id / turn / query / tokens / tool / tool_success / latency_ms / level。# agent_loop_minimal.pyimportjsonimportrandomimporttime TOOLS[search_api,weather_api,calculator,None]defrun_agent(n_turns:int5,trace_id:strt-001):forturninrange(1,n_turns1):event{trace_id:trace_id,turn:turn,query:f用户问题 #{turn},tokens:random.randint(30,200),tool:random.choice(TOOLS),tool_success:True,latency_ms:round(random.uniform(120,800),1),level:info,}print(json.dumps(event,ensure_asciiFalse))time.sleep(0.02)if__name____main__:run_agent()2) 技巧 2structlog processor 链做治理截断 脱敏# structlog_agent.pyimportreimportstructlogdeftruncate_long_fields(max_len:int200):def_p(logger,method_name,event_dict):fork,vinlist(event_dict.items()):ifisinstance(v,str)andlen(v)max_len:event_dict[k]v[:max_len]...truncatedreturnevent_dictreturn_pdefmask_secrets():secret_rere.compile(r(sk-|token)[A-Za-z0-9_-])def_p(logger,method_name,event_dict):fork,vinlist(event_dict.items()):ifisinstance(v,str):event_dict[k]secret_re.sub(r\1***,v)returnevent_dictreturn_p structlog.configure(processors[structlog.processors.TimeStamper(fmtiso),structlog.stdlib.add_log_level,mask_secrets(),truncate_long_fields(240),structlog.processors.JSONRenderer(),],wrapper_classstructlog.stdlib.BoundLogger,context_classdict,logger_factorystructlog.PrintLoggerFactory(),)defdemo():logstructlog.get_logger(agent)log.info(agent_turn,trace_idt-002,turn1,tokens128,toolsearch_api,tool_successTrue,latency_ms312.4,promptx*500,notetokenabcdefg123456,)if__name____main__:demo()3) 技巧 3loguru sink 分流终端可读 JSON 可查# loguru_agent.pyimportjsonfromloguruimportloggerdefjson_sink(message):rmessage.record er[extra]entry{time:r[time].isoformat(),level:r[level].name,trace_id:e.get(trace_id),turn:e.get(turn),tokens:e.get(tokens),tool:e.get(tool),tool_success:e.get(tool_success),latency_ms:e.get(latency_ms),event:r[message],}print(json.dumps(entry,ensure_asciiFalse))defdemo():logger.remove()logger.add(lambdam:print(m,end),format{time} {level} {message} {extra}\n)logger.add(json_sink,format{message})logger.bind(trace_idt-003,turn1,tokens88,toolweather_api,tool_successTrue,latency_ms210.5).info(agent_turn)if__name____main__:demo()4) 技巧 4用一段 Python 直接查出“最费 token 的轮次”# analyze_results.pyimportjsonfrompathlibimportPathdefmain():datajson.loads(Path(experiment/results_advanced.json).read_text(encodingutf-8))turnsdata[turns_log]heavysorted([tfortinturnsift[tokens]100],keylambdax:x[tokens],reverseTrue)print(token100 的轮次)fortinheavy:print(f- turn{t[turn]}tokens{t[tokens]}tool{t[tool]}latency_ms{t[latency_ms]})if__name____main__:main()5) 技巧 5contextvars 跨 async 传播 trace_id# contextvars_trace.pyimportasyncioimportcontextvars trace_id_varcontextvars.ContextVar(trace_id,default-)deflog(msg:str):print(ftrace_id{trace_id_var.get()}{msg})asyncdefworker(name:str):log(fstart{name})awaitasyncio.sleep(0.05)log(fend{name})asyncdefmain():tokentrace_id_var.set(t-ctx-001)try:awaitasyncio.gather(worker(a),worker(b))finally:trace_id_var.reset(token)if__name____main__:asyncio.run(main())本地小实验结果文件在哪、怎么看本文 run 目录里有两份结果文件experiment/results.json四种方案的 3 轮对比含耗时、JSON 可解析性experiment/results_advanced.json10 轮模拟日志 统计分析如果你只想验证“结构化日志能不能被快速查询”直接跑analyze_results.py就能打印token100的轮次。对比表4 种方案怎么选含本地实验数据方案JSON 可解析字段可查询3 轮开销ms结论print否否0.021只适合临时 debugstdlib logging否否0.111结构化支持弱structlog是是0.272适合做截断/脱敏治理loguru是是2.518上手快文件管理友好demo 含初始化数据来源experiment/results.json常见坑你很可能会踩一次把 prompt/工具返回原样写进日志日志会爆炸查询也会变慢。解决默认截断技巧 2。字段名不稳定今天叫turn_id明天叫step后天叫round统计脚本直接失效。解决固定字段集合。没有 trace_id并发一上来你根本串不起来同一次请求。解决contextvars技巧 5。FAQQ1结构化日志会不会太慢慢的不是 JSON慢的是你把超长 prompt/工具返回原样写进去了。建议默认截断 脱敏。Q2tokens 字段怎么拿先把字段结构固定住没有真实 usage 时可以先用估算占位等接入真实返回后再替换。Q3能不能记录 prompt可以但只记录必要片段并且默认截断。你今天就能落地的最小版本固定字段turn/tokens/tool/latency_ms输出 JSON 可解析做到这两点Agent 调试会从“翻一堆文本”变成“查一条事件流”。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2624917.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!