给Agent函数返回值做schema校验防脏数据
智能体调外部函数/工具,最容易被忽略的一环是:返回值你信了它就脏了。接口偶尔少个字段、类型变了、返回个 null,模型拿着脏数据接着往下推,错误一路传导到最终回答。给函数返回值套一层 schema 校验,是我后来必加的护栏。用 Q&A 形式把这事讲清楚。
Q:模型不是挺聪明吗,脏一点的数据它自己能兜住吧?
A:不能指望。我搭的订单查询助手,工具返回里有个 amount 字段,正常是数字。某次上游接口异常,返回的是字符串 "null"(注意,是字符串而不是真 null)。模型拿到后,在回答里算总价时把它当成了某个值,给用户报了个离谱的金额。模型不会替你校验数据合法性,它默认你喂的都是对的。脏数据进去,错误答案出来。
Q:那 schema 校验具体校什么?
A:我至少校三样:
-
必填字段在不在。约定要返回
order_id、amount、status,少任何一个直接判不合格。 -
类型对不对。
amount必须是 number,来个字符串就拦下。 -
取值范围/枚举合不合法。
status只能是paid/unpaid/refunded里的一个,返回个"成功"这种野值就拦。
我用一个 JSON Schema 描述期望结构,工具一返回就先过校验,过了才让模型用:
{
"type": "object",
"required": ["order_id", "amount", "status"],
"properties": {
"order_id": { "type": "string" },
"amount": { "type": "number" },
"status": { "enum": ["paid", "unpaid", "refunded"] }
}
}
Q:校验没过怎么办,直接报错给用户?
A:分情况,别一刀切报错。我的处理是:
-
字段缺失/类型错 → 先重试一次工具调用,很多时候是上游瞬时抽风,重试就好了。
-
重试还不过 → 不把脏数据给模型,而是给模型一个明确的"这次没拿到有效数据"的信号,让它礼貌地告诉用户"订单信息暂时查不到",而不是硬编。
-
枚举越界这种 → 我会做一层兜底映射,比如上游偶尔返回中文"已支付",我映射成
paid再放行,而不是直接拒。
最忌讳的是校验不过就把原始脏数据透传给模型——那校验白做了。
Q:实操有什么坑?
A:几个真的。
一是别把 schema 写太死。我一开始把每个字段都设成必填,结果上游一个可选字段偶尔不返回,校验天天报红,其实那字段压根不影响回答。后来分清楚"核心字段必填、辅助字段可选",误拦才降下来。
二是校验位置要在"工具返回后、喂给模型前",这个夹缝里。放早了工具还没返回,放晚了脏数据已经进模型了。
三是个我交过学费的细节:嵌套对象要递归校验。我最初只校了顶层字段,结果 items 数组里某个元素的价格是脏的,顶层看着挺好,模型用到明细时还是出错了。该往里钻就得往里钻。
Q:值得为这个花精力吗?
A:值。说个取舍——加了校验,确实会偶尔出现"上游其实数据没问题,只是格式跟我 schema 约定有点出入,被误拦了"的情况,需要回头放宽规则,有维护成本。但比起脏数据悄无声息混进回答、最后用户拿着错误金额来找你,这点维护成本太划算了。脏数据的可怕在于它不报错、只是默默错,schema 校验就是把"默默错"变成"明确拦"。
这套工具返回值校验,我是在一个零代码、还能把成品发布成 API 的平台上配的——工具节点后面挂一个 schema 校验节点,不过就走重试或兜底分支,逻辑拖出来连一下就成,不用自己写一堆 if-else 防御代码。
模型推理走的讯飞星辰 MaaS,现成 API 调,没自己搭算力。
更多推荐




所有评论(0)