Agent的“嵌套JSON”噩梦:当Action Input变成字符串套娃
【导航台账】制造业数据与AI践行者老蒋的技术博客全系列文章汇总持续更新文章摘要在调用Agent工具时明明传了date参数却反复报错Field required。排查发现LangChain的ReAct Agent在生成Action Input时将整个JSON对象作为字符串嵌套进了line_name字段导致Pydantic只解析到第一个字段。本文剖析Agent参数生成的内部机制并提供“防御性JSON解析”的通用解决方案。适用于LangChain 0.3.x版本的Agent工具开发。问题现象兄弟们这个故事有点意思。前面几篇排坑笔记你们也看到了我们把__init__.py导入链污染搞定了把版本碎片化搞定了把中文括号也搞定了。我以为世界就此清净了。然后我信心满满地跑起了Agent测试输入计算交互屏组装A线在2026-07-12的OEEAgent的思考链正常启动工具调用正常触发一切看起来都很美好——直到它报了这个错❌ 错误: 1 validation error for OEEInput date Field required [typemissing, input_value{line_name: {line_nam... date: 2026-07-12}}, input_typedict]我当时的第一反应是这不科学啊......我明明传了date而且从日志里看Action Input里面清清楚楚写着date: 2026-07-12。Pydantic凭什么说Field required根因分析说实话这个问题我盯着屏幕看了十分钟甚至怀疑过是不是Pydantic版本又出幺蛾子了。后来我把Agent生成的Action Input完整打印出来一看真相大白。第一层Agent偷懒把JSON当字符串塞进了一个字段这是Agent生成的Action Input{line_name: {\line_name\: \交互屏组装A线\, \date\: \2026-07-12\}}这是我希望它生成的Action Input{line_name: 交互屏组装A线, date: 2026-07-12}看出来区别了吗Agent把整个JSON对象当作一个字符串塞进了line_name字段里。导致Pydantic在解析时只看到了line_name这一个字段date被埋在了字符串内部根本解析不到。第二层为什么会这样——Agent的“自作聪明”LangChain的ReAct Agent在生成Action Input时会尝试自动判断参数的格式。当我定义的OEEInput有两个字段line_name和date时Agent的内心活动大概是这样的“用户说要计算OEE我得调用calculate_oee。这个工具需要两个参数我该怎么传呢我干脆把两个参数打包成一个JSON字符串一次性塞进去省事。”于是它就干出了这种“字符串套娃”的骚操作。它不知道的是Pydantic在解析时是按字段名来匹配的你塞得再好字段名对不上它就报错。说白了Agent太“聪明”了聪明到帮我们做了多余的事。第三层这坑为什么容易踩因为LangChain 0.3.x的create_react_agent对输出格式的约束不够严格。它告诉Agent要输出Action Input但没有强制要求这是一个扁平的JSON对象Agent就有机会自由发挥。而Python开发者习惯了用json.dumps()很容易在Prompt中不小心给Agent“示范”了嵌套JSON的写法——你一旦在Prompt里写了个JSON示例Agent就会学你。解决方案说实话让Agent别自作聪明这事靠“教”是教不会的。直接上防御性编程——在工具内部自己处理这种骚操作。第一步修改_run方法增加嵌套检测在tools/oee_calculator.py的_run方法开头加入这段逻辑def _run(self, line_name: str, date: Optional[str] None) - str: # ---- 防御性解析处理Agent的“字符串套娃” ---- if isinstance(line_name, str) and line_name.strip().startswith({) and line_name.strip().endswith(}): try: import json data json.loads(line_name) # 从嵌套JSON中提取真正的参数 line_name data.get(line_name, line_name) date data.get(date, date) except json.JSONDecodeError: pass # 继续原有逻辑...这段代码的逻辑很简单检查line_name是不是一个JSON字符串以{开头、以}结尾解套如果是用json.loads()解开从中提取真正的line_name和date兜底如果解析失败保持原值不变第二步将date字段设为可选把OEEInput的date字段改成Optional并提供默认值class OEEInput(BaseModel): line_name: str Field(description产线全称) date: Optional[str] Field(defaultNone, description日期不填则默认今天)然后修改_run方法签名def _run(self, line_name: str, date: Optional[str] None) - str: if date is None: date datetime.now().strftime(%Y-%m-%d) # 继续...第三步同样操作应用到shift_query.py不要只改一个工具query_shift也会有同样的问题。把ShiftInput的date也改成Optional并在_run中加入相同的解析逻辑。验证结果修改之后重新运行 你: 计算交互屏组装A线在2026-07-12的OEE Entering new AgentExecutor chain... Thought: 需要调用calculate_oee工具 Action: calculate_oee Action Input: {line_name: 交互屏组装A线, date: 2026-07-12} Observation: {line: 交互屏组装A线, oee: 86.39, quality_rate: 97.0, ...} Final Answer: 交互屏组装A线在2026-07-12的OEE为86.39% Agent: 交互屏组装A线在2026-07-12的OEE为86.39%经验总结怕你忘了我再啰嗦一遍Agent的Action Input不一定是你想要的那个样子它可能会自作主张地帮你“优化”格式。落到具体操作上就是三条永远不要完全信任Agent生成的参数格式。LangChain的ReAct Agent在复杂场景下可能会输出嵌套JSON、纯文本、甚至把多个参数拼成一个字符串。写防御性代码是唯一靠谱的方式。在_run()方法开头加一层“JSON检测解套”逻辑。这招不止对付嵌套JSON还能处理line_name变成乱七八糟字符串的情况。本质上就是先判断它是不是JSON是就解开不是就当普通字符串用。所有工具类的date字段都设为Optional。别逼用户每次都要手动输入日期让工具自己处理默认值。这样即使Agent漏传了date你的工具也不会崩。调试技巧如果遇到奇怪的Field required报错先别急着改代码。在_run()方法最开头加一行print(fDEBUG: line_name{line_name}, date{date})看看Agent实际传入的值是什么。很多时候你会发现它传入的东西跟你想象的根本不是一回事。说白了就是一句话不要相信Agent要相信防御性代码。系列导航本文属于《数据与AI工程排坑笔记》系列上一篇Pydantic Field(description...)中的中文括号一个隐藏的SyntaxError下一篇《PromptTemplate vs JSON花括号一场变量解析的战争》即将发布本文问题源自智联工坊实战制造知识库工具调用Agent从零搭建OEE手册排班-CSDN博客 完整源码及深度教程见该文详细内容。建议收藏下次遇到类似的Field required报错可以快速对照本文排查。互动与交流你在使用LangChain Agent时有没有遇到过它“自作聪明”帮你做了多余操作的情况欢迎在评论区吐槽咱们互相安慰一下——也让我知道多少人被Agent坑过的人关于作者制造业数据与AI践行者老蒋23年IT老兵。聚焦制造业数据架构与AI融合落地。全流程实战全源码开源。标签#排坑笔记#LangChain#Agent#踩坑实录