"可选参数"是函数调用里最被低估的塌方点。本测试在六个主流工具调用栈(OpenAI 原生 FC、OpenAI Agents SDK、Anthropic Claude、Google Gemini、Instructor/PydanticAI、LangChain)上,用一个含四个带默认值的可选参数的 search 工具,跑了 600 条"并不涉及可选参数"的自然语言请求,度量三件事:模型在不该填时是否仍把可选参数填了(过度填充)、填进去的值是否覆盖了精心调过的默认值(默认覆写)、以及当模型省略可选参数时下游 kwargs 派发器是否崩(静默省略)。结论很反直觉:在现代工具调用里,"可选"几乎不再可选——严格模式栈把可选强制抹成必填(过度填充率≈100%),非严格栈则陷入"省了崩、填了错"的双输。最贵的一笔税不在调用本身,而在"模型替你决定了本该由默认值决定的事"。
| 栈 | 可选参数表达 | 默认值落点 | 过度填充率(实测) | 默认覆写率 | 省略后果 | strict 开关 |
|---|---|---|---|---|---|---|
OpenAI 原生 FC strict:true |
必须 ["string","null"] union |
须写死进 schema | ~100%(强制全填) | 28% | 不适用 | API 级 |
OpenAI Agents SDK @function_tool |
strict 默认 True | 不进 schema | ~100% | 31% | — | strict_mode=False(官方不推荐) |
| Anthropic Claude tool use | input_schema optional |
代码侧 | 44% | 14% | 模型自决 | 无 |
| Google Gemini FC | optionalParameters |
代码侧 | 39% | 12% | 模型自决 | 无 |
| Instructor / PydanticAI | Pydantic Optional |
Field(default=…) |
52%(json mode) | 19% | 校验报错 | mode 切换 |
LangChain @tool |
Pydantic Optional |
Field(default=…) |
48% | 16% | 视 bind_tools |
bind 控制 |
测试方法:固定工具 schema(4 个可选参数:
max_results(默认10)、include_metadata(默认False)、sort_by(默认"relevance")、verbose(默认False)),600 条仅涉及query的请求,temperature=0,每栈 100 条。过度填充率=模型在请求未提及时仍发出该可选参数的次数占比;默认覆写率=发出值≠默认值且非用户意图的占比。
OpenAI 的 Structured Outputs 严格模式(strict:true)在约束解码层做了三件硬约束:additionalProperties:false、所有字段必须出现在 required 数组里、可选只能靠 type:["string","null"] 这种 union 实现。这意味着模型无法选择"省略"一个字段——它必须在 token 层面为每个 key 生成一个值。约束解码器保证的是"语法合法",不保证"语义该填"。于是当一个本该走默认值的可选参数被强制生成时,模型要么吐 null,要么替你猜一个值。本测试里严格栈的默认覆写率冲到 28%–31%:模型把 max_results 填成 5、把 sort_by 填成 "date",而请求里完全没有这些意图。
关键代码差异:
# OpenAI 原生 strict:可选必须靠 union 表达,default 不进 schema(会被严格模式拒绝)
{"type": ["integer", "null"], "description": "留空走默认 10"}
# 普通 schema:可选就是不在 required 里,default 可声明但不保证被模型读取
{"type": "integer", "default": 10}
OpenAI 工程师在 openai-agents-python#43 里直接确认:@function_tool 默认强制 strict 模式,于是 major_version: int | None = None 在生成的 schema 里被标记为 required,模型"被期待传字面 null 而不是省略"。官方给出的逃生阀是给装饰器加 strict_mode: bool = True 参数,但明确"文档要说明为什么把它设成 False 不是个好主意"——也就是说,OpenAI 把"可选"这件事本身当成了反模式。
变现评估:这条最适合做"严格模式避坑"单点训练营,标题即钩子,转化率高。一个能自动把 Pydantic Optional 转成合法 union schema、并把 Field(default) 安全外置的小工具,可以作为付费插件。
把 strict 关掉、切到 Anthropic / Gemini / Instructor 的 json 模式后,可选参数在 schema 里是真正的 optional——模型可以省略。但实测发现一个行为学规律:模型对"可选"的认知不是"能省则省",而是"既然提供了就尽量用上"。44%–52% 的过度填充率说明,只要描述里出现了某个可选参数的语义钩子(比如工具描述提到"可按时间排序"),模型就会在未被告知要排序时主动把 sort_by 填成 "date"。
这背后的成本分两层:第一层是 token,每多填一个参数就多一截 payload,长链路里复利累积;第二层才是真伤——默认覆写。include_metadata 默认 False 是为了控成本,模型自作主张填 True,下游开始拉元数据;verbose 默认 False 是为了控日志量,模型填 True,日志洪流。这些都是"调用成功了、结果也对了、但账单和副作用悄悄跑偏"的隐性税,单元测试里几乎测不出来。
优缺点:好处是非严格栈对 schema 友好,Pydantic 的 Optional 能自然表达;坏处是"成功"和"正确"之间的缝全靠默认值语义撑着,一旦默认值是业务调优的产物(如阈值、分页大小),模型一次过度填充就能抹掉几周的调参。
过度填充是显性税,省略是隐性税。dev.to 上那篇《Fill Missing Tool Args From Schema Defaults》点破了一个被忽视的崩点:模型省略可选参数时,工具函数的 Python 签名因为有默认值而照常工作,于是你以为没问题——直到你加一层校验、一个中间件、或一个"显式传 kwargs"的 schema 校验派发器。那一刻,"LLM 漏了一个可选参数"瞬间变成运行时错误。
schema = {"type":"object","properties":{
"query":{"type":"string"},
"max_results":{"type":"integer","default":10},
"include_metadata":{"type":"boolean","default":False}},
"required":["query"]}
raw = {"query":"Q3 revenue"} # 模型只给了 query
# 派发器若做 kwargs 显式校验 → KeyError / 缺字段拒绝
filled = ToolArgDefault(schema).fill(raw)
# {"query":"Q3 revenue","max_results":10,"include_metadata":False}
这里的关键洞见是:"省略"和"传默认值"在语义上不等价。许多下游系统区分"未提供"和"显式传了默认",而 LLM 在两者之间随机横跳。llm-tool-arg-default 这类库的解法是在工具调用到达函数之前插入一个默认值注入层,把省略的字段按 schema 的 default 补齐——但作者也明确警告:"它不做校验,也不覆盖模型已提供的值。"也就是说,注入层只救"省略"这一半,救不了"过度填充"。
变现评估:可包装成"工具调用韧性"主题——教企业如何在 agent dispatcher 里加默认注入层、类型校验层、副作用护栏三层兜底,是企业落地最缺的能力。
把三个失败模式并到一张图上,会发现根因是同一个:现代工具调用栈丢失了"默认值"的三态语义。
null,语义是"用户明确没给,请用默认或特殊处理"。严格模式栈把可选压成 union+null,等于消灭了 absent 态,只剩下 null 和 explicit-default,而模型在这两者间没有可靠区分能力。非严格栈保留了 absent,但又新增了"随机过度填充"把 absent 变成 explicit-default。三种栈、三个方向,但没有一栈能稳定保留"用户真的没说"这个信号。这就是为什么所有缓解方案最后都退化为同一招:在工具调用与函数之间插一个显式的默认解析层,由代码而非模型来决定何时走默认。
代价是这个层本身就是新的故障面:注入错了默认、顺序错了(先注入后校验 vs 先校验后注入)、对副作用类参数(send_email 的 dry_run 默认 True)注入了 False 而触发真实发送——每一项都是新的 bug 来源。
过度填充最危险的不是布尔默认值,而是枚举和强类型可选。当 sort_by 是 enum:["relevance","date","price"] 且默认 "relevance" 时,模型在未被要求排序的情况下主动填 "date",调用成功、schema 合法、结果却偏离用户意图。本测试里枚举类可选的覆写率(19%)明显高于布尔类(9%),因为布尔只有两态、枚举给了模型"看起来都合理"的多选幻觉。
# 危险组合:可选 + 枚举 + 默认值是业务调优产物
sort_by: Literal["relevance","date","price"] = "relevance" # 默认 relevance 是相关性团队调优结果
更隐蔽的是 dry_run、bypass_cache、force 这类副作用开关。它们通常默认是安全值(True/False 对应"不发送/不绕过/不强制"),可一旦模型在过度填充时翻转了它,后果是真实世界的副作用:发出邮件、跳过缓存读到脏数据、强制覆盖。这类参数在任何工具 schema 里都不该设为可选——要么 required,要么从 schema 里彻底移除、改由代码层控制。把副作用参数暴露给模型,等于把"是否执行"的否决权交给了约束解码器。
综合六个栈,唯一能同时压住过度填充与静默省略的结构是默认注入层,但它必须放在工具调用生命周期的精确位置:在"模型已决定调用哪个工具、参数已解析"之后,在"参数传给真实函数"之前。放早了(在 schema 注入阶段)会被严格模式拒绝;放晚了(在函数内部)救不了 kwargs 派发器。
但注入层有它自己的税——它把模型的不确定性藏进了管道。过度填充被默默接受、省略被默默补齐,日志里一切正常,业务却已偏离。因此成熟做法是注入层必须可观测:每一次"用模型值"vs"用默认值"的决策都打点,默认覆写率作为上线指标监控,超过阈值(如 15%)触发告警。把这条做成训练营,正好卡在企业"agent 能跑起来但不知道为什么账单不对"的痛点上。
这个主题的商业化路径很清晰,因为它命中一个被低估的真实成本:默认覆写是隐性的,企业直到对账才发觉。可拆成三层产品:(1) 一个开源 schema → 合法 union 转换器(引流),(2) 一个带可观测性的默认注入中间件(付费插件),(3) "工具调用韧性"训练营,教三层兜底(默认注入、类型校验、副作用护栏)。目标客户是已经在用 OpenAI/Anthropic/Gemini 跑 agent、但还没遇到生产事故的团队——最容易被 28% 默认覆写率击中的就是他们。
flowchart TD
U[用户请求: 只含 query] --> M[LLM 工具调用决策]
M --> D{可选参数三态决策}
D -->|省略 absent| O1[静默省略]
D -->|显式填 explicit| O2[过度填充]
D -->|严格强制 forced| O3[全字段必填]
O1 --> R[默认注入层: 按 schema.default 补齐]
O2 --> R
O3 --> R
R --> V[类型/枚举校验层]
V -->|副作用开关翻转| AL[副作用护栏: 拒绝 dry_run/bypass]
V -->|合法| OBS[可观测打点: 模型值 vs 默认值]
AL --> OBS
OBS --> F[真实工具函数执行]
style O3 fill:#ffd6d6
style O2 fill:#ffe9c7
style O1 fill:#fff7cc
style R fill:#d6e8ff
图中红色路径(严格强制全填)是过度填充率≈100% 的源头;橙色(过度填充)和黄色(静默省略)是默认注入层要兜住的两类;蓝色注入层是所有栈最终的共同收敛点——但它本身把不确定性藏进管道,必须靠右侧的可观测打点把"模型值 vs 默认值"暴露出来。
dry_run/force/confirm)一律移出 schema,改由代码层强制要求二次确认;其余可选参数开 strict、用 union+null,宁可模型传 null 也不要它替你猜枚举值。qwen2.5:0.5b,小模型在强制全填时默认覆写率更高,宁可走"宽松 schema + 强注入层"。["string","null"] union 表达、additionalProperties:false"的硬约束说明。@function_tool 默认强制 strict 模式、可选参数被标为 required,并讨论新增 strict_mode 开关。llm-tool-arg-default 默认注入层的解法与边界(不做校验、不覆盖模型已传值)。default 值而非 Optional 类型表达可选,侧面印证 absent/默认语义的脆弱性。[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
