三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

AI Agent调试实战:日志、断点与可视化三大核心方法解析

AI Agent调试实战:日志、断点与可视化三大核心方法解析

1. 项目概述:为什么调试 Agent 是开发者的必修课

在 AI Agent 开发领域,我们常常陷入一个怪圈:花 80% 的时间写代码,然后用 200% 的时间来调试和排查为什么 Agent 的行为与预期不符。无论是基于 LangChain、AutoGPT 还是其他自研框架构建的 Agent,一旦它开始与环境交互、调用工具、进行链式思考,其内部状态就变得像一个黑盒。你输入一个指令,它可能输出完美的答案,也可能陷入死循环、调用错误的 API,或者给出一个看似合理实则荒谬的推理过程。这时,高效的调试手段就不再是“锦上添花”,而是“雪中送炭”的生存技能。

我自己在构建一个自动化数据分析 Agent 时就深有体会。Agent 的任务是读取数据库,分析趋势,并生成报告。在初期,它经常在“选择分析维度”这一步卡住,日志里只显示“正在思考...”,然后就没有然后了。没有有效的调试工具,排查这种问题就像在迷宫里摸黑找路。后来,我系统性地整合了日志、断点和可视化这三种调试姿势,才真正把开发效率提了上来。今天,我就把这套结合了传统软件工程和 AI 系统特性的调试方法论分享给你,无论你是刚接触 Agent 的新手,还是正在优化复杂智能体的老手,相信都能从中找到直接可用的“武器”。

简单来说,这三种姿势构成了一个调试的立体视角:日志用于事后复盘和追踪执行流,是“发生了什么”的历史记录;断点用于实时干预和状态检查,是“正在发生什么”的现场勘查;可视化用于理解复杂结构和数据流,是“整体是什么样”的宏观俯瞰。三者结合,你就能从时间、状态和空间三个维度,完全掌控你的 Agent。

2. 核心调试姿势一:结构化日志——Agent 的“飞行数据记录仪”

如果把 Agent 的一次完整运行比作一次飞行,那么日志就是它的“黑匣子”或“飞行数据记录仪”。它不会阻止“坠机”,但能在“事故”发生后,告诉你每一刻发生了什么。对于 Agent 这种具有非确定性、多步骤特性的系统,漫无目的地打印print(“here”)是灾难的开始。我们需要的是结构化、分级别、带上下文的日志。

2.1 日志级别与结构化输出

首先,抛弃简单的print语句。使用 Python 标准的logging模块,并定义清晰的日志级别。

import logging import sys from datetime import datetime # 创建 Agent 专用的 logger agent_logger = logging.getLogger(‘agent_core’) agent_logger.setLevel(logging.DEBUG) # 开发时设为 DEBUG,生产环境设为 INFO 或更高 # 创建控制台处理器,并设置更丰富的格式 console_handler = logging.StreamHandler(sys.stdout) formatter = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - [%(funcName)s] - %(message)s’) console_handler.setFormatter(formatter) agent_logger.addHandler(console_handler) # 同时可添加文件处理器,用于持久化 file_handler = logging.FileHandler(f‘agent_debug_{datetime.now():%Y%m%d}.log’) file_handler.setFormatter(formatter) agent_logger.addHandler(file_handler)

这个格式包含了时间、日志器名称、级别、函数名和消息。当你在 Agent 的不同组件(如规划器、工具执行器、记忆模块)中调用agent_logger.debug(“开始规划任务...”)时,你能立刻知道这条日志来自哪个模块的哪个函数。

日志级别使用心得:

  • DEBUG: 记录最详细的流程信息,如“正在尝试调用工具 X,参数为 {...}”、“LLM 原始响应为:...”。这些信息量巨大,只在深度排查时开启。
  • INFO: 记录关键的业务节点,如“任务规划完成,共 3 个步骤”、“成功调用天气 API,获取到北京数据”。这是监控 Agent 健康状态的主要级别。
  • WARNING: 记录非预期但可处理的情况,如“工具 Y 返回了空结果,将使用默认值”、“用户输入模糊,请求澄清”。
  • ERROR: 记录导致当前任务无法继续的错误,如“数据库连接失败”、“关键 API 返回 500 错误”。
  • CRITICAL: 记录导致整个 Agent 系统崩溃的错误,如“内存溢出”、“配置密钥完全失效”。

