GPT-5.6 Sol 为什么无法在 Chat Completions 中同时使用函数工具和 reasoning_effort?

作者:袖梨 2026-09-18

GPT-5.6 Sol 并不是不支持函数调用,也不是不支持 Chat Completions。问题出在一个更窄的组合约束:当请求发往 /v1/chat/completions,同时携带函数类型的 tools,又把 reasoning_effort 设为会启用推理的档位时,服务端会拒绝这个组合。对现有应用来说,处理方式只有两条主线:继续使用 Chat Completions 时将推理强度设为 none,或者迁移到 Responses API,在保留推理能力的同时完成工具调用。

这个现象容易被误读,是因为模型能力表会同时列出 Chat Completions、Function calling 和 Reasoning。三个项目各自受支持,不代表它们在每个端点、每种参数组合下都能叠加。排查时应把“模型有没有某项能力”与“当前端点能否表达并执行这组能力”分开看。

错误真正表示什么

当请求包含 tools 和非 nonereasoning_effort 时,失败发生在请求校验阶段,而不是模型思考后决定不调用工具。常见表现是接口直接返回 4xx 错误,响应中没有可继续处理的助手消息,也不会产生有效的工具调用参数。因此,修改提示词、增加“必须调用工具”的系统指令、调整 tool_choice 或重复重试都不能解决问题。

这里的函数工具是开发者在请求中声明的 type: function 工具。模型先返回函数名和结构化参数,应用执行函数,再把执行结果送回模型。reasoning_effort 则控制推理模型投入的计算强度。两者分别有效,但在 Chat Completions 上启用推理后再组合函数工具,会碰到该端点的组合限制。

不能仅凭错误信息进一步断言服务端的内部实现原因。合理的工程判断是:Chat Completions 的消息和工具回合协议较早,而 Responses API 面向推理状态、工具输出和连续响应项目提供了更完整的表达方式。但这只是理解迁移方向的接口层解释,不应写成模型内部架构的确定事实。对调用方而言,服务端返回的显式约束才是可依赖的边界。

先用最小请求确认问题

排查时不要从包含流式输出、多个工具、代理框架和中转服务的完整应用开始。先直接使用官方 SDK 构造一个只有单个函数工具的最小请求。下面的 Python 示例会在 Chat Completions 中同时传入工具和推理强度,用来复现组合问题;它不是推荐的生产配置。

from openai import OpenAI

client = OpenAI()

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "查询指定城市的天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string"}
                },
                "required": ["city"],
                "additionalProperties": False
            },
            "strict": True
        }
    }
]

completion = client.chat.completions.create(
    model="gpt-5.6-sol",
    messages=[
        {"role": "user", "content": "查询杭州天气"}
    ],
    tools=tools,
    reasoning_effort="medium"
)

如果这个最小请求仍被拒绝,再把 reasoning_effort 改为 none,其余字段保持不变。若请求随即能够返回工具调用,就已经定位到端点与参数组合,而不是函数 JSON Schema、提示词或业务工具实现。调试时一次只改一个变量,结论会比在完整代理链路中反复试错可靠得多。

方案一:保留 Chat Completions,关闭推理

如果应用已有稳定的 messages 历史管理、工具消息回填和流式解析逻辑,而且任务本身不依赖高强度推理,最小改动方案是明确设置 reasoning_effort="none"。不要仅仅删除这个字段,因为 GPT-5.6 的默认推理强度可能不是 none;显式设置才能避免默认值让同一个组合再次触发错误。

completion = client.chat.completions.create(
    model="gpt-5.6-sol",
    messages=[
        {"role": "user", "content": "查询杭州天气"}
    ],
    tools=tools,
    reasoning_effort="none",
    tool_choice="auto"
)

message = completion.choices[0].message
for call in message.tool_calls or []:
    print(call.id, call.function.name, call.function.arguments)

这个方案保留函数调用,但牺牲可配置推理。它适合查库存、查天气、读取账户状态、调用确定性业务接口等任务,因为模型的主要职责是识别意图并生成符合 Schema 的参数。对于复杂规划、跨工具分析或需要在多个证据之间权衡的工作,把推理强度关掉可能明显降低效果,此时应选择迁移。

方案二:迁移到 Responses API

需要同时使用推理与函数工具时,Responses API 是更合适的接口。请求主体从 messages 改为 input,推理配置改为 reasoning={"effort": "medium"},函数工具的定义也采用 Responses 的字段结构。迁移的重点不只是换一个方法名,还包括识别输出项目、执行函数以及用调用标识回传结果。

from openai import OpenAI
import json

client = OpenAI()

response = client.responses.create(
    model="gpt-5.6-sol",
    input="查询杭州天气",
    reasoning={"effort": "medium"},
    tools=[
        {
            "type": "function",
            "name": "get_weather",
            "description": "查询指定城市的天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string"}
                },
                "required": ["city"],
                "additionalProperties": False
            },
            "strict": True
        }
    ]
)

