DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

Mustache 参数报错

Mustache 聊天模板能渲染 user 字典,as_tool 却报 string_type。显式声明嵌套参数,在工具校验后转回普通字典,验收真实姓名没有变空。

ChatPromptTemplate 使用 {{user.name}}、{{user.company}},直接传入 user 字典能正常渲染。转换成 as_tool() 后,同一份输入却报 Input should be a valid string,工具参数也把 user 描述成 string。

这条情况有 langchain-core 1.4.8 与后续源码反馈,已核对的正式 1.6.10 仍有两层需要分别处理:聊天提示词的嵌套输入 schema,以及工具校验后传给 Mustache 的对象表示。

改对 schema 还不够

ChatPromptTemplate 使用通用输入 schema,未明确指定类型的顶层变量默认是 str。Mustache 模板需要的 user 本来是带 name、company 的对象,渲染能力与声明的工具参数因而不同。

普通 PromptTemplate 已有 Mustache 专用 schema,但只把聊天模板换成它,或只给工具补一个嵌套 Pydantic schema,并不能保证渲染正确。工具校验后,嵌套 user 可能成为 Pydantic 模型实例;Mustache 的点路径只遍历映射、列表与元组,不遍历任意 Python 对象。没有再转换时,姓名和公司可能静默变成空字符串。

因此需要同时核对“模型看见的输入 schema”和“渲染器真正收到的输入”,不能只以 ValidationError 消失为准。

显式声明,再转成字典

保留嵌套 user 契约时,可以用明确的工具 schema,并在提示词前将已校验的 User 转成普通字典。下面定义一个工具工厂,不创建模型实例,也不调用模型或工具:

from pydantic import BaseModel
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableLambda

class User(BaseModel):
    name: str
    company: str

class GreetingArgs(BaseModel):
    user: User

def template_input(values):
    user = values["user"]
    if isinstance(user, User):
        user = user.model_dump()
    return {"user": user}

def make_greeting_tool(model):
    prompt = ChatPromptTemplate.from_messages(
        [("human", "Write a greeting for {{user.name}} from {{user.company}}.")],
        template_format="mustache",
    )
    chain = RunnableLambda(template_input) | prompt | model
    return chain.as_tool(
        args_schema=GreetingArgs,
        name="greet",
        description="Greet a user using their name and company.",
    )

这是仅有 user 两个字符串字段的示例。真实工具应沿用原来的必填、可选、别名、额外字段和类型验证,不用示例 schema 覆盖业务契约。输入适配器也应保留模板实际需要的其他字段、消息历史和 partial 设置。

model_dump() 只在这里处理已知 User,不把任意传入对象的属性暴露给模板。不要修改 Mustache 的安全边界,让它随意遍历 Python 对象;也不要把 user 序列化成 JSON 字符串,那仍不能供 user.name 查找。

另一种办法是经过调用方协商,把接口改成两个明确的平面字符串字段,并同步模板、工具签名和已有调用方。这会改变公开输入契约,应按自己的接口流程处理,不能只改模板一端。

验收实际渲染出的内容

检查工具 schema 中 user 是对象,name、company 的类型和必填要求准确,再用获准的无副作用模型替身核对经过工具入口后,提示词仍含真实姓名和公司。缺字段、字段类型错误也应按原契约拒绝,不能悄悄变成空白问候。

直接 prompt.invoke 成功,只证明字典渲染这一段正常,不能替代工具入口验收。反过来,工具接受对象也只说明校验通过;最终渲染为空时,应先检查嵌套模型转换,而不是让模型猜测缺失字段。