2.2 为 Agent 关键生命周期事件打点

一个典型的 Agent 运行包含多个生命周期阶段。在每个阶段输出结构化的日志,能让你快速定位问题发生在哪个环节。

class MyAgent: def run(self, user_input): agent_logger.info(f“[Agent Start] 用户输入: ‘{user_input}‘”) # 阶段1: 意图理解与规划 agent_logger.debug(“进入意图理解与规划阶段”) plan = self.planner.plan(user_input) agent_logger.info(f“任务规划完成,生成步骤: {len(plan.steps)}”) for i, step in enumerate(plan.steps): agent_logger.debug(f“步骤{i+1}: {step.action} with {step.args}”) # 阶段2: 逐步执行 for i, step in enumerate(plan.steps): agent_logger.info(f“[Step {i+1}] 开始执行: {step.action}”) try: result = self.execute_tool(step.action, step.args) agent_logger.info(f“[Step {i+1}] 执行成功,结果摘要: {str(result)[:100]}...”) agent_logger.debug(f“[Step {i+1}] 完整结果: {result}”) # 详细结果放在 DEBUG except Exception as e: agent_logger.error(f“[Step {i+1}] 执行失败,错误: {e}”, exc_info=True) # exc_info 会打印堆栈 # 可能的重试或降级逻辑 break # 阶段3: 结果整合与响应 agent_logger.debug(“进入结果整合阶段”) final_response = self.synthesizer.synthesize(plan, results) agent_logger.info(f“[Agent End] 生成最终响应,长度: {len(final_response)}”) return final_response

通过这种方式,日志不再是杂乱无章的文本流,而是一个有明确章节的故事。当 Agent 执行失败时,你可以快速查看最后一个[Step X] 开始执行和紧随其后的ERROR日志,精准定位问题步骤。

2.3 高级技巧:关联 ID 与 JSON 日志

在并发或异步场景下,多个用户请求交织,日志会混在一起。这时需要引入Request IDSession ID

import uuid class RequestContext: def __init__(self): self.request_id = str(uuid.uuid4())[:8] # 生成短 ID def log(self, message, level=“info”): # 将 request_id 注入日志格式 log_message = f“[Req:{self.request_id}] {message}” getattr(agent_logger, level)(log_message) # 在每次 Agent 调用时创建上下文 def handle_request(user_input): ctx = RequestContext() ctx.log(f“处理请求: {user_input}”) agent = MyAgent(ctx) # 将上下文传入 Agent result = agent.run(user_input) ctx.log(“请求处理完毕”) return result

更进一步,对于使用 ELK(Elasticsearch, Logstash, Kibana)或 Loki 等日志平台团队,输出 JSON 格式的日志是更好的选择,便于后续的筛选、聚合和分析。

import json class JsonFormatter(logging.Formatter): def format(self, record): log_record = { “timestamp”: self.formatTime(record), “level”: record.levelname, “logger”: record.name, “function”: record.funcName, “message”: record.getMessage(), “request_id”: getattr(record, ‘request_id’, ‘N/A’) } if record.exc_info: log_record[“exception”] = self.formatException(record.exc_info) return json.dumps(log_record) json_formatter = JsonFormatter() console_handler.setFormatter(json_formatter)

日志调试的注意事项:

  1. 避免日志副作用:确保日志记录本身(尤其是 DEBUG 级别记录大对象)不会显著影响 Agent 性能,或意外修改程序状态。
  2. 敏感信息脱敏:在日志中自动过滤掉密码、API密钥、个人身份信息(PII)。可以在 Formatter 或 Filter 中实现正则替换。
  3. 日志轮转:使用logging.handlers.RotatingFileHandlerTimedRotatingFileHandler防止日志文件无限膨胀。
  4. 区分环境:开发环境可以输出 DEBUG 日志到控制台,生产环境则应只输出 INFO 及以上级别到文件,并对接监控系统。

3. 核心调试姿势二:交互式断点调试——深入 Agent 的“思维现场”

