OpenAI Responses API 工具调用工具参数校验失败时怎样保留可诊断信息为什么结果为空或不符合预期
OpenAI Responses API 的工具调用出现“参数校验失败”时,最容易误判的是把空的 output_text 当成接口没有返回。实际上,Responses 可能返回的是 function_call 项而不是文本消息;如果工具 schema 在请求阶段就不符合严格模式要求,则连可处理的工具调用都不会产生。排查时要先判断失败层级,再保留原始响应中的调用标识和参数字符串。
官方地址:https://developers.openai.com/api/docs/guides/function-calling
实用做法是:先把整个响应和每个function_call的call_id、工具名、原始arguments写入结构化日志,再解析 JSON 和执行业务校验。校验失败也要返回一个带错误信息的function_call_output,不要直接丢弃这次调用。
先判断参数错误发生在哪一层
同一句“参数校验失败”可能指三种情况。第一种是请求中的函数 schema 本身不满足 strict 要求,例如对象没有关闭 additionalProperties,或属性没有全部列入 required;这类问题通常在请求阶段被拒绝。第二种是请求成功,模型返回了 function_call,但应用把 arguments 解析成业务对象时发现类型、范围或必填条件不满足。第三种是参数合法,但工具执行失败,例如库存服务超时。
三层错误的记录字段不能混在一起。请求阶段保存 HTTP 错误和 schema 摘要;模型返回阶段保存 response.id、call_id、name 与原始参数;执行阶段保存工具名、业务错误码和是否已经产生副作用。这样才能回答“模型没给参数”“参数不符合业务规则”还是“工具已经执行但依赖失败”。
严格模式下先把 schema 写完整
官方函数调用指南建议启用 strict。严格模式要求对象的 additionalProperties 为 false,并且 properties 中的字段都出现在 required。如果某个字段在业务上可选,可以把它的类型写成包含 null,但仍然保留在 required 数组里。下面的工具只表达“查询订单状态”这一件事,避免把多个业务分支塞进一个模糊 schema。
from openai import OpenAI
client = OpenAI()
tools = [{
"type": "function",
"name": "lookup_order",
"description": "查询订单当前状态,不执行修改操作",
"strict": True,
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "业务订单号"
},
"channel": {
"type": ["string", "null"],
"enum": ["web", "app", None],
"description": "订单来源;未知时传 null"
}
},
"required": ["order_id", "channel"],
"additionalProperties": False
}
}]
# 保留请求与工具定义的版本,便于把 schema 错误和业务错误分开。
response = client.responses.create(
model="gpt-6-astra",
input="查询订单 A-100 的状态",
tools=tools,
)
这里的 channel 虽然可以是空值,但它仍是必填属性。不要为了“可选”而从 required 删除它,否则严格模式下模型和应用的契约会变得不一致。模型名称、账号权限等部署参数应按你的当前项目配置填写,示例重点是工具 schema 的结构。
不要只读 output_text,先保存 function_call
Responses 的输出数组可能同时包含推理、消息和函数调用项。工具调用项的 arguments 是 JSON 编码的字符串,不能把它当成已经校验过的 Python 字典。应用侧应先保存原文,再解析;解析失败时仍然要留下原始字符串,方便定位模型输出、序列化边界或 SDK 适配问题。
import json
import logging
logger = logging.getLogger(__name__)
def collect_tool_calls(response):
calls = []
for item in response.output:
# 只有 function_call 才进入工具参数处理,文本项不能代替它。
if item.type != "function_call":
continue
record = {
"response_id": response.id,
"call_id": item.call_id,
"name": item.name,
"arguments_raw": item.arguments,
}
try:
# 先解析 JSON,再交给业务层做类型和权限校验。
record["arguments"] = json.loads(item.arguments)
record["parse_error"] = None
except json.JSONDecodeError as exc:
# 不覆盖原文,错误位置对复盘不应丢失。
record["arguments"] = None
record["parse_error"] = {
"type": type(exc).__name__,
"message": str(exc),
}
logger.info("responses_tool_call=%s", record)
calls.append(record)
return calls
calls = collect_tool_calls(response)
if not calls:
# output_text 为空时,先记录输出类型,不要直接下结论说“没有结果”。
logger.warning("no_function_call response_id=%s output_types=%s",
response.id, [item.type for item in response.output])

如果这段日志显示输出类型是 function_call,而不是 message,那么 output_text 为空是可以解释的。真正要处理的是调用项中的 call_id 和参数,而不是反复读取文本字段。
校验失败时把诊断信息送回工具循环
解析成功不等于业务参数可用。以订单查询为例,order_id 为空、渠道值不在允许集合或当前用户无权查询,都应该生成可追踪的结构化错误。错误返回给模型时使用同一个 call_id,同时把日志中的敏感字段做脱敏;不要把数据库连接串、访问令牌或完整个人信息塞进工具输出。
def validate_order_args(args):
# 业务校验和 JSON Schema 校验分层,便于定位真正的失败原因。
if not isinstance(args, dict):
return "arguments 必须是对象"
if not isinstance(args.get("order_id"), str) or not args["order_id"].strip():
return "order_id 不能为空"
if args.get("channel") not in {"web", "app", None}:
return "channel 只能是 web、app 或 null"
return None
input_items = list(response.output)
for call in collect_tool_calls(response):
error = call["parse_error"] or validate_order_args(call["arguments"])
if error:
# 用原 call_id 绑定失败结果,避免模型继续等待一个不存在的工具结果。
input_items.append({
"type": "function_call_output",
"call_id": call["call_id"],
"output": json.dumps({
"ok": False,
"error_code": "INVALID_TOOL_ARGUMENTS",
"message": error,
}, ensure_ascii=False),
})
continue
# 通过校验后才调用有副作用的服务,并把结果序列化为字符串。
result = lookup_order(call["arguments"]["order_id"], call["arguments"]["channel"])
input_items.append({
"type": "function_call_output",
"call_id": call["call_id"],
"output": json.dumps(result, ensure_ascii=False),
})
follow_up = client.responses.create(
model="gpt-6-astra",
input=input_items,
tools=tools,
)
function_call_output 的 output 通常使用字符串,内容可以是 JSON、错误码或普通文本。将错误写成稳定的 error_code 和简短 message,比把 Python 异常堆栈原样暴露给模型更容易控制。若工具已经产生副作用,则不要因为后续模型回复异常而盲目重试,应依靠 call_id 或业务幂等键判断是否处理过。

