成本优化

控制输出长度到底能省多少钱:一次实测

聊 LLM 成本优化,大家第一反应都是”裁剪 prompt”——我们之前写过Prompt token 裁剪 12 个秘诀专门讲这个。但很少有人算过一笔账:输出 token 的单价通常是输入 token 的 3-5 倍,一个啰嗦的回答比一个啰嗦的提问更烧钱。本文换个方向,专门讲怎么控制”出口”,并给出一套能实际量化省钱效果的方法。

一、为什么输出比输入更值得关注

以主流模型的定价结构为例,输出 token 单价普遍是输入 token 的 3-5 倍(具体倍率各家不同,请以当前官方定价为准)。这意味着同样是 1000 token 的浪费,发生在输出端的成本损失通常是输入端的好几倍。而输出端的浪费往往更隐蔽——你能一眼看出 prompt 里有段废话,但很难第一时间意识到模型的回答里有 30% 是不必要的客套和重复。

二、三种控制手段,效果不一样

1. max_tokens 硬截断

最直接但也最粗暴的手段——设一个上限,模型生成到这个长度就被强制截断。优点是绝对可控,成本上限一目了然;缺点是截断位置不智能,很可能在一句话说到一半时被切断,导致内容不完整,反而需要重新请求,总成本不降反升。

适合用在你对输出结构有把握的场景,比如”生成一条不超过 140 字的摘要”,模型正常情况下不会跑到 140 字之外,max_tokens 只是一个安全阀,不是主力控制手段。

2. Prompt 里显式约束长度

比硬截断更聪明的做法,是在 prompt 里直接告诉模型”输出控制在 3 句话以内”或”只列出结论,不要展开论证”。这种方式让模型自己判断在哪里收尾,比外部硬截断更少产生”半句话”的问题。

实测中这种方式的效果和措辞强相关。含糊的约束(比如”简洁一点”)效果有限,模型对”简洁”的理解弹性很大;具体的约束(比如”不超过 5 个 bullet,每条不超过 20 字”)效果明显更稳定。

3. 结构化输出(JSON Schema / 固定字段)

让模型按照预定义的 JSON Schema 输出,天然会挤掉大量”废话性”文本——没有 schema 时模型习惯性地加开场白(“好的,我来为你分析一下”)、总结句、免责声明,这些在结构化输出里基本会被格式约束自然消除。

这个手段的额外好处是输出长度的方差也会显著降低,也就是说不仅平均更短,长度还更可预测,这对成本预算和延迟预估都有好处。

三、怎么实测”省了多少钱”

光说”应该有用”没有说服力,下面是一个可复现的实测框架:

  1. 准备一批代表性任务(20-30 条即可),覆盖你业务里的典型请求类型
  2. 跑一遍”无约束”基线:不加任何长度控制,记录每条任务的输出 token 数
  3. 分别跑三组对照:只加 max_tokens、只加 prompt 长度约束、只用结构化输出,分别记录输出 token 数
  4. 计算相对基线的降幅,同时人工检查内容完整性有没有受损——这一步不能省,省了钱但内容废了没有意义
def measure_output_savings(client, model, tasks, variant_prompts):
    results = {}
    for variant_name, wrap_prompt in variant_prompts.items():
        total_tokens = 0
        for task in tasks:
            resp = client.chat.completions.create(
                model=model,
                messages=[{"role": "user", "content": wrap_prompt(task)}],
            )
            total_tokens += resp.usage.completion_tokens
        results[variant_name] = total_tokens
    baseline = results["baseline"]
    return {k: round((baseline - v) / baseline * 100, 1) for k, v in results.items()}

跑完把百分比降幅乘以你的输出 token 单价,就能换算出实际的每千次调用省了多少钱——这个数字比任何”最佳实践”清单都更有说服力,尤其是拿去跟团队申请把长度约束写进标准 prompt 模板时。

四、分场景策略:不是所有任务都该往短了压

任务类型适合的控制手段原因
摘要/分类/打标签结构化输出 + 短 max_tokens输出本身就该是确定性的短结果
客服问答Prompt 长度约束(如”3 句话以内”)用户体验要求简洁,但不能生搬硬截断
代码生成只用 max_tokens 做安全阀,不做强约束代码长度由逻辑复杂度决定,强行压缩会导致语法不完整
长文写作/报告生成不做长度压缩,改用分段生成+流式返回这类任务的”啰嗦”是需求本身,压缩会牺牲内容质量

判断标准很简单:如果任务的”正确答案”天然就短,用结构化输出把冗余挤掉是纯收益;如果任务的价值就在于内容的详细程度,压缩长度等于压缩价值,这种情况不该在长度上做文章,应该去看有没有更省钱的模型分级路由或者Prompt Caching空间。

五、一个容易被忽略的反模式:截断导致返工

如果 max_tokens 设得过于激进,模型的回答在关键信息说完之前就被切断,调用方往往要么发现内容不完整后重新请求一次(双倍成本),要么把不完整的结果直接用了(业务风险)。这种”省小钱吃大亏”的情况在实测中并不少见,尤其是当任务的实际所需长度本身就有较大波动时——按最短情况设置的硬上限,会在稍复杂的输入上频繁触发截断。

稳妥的做法是:max_tokens 设置留出比预期长度多 30%-50% 的余量,真正的长度控制交给 prompt 约束和结构化输出去做,max_tokens 只作为防止极端异常(比如模型陷入重复输出循环)的兜底。

六、相关阅读