【导航台账】制造业数据与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的OEE

Agent的思考链正常启动,工具调用正常触发,一切看起来都很美好——直到它报了这个错:

❌ 错误: 1 validation error for OEEInput
date
  Field required [type=missing, input_value={'line_name': '{"line_nam... "date": "2026-07-12"}'}, input_type=dict]

我当时的第一反应是:这不科学啊......😀

我明明传了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_namedate)时,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
    # 继续原有逻辑...

这段代码的逻辑很简单:

  1. 检查line_name是不是一个JSON字符串?(以{开头、以}结尾)

  2. 解套:如果是,用json.loads()解开,从中提取真正的line_namedate

  3. 兜底:如果解析失败,保持原值不变

第二步:将date字段设为可选

OEEInputdate字段改成Optional,并提供默认值:

class OEEInput(BaseModel):
    line_name: str = Field(description="产线全称")
    date: Optional[str] = Field(default=None, 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也会有同样的问题。把ShiftInputdate也改成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不一定是你想要的那个样子,它可能会自作主张地帮你“优化”格式。

落到具体操作上就是三条:

  1. 永远不要完全信任Agent生成的参数格式。LangChain的ReAct Agent在复杂场景下,可能会输出嵌套JSON、纯文本、甚至把多个参数拼成一个字符串。写防御性代码是唯一靠谱的方式。

  2. _run()方法开头加一层“JSON检测+解套”逻辑。这招不止对付嵌套JSON,还能处理line_name变成乱七八糟字符串的情况。本质上就是:先判断它是不是JSON,是就解开;不是就当普通字符串用。

  3. 所有工具类的date字段都设为Optional。别逼用户每次都要手动输入日期,让工具自己处理默认值。这样即使Agent漏传了date,你的工具也不会崩。

  4. 调试技巧:如果遇到奇怪的Field required报错,先别急着改代码。在_run()方法最开头加一行print(f"DEBUG: line_name={line_name}, date={date}"),看看Agent实际传入的值是什么。很多时候你会发现,它传入的东西跟你想象的根本不是一回事。

        说白了就是一句话:不要相信Agent,要相信防御性代码。

系列导航


本文问题源自智联工坊实战:制造知识库工具调用Agent从零搭建(OEE+手册+排班)-CSDN博客 完整源码及深度教程见该文详细内容。

💡 建议收藏:下次遇到类似的Field required报错,可以快速对照本文排查。

互动与交流

        你在使用LangChain Agent时,有没有遇到过它“自作聪明”帮你做了多余操作的情况?欢迎在评论区吐槽,咱们互相安慰一下——也让我知道多少人被Agent坑过的人😀😀😀

关于作者

        制造业数据与AI践行者老蒋,23年IT老兵。聚焦制造业数据架构与AI融合落地。全流程实战,全源码开源。

标签#排坑笔记 #LangChain #Agent #踩坑实录

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