LLM 输出太长怎么控?让模型少废话是最划算的省钱手段
一个团队的账单从每月一百多刀涨到七百多刀,来找我看怎么砍。他们已经做过两轮优化:换过一次更便宜的模型,又把系统提示词从两千字压到八百字。折腾了一周,账单降了不到一成。
我让他们把最近一千条请求的 usage 字段导出来,看了三分钟就找到了问题:平均输出 1600 多个 token。而他们的产品界面上,展示给用户的只有一个三行的摘要卡片——模型每次都先写一段”好的,我来帮您分析这份文档”,再列六条要点,每条要点后面还跟一段”这意味着……”的解释,最后再来一段总结。前端把这坨东西正则切一刀,只渲染中间那三行。
剩下那 1400 个 token,钱照付,用户一眼没看见。
我见过太多这样的场景了。优化成本的时候,大家的第一反应永远是换模型或者压 prompt,很少有人先低头看一眼输出。但输出恰恰是三个变量里单价最贵、同时又最容易改的那一个——改 prompt 里的一句话就能见效,不需要换模型、不需要重构 RAG、不需要动任何架构。
先看清楚:输出的单价到底比输入贵多少
拿一份公开的定价表来看具体数字。下面是 DeepInfra 官方定价页列出的几个模型,单位是美元 / 100 万 token:
| 模型 | 输入 | 缓存输入 | 输出 |
|---|---|---|---|
| DeepSeek-V4-Pro | $1.30 | $0.10 | $2.60 |
| DeepSeek-V4-Flash | $0.09 | $0.018 | $0.18 |
| DeepSeek-V3.2 | $0.26 | $0.13 | $0.38 |
| DeepSeek-V3.1-Terminus | $0.27 | $0.13 | $0.95 |
| DeepSeek-V3.1 | $0.25 | $0.13 | $0.95 |
来源:DeepInfra 官方定价页(deepinfra.com/pricing),核对日期 2026-08-07。价格随时可能调整,下单前以官方定价页为准。本文所有算例都是拿这张表做的算术演示,不是报价。
注意这张表里的比例关系。V4-Pro 是 $1.30 对 $2.60,输出正好是输入的 2 倍;V4-Flash 是 $0.09 对 $0.18,同样是 2 倍。而 V3.1 和 V3.1-Terminus 更极端:输入 $0.25 左右,输出 $0.95,接近 4 倍。
倍数关系为什么普遍是这个方向,涉及推理阶段 prefill 和 decode 的计算特性差异,这里不展开,可以看 输入价与输出价为什么不同 那篇。你现在只需要记住一个结论:在账单上,一个输出 token 顶两个到四个输入 token。
这个倍数直接推出一条非常好用的判据。以 V4-Pro 这种 2 倍关系为例:
只要输出 token 数超过输入 token 数的一半,输出就占了账单的大头。
很多人对这条判据的反应是”不可能吧,我 RAG 塞了五千字上下文进去,输出才几百字,输出能占多少”。这个直觉在部分场景下是对的,但没你想的那么普遍。
第一步:量化输出在你账单里的占比
别凭感觉,做一次实测。步骤很简单:
- 从生产日志里捞最近的一批真实请求(一千条起,覆盖一个完整的工作日,别只挑白天高峰)
- 每条记录取响应里的 usage 字段——输入 token 数、输出 token 数。绝大多数 OpenAI 兼容接口都会返回这个字段,具体字段名以你所用平台的官方文档为准
- 分别求和,各自乘以对应单价
- 算出输出成本占总成本的百分比
再进一步,按业务场景分组算,而不是笼统算一个总数。因为不同场景的结构差异极大,混在一起算平均数会把问题掩盖掉。
下面用假设参数演示一次。假设四类典型场景,都用 V4-Pro 的挂牌价($1.30 输入 / $2.60 输出,每 100 万 token),统一按 1000 次请求计算:
| 场景 | 单次输入 | 单次输出 | 1000 次输入成本 | 1000 次输出成本 | 合计 | 输出占比 |
|---|---|---|---|---|---|---|
| A 客服问答 | 1,200 | 800 | $1.56 | $2.08 | $3.64 | 57.1% |
| B 长文档问答 | 6,000 | 500 | $7.80 | $1.30 | $9.10 | 14.3% |
| C 报告生成 | 4,000 | 2,500 | $5.20 | $6.50 | $11.70 | 55.6% |
| D 代码解释 | 800 | 1,800 | $1.04 | $4.68 | $5.72 | 81.8% |
算术核对(以场景 C 为例):1000 次请求共输入 4,000 × 1000 = 400 万 token,即 4 × $1.30 = $5.20;共输出 2,500 × 1000 = 250 万 token,即 2.5 × $2.60 = $6.50;合计 $11.70,输出占 6.50 ÷ 11.70 = 55.6%。
场景 C 是最值得盯的那个,也是最反直觉的:输入 token 数是输出的 1.6 倍,输出却占了账单的 55.6%。因为 1.6 倍的量差,被 2 倍的价差反超了。
所以那句”我上下文很长所以输出无所谓”的直觉,只在场景 B 那种极端配比下成立——输入是输出的 12 倍。一旦输入输出比落到 3:1 以内,输出就已经在账单里占据可观份额了。
顺便说一句,场景 D 那种输入短、输出长的形态(代码解释、文案生成、翻译润色、内容改写),输出占比逼近八成。这类业务如果不控输出长度,等于把预算的四分之三交给了一个你根本没审视过的变量。
让模型少废话的手段,按性价比排序
下面这个排序是按”收益 ÷ 改动量”排的,不是按收益绝对值排的。排在前面的几条,你今天下午就能改完上线。
1. 直接在 prompt 里约束输出形态(收益最大,改动最小)
这条无论如何都排第一。绝大多数模型默认的行为是”礼貌、完整、乐于解释”,因为它们被训练成这样。你不说,它就会给你加开场白、加解释、加总结。
具体写法上,有效和无效的差别很明显:
弱约束(基本没用):
请简洁回答。
强约束(有效):
只输出最终结果,不要解释推理过程,不要写开场白和结尾总结。
输出不超过三句话。
“请简洁”这类形容词对模型几乎没有约束力,因为”简洁”没有可判定的标准。有效的约束都是可判定的:只输出什么、不要输出什么、不超过几句、不超过几条。
几条实操经验:
- 正面清单比负面清单管用。“只输出 JSON 对象”比”不要输出多余内容”效果稳定得多,因为前者定义了应该输出什么,后者只排除了一部分。
- 禁开场白要单独写一句。“不要以’好的”当然’开头”这种具体到词的指令,比笼统的”直接回答”有效。
- 约束句放在 prompt 末尾,紧挨着用户输入之前。放在系统提示词开头、中间隔着两千字上下文的地方,遵守率会掉。
- 改完立刻回测。约束改动是有可能改变答案质量的,别改完就上线。
2. 用结构化输出把自由发挥的空间关掉
Prompt 约束是”请你别啰嗦”,结构化输出是”你只能填这几个格子”。后者的下界更硬。
当你要求模型返回一个只有三个字段的 JSON 对象时,它没有地方可以塞开场白和总结——那些内容在 schema 里没有对应位置。这比自然语言约束可靠得多,尤其是在长对话、复杂上下文这些容易让模型”忘记”约束的场景下。
代价有两个,都要提前想清楚:
一是schema 设计本身会引入成本。字段名、字段说明都要写进请求里,字段起得又长又多,你在输入侧又加回来一部分。字段名用简短的英文标识符,字段说明能省则省。
二是结构化输出失败时的返工成本。模型返回的 JSON 解析不出来,你就要重试,重试的那一次是全额付费的。这部分怎么算账,结构化输出的返工成本 那篇讲得比较细,这里不重复。
3. 设置最大输出长度上限(有效,但代价必须讲清楚)
绝大多数 OpenAI 兼容接口都支持 max_tokens 这类最大输出长度参数(具体参数名和默认值以你所用平台的官方文档为准)。设一个上限,是最硬的止损手段——不管模型多想说,超过就停。
但这条排在第三位,不是第一位,因为它的代价是实打实的:它不会让模型”说得更短”,它只会让模型”说到一半被切断”。
这个区别至关重要。前两条手段是让模型自己规划出一个短答案,答案是完整的;max_tokens 是在生成过程中一刀切,你拿到的很可能是半截 JSON、半句话、没闭合的括号。
所以设上限必须配套两件事:
第一,解析层容错。 拿到响应先判断结束原因(多数接口会在响应里给出一个表示为什么停止的字段,具体字段名以官方文档为准)。如果是因为触顶而停,就不能当正常结果处理——半截 JSON 直接扔进 json.loads 会抛异常,而这个异常如果没被捕获,可能在生产里表现成一个莫名其妙的 500。
第二,触顶要有监控和降级路径。 触顶率是个必须打点的指标。如果长期是 0,说明这个上限设了等于没设,可以往下压试试;如果触顶率有个位数百分比,说明它在真正干活,但也说明有那么一部分用户拿到了残缺结果,你要想好这些请求怎么办——是提示用户重试、是自动用更大的上限重跑一次、还是把已生成的部分展示出来。
上限该设多少? 我的做法是:先不设上限跑一段时间,统计真实输出长度的分位数,取 p95 或 p99 附近作为起点,再观察触顶率。上来就凭感觉设一个数,要么形同虚设,要么天天截断。
还有个容易忽略的点:max_tokens 只是止血,不是治疗。它防的是”模型突然抽风写了五千字”这种尾部风险,压不下你的中位数成本。真正压中位数的还是前两条。
4. 先结论后理由 + 前端只渲染结论——这是体验优化,不是成本优化
这个模式确实有用:让模型先输出结论,再输出理由,前端默认只展开结论,用户想看理由再点开。首屏内容出现得早,感知延迟明显下降。
但请务必分清楚:模型把理由写完了,这部分 token 你照付。前端折不折叠、渲不渲染,跟计费一分钱关系没有。
我特意把这条单列出来,是因为我见过团队把这个改动写进”成本优化”的收益汇报里,然后下个月账单一分没降,大家一脸茫然。它属于体验优化,该做,但别记在成本优化的账上。
真要把这部分钱省下来,得改成两段式:默认只请求结论,用户点开”查看理由”时再发第二次请求。代价是多一次往返、多一次输入计费(上下文要重发一遍),所以只有在展开率明显偏低的时候才划算。如果十个用户里有八个都会点开,两段式反而更贵。
判断很简单:设展开率为 p,两段式在 p 较小时省钱,p 接近 1 时因为重复计费输入而更贵。先去日志里查一下你的真实展开率,再决定。
5. 别让模型复述输入
有一类 prompt 写法是纯烧钱的:
请先重复一遍我的问题,然后再回答。
请先把我提供的原文完整列出来,再逐段分析。
请在回答的每一部分开头,先引用对应的原文段落。
这些指令让模型把你已经付过输入费的内容,再按输出价付一遍。以 V4-Pro 为例,同一段 1000 token 的文本,作为输入是 $0.0013 / 1000 次请求量级的开销,被复述成输出就变成 $0.0026 的量级——同样的字,价格翻倍。
为什么会有人这么写?多半是从早期的 prompt 教程里抄来的。“让模型复述问题以确认理解”在很久以前的弱模型上有一定作用,但对现在的模型基本是纯开销。
同类的还有几种,一起排查掉:
- 让模型输出时把表格的表头和不变的列重新完整打一遍
- 长对话里让模型”总结一下我们前面聊的内容”(总结本身是输出,而且它还会进入下一轮的输入,双份)
- 翻译场景里要求”原文和译文对照输出”——如果你手上本来就有原文,前端拼接就行,没必要让模型再打一遍
唯一的例外是模型需要精确定位引用位置的场景(比如要求标注答案来自原文哪一句)。这时候复述是功能需求,不是浪费。但也应该只复述必要的那一小段,而不是整篇。
6. 推理类模型的思考过程也是输出
这条最容易被漏掉,因为它在界面上经常是折叠的、灰色的、不显眼的。但推理模型生成的思考内容属于生成出来的 token,在计费上通常按输出计(具体计费口径以你所用平台的官方文档为准,各家不完全一致,这一点务必自己确认)。
这意味着一件事:一个”看起来只回复了两句话”的推理模型请求,实际输出 token 数可能是可见部分的好几倍。
处理原则:
- 先判断任务需不需要长推理。分类、抽取、格式转换、简单问答这类任务,推理过程带来的准确率提升往往很有限,但成本是实打实的。
- 需不需要开启、能不能限制推理长度,各家的做法不一样,以你所用平台的官方文档为准。有的平台提供了控制项,有的没有。
- 不要用平均值判断,要看分位数。推理长度的分布通常是长尾的——大部分请求思考几百个 token,少数难题能思考几千个。你的账单里那些尖峰,往往就来自这个长尾。
多轮对话的复利效应:这一节最值钱
前面几节讲的都是”输出贵一倍”这个一次性的账。但在多轮对话里,事情要严重得多。
原因很简单:这一轮的输出,会变成下一轮的输入。
你每一轮把完整历史发回去,模型上一轮说的每一个字都要按输入价重新计费一次。第一轮的回复,在一场十轮的对话里会被当作输入重新计费九次。所以输出长度不是一次性成本,它会在后续每一轮里被重复收费。
用假设参数算一遍
假设一场 10 轮对话,每轮都把完整历史发回去(不做任何裁剪),参数如下:
- 系统提示词 300 token,每轮都发
- 每条用户消息 100 token
- 每条模型回复 R token
- 单价用 V4-Pro:输入 $1.30 / 100 万,输出 $2.60 / 100 万
第 n 轮的输入 = 300(系统)+ 100n(前 n 条用户消息)+ (n−1)×R(前 n−1 条模型回复)。
十轮累计:
- 累计输入 = 10 × 300 + 100 × (1+2+…+10) + R × (0+1+…+9) = 3,000 + 5,500 + 45R = 8,500 + 45R
- 累计输出 = 10R
注意那个 45R。它的含义是:十条回复总共被当作输入重新计费了 45 次,平均每条回复被重复计费 4.5 次。
现在代入两组数:
情况一,每轮回复 600 token:
- 累计输入 = 8,500 + 45 × 600 = 8,500 + 27,000 = 35,500 token
- 累计输出 = 6,000 token
- 输入成本 = 35,500 ÷ 1,000,000 × $1.30 = $0.046150
- 输出成本 = 6,000 ÷ 1,000,000 × $2.60 = $0.015600
- 单场对话总成本 = $0.061750
情况二,每轮回复压到 300 token(减半):
- 累计输入 = 8,500 + 45 × 300 = 8,500 + 13,500 = 22,000 token
- 累计输出 = 3,000 token
- 输入成本 = 22,000 ÷ 1,000,000 × $1.30 = $0.028600
- 输出成本 = 3,000 ÷ 1,000,000 × $2.60 = $0.007800
- 单场对话总成本 = $0.036400
对比:
| 每轮 600 token | 每轮 300 token | 降幅 | |
|---|---|---|---|
| 累计输入 token | 35,500 | 22,000 | −38.0% |
| 累计输出 token | 6,000 | 3,000 | −50.0% |
| 输入成本 | $0.046150 | $0.028600 | |
| 输出成本 | $0.015600 | $0.007800 | |
| 总成本 | $0.061750 | $0.036400 | −41.1% |
省下 $0.061750 − $0.036400 = $0.025350,占原成本的 0.025350 ÷ 0.061750 = 41.1%。
这个数字为什么值得单独拎出来讲
如果你只盯着输出这一栏,你会以为把输出减半只能省 $0.007800,占总成本的 12.6%。但实际省了 41.1%,是你预期的 3.25 倍。
多出来的那部分全在输入侧:少生成的 3,000 个输出 token,同时让累计输入少了 13,500 个 token。
换个角度算,更直观。在这个 10 轮的设定下,多生成 1 个输出 token 的真实成本是:
- 作为输出,收 1 次:$2.60 / 100 万
- 作为后续轮次的输入,平均再收 4.5 次:$1.30 × 4.5 = $5.85 / 100 万
- 合计 $8.45 / 100 万
价格表上写着 $2.60,实际是 $8.45,3.25 倍。对话轮数越多,这个倍数越大。
这也解释了一个常见现象:不少团队的对话类产品,账单增速远快于用户数增速。因为账单是随对话轮数的平方量级增长的(前面那个 45 就是 10×9÷2 来的),而不是随请求数线性增长。
两个能压住复利的办法
一是命中缓存。 如果重发的历史部分能命中缓存,这部分按缓存输入价计费。DeepInfra 的 V4-Pro 缓存输入是 $0.10 / 100 万,对比普通输入的 $1.30,差了约 13 倍。在理想情况下(假设重发部分全部命中),上面那个真实成本会变成 $2.60 + $0.10 × 4.5 = $3.05 / 100 万,倍数从 3.25 倍掉到 1.17 倍,复利效应基本被抹平。
但要提醒的是:能不能命中、命中条件是什么、缓存存活多久,各平台规则不同,以官方文档为准。别假设它一定会命中——把缓存命中率打成指标去观测,比看文档更靠谱。缓存的具体用法可以参考 大模型 API 成本优化。
二是裁剪历史。 只发最近 N 轮,或者把早期历史压缩成一段摘要。这是控制长对话成本的常规做法,也顺带解决了上下文窗口撑爆的问题——上下文超限怎么办 那篇讲了具体做法和取舍。
两个办法可以叠加,但要注意裁剪历史会破坏缓存前缀(前缀变了,缓存就不命中了),两者存在冲突。具体怎么配,得看你的对话长度分布,没有通用答案。
别过度压缩:省下来的可能不如追问贵
上面讲了一堆怎么砍,现在讲反面。
我见过更糟的情况:一个团队把输出上限压到很低,账单确实降了三成,但客服工单量涨了一倍。因为模型的回答变得残缺,用户看不明白就再问一遍——而追问的那次请求,输入里带着完整的上下文和上一轮的残缺回答,成本比第一次还高。
算一笔账你就明白了。假设正常回答成本是 1 个单位,你砍到 0.6。但如果这个改动让 30% 的请求需要追问一次,追问那次的成本大约是 1.2(因为上下文更长了),那么:
- 优化前:1.0
- 优化后:0.6 + 0.3 × 1.2 = 0.6 + 0.36 = 0.96
省了 4%,代价是三成用户的体验变差、客服工单翻倍。这笔账明显是亏的。
所以关键是找到那个拐点,而拐点必须用验收标准去测,不能凭感觉砍。 具体做法:
- 先写下验收标准,再动手改。 什么叫”回答合格”,要写成可判定的条目——比如”包含明确的结论”、“给出至少两条依据”、“覆盖用户问题中的全部子问题”。写不出验收标准,说明你还不知道自己要什么,别开始压缩。
- 准备一个固定的评测集。 三五十条覆盖典型场景的真实请求,包括那些棘手的边缘情况。每次改约束都跑一遍这个集合。
- 阶梯式往下压,每一档都测。 比如从不限制,到 800、600、400、300,看合格率在哪一档开始明显掉。那个掉点前的一档,就是你的拐点。
- 同时盯业务指标。 追问率、会话轮数、点踩率、客服工单量。这些比评测集更真实——评测集通过了但追问率涨了,说明你的验收标准写漏了东西。
还有一类场景压根就不该压:输出本身就是交付物的场景。用户要一篇文案、一份报告、一段代码,输出就是产品价值本身。这种场景该优化的是”别写没人看的部分”(开场白、免责声明、重复的总结),而不是”总长度砍一半”。分清”废话”和”内容”,砍前者,别碰后者。
把平均输出长度打成指标
前面所有优化,如果不监控,三个月后就会悄悄退回去。
我强烈建议把平均输出 token 数打成一个常规指标,和延迟、错误率放在同一块看板上。理由是:这个数字的漂移,几乎总是意味着某个你不知道的变更发生了。
具体怎么打:
- 按端点 / 按业务场景分组,别只有一个全局平均值。全局值会把问题稀释掉——A 场景涨了一倍,B 场景量大且没变,全局平均可能只动了几个百分点。
- 同时记 p50 和 p95,不要只记平均值。平均值对长尾不敏感,而成本尖峰恰恰来自长尾。p95 突然抬头,说明有一类请求在失控。
- 同时记输入 token 数和它们的比值。输出/输入比是个很好的健康指标,它比绝对值更能反映”模型是不是变啰嗦了”。
- 触顶率单独记(如果你设了输出上限)。触顶率变化说明输出长度分布在移动。
- 设一个告警阈值,比如日均输出长度环比涨 20% 就告警。
平均输出长度悄悄上涨,常见原因就那么几个,按排查顺序:
- prompt 被改过了。 有人加了一句”请详细说明”,或者删掉了那句”不要解释”。把 prompt 纳入版本管理,改动走 review,这是最省事的预防手段。
- 模型版本变了。 用了带浮动指向的模型名,平台在后面换了实际权重,新版本的输出风格更啰嗦。生产环境应尽量锁定明确的模型版本。
- 上游输入变了。 用户的问题变复杂了,或者 RAG 召回的片段变多了,模型自然回得更长。这不是模型的问题,是上游的问题。
- 新场景混进了老端点。 有人复用了你的接口跑另一类任务,指标被平均进来了。这也是为什么要按场景分组。
有了这个指标,账单异常的时候你能在五分钟内分辨出”是量涨了”还是”是每次变贵了”,而不是对着账单发呆。想搭一套完整的成本预估口径,可以配合 token 成本估算 一起做。
自查清单
改之前,按这个顺序过一遍:
- 导出最近 1000 条真实请求的 usage,按业务场景分组,算出输出成本占比。 没有这个数字,后面所有优化都是盲改。
- 检查 prompt 里有没有”请先重复我的问题""请先列出原文”这类复述指令,有就删掉——这是纯烧钱,删了没有任何副作用。
- 在 prompt 末尾加可判定的输出约束(“只输出结果,不要解释""不超过三句话”),别写”请简洁”这种没有判定标准的形容词。
- 能上结构化输出的场景就上,把自由发挥的空间从根上关掉,同时评估好解析失败的返工成本。
- 设置最大输出长度上限,并同步给解析层加容错——判断是否因触顶而停止,半截结果不能当正常结果处理,触顶率要打点。
- 如果是多轮对话产品,把这一节的算例套一遍自己的参数,看看输出长度在你的对话轮数下被重复计费了多少次,再决定优先级。
- 压缩前先写验收标准和评测集,阶梯式下压,每一档都测合格率,同时盯追问率和工单量,找到拐点就停手。
- 把平均输出 token(p50 / p95)、输出输入比、触顶率打成指标上看板,设环比告警,防止三个月后悄悄退回原样。
最后重申一句本文所有算例的口径:单价取自 DeepInfra 官方定价页(核对日期 2026-08-07),其余参数(token 数、对话轮数、追问率)均为便于说明的假设值,请务必换成你自己日志里的真实数字重算。实际价格以官方定价页为准。