日志是回顾,而断点调试是“现场直播”。当 Agent 的行为诡异,而日志又无法揭示其“内心活动”时,你就需要挂起它的执行,深入其内部,检查每一刻的变量状态、执行路径。对于 Python Agent 开发,PDBVSCode 调试器是两大神器。

3.1 使用 PDB 进行命令行断点调试

PDB 是 Python 自带的调试器,无需额外安装,在代码中任何位置插入import pdb; pdb.set_trace(),程序运行到此处就会暂停,进入交互式调试命令行。

在 Agent 调试中的典型用法:假设你的 Agent 在决定使用哪个工具时出了错。

def decide_tool(self, observation): # ... 一些推理逻辑 tool_name = llm_call(observation) # 假设这里返回的工具名不对 import pdb; pdb.set_trace() # 在此处打断点 tool = self.toolbox.get(tool_name) # 可能在这里抛出 KeyError return tool

当程序暂停后,你可以:

  • l(list): 查看当前行附近的代码。
  • p tool_name: 打印tool_name变量的值,看看 LLM 到底返回了什么。
  • n(next): 执行下一行。
  • s(step): 进入函数内部。
  • c(continue): 继续运行直到下一个断点或程序结束。
  • q(quit): 退出调试。

更优雅的方式:使用breakpoint()在 Python 3.7+ 中,可以直接使用内置函数breakpoint(),它会自动调用配置好的调试器(默认是 PDB,但可以通过PYTHONBREAKPOINT环境变量配置为 IPython 的debugger等)。

3.2 使用 VSCode 进行图形化断点调试

