首页 > AI教程 >调试Agent的3种方法:日志、断点与可视化

调试Agent的3种方法:日志、断点与可视化

来源:互联网 2026-07-13 06:27:02

调试Agent比普通程序复杂,因自然语言输入、LLM推理不可见、多节点编排及流式输出。三种调试方法:日志记录LLM调用、工具调用与循环轮次;eino-extdevops交互调试器提供节点SSE状态与耗时;Mermaid可视化生成Graph图。不同问题可选对应姿势。

读完这篇你会知道

调试Agent的过程与调试普通程序存在显著差异。普通程序逻辑固定,输入输出可预期,断点一处即可清晰查看状态。而Agent的调试则复杂得多,涉及自然语言输入、LLM内部推理不可见、多节点编排以及流式输出等挑战。

为什么调试Agent比调试普通程序难

普通程序:函数入参固定,输出确定,断点打下去就能看到状态。

长期稳定更新的攒劲资源: >>>点此立即查看<<<

调试Agent的3种方法:日志、断点与可视化

Agent:

  • 输入为自然语言,不同表述会触发不同路径
  • LLM的中间推理过程不可见,无法直接获知其推理内容
  • 多节点编排,若某一节点响应慢或输出错误,需追溯多层才能定位
  • 流式输出边生成边处理,出错时可能已输出部分内容

下文将介绍三种应对上述问题的调试方法,逐一说明。

姿势一:加日志

虽然方法略显基础,但它是直接且有效的调试手段,适用于初期阶段或尚未使用编排框架的场景。

记录什么内容

至少记录以下三类信息:

// 1. 每次 LLM 调用的输入和输出 log.Printf("[llm] input: %v", messages) resp, err := chatModel.Generate(ctx, messages) log.Printf("[llm] output: %s, finish_reason: %s", resp.Content, resp.ResponseMeta.FinishReason) // 2. 工具调用 log.Printf("[tool] call: %s, args: %s", toolName, argsJSON) result, err := tool.Invoke(ctx, args) log.Printf("[tool] result: %s", result) // 3. 循环轮次(ReAct 循环最容易死循环) log.Printf("[react] turn=%d, action=%s", turn, action)

Token用量建议记录在INFO级别:

usage := resp.ResponseMeta.Usage log.Printf("[token] prompt=%d, completion=%d, total=%d", usage.PromptTokens, usage.CompletionTokens, usage.TotalTokens)

无需记录的内容:

  • 中间字符串拼接过程(属于代码逻辑,非Agent决策)
  • 每个HTTP请求的headers(信息过于冗杂,会掩盖关键信息)

使用Callback统一添加日志(不污染主流程)

在E31中,Agent直接调用agent.Stream(ctx, messages)。如需添加日志但不修改主流程,可通过callback实现:

import "github.com/cloudwego/eino/callbacks" type DebugCallback struct{} func (d *DebugCallback) OnStart(ctx context.Context, info *callbacks.RunInfo, input callbacks.CallbackInput) context.Context { log.Printf("[%s] start: %T", info.Name, input) return ctx } func (d *DebugCallback) OnEnd(ctx context.Context, info *callbacks.RunInfo, output callbacks.CallbackOutput) context.Context { log.Printf("[%s] end: %T", info.Name, output) return ctx } func (d *DebugCallback) OnError(ctx context.Context, info *callbacks.RunInfo, err error) context.Context { log.Printf("[%s] error: %v", info.Name, err) return ctx }

随后将callback注册到context:

ctx = callbacks.CtxWithHandlers(ctx, []callbacks.Handler{&DebugCallback{}}) sr, err := agent.Stream(ctx, messages)

这样无需修改Agent主流程,所有节点的生命周期事件均会触发日志记录。

姿势二:eino-ext devops 交互调试器

自行添加日志只能查看已设定的点,且无法观察节点间的数据流转。eino-ext/devops提供了一个本地HTTP调试服务器,每个节点执行后推送一条SSE事件,包含输入、输出、耗时和Token数。

启动调试服务器:

