提到 Responses API不少人的第一反应是这不就是官方把 Chat Completions 换了个名字吗其实差别非常明显。我最近把一个问答服务从旧的补全接口迁到 Responses API同样的业务量成本账单比原来低了不止一半而且不是通过任何灰色渠道完全是官方接口自己的定价机制和用法差异带来的。这篇文章就专门拆一拆这两件事Responses API 到底该怎么用以及怎么把它用得比“默认调用”便宜一半以上。Responses API 是官方在补全接口之后推出的新一代生成接口把普通对话、工具调用、知识检索、代码执行这些能力统一到了同一套协议里。对于做 Agent、RAG、自动化流程的开发者来说它算是目前接入成本和后期维护成本都比较低的选择。如果你正在写一个需要连续对话、调用外部工具或者做结构化输出的项目这篇文章可以直接当入门手册用。1. 为什么“Responses API”自带省钱潜质1.1 这一代接口本质上是在整合“补全工具状态”要理解省钱逻辑先得看懂这一代接口到底改了什么。旧的 Chat Completions 接口只解决一件事传入一串消息返回一条补全结果。工具调用要靠开发者手动拼消息、手动塞 function_call 结果连续对话要把整段历史反复重发业务一复杂代码里全是拼接逻辑。Responses API 直接把“会话状态”这个概念做进了接口里。你可以把多轮对话、工具返回结果、检索片段统一交给接口自己去维护上下文。这不是简单换皮而是把很多原本需要前端或后端自己负责的状态管理、并发控制、上下文压缩工作收编了。从省钱角度看这一点非常关键。因为它允许你只用一条 previous_response_id 就把整个历史带上省去了自己把历史消息全部序列化再塞进 input 的环节。而历史消息一旦由官方服务端管理输入 token 的重复发送量就能得到明显控制。很多项目成本高不是模型输出贵而是每轮请求都在重复发送大量不变的上下文这部分钱非常隐性。1.2 便宜一半的机制来自哪里很多人看到“比官方便宜一半以上”这几个字第一反应是去找第三方渠道或者拼车号。这里先表个态完全不需要也不建议。官方定价机制里本身就藏着两个稳定折扣源——缓存和批量接口。缓存是自动生效的。当你的请求前缀和之前请求的前缀一致时这部分输入 token 会按缓存价计费。不同模型的缓存折扣不一样老模型可能只有五折新的高性价比模型缓存价能低到原价的四分之一甚至更低。批量接口则是把一段时间内不急着要结果的任务打包提交官方给大约五折的价格。两个折扣叠加再加上模型档位的选择成本降到默认直连方式的一半以下是非常现实的。但折扣只是基础。真正决定账单大小的是你怎么设计请求结构。比如把固定系统提示词放在 input 最前面、把动态变化的内容放在后面缓存命中率就会明显提高。再比如有状态会话虽然方便但如果一个会话长期不清理后续每次请求的输入 token 会越滚越大反而比无状态更贵。这些用法层面的差异才是“同一套官方接口有人用得便宜、有人用得贵”的根本原因。2. 动手前先吃透四个核心概念2.1 输入项、响应与会话状态Responses API 里最基础的两个概念是 input 和 response。input 可以是纯文本字符串也可以是一个数组数组里的每个元素叫 item。item 的类型包括消息、函数调用、函数调用结果、检索结果等。response 是模型返回的结果块里面同样是一组输出 item。可以这么理解过去你发请求给服务员点菜每次都要把“我姓什么、坐在哪桌、口味偏好”重复说一遍。Responses API 则是你办了一张会员卡第一次把信息登记好之后直接报卡号就行。卡号就是 previous_response_id登记表就是官方服务端维护的会话状态。这套机制对写业务代码的影响很大。原来你需要自己设计一套消息历史结构、自己做 tool 循环的上下文拼接现在接口帮你存了一部分。但千万别以为有了它就可以无脑依赖服务端帮你存状态不代表不花钱这么大的历史每次参与计算都会产生输入 token。所以后面我会专门讲什么时候该用有状态什么时候该用无状态。2.2 有状态模式与无状态模式Responses API 支持两种调用姿势。第一种是无状态store 设为 False默认每次请求都在 input 里明确告诉模型所有需要的信息。第二种是有状态store 设为 True配合 previous_response_id让官方服务端把之前的会话内容自动拼到这次请求里。有状态模式对开发者非常友好尤其是做客服机器人、多轮问答时代码量能少一大截。但代价是上下文会随着轮次逐渐变长。一个 20 轮的长会话前面 19 轮的完整内容都可能被当作历史带进来。假设模型上下文窗口是 128K后面每轮几乎都在按 100K 以上的输入量计费。我的经验是有状态模式适合轮次少、上下文变化快的场景无状态模式适合那些上下文可以在本地被压缩、截断或摘要的业务。很多高成本账单问题就出在把有状态会话当成无限记忆来用导致越往后越贵。2.3 内置工具与函数调用Responses API 的第二大改进是 tools 参数。你可以直接在请求里声明要使用哪些工具比如网页搜索、文件搜索、代码解释器也可以是自定义的函数调用。模型会根据用户问题自动决定要不要调用工具以及怎么组织参数。内置工具的价值是省事。以前要实现联网问答你得自己抓网页、清洗正文、拼进上下文现在用 web_search 类型工具就能让模型自己完成检索与引用。文件搜索类似适合挂载一批文档做知识库问答。代码解释器则适合需要计算、绘图、跑数据脚本的场景。自定义函数调用则用于接入你自己的业务系统。模型只负责生成调用参数真正执行还是由你的后端完成。Responses API 里最需要注意的是工具结果回传的格式函数执行完要把结果包装成对应 item再作为 input 传给同一个会话模型才会继续生成最终回答。2.4 输出控制参数几个最容易被忽略的细节很多开发者习惯了老接口的风格把 temperature、top_p 一股脑塞给所有模型。但在 Responses API 里新一代推理模型对 temperature 的支持非常有限甚至有些模型直接不支持传了就会报参数错误。reasoning 类模型建议通过 reasoning.effort 来控制思考深度而不是调节温度。max_output_tokens 这个参数值得重视。我见过不少项目因为没设上限模型在一个离谱的循环里生成了上千 token费用翻了几倍。设置一个合理的输出上限能很自然地限制成本边界。另一方面如果业务需要稳定 JSON 格式官方也提供了结构化输出能力只要把输出格式声明为 JSON Schema模型就会严格按结构返回省去了解析失败重试的钱。3. 从零跑通环境、代码与参数3.1 环境准备整个过程只需要两个前置条件一个官方 API Key以及装了 Python 3.9 的环境。安装 SDK 用一行命令pip install -U openai然后设置环境变量。Linux 或 macOS 可以这样export OPENAI_API_KEY你的KeyWindows PowerShell 则用$env:OPENAI_API_KEY你的Key建议不要把 Key 写死在代码里。无论你是个人项目还是团队协作环境变量方式都更安全也方便在不同环境之间切换。3.2 最小可用示例无状态安装好之后先跑一个最简单的无状态调用。这一步能验证 Key、网络和基本调用链是否正常。from openai import OpenAI client OpenAI() response client.responses.create( modelgpt-4o-mini, input用两句话说明白什么是缓存计费, ) print(response.output_text)这里的client.responses.create就是 Responses API 的入口。input 直接传字符串SDK 会自动包装成消息项。output_text是便捷属性用来拿模型输出的纯文本内容。如果这步通了说明基础链路没问题。我在这一步还建议顺手打印一下response.id因为后面带历史、做多轮会话都要用到这个 ID。3.3 带历史的有状态示例接下来模拟一个连续对话场景。第一次请求让模型记住“今天天气适合跑步吗”第二次请求带着上一次的 ID 追问。first client.responses.create( modelgpt-4o-mini, input今天天气适合跑步吗, storeTrue, ) first_id first.id second client.responses.create( modelgpt-4o-mini, previous_response_idfirst_id, input那如果是雨天呢, storeTrue, ) print(second.output_text)注意两个关键点。第一传previous_response_id时必须同时设storeTrue否则官方服务端没有保存历史这条参数就失效了。第二第二次请求里我没有再重复“今天天气适合跑步吗”这句话但模型应该能理解“那如果是雨天呢”指的是同一个话题。这就是有状态会话的价值。我不建议一上来就把所有工具和状态都打开。先把最简单的无状态、有状态跑通再逐步加复杂度。这样出问题时你能很快定位是业务问题还是接口用法问题。3.4 带内置工具的示例接下来加工具。最典型的是联网搜索需求很简单让模型自己去查资料并总结。response client.responses.create( modelgpt-4o-mini, input帮我查一下今天的行业新闻并用三点总结。, tools[ { type: web_search } ], ) print(response.output_text)当 tools 参数里声明了 web_search模型就会在需要时发起搜索。从效果上看它相当于把“搜索、读取、总结、引用”打包成一个动作。文件搜索和代码解释器的用法类似只是 type 不同。需要注意的是这些内置工具通常有单独的使用费用官方文档里会有明确说明。对于高频率调用的场景我一般会先估算工具使用费在整体账单里的占比再决定要不要接自定义函数代替。3.5 输出结构稳定化与容错做业务接口时我强烈建议让模型输出固定结构而不是返回一段话再让代码去解析。一种是官方提供的结构化输出能力直接声明 JSON Schema另一种是代码层面做校验。如果你暂时不想深挖官方结构化参数也可以先这样处理import json response client.responses.create( modelgpt-4o-mini, input给我一个JSON包含三个学习建议每个建议有标题和描述。, ) text response.output_text try: data json.loads(text) print(data) except json.JSONDecodeError: print(解析失败需要重试或调整提示词)这段代码的意义在于让异常暴露在明处而不是让脏数据流到业务下游。实际开发中解析失败的处理比大多数人想象得常见。我在项目里遇到过模型多输出了一句解释文字导致 JSON 解析失败的情况后来改成结构化输出声明之后这种问题基本绝迹。4. 把费用压下一半以上的实操清单4.1 模型档位先选对再谈省钱模型选型是成本控制的第一道关卡。Responses API 支持不同档位的模型从高能力模型到高性价比模型再到 mini 规模模型每档价格差距很大。这不代表越便宜越好而是要根据任务复杂度来选。如果一个任务只是简单的分类、改写、抽取用 mini 档模型完全够用如果任务涉及复杂推理、长文写作、多步工具调用再用回高能力模型。一个常见做法是“路由”先用轻量模型做初筛判断任务难度把简单问题直接解决掉只有困难问题才转发给更贵的大模型。这个策略能把整体成本压低一大截而用户几乎感知不到差异。另外要警惕“顺手调贵模型”的惯性。我之前有个项目一直默认用旗舰模型后来发现其中 70% 的请求根本不需要那么强的大脑换成性价比档位后账单直接降了一个数量级。4.2 让缓存稳定命中前缀顺序决定成本缓存是官方自动行为不需要手动开关但你可以通过请求结构来影响命中率。核心规律是缓存的粒度是前缀匹配如果两次请求的前缀完全一致前缀部分就会命中使用缓存价格。所以请求结构设计就有讲究了。系统提示词、固定工具定义、固定示例段落这些内容要尽量放在 input 的前面。用户问题、时间戳、随机 token 等动态内容要尽量放在后面。如果你把用户问题放在前面后面大段固定指令每次都会跟着变化缓存就很难命中。还有一点不要频繁改动系统提示词。哪怕只是改了一个标点都会导致前缀分叉让之前积累的缓存全部失效。我在实际项目中会把提示词的版本号固化到应用配置里需要调整时就整体升级一版而不是每轮动态拼接。下面用表格对比一下缓存友好型和非友好型的请求结构请求结构具体示例缓存命中影响固定前缀 动态后缀系统提示 工具定义 用户问题前缀稳定命中率高动态前缀 固定后缀用户问题 系统提示前缀每次都变命中率低频繁微调提示词同一系统提示每隔几句改一次前缀分叉缓存失效4.3 历史管理别让上下文越长越贵上下文管理是省钱库里最大的一块。很多人觉得有状态模式把所有历史交给官方管理就万事大吉但每轮请求的输入 token 不仅包含新问题还包含全部旧历史。我的做法是对长会话设置一个“水滴”比如最近 N 轮完整保留再往前的历史用模型生成摘要摘要本身作为上下文继续传递。这样一来模型仍然能理解早期对话的意图但当轮请求的输入 token 被显著压缩了。另一个技巧是主动截断。对于那些已经完成、不再影响后续对话的冗长内容比如大段工具返回结果、搜索原文就没必要一直保留在上下文中。只保留结论把原始文本从历史里摘掉。这个动作单独看可能只省几百 token但在高频调用下积少成多一个月能省下的费用相当可观。4.4 批量接口再拿五折如果业务里有不需要立即返回结果的任务批量接口是必须知道的省钱手段。像批量生成摘要、离线数据标注、定时报表、大批量内容分类这些场景完全可以走批量任务。批量任务的核心流程是把多个请求体按行写入 JSONL 文件然后通过官方接口提交。每个请求体都是一次完整的 responses.create 调用参数。提交后异步执行完成后统一取回结果。这种方式对应模型的标准价格大约打五折。举个例子假设你要跑一万条商品描述分类每条请求约 2K 输入 token、500 输出 token。如果同步逐条调用费用按全价算如果打包成批量任务光这一项就能省一半。代价只是不能立刻拿到结果一般需要等一段时间。4.5 一个成本模拟计算空谈省钱不直观我做一个模拟账本。假设一个常见问答场景平均每轮请求带 12K 输入 token输出 1.5K token一个月跑 1000 轮模型按某档常见官方价格估算输入约 2 美元/百万 token输出约 10 美元/百万 token。默认方式下输入费用12K × 1000 12M token费用 24 美元输出费用1.5K × 1000 1.5M token费用 15 美元总计39 美元优化后我做了三件事把固定系统提示放最前缓存命中率提升到约 70%改为只回传最近两轮上下文每轮输入从 12K 压到 6K缓存命中部分按原价的四分之一计费。未命中输入6K × 1000 × 30% 1.8M费用 3.6 美元缓存命中输入6K × 1000 × 70% 4.2M费用约 2.1 美元输出费用不变15 美元总计约 20.7 美元如果这个场景允许异步处理再走批量接口拿五折总费用还能再压到约 10.35 美元。对比最初的 39 美元相当于省了七成以上。这里的具体价格只是示例每个模型的官方单价不同你需要以自己的定价页为准但这个计算思路是通用的。5. 常见问题与排查技巧实录5.1 响应格式不符合预期最常见的问题之一是模型返回的 JSON 里混入了额外文字或者干脆输出 Markdown 代码块。这类问题在纯文本输入、未声明结构化输出时尤其明显。排查思路不是反复调提示词而是优先考虑官方结构化输出能力把格式约束交给接口。另外max_output_tokens 设置太短也可能导致输出被截断JSON 不完整。如果发现输出总是戛然而止先检查是不是输出上限过小。调参时注意输出上限不是越大越好要结合业务真实需要来定。5.2 状态会话失效或历史丢失有人会碰到这种情况第二天继续对话传了 previous_response_id模型完全忘了之前聊过什么。大概率是服务端保存的会话有有效期限制或者你在中间换过模型、改过 store 参数。Responses API 的会话状态不是永久存储不能当成数据库用。我的建议是重要业务信息不要只依赖 previous_response_id。要么在无状态模式下自己把关键信息持久化要么在每次调用时把核心背景重新写进 input。对长期记忆来说外部向量库或数据库仍然是更可靠的方案。5.3 推理模型报参数错误换用推理模型后偶尔会看到一些参数不支持的报错。最典型的是 temperature、top_p 这类采样参数。推理模型的思路是让模型自己决定思考深度直接用温度控制不一定生效甚至会被拒绝。遇到这种情况先看官方文档里该模型支持哪些参数。通常在 responses.create 参数里传 reasoning.effort 来控制思考强度就够了。不要从老接口把整套参数原封不动搬过来。5.4 缓存命中率远低于预期缓存是省钱的隐形引擎但它也有脾气。前缀匹配要求很高以下情况都会让缓存失效每次请求都带时间戳系统提示词里有随机内容工具定义顺序不固定请求之间前缀不一致。另外缓存也有长度限制超长内容不一定能完整命中。排查时先看响应对象里有没有返回缓存命中的 token 数量用来判断实际命中情况。然后重点检查请求前缀是否“每次都长一样”。如果发现了动态内容在前缀区把它挪到可变区间里。5.5 工具调用循环跑飞启用函数调用后模型可能陷入“调用工具、回传结果、再调用工具”的死循环。尤其当工具返回结果不理想时模型会尝试反复调用token 消耗一路狂飙。解决方案是限制轮数。在前端代码里维护一个最大迭代次数比如 5 轮达到上限就强制返回兜底回答。同时工具返回结果要尽可能精简明确如果返回的是大段原始数据模型很容易在理解上跑偏导致反复调用。我会在工具返回结果前做一次摘要只把关键信息回传给模型效果立竿见影。6. 最后分享几个我反复踩过的坑Responses API 用下来我个人体会最深的一点是它确实更省事但“省事”不等于“放任不管”。第一次我把所有请求都切到有状态模式结果一个长会话跑到三十几轮之后每轮请求的输入 token 已经膨胀到接近上下文窗口上限费用比原先无脑重发整段历史还要夸张。后来我学会了一个最简单的习惯每轮调用前问自己一句这轮对话真的需要带全部旧历史吗第二个坑是提示词版本控制。有一段时间我为了调效果几乎每天改系统提示词每次改动都让缓存前缀分叉缓存命中率掉得厉害。后来我把提示词都收敛到固定版本只在发布新版本时整体切换成本才真正稳下来。如果你准备把现有项目迁到 Responses API我的建议是不要一次全量替换。挑一个非核心模块先跑起来把有状态、无状态、工具调用、缓存命中这些基础能力都摸透再逐步扩大范围。这套接口能帮你省钱但它更像个需要磨合的搭档你用对了地方成本优势才会真正显现出来。
阅读完成 · 觉得有帮助?