对于复杂项目,图形化调试器效率更高。VSCode 的调试功能非常强大。

  1. 配置 launch.json: 在你的项目.vscode/launch.json文件中,添加一个 Python 调试配置。
    { “version”: “0.2.0”, “configurations”: [ { “name”: “Python: Debug Agent”, “type”: “debugpy”, “request”: “launch”, “program”: “${workspaceFolder}/run_agent.py”, // 你的 Agent 启动脚本 “args”: [“--query”, “今天的天气怎么样?”], // 启动参数 “console”: “integratedTerminal”, “justMyCode”: false // 设为 true 可跳过库文件的调试 } ] }
  2. 设置断点:在代码行号左侧点击,设置红色断点。你可以设置条件断点(例如,当tool_name == “某个错误值”时才中断)、日志点(不中断,只输出信息)。
  3. 启动调试:按 F5 启动。程序会在断点处暂停。
  4. 检查与交互
    • 变量窗口:查看所有局部变量和全局变量的当前值。
    • 监视窗口:添加你想持续监视的表达式(如len(memory.messages))。
    • 调用堆栈:查看当前函数是如何被一层层调用的,这对于理解 Agent 的决策链至关重要。
    • 调试控制台:可以直接执行 Python 代码,修改当前上下文中的变量,然后继续执行,观察影响。

3.3 Agent 调试的特殊场景:异步与多线程

许多现代 Agent 框架使用异步来提高 I/O 效率(如等待 LLM 响应、调用网络 API)。调试异步代码需要特别注意。

  • 对于 asyncio:VSCode 和 PyCharm 对异步调试的支持已经很好。确保你的启动配置中“subProcess”: true。在调试时,调用堆栈会显示多个并发的任务。
  • 使用asyncio.run()包装:如果你的调试入口是同步的,但内部调用了异步的 Agent 核心,可以用asyncio.run(main())来启动。
  • 调试技巧:在异步函数中打上断点,当程序暂停时,你可以在调试控制台使用await表达式来手动执行协程,检查中间状态。例如,在等待 LLM 响应的await llm.agenerate(...)语句前打断点,暂停后,在控制台输入p prompt查看发送的提示词,甚至可以手动修改 prompt 再继续执行,看 LLM 的响应是否会变化。

断点调试的实操心得:

  1. 不要滥用断点:在关键决策函数(如plandecide_toolhandle_error)入口和可能出错的分支上设置断点,而不是每一行。
  2. 善用条件断点:当某个错误只在特定输入下出现时,条件断点能帮你快速捕捉到那个场景,避免在正常流程中反复中断。
  3. 结合日志使用:先通过日志缩小问题范围,确定大概的故障模块或步骤,再用断点进行微观侦查。
  4. 调试记忆(Memory):Agent 的记忆(如对话历史、向量存储)是其状态的核心。在断点暂停时,仔细检查记忆对象里存储的内容是否正确、是否包含了不该有的信息或丢失了关键信息。

4. 核心调试姿势三:可视化——洞悉 Agent 的“思维图谱”

当 Agent 的决策链很长、工具调用复杂、内部状态多维时,纯文本的日志和单点的断点仍然让人难以把握全局。这时,可视化工具能帮你将复杂的执行过程、数据结构转化为一目了然的图表。这里我们主要探讨两种可视化:执行流程可视化内部状态/数据结构可视化

4.1 执行流程与调用链可视化

这旨在回答一个问题:“我的 Agent 为了完成这个任务,到底走了哪条路?调用了哪些工具?顺序如何?”

方法一:手动生成 Mermaid 流程图Mermaid 是一种基于文本的图表生成工具,非常适合在代码中嵌入并生成流程图。你可以在 Agent 的关键节点收集信息,最后生成一个 Mermaid 脚本。

class TracedAgent: def __init__(self): self.execution_graph = [] # 用于存储执行步骤 self.graph_sequence = 0 def log_step(self, action, input_data, output_data): self.graph_sequence += 1 step_id = f“step{self.graph_sequence}” self.execution_graph.append({ ‘id’: step_id, ‘action’: action, ‘input’: str(input_data)[:50], # 摘要 ‘output’: str(output_data)[:50] }) def generate_mermaid(self): mermaid_lines = [“graph TD”] for i, step in enumerate(self.execution_graph): # 定义节点,格式:节点ID[显示内容] # 用矩形表示动作,圆角矩形表示输入/输出 mermaid_lines.append(f“ {step[‘id’]}[{step[‘action’]}]”) if i > 0: # 连接上一个节点和当前节点 prev_id = self.execution_graph[i-1][‘id’] mermaid_lines.append(f“ {prev_id} --> {step[‘id’]}”) # 可以添加输入输出作为子图或注释,这里简化处理 return “\n”.join(mermaid_lines) # 在 Agent 执行过程中 agent = TracedAgent() agent.log_step(“Plan”, user_input, plan) for step in plan.steps: agent.log_step(f“Tool: {step.action}”, step.args, result) agent.log_step(“Synthesize”, intermediate_results, final_response) mermaid_code = agent.generate_mermaid() print(mermaid_code)

将输出的文本复制到 Mermaid Live Editor 或支持 Mermaid 的 Markdown 编辑器(如 Typora、Obsidian、GitHub/GitLab Wiki),就能立即看到一幅执行流程图。这对于向团队解释 Agent 的行为逻辑,或者在文档中记录典型执行路径,非常有帮助。

方法二:集成 LangSmith 或自定义追踪系统如果你使用 LangChain,强烈推荐使用LangSmith。它提供了开箱即用的、强大的可视化追踪功能。只需设置好 API 密钥,你的 LangChain Agent 的所有运行(包括 LLM 调用、工具调用、链式步骤)都会被自动记录,并在 LangSmith 的 Web 界面上以时间线和水滴图的形式清晰展示。你可以看到每一步的耗时、输入输出、甚至 LLM 的提示词和完成结果。这对于性能分析和优化提示词至关重要。

对于非 LangChain 框架,你可以借鉴其思路,构建一个简单的追踪客户端,将执行事件(开始、结束、错误)发送到一个中心服务(如 Zipkin、Jaeger,或者简单的 Flask 服务+数据库),然后自己用前端图表库(如 ECharts、D3.js)绘制调用链图。

4.2 内部状态与数据结构可视化

这旨在回答:“在某个时刻,Agent 的记忆里有什么?它的目标分解成了什么样子?向量数据库里检索到的内容相关吗?”

记忆(Memory)可视化:如果使用对话历史记忆,可以定期将其内容(如最近的 10 轮对话)以清晰的对话格式打印或保存。如果使用向量记忆,可以可视化检索过程:对于一次查询,展示被检索到的 Top-K 个片段及其相似度分数。

def visualize_retrieval(query, chunks, scores): “”“简单地在控制台打印检索结果表格”“” print(f“查询: ‘{query}‘”) print(“-” * 80) print(f“{‘序号’:<5} {‘相似度’:<10} {‘内容片段’:<60}”) print(“-” * 80) for i, (chunk, score) in enumerate(zip(chunks, scores)): # 限制片段长度以便显示 snippet = (chunk[:57] + ‘...’) if len(chunk) > 60 else chunk print(f“{i+1:<5} {score:<10.4f} {snippet:<60}”) print(“-” * 80)

对于更复杂的记忆结构(如知识图谱),可以考虑使用networkx库生成图,并用matplotlibpyvis进行交互式绘制。

工具调用参数与结果可视化:对于涉及复杂数据结构(如 JSON、字典列表)的工具调用,使用 Python 的pprint(pretty print) 模块可以大幅提升可读性。

from pprint import pprint agent_logger.debug(“工具调用参数详情:”) pprint(tool_call_args, indent=2, depth=2) # depth 控制展开层级 agent_logger.debug(“工具返回结果详情:”) pprint(tool_result, indent=2, depth=3)

可视化调试的注意事项:

  1. 性能开销:生成可视化数据(尤其是实时生成复杂图表)会带来额外开销。建议在开发调试阶段开启,在生产环境中关闭或仅采样开启。
  2. 信息密度:可视化是为了洞察,而不是炫技。确保图表传递的信息是核心的、关键的。避免让图表过于花哨而淹没了重点。
  3. 自动化集成:将关键的可视化(如每次运行的 Mermaid 流程图)作为日志的一部分自动保存下来,便于后续对比分析。可以配置当任务失败时,自动生成并附加更详细的可视化报告。

5. 三种姿势的融合实战:调试一个失控的搜索分析 Agent

让我们通过一个虚构但典型的案例,看看如何综合运用这三种姿势。假设我们有一个“网络搜索分析 Agent”,它的任务是:根据用户问题,搜索最新信息,并进行分析总结。但用户反馈,当问“苹果公司最新财报”时,Agent 有时会去搜索水果“苹果”的种植信息。

第一步:日志定位异常环节首先,我们检查 INFO 级别日志。

2023-10-27 14:30:01 - agent_core - INFO - [run] - [Agent Start] 用户输入: ‘苹果公司最新财报’ 2023-10-27 14:30:02 - agent_core - INFO - [run] - 任务规划完成,生成步骤: 3 2023-10-27 14:30:03 - agent_core - INFO - [run] - [Step 1] 开始执行: web_search 2023-10-27 14:30:05 - agent_core - INFO - [run] - [Step 1] 执行成功,结果摘要: 关于苹果种植技术、市场价格... 2023-10-27 14:30:05 - agent_core - ERROR - [run] - [Step 2] 执行失败,错误: AnalysisError: 搜索...

日志清晰地显示,问题出在第一步web_search。它成功执行了,但返回的结果却是关于水果苹果的。这说明规划器给出的搜索指令(query)可能有问题。

第二步:断点深入决策现场我们在规划器生成搜索 query 的代码处设置条件断点(条件:用户输入包含“苹果”)。

def generate_search_query(self, user_input): # 这里是规划器调用 LLM 生成搜索 query 的逻辑 prompt = f“请将以下用户问题转化为一个精准的网页搜索查询词:{user_input}” # 假设调用 LLM search_query = llm_call(prompt) # 在此行设置条件断点:if ‘苹果’ in user_input return search_query.strip()

当断点触发时,我们在调试控制台检查promptsearch_query的值。发现search_query的值是“苹果 最新”。这太模糊了!LLM 没有理解到这里的“苹果”是指公司。这说明我们的提示词(prompt)需要优化,可能需要提供更多上下文或示例。

第三步:可视化理解整体流程与决策依据我们启用追踪功能,生成这次失败运行的 Mermaid 流程图。

graph TD step1[Plan: 分析任务] step2[Tool: web_search] step3[Tool: analyze_results] step1 --> step2 step2 --> step3

图很简单,但结合我们收集的每一步的输入输出数据(在追踪日志里):

  • Step1 输入:用户问题:‘苹果公司最新财报’
  • Step1 输出:计划步骤:[‘web_search’, ‘analyze_results’](缺少具体 query)
  • Step2 输入:query:‘苹果 最新’
  • Step2 输出:搜索结果:水果苹果相关...

可视化虽然没有直接解决问题,但它以一种结构化的方式,将日志中的文本信息和断点发现的代码位置关联起来,清晰地展示了故障的传播路径:模糊的规划结果导致了错误的搜索指令

综合解决方案:

  1. 优化提示词:修改规划器的提示词,明确要求识别实体歧义。例如:“用户问题:‘{user_input}’。请识别其中的关键实体,并生成一个能消除歧义、精准的网页搜索查询词。如果涉及公司名,请补充‘公司’或股票代码。”
  2. 增加验证步骤:在web_search工具被调用前,加入一个简单的验证规则。例如,如果 query 是“苹果”,且上下文没有明确指向水果,则向用户发起澄清:“您指的是苹果公司 (Apple Inc.),还是水果苹果?”
  3. 完善日志:在规划器输出中,不仅记录步骤,也记录生成的中间指令(如搜索 query),并将日志级别设为 INFO,便于日常监控。

通过这个案例,你可以看到:日志快速指出了问题方向(Step 1 结果不对),断点精准定位了问题根源(提示词导致 query 模糊),而可视化则帮助我们和团队沟通,理清了问题发生的逻辑链条。三者环环相扣,缺一不可。

6. 进阶调试策略与工具链集成

掌握了三种基本姿势后,我们可以追求更高效、更自动化的调试体验。

6.1 构建可观测性(Observability)仪表盘

对于部署在服务器上的 Agent 服务,我们需要远程的、集中的可观测能力。这超越了本地调试,涵盖了指标(Metrics)、日志(Logs)和追踪(Traces),即MLT 三大支柱

  • 指标 (Metrics):使用prometheus_client等库,收集 Agent 的关键指标,如:请求量、平均响应时间、各工具调用耗时、LLM 调用 token 消耗、缓存命中率、错误率等。通过 Grafana 进行可视化,可以一眼看出系统的健康度。
  • 日志 (Logs):如前所述,将结构化的 JSON 日志输出,并通过 Filebeat、Fluentd 等工具收集,发送到 Elasticsearch 或 Loki,实现高效的聚合查询和告警。
  • 追踪 (Traces):使用 OpenTelemetry 这样的标准来记录分布式追踪。为每个用户请求生成一个唯一的 Trace ID,并在这个请求流经 Agent 的各个组件(规划、工具调用、LLM、记忆存储)时,创建 Span。这样你可以在 Jaeger 或 Zipkin 的界面上看到一个请求完整的、带有时延的调用链,非常直观地发现性能瓶颈。

将这三者关联起来(通过统一的 Request ID),你就能实现强大的调试能力:当 Grafana 仪表盘显示错误率飙升时,你可以快速在 Kibana 中过滤出错误日志,然后通过 Trace ID 在 Jaeger 中找到对应的缓慢或失败的调用链,精确找到是哪个工具的哪个 API 调用出了问题。

6.2 自动化测试与场景回放

调试不应该总是被动的。为你的 Agent 核心逻辑编写单元测试和集成测试。

  • 单元测试:测试工具函数、状态处理函数、简单的决策逻辑。使用pytest框架,配合monkeypatch来模拟 LLM 和外部 API 的响应。
  • 集成测试:模拟端到端的用户会话。记录下典型的用户输入和期望的 Agent 输出(或输出应满足的断言,如包含某个关键词、调用了某个工具)。当代码修改后,运行这些测试用例,确保没有回归错误。
  • 场景回放:当线上出现一个难以复现的 bug 时,如果日志足够详细(记录了完整的输入、中间决策、外部调用参数),你可以尝试在开发环境中“回放”这个场景。即用记录的输入数据,在相同的代码版本下重新运行,配合详细的日志和断点,复现并定位问题。这要求你的 Agent 逻辑具有一定的确定性(对于相同的输入和外部依赖响应,输出相同)。

6.3 针对 LLM 不确定性的调试技巧

Agent 的核心驱动力——大语言模型(LLM)——具有内在的不确定性。同样的提示词,可能产生不同的输出。这给调试带来了挑战。

  1. 固定随机种子:在开发调试时,为你的 LLM 调用设置固定的随机种子(如果底层库支持),例如在 OpenAI 调用中设置seed参数。这可以确保在多次运行中,只要提示词和参数不变,LLM 的输出就是确定的,便于复现问题。
  2. 提示词版本化与 A/B 测试:将提示词模板存储在代码或配置文件中,并赋予版本号。当修改提示词后,通过 A/B 测试或对比实验,评估新提示词在关键指标(如任务成功率、工具调用准确率)上的表现。这使调试从“感觉不对”变为“数据驱动”。
  3. 思维链(CoT)可视化:如果 Agent 使用了思维链(Chain-of-Thought)提示,务必在 DEBUG 日志中完整记录 LLM 产生的整个推理过程。这个“内心独白”是理解 Agent 为何做出错误决策的最宝贵材料。你可以分析它在哪一步推理出现了偏差。

7. 常见问题排查手册(Q&A)

在实际操作中,你一定会遇到一些共性问题。这里我整理了一份速查手册,附上排查思路。

问题现象可能原因排查步骤(结合三种姿势)
Agent 陷入循环,重复相同操作1. 记忆未更新,导致每次规划看到相同历史。
2. 终止条件判断逻辑有误。
3. LLM 在循环提示下产生了循环内容。
1.日志:检查每次循环的规划输入,看历史记忆是否被正确包含且更新。
2.断点:在判断任务是否完成的函数 (is_complete) 处打断点,检查判断逻辑和输入状态。
3.可视化:绘制执行流图,观察循环结构。检查提示词是否包含了导致循环的指令。
工具调用总是失败或返回意外结果1. 工具参数格式错误。
2. 工具依赖的外部服务异常或权限不足。
3. LLM 生成的参数解析错误。
1.日志:在 DEBUG 级别记录工具被调用时的完整参数原始返回
2.断点:在工具调用前一刻打断点,手动检查即将发送的参数,并尝试在 Python 交互环境或 Postman 中手动调用该工具。
3.可视化:对比成功和失败案例的工具调用参数差异。
Agent 响应速度极慢1. 某个工具或 LLM 调用耗时过长。
2. 规划步骤过多,串行执行。
3. 记忆检索(如向量搜索)在大型库中效率低。
1.日志:为每个关键操作记录时间戳,计算耗时。或使用loggingTiming功能。
2.可视化(追踪):使用 LangSmith 或 OpenTelemetry 查看调用链瀑布图,定位耗时最长的 Span。
3.断点/分析:检查向量搜索的 Top-K 值是否过大,索引是否需要优化。
Agent 忽略了关键的用户指令1. 意图识别(NLU)模块错误。
2. 规划器未能将用户指令分解为对应步骤。
3. 记忆覆盖,旧上下文冲掉了新指令。
1.日志:记录并对比原始用户输入和意图识别/规划器的输出。
2.断点:在意图识别和规划函数入口设置断点,单步执行,观察内部表示。
3.可视化:可视化记忆池的内容,检查用户的最新指令是否被正确存储和加权。
生产环境与开发环境行为不一致1. 环境变量或配置不同(如 API 密钥、模型版本)。
2. 依赖库版本差异。
3. 生产环境的数据(记忆库)状态不同。
1.日志:在应用启动时,以 INFO 级别打印关键配置的哈希或摘要(避免泄露密钥)。对比两个环境的日志开头。
2.可观测性:生产环境务必开启详细的错误日志和指标监控,当出现差异时,对比两边的监控图表和错误信息。
3.回放:尝试将生产环境出错的请求参数和上下文,在开发环境进行回放调试。

调试 Agent 是一个从混沌到清晰的过程。日志、断点、可视化是你手中最重要的三盏灯。日志照亮来时的路,让你能复盘追溯;断点让你能冻结时间,仔细审视当下的每一个细节;可视化则为你展开一幅全景地图,看清系统各部分的关系与数据流动。

← 返回列表