import "github.com/cloudwego/eino-ext/devops" func main() { ctx := context.Background() // 启动调试 HTTP 服务器(默认 127.0.0.1:52538) if err := devops.Init(ctx); err != nil { log.Fatal(err) } // 正常编译和运行你的 Agent // ... }

devops.Init会在全局注册一个GraphCompileCallback,后续所有编译的Graph/Chain均会被自动捕获。

在浏览器中进行调试:

访问http://127.0.0.1:52538(或使用Eino官方IDE插件),可查看:

  • 所有已编译的Graph列表
  • 每个Graph的节点-边拓扑图(Canvas)
  • 从任意节点开始执行(无需从头运行)
  • 每个节点完成后推送NodeDebugState:输入、输出、Token数、耗时

通过命令行查看SSE流(无需浏览器):

# 创建调试线程 curl -X POST http://127.0.0.1:52538/eino/devops/debug/v1/graphs/{graph_id}/threads # 从指定节点开始,SSE 流式返回每节点状态 curl -N -X POST http://127.0.0.1:52538/eino/devops/debug/v1/graphs/{graph_id}/threads/{tid}/stream -H 'Content-Type: application/json' -d '{"from_node": "ChatModel", "input": {...}}'

适用场景:

  • 工具未被调用——查看ChatModel节点输出是否包含tool_calls
  • 某个节点耗时异常——每帧NodeDebugState包含毫秒级耗时
  • 希望从中间节点开始重试,无需重新运行前置节点

注意:devops服务器仅用于开发环境,请勿在生产部署中启动它。

姿势三:Mermaid 可视化

Agent执行的路径是怎样的?通过可视化工具直接绘制Graph。

import "github.com/cloudwego/eino/devops" // graph 编译前,生成 Mermaid 图 diagram, err := devops.Visualize(graph) if err != nil { log.Fatal(err) } fmt.Println(diagram)

输出为标准Mermaid文本:

graph TD __start__ --> ChatTemplate ChatTemplate --> ChatModel ChatModel --> |tool_calls != nil| ToolsNode ChatModel --> |finish_reason == stop| __end__ ToolsNode --> ChatModel

将这段文本粘贴到mermaid.live,即可查看图形:

[start] → [ChatTemplate] → [ChatModel] (有工具调用) [ToolsNode] → [ChatModel] (stop)[end]

适用场景:

  • 接手他人编写的Agent,需要了解其结构
  • 怀疑分支路由配置有误(例如工具调用应返回ChatModel,但实际走到了end)
  • 向团队评审时说明Agent的执行流程

在HTTP handler中暴露调试端点(开发环境):

// 开发环境加一个 /debug/graph 端点 http.HandleFunc("/debug/graph", func(w http.ResponseWriter, r *http.Request) { diagram, _ := devops.Visualize(graph) w.Header().Set("Content-Type", "text/plain") fmt.Fprint(w, diagram) })

三种姿势如何选择

问题 推荐姿势
Agent 未按预期调用工具 姿势二(devops),查看ChatModel节点输出是否包含tool_call
工具返回了什么内容 姿势二(devops),查看ToolsNode节点输出
某次请求消耗了多少Token 姿势一(日志),在OnEnd callback中记录usage
新接手Agent,不了解其结构 姿势三(Mermaid),先画图再阅读代码
某个节点报错但缺少上下文 姿势二(devops)+ 姿势一(OnError callback)
分支路由配置错误,走了错误路径 姿势三(Mermaid)查看图 + 姿势二确认实际路径

实战:一次完整调试流程

假设你的Agent询问天气问题,却没有调用get_weather工具,直接回复“我不知道”:

第一步:启动devops,重现问题

devops.Init(ctx) // 加这一行,启动本地调试服务器

访问http://127.0.0.1:52538,选择你的Graph,创建调试线程,发送问题。

查看ChatModel节点的输出:

{"role": "assistant", "content": "我不知道北京今天的天气"}

没有tool_calls字段——LLM未调用工具。

第二步:查看ChatModel的输入

[{"role": "system", "content": "你是一个助手"}, {"role": "user", "content": "北京今天天气怎么样?"}]

Prompt中未提及工具,LLM不知道有工具可用。

根因:工具未绑定到ChatModel。修复方法:

// 错误:直接用 chatModel runner := chain.AppendChatModel(chatModel) // 正确:绑定工具 chatModelWithTools, _ := chatModel.WithTools([]*schema.ToolInfo{weatherToolInfo}) runner := chain.AppendChatModel(chatModelWithTools)

小结

三种调试姿势:

  1. 日志 + Callback:精确记录关注点,适用于生产环境监控
  2. compose.WithDebug:自动记录所有节点I/O,适用于开发调试(生产环境需关闭)
  3. Mermaid 可视化:绘制Graph,适用于理解结构和排查路由问题

Agent调试的思路与传统程序一致:缩小范围,找到第一个行为偏离预期的节点。WithDebug是快速缩小范围的有效工具。

下一篇E36将拆解compose.WithDebug的源码,分析一行代码背后如何在每个节点插入记录逻辑。

代码参考:eino-examples/quickstart · Eino devops/visualize

侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述

热游推荐

更多
湘ICP备14008430号-1 湘公网安备 43070302000280号
All Rights Reserved
本站为非盈利网站,不接受任何广告。本站所有软件,都由网友
上传,如有侵犯你的版权,请发邮件给xiayx666@163.com
抵制不良色情、反动、暴力游戏。注意自我保护,谨防受骗上当。
适度游戏益脑,沉迷游戏伤身。合理安排时间,享受健康生活。