为什么结果为空:一份最小复查清单
遇到“结果为空或不符合预期”时,按以下顺序复查,通常比先改提示词更快:
- 先看 HTTP 请求是否成功,以及工具 schema 是否因 strict 约束被拒绝;若请求失败,检查
required和additionalProperties。 - 再记录
response.id、每个输出项的type、call_id、name和arguments_raw;不要只记录output_text。 - 解析参数后分别记录 JSON 解析错误和业务校验错误;两者修复方向不同。
- 把失败结果绑定回原
call_id,再检查下一次 Responses 请求是否携带了该结果。 - 如果工具有写操作,记录幂等键、执行状态和外部依赖错误,避免把“模型又调用了一次”当成安全重试。
这套方式的边界也很明确:它只能改善诊断和工具循环的可恢复性,不能替代权限检查、业务幂等、敏感信息脱敏或服务端超时治理。先让 schema 契约稳定,再让原始调用可见,最后把业务错误变成模型能够理解的工具结果,空的文本字段就不再是排查的唯一线索。
相关问题
为什么 strict 模式下请求直接失败?通常是对象 schema 没有设置 additionalProperties: false,或属性没有全部列入 required;先修复契约,再看模型输出。
为什么 function_call 有参数但 output_text 为空?因为响应当前项是工具调用而非文本消息。读取输出项的类型,并用 call_id 提交工具结果。
工具返回错误后还要不要重试?只有在错误可恢复、没有重复副作用且幂等条件明确时才重试;否则保留错误结果并交给上层业务处理。
Anthropic Claude tool use怎样把tool_use和tool_result配成一轮可继续的对话
- 上一篇
- Anthropic Claude tool use怎样把tool_use和tool_result配成一轮可继续的对话
- 下一篇
- vLLM OpenAI 兼容服务怎样用 JSON Schema 约束结构化输出
-
- 科技周边 · 人工智能 | 27分钟前 | 人工智能 · 结构化输出 vLLM JSON Schema OpenAI兼容服务 structured_outputs
- vLLM OpenAI 兼容服务怎样用 JSON Schema 约束结构化输出
- 240浏览 收藏
-
- 科技周边 · 人工智能 | 31分钟前 |
- Anthropic Claude tool use怎样把tool_use和tool_result配成一轮可继续的对话
- 158浏览 收藏
-
- 科技周边 · 人工智能 | 33分钟前 | python · openai · 参数校验 JSON Schema 工具调用 OpenAI Responses API
- OpenAI Responses API 工具调用工具参数校验失败时怎样保留可诊断信息怎样完成一个可复用的最小示例
- 106浏览 收藏
-
- 科技周边 · 人工智能 | 36分钟前 |
- Hugging Face Datasets streaming怎样用shuffle的buffer_size打散大语料并保持每轮可复现
- 113浏览 收藏
-
- 科技周边 · 人工智能 | 42分钟前 |
- Hugging Face Datasets streaming大数据集怎样流式读取而不一次载入内存怎样完成一个可复用的最小示例
- 306浏览 收藏
-
- 科技周边 · 人工智能 | 44分钟前 |
- ONNX Runtime 量化怎样比较动态量化与静态量化的部署差异怎样在批处理代码中减少额外分配
- 139浏览 收藏
-
- 科技周边 · 人工智能 | 53分钟前 |
- ONNX Runtime 量化怎样比较动态量化与静态量化的部署差异为什么结果为空或不符合预期
- 242浏览 收藏
-
- 科技周边 · 人工智能 | 57分钟前 |
- ONNX Runtime 量化怎样比较动态量化与静态量化的部署差异怎样完成一个可复用的最小示例
- 374浏览 收藏
-
- 科技周边 · 人工智能 | 59分钟前 |
- 多模态模型评测怎样分别记录图像理解与文本生成指标怎样在批处理代码中减少额外分配
- 442浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 |
- 多模态模型评测怎样分别记录图像理解与文本生成指标怎样完成一个可复用的最小示例
- 289浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 965次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 966次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 1077次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 1057次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 888次使用
-
- 量化模型本地推理的显存估算方法
- 2026-10-17 501浏览
-
- 本地大模型反复输出同一句话怎么调整生成参数
- 2026-09-06 501浏览
-
- Python 调用大模型时如何用结构化输出校验 JSON:从解析失败到可重试
- 2026-08-29 501浏览
-
- AI写作工具免费版安装教程(含豆包Clawdbot)
- 2026-05-30 501浏览
-
- WPS AI能自动生成PPT吗?输入主题一键制作演示文稿
- 2026-05-27 501浏览

