ARTICLE DETAIL

资讯详情

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

排坑笔记:LangChain 多工具 Agent 完整性校验 return_intermediate_steps 事后核对方案

排坑笔记:LangChain 多工具 Agent 完整性校验 return_intermediate_steps 事后核对方案 【博文导航】四阶段学习路径版持续更新 关于【智联工坊】那些事 文章摘要多工具数据质量巡检 Agent 注册 5 个工具模型只调用 4 个就输出结论报告看似完整却缺失维度靠提示词约束始终是概率性的。本文提供工程化解决方案通过集合差集校验做事后完整性兜底漏调工具自动补执行并留痕配合桩测试锁定效果把工具调用完整性从模型自觉变成可度量、可审计的工程不变量适用于所有生产级多工具 Agent 场景。目录一、问题现象二、影响范围三、排查过程第一层确认是「模型没调」而不是「工具没注册」第二层定位小模型为什么提前收敛第三层换个思路把完整性从「事前约束」挪到「事后校验」四、解决方案方案一提示词硬约束保留成本低方案二集合差集校验 漏调留痕核心方案三用桩测试把这条不变量锁死五、验证结果六、预防措施 系列导航 评论区互动与既有笔记的关系Agent 反复调用工具死循环163609470 与 Prompt 写了 2000 字Agent 反而躺平了163478743 都在讲「用 Prompt 规则约束工具调用行为」return_intermediate_steps 一开 Memory 就报警163479398 讲的是这个开关与 Memory 的配置冲突。本文的切入口不同不依赖模型守规矩用同一个return_intermediate_steps开关去做事后完整性核对并把核对结果变成可观测指标。一、问题现象【智联工坊】实践之旅的案例《工业数据质量自动检测方案 3σ 原则 Agent 编排 分层容错》一文中对50 万行传感器数据的对话式巡检实测。Agent 注册了 5 个工具null_check、duplicate_check、outlier_check、delay_check、structure_check。开 verbose 盯日志它顺次调了 4 个内容检测工具然后直接输出 Final Answer——structure_check全程没被调用。整轮耗时 2m07s报告排版完整、结论完整、语气笃定唯独缺了整个结构维度。我的第一反应是这不科学啊……系统提示词里工具清单写得清清楚楚还专门写了「结构体检与内容检测同等重要」模型怎么就当没看见 快速自检你是不是也遇到了这些现象▢ 注册了 N 个工具实测只调了其中一部分报告却看不出缺项▢ 靠人工翻 verbose 日志才发现漏调下一次有没有漏全凭运气▢ 提示词里写了硬约束模型这次遵守、下次不遵守无法复现本文一次性解决以上所有问题。二、影响范围漏检的危害取决于漏掉的是什么而不是漏了多少个漏掉的维度后果发现难度结构体检本次编码/列结构/时间戳未验证下游检测的输入本身不可信高报告格式正常人工审阅看不出来数值类检测异常值漏报故障苗头被抹平中与历史基线对比才可能发现重复/延迟类统计口径失真但不致命中提示词层面同类漏调在每次巡检随机复现最高漏调率无法统计最麻烦的一点是延迟暴露报告当天看不出问题直到某天按它做了决策才发现那个维度从来没查过。三、排查过程第一层确认是「模型没调」而不是「工具没注册」 快速自检命令开启return_intermediate_stepsTrue后执行以下代码即可快速核对工具调用完整性from agent.guard import _called_tools # 执行完Agent后提取已调工具集合 called _called_tools(result) print(f已调工具{sorted(called)})先排除工程侧问题再去怀疑模型。python -c from agent.builder import build_executor; e build_executor(); print([t.name for t in e.tools])本次输出 5 个工具注册正常。再看 verbose 日志里的调用轨迹确认structure_check是从未出现在轨迹里而不是调用了但抛异常被吞掉。排查陷阱拿到注册列表就下结论「模型偷懒」很容易误判。如果工具在注册时因为异常被跳过编码错、参数缺日志上看到的现象和模型漏调一模一样。第二层定位小模型为什么提前收敛7b 级模型在 ReAct 循环里拿到 4 项长 JSON 结果后Observation 区已经很长模型「感到信息充分」直接收敛。提示词升级 v1.0.1 加了「全部工具返回前禁止 Final Answer」的硬约束后复跑确实调齐了 5 个——但这属于概率性守规矩不是保证。第三层换个思路把完整性从「事前约束」挪到「事后校验」事前约束提示词作用于概率事后校验代码作用于确定。既然漏调率需要长期观测、需要在回归里锁死位置就必须在代码侧且必须能留下数据。四、解决方案三道防线方案成本与定位分析表防线层级方案可靠性成本定位第一道提示词硬约束概率性低覆盖大多数常规场景第二道集合差集校验 漏调补执行确定性中核心兜底生产级必备第三道桩测试回归验证确定性低CI / 交付前校验锁死效果方案一提示词硬约束保留成本低【硬性约束】必须依次调用全部工具各一次null_check、duplicate_check、outlier_check、delay_check、structure_check。 五个工具全部返回结果之前禁止输出 Final Answer。它能覆盖大多数场景但只能当第一道防线不能当保障。方案二集合差集校验 漏调留痕核心思路执行结束后取「已调工具集合」与「注册工具全集」求差集差集非空即触发补执行并把差集写进结果里长期可查。# agent/guard.py节选 def run_with_tool_guard(executor: Any, tools: Sequence[Tool], query: str) - Dict[str, Any]: 带工具完整性兜底的 Agent 执行入口编排层第二道防线。 设计思路: 第一道防线是系统提示词的全工具必调约束低成本、覆盖大多数场景 第二道防线是本函数的代码级校验确定性强、不依赖模型自觉。 边界情况: 漏调工具补执行失败时返回 {error, suggestion} 结构占位 保证报告维度齐全可审计合并失败降级为原文追加主流程不中断。 raw executor.invoke({input: query}) # executor 须开 return_intermediate_stepsTrue result: Dict[str, Any] dict(raw) if isinstance(raw, dict) else {output: str(raw)} expected {t.name for t in tools} # 注册全集 完整性核对基准 called _called_tools(result) # 从 intermediate_steps 提取已调工具 missing sorted(expected - called) # 差集 漏调清单 result[expected_tools] sorted(expected) result[called_tools] sorted(called) result[fallback_executed] missing # 留痕可统计漏调率 if not missing: logger.info(工具完整性校验通过: 已调 %d/%d 个工具, len(called), len(expected)) return result logger.warning(完整性兜底触发: 模型漏调 %s编排层自动补执行, missing) name_to_tool {t.name: t for t in tools} extra: Dict[str, str] {} for name in missing: try: extra[name] str(name_to_tool[name].func()) except Exception as exc: # noqa: BLE001 补执行失败不中断主流程留结构化占位 logger.error(兜底补执行 %s 失败: %s, name, exc) extra[name] json.dumps(_TOOL_ERROR_FALLBACK, ensure_asciiFalse) result[fallback_outputs] extra draft str(result.get(output, )) if AGENT_FALLBACK_MERGE: try: result[output] _merge_with_llm(query, draft, extra) return result except Exception as exc: # noqa: BLE001 模型不可用时降级为原文追加 logger.error(兜底合并失败降级为原文追加: %s, exc) result[output] draft _append_raw(extra) return result四个设计点差集核对是 O(n) 的集合运算成本可忽略补执行失败不中断主流程留{error, suggestion}结构占位保证维度齐全可审计合并走 LLM 但失败自动降级为原文追加无论是否触发都写fallback_executed漏调率因此可统计——跑一周就知道是稳定复现还是偶发。方案三用桩测试把这条不变量锁死# tests/test_guard.py节选 def test_guard_catches_missing_tools() - bool: 漏调场景模型只调 2 个工具兜底必须补齐其余 3 个并留痕。 builder QualityAgentBuilder(str(DATA_FILE)) builder.register_detection_tools() # 注册与构建解耦工具层可脱离模型测试 assert builder.tools, 注册工具集为空差集校验会恒真空转 # 防基准为空 executor _StubExecutor([null_check, duplicate_check]) result run_with_tool_guard(executor, builder.tools, 帮我检查数据质量) called set(result[called_tools]) fallback set(result[fallback_executed]) assert called {null_check, duplicate_check}, f桩调用集合不符: {called} assert fallback {t.name for t in builder.tools} - called, f兜底集合不符: {fallback} return True桩 Executor 只返回与真实AgentExecutor(return_intermediate_stepsTrue)相同的结构被测代码走的是生产同一条路径合并开关置 false测试零模型依赖CI 里也能跑。五、验证结果验证层方式结果真实模型50 万行AGENT_VERBOSEtrue python 02_test_cli.py2m48s5/5 工具调齐报告含结构体检数字与独立检测一致桩单测·漏调只调 2 个工具兜底精确补齐 3 个输出含追加小节桩单测·全调5 个工具全调零触发、原样透传不产生额外模型开销✅ 修复成功三大标志✅ 日志出现「工具完整性校验通过: 已调 5/5 个工具」或「完整性兜底触发: 模型漏调 […]」 补执行清单✅ 结果字典留痕齐全expected_tools/called_tools/fallback_executed可审计、可统计✅ 桩单测两条路径全绿且基准集合非空断言在位见预防措施第三条六、预防措施怕你忘了我再啰嗦一遍凡是「靠模型自觉」保证的流程完整性都要在代码层补一次事后校验并让校验结果可统计、可回归。落到具体操作上就是三条完整性靠集合运算判定已调集 ⊇ 注册全集取差集即可不做字符串匹配、不解析自然语言。兜底必须留痕补执行清单写进结果字典与日志漏调率才是可观测指标否则你只能靠人肉翻日志。包含性断言先验基准非空本次写单测时踩过一个隐蔽坑——工具注册耦合在build()内部测试里直接取.tools拿到的是空列表expected空集让差集恒为空兜底「未触发」全绿通过。「核对已调 ⊇ 注册全集」这类校验基准为空时恒真形同虚设却显示通过比没有校验更危险。解法是注册与构建解耦register_detection_tools()公开方法并对基准集先断言非空。适用范围适用于所有多工具 AgentReAct / Function Calling尤其工具数 ≥ 3、且各维度结果不允许缺失的巡检、审计、合规类场景。模型越小、Observation 越长事前提示词约束越不可靠事后校验越必要。建议如下・推荐场景工具数≥3、维度不允许缺失的巡检、审计、合规类生产级 Agent・简易场景单工具、对话式 Demo、容错要求低的场景仅提示词约束即可・模型越小、观察上下文越长事后校验的必要性越高。标签#LangChain#AI Agent#排坑笔记#多工具协同#工具调用#工程化#质量保障#Agent开发 系列导航系列传送门【制造业数据与AI落地实战】 【AI赋能数据开发工程手册】【数据与AI工程排坑笔记】本文问题源自智联工坊实战工业数据质量自动检测方案 3σ 原则 Agent 编排 分层容错完整实践【热榜文精品推荐】TOP1、我用 WorkBuddy 分析了 30 篇 CSDN 博客发现 3 个反直觉的流量真相TOP2、还在翻 git log 写周报WorkBuddy 一键生成结构化周报TOP3、老攻城狮的AI开发环境搭建全记录从零到跑通本地大模型一日速通版TOP4、LangChain Agent 反复调用工具死循环结构化返回 Prompt 规则TOP5、智联工坊实战多工具协同Agent让AI像人类一样规划与执行复杂任务TOP6、代码审查不想得罪人WorkBuddy 先做第一轮审查 评论区互动兄弟们Agent 工具漏调的排坑指南更了不靠改提示词用代码级集合差集校验做兜底漏调自动补执行还留痕可统计可审计。整理好了可直接复用的 guard.py 模块和桩测试代码评论区留「Agent 兜底」我发你。你们做生产级 Agent 还踩过什么工程化的坑评论区聊聊点赞高的我接着出排坑篇。
返回列表