tool_outputs = []
for item in response.output:
    if item.type != "function_call":
        continue
    arguments = json.loads(item.arguments)
    result = {"city": arguments["city"], "temperature": 23}
    tool_outputs.append(
        {
            "type": "function_call_output",
            "call_id": item.call_id,
            "output": json.dumps(result, ensure_ascii=False)
        }
    )

if tool_outputs:
    response = client.responses.create(
        model="gpt-5.6-sol",
        previous_response_id=response.id,
        input=tool_outputs,
        reasoning={"effort": "medium"}
    )
    print(response.output_text)

示例中的天气结果是演示数据,生产代码必须真正调用业务函数,并对参数和返回值做校验。使用 previous_response_id 可以把工具结果关联到上一轮响应;如果系统选择自行保存全部上下文,也必须完整保留工具调用标识,不能只把函数结果拼成普通用户消息。

迁移时最容易遗漏的差异

输出不再只有 choices

Chat Completions 通常从 choices[0].message 读取文本和工具调用。Responses 返回的是一组有类型的输出项目,文本、函数调用以及其他项目可能同时存在。代码不能假设第一个项目一定是文本,也不能只读取便捷的 output_text 后忽略函数调用。稳妥做法是按 item.type 分派处理。

工具回传要保留 call_id

一次响应可能请求多个工具。应用执行后,必须将每个结果与原调用的 call_id 对应。若并发执行时丢失顺序或错误复用标识,模型会收到无法匹配的结果。可以在内部建立以调用标识为键的任务表,并在超时、失败和取消时也产生明确的结构化结果。

流式事件需要重新解析

旧代码若依赖 delta.contentdelta.tool_calls,不能原样套用到 Responses。应根据 Responses 的事件类型分别累计文本增量、函数参数增量和完成事件,并在参数完整后再反序列化。不要在尚未结束的 JSON 参数片段上调用解析器。

不要混用两套工具结构

Chat Completions 的函数定义通常嵌套在 function 字段内,而 Responses 的函数工具字段布局不同。若项目有自己的统一工具描述,应分别实现两个适配器,并为生成的请求做快照测试。直接把一套请求体转发到另一个端点,容易得到字段无效或工具未识别的错误。

如何选择合适的修复路径

选择标准不是“哪个接口更新”,而是业务是否需要推理。若函数选择简单、现有 Chat Completions 集成庞大且近期不准备改造,可以固定 reasoning_effort="none",并为这个约束增加自动化测试。若工具链涉及多步规划、复杂判断或未来还要接入更多模型工具,则应迁移到 Responses,以免继续在旧端点的组合边界上增加兼容逻辑。

不建议通过捕获错误后自动关闭推理并静默重试。这样虽然可能恢复请求,却会在用户不知情时改变质量和成本特征。更可控的做法是启动时校验配置:发现 Chat Completions、函数工具与非 none 推理同时启用,就直接给出配置错误;只有产品明确允许降级时,才记录告警并执行预先定义的回退策略。

验证修复是否完整

至少建立一个小型兼容性矩阵,覆盖端点、推理强度、是否携带工具以及是否流式四个维度。测试不需要调用真实天气或支付服务,可以使用返回固定值的本地函数。关键断言包括:请求没有在参数校验阶段失败;函数名和参数可以解析;工具结果使用正确调用标识回传;最终文本能够生成;异常工具结果不会被误当成成功。

cases = [
    ("chat", "none", True, True),
    ("chat", "medium", True, False),
    ("responses", "medium", True, True),
    ("responses", "medium", False, True),
]

# 四元组最后一项表示该配置是否应被应用接受。
# 对预期不支持的组合,应在本地配置校验阶段失败。

还要记录实际使用的模型标识、端点、推理强度和工具数量,但不要把密钥、完整用户输入或敏感工具参数写入日志。如果调用经过兼容代理或第三方网关,应先用官方端点复现最小请求,再判断限制来自上游接口还是代理的参数映射。仅凭“兼容 OpenAI 协议”的声明,不能推定它完整支持每个新模型和所有参数组合。

常见误区

第一,模型页面显示 Function calling supported,不等于所有推理档位都能在每个端点中与它组合。第二,将 reasoning_effort 从请求中删除不一定等同于关闭推理,默认值仍可能启用推理。第三,错误发生在请求层时,指数退避没有意义,只会重复发送同一无效配置。第四,换成旧模型可能暂时绕开限制,却会掩盖接口选择问题,并给后续升级留下同样的故障点。

因此,这个问题的准确结论是:GPT-5.6 Sol 的函数调用能力没有消失,受限的是 Chat Completions 上函数工具与启用状态的 reasoning_effort 组合。短期兼容方案是显式使用 none,长期且需要推理的方案是迁移到 Responses API。把限制固化为配置校验和兼容性测试,才能避免下一次模型切换时把同类错误误判为工具服务故障。

相关文章

精彩推荐