
开发大模型应用的同学最近可能都听过一个词Tokenmaxxing。它的字面意思很好理解——“把 Token 数量拉到极限”。但真正值得讨论的并不是这个词本身而是它背后指向的优化观我们评估一个 AI 功能到底应该看“模型输出了多少字”还是看“模型解决了多少问题”近期微软在工程师群体中反复强调一个原则“Tokenmaxxing is not what we are optimizing for”也就是“Token 数量最大化并不是我们要优化的目标”。这句话看似反直觉因为很多人在验收大模型效果时默认把“输出长度”等同于“输出质量”。本文将围绕这句话拆解它的技术含义从 Token 计费、Prompt 设计、输出约束、评估体系到工程实践完整梳理一套可落地的大模型应用优化方案。1. 背景概念Tokenmaxxing 到底是什么1.1 Token 与 Tokenmaxxing 的基本概念先说一下 Token 是什么。大模型并不像人一样逐字阅读文字而是先把文本切分成更小的片段这些片段称为 Token词元。在英文场景里一个单词通常对应 1 到 2 个 Token。在中文场景里一个汉字通常对应 1 到 2 个 Token。在代码场景里一个英文单词、符号、空格都可能占用一个 Token。Token 数量同时决定了三件事维度与 Token 的关系输入成本请求中的 Prompt 和上下文越长输入 Token 越多费用越高输出成本模型生成的回答越长输出 Token 越多费用越高延迟模型每生成一个 Token 都耗时输出越长用户等待越久所谓 Tokenmaxxing指的是一种把“最大化生成 Token 数量”当作优化目标的倾向。典型表现包括Prompt 里写“请尽量详细回答”。模型已给出结论还要补一句“再扩展一下”。把 300 字能说清的问题硬生生扩写成 1500 字。对输出长度不做任何约束生成完整代码时不考虑冗余。这种做法的初衷不难理解在不少人的直觉里“答得多”总比“答得少”显得专业。但从工程角度看它带来的是费用上涨、响应变慢、可读性下降甚至幻觉概率增加。1.2 微软说的“不是优化目标”应该如何理解“Tokenmaxxing is not what we are optimizing for”这句话并不是说“不要省 Token”而是说Token 消耗量只是一个观测指标不是优化目标。目标应当是任务完成度、用户体验、业务效果Token 数量是约束条件不是评分标准。举个例子。一个客服知识库问答系统它的优化目标应该是用户能否快速找到解决方案答案是否准确能否通过人工质检用户是否还需要二次提问而 Token 消耗量应该被当作成本项纳入考量在达到上述目标的前提下Token 越少越好。顺序不能反。一旦把“Token 少”当作唯一目标就会走向反面提示词太短导致上下文缺失、回答太短导致用户看不懂。这就是为什么“不是优化目标”和“不需要省 Token”必须是两回事。1.3 这篇文章能带给你什么下面我会从三个实操角度帮你建立一套可复用的大模型应用优化方法Token 计数与成本分析知道 Token 花在了哪里。输出约束与 Prompt 设计用结构化方式倒逼模型输出高质量短文本。评估体系搭建不靠“字数”判断好坏的工程化方法。2. 优化目标拆解质量、成本、延迟的三角关系2.1 一个 AI 功能的三元组指标任何接入大模型的功能在评估时都可以拆成三个互相制约的维度质量、成本、延迟。指标含义常见度量方式质量输出是否符合语义、格式、事实、业务规则人工评分、自动指标、线上转化率成本单次请求的输入输出 Token 费用单次调用价格、月成本、单用户成本延迟从发起请求到返回首个 Token 的时间P50、P95 响应时间当你知道一个功能需要同时优化三个维度时就会理解为什么“多发 Token”不一定是好消息。如果你的模型在回复“如何配置 ODBC 连接 SQL Server”时输出了 1000 字的背景介绍才进入正题那么用户前 5 秒可能什么都没看到——这就是典型的延迟变差同时你还要为那 1000 字里的 800 字无关内容付费这是成本变差。2.2 输出长度其实是代理指标在软件工程里有一个词叫“代理指标”Proxy Metric指的是用一个容易测量的变量代替一个难以直接测量的目标。输出长度就是最典型的代理指标。为什么大家会用它因为评价“回答好不好”成本很高需要人工阅读、评审、标注而“回答多长”是肉眼可见的甚至可以直接用 Token 数统计出来。但代理指标的陷阱在于它测得了过程却测不到结果。一段 200 字的回答可能精准解决了问题一段 2000 字的回答可能包含了三次自相矛盾的观点。如果你把所有 prompt 都加上“请详细回答”实际上是在激励模型堆砌文字而不是激励模型深度思考。2.3 一个可落地的评分公式在工程实践里我建议把大模型输出质量拆成客观分和主观分综合得分 0.5 × 客观分 0.5 × 主观分其中客观分由规则自动计算包括关键词覆盖率、格式合规率、事实冲突数、输出长度惩罚项。主观分由人工或更强模型打分包括语义相关性、逻辑连贯性、可执行性。注意输出长度只应该出现在“惩罚项”里当长度显著超过参考回答时给予轻微扣分而不是作为加分项。这样才能让团队把注意力放在“内容有效性”上而不是“内容量”。3. Token 计数实践先知道 Token 花在哪了3.1 使用 tiktoken 统计 Token 数在动手优化之前第一步是掌握 Token 统计工具。OpenAI 官方提供了一个轻量级库tiktoken可以按模型对应的编码器计算 Token 数。很多国产模型平台也提供了类似的 Tokenizer 工具原理相通。示例代码Python# 文件路径token_counter.py import tiktoken def count_tokens(text: str, model: str gpt-4o) - int: 按指定模型的编码器统计 Token 数。 不同模型的编码器可能不同如果传入模型不支持 会回退到 cl100k_base 编码器。 try: encoding tiktoken.encoding_for_model(model) except KeyError: # 部分新模型未提前注册时可手动指定编码器 encoding tiktoken.get_encoding(cl100k_base) return len(encoding.encode(text)) if __name__ __main__: # 模拟一段中文 Prompt prompt 请回答什么是 Tokenmaxxing它为什么不是优化目标 print(Token 数量, count_tokens(prompt))运行后你会得到一个整数这就是该文本在当前编码器下的 Token 数。注意中英文混合文本的 Token 切分差异很大实际生产环境建议用真实业务文本做采样统计。3.2 输入输出 Token 的计费模型不同平台计费方式不同但大部分 OpenAI 兼容接口都遵循“输入 Token 和输出 Token 分开计价”的规则。示意如下单次请求费用 输入 Token 数 × 输入单价 输出 Token 数 × 输出单价通常在单价上输入 Token 比输出 Token 便宜但没有简单到“只要减少输出就能省钱”。如果为了减少输出而增加大量系统提示词输入费用反而上升。优化时必须看总费用而不是孤立的输出长度。3.3 定位 Token 黑洞一个比较实用的做法是在接口调用层统一打印日志# 文件路径call_llm_logger.py import json import time def log_llm_call(messages, response): 记录一次 LLM 调用的核心元信息便于后续成本分析。 prompt_tokens response.usage.prompt_tokens if response.usage else 0 completion_tokens response.usage.completion_tokens if response.usage else 0 log_entry { timestamp: time.strftime(%Y-%m-%d %H:%M:%S), prompt_chars: sum(len(m.get(content, )) for m in messages), prompt_tokens: prompt_tokens, completion_tokens: completion_tokens, total_tokens: prompt_tokens completion_tokens, } print(json.dumps(log_entry, ensure_asciiFalse))通过日志你可以定期分析哪些请求的completion_tokens远超预期。如果发现 80% 的成本都集中在某类问题接下来就优先优化那类问题的 Prompt。4. 实战一用 max_tokens 与 stop 参数控制输出边界4.1 max_tokens 应该怎么设置max_tokens是接口中最基础的长度控制参数它决定模型最多生成多少个 Token。很多人要么不设置要么设置成 4096 或 8192 的很大值。关于 max_tokens正确的做法是结合任务类型设置上限任务类型建议 max_tokens说明短问答300 - 500控制模型废话代码补全800 - 1500给足核心代码空间文本摘要500 - 800摘要本身就不应该太长长文档处理2000 - 4000需要输出完整结构化方案示例代码# 文件路径llm_call_controlled.py from openai import OpenAI client OpenAI( api_keyyour-api-key, base_urlhttps://api.openai.com/v1, ) response client.chat.completions.create( modelgpt-4o-mini, messages[ {role: system, content: 你是技术支持工程师回答要简洁、准确。}, {role: user, content: 如何排查 Microsoft ODBC Driver 17 for SQL Server 的 Named Pipes 连接错误} ], max_tokens400, temperature0.3, ) print(response.choices[0].message.content)这里的关键不是把 max_tokens 设得多小而是先有一个合理预期这个任务的标准答案大概需要多少字。200 字能答清的问题不要给 2000 字的额度。4.2 stop 序列让模型在“不该继续”的地方停下来stop参数可以让模型遇到指定字符串时停止生成。使用场景非常广生成 JSON 时遇到}后停止。生成列表时遇到固定结尾标记后停止。生成对话时遇到“用户”后停止。示例response client.chat.completions.create( modelgpt-4o-mini, messages[ {role: user, content: 列出 3 条大模型应用优化建议每条不超过 30 字。} ], max_tokens300, stop[\n\n], )不过要小心stop 是基于字符串匹配的如果输出文本本身包含该字符串可能被意外截断。实际项目中要在测试集上验证 stop 的稳定性。4.3 结构化输出比长文本更省心另一个控制输出量的方式是直接要求模型返回结构化 JSON。结构化输出具备天然边界模型不会无限扩展因为 JSON 的结构本身就是约束。示例response client.chat.completions.create( modelgpt-4o-mini, messages[ {role: system, content: 你只输出 JSON不要输出任何额外文字。}, {role: user, content: 分析下面这段日志的异常原因并给出修复建议。日志Named Pipes Provider: Could not open a connection to SQL Server} ], response_format{type: json_object}, temperature0, ) content response.choices[0].message.content print(content)输出示例{ error_type: connection_failed, possible_cause: SQL Server 未启用 Named Pipes 协议或网络不通, fix_suggestions: [ 检查 SQL Server 配置管理器中的 Named Pipes 协议, 确认防火墙放行 1433 端口, 检查客户端连接字符串中的 Server 名称是否可解析 ] }结构化的好处是输出 Token 稳定可控下游解析简单测试断言方便。这也是很多生产级 AI 功能的标配做法。5. 实战二Prompt 约束工程设计5.1 系统提示词里先定“输出策略”如果你在每一条用户请求里反复强调“请简洁回答”系统提示词也写得很随意模型依然可能自由发挥。更好的做法是把输出策略直接放进系统提示词。对比一下弱提示你是一个 AI 助手请回答用户问题。强提示你是一个 AI 助手。回答要求 1. 先给结论再给依据。 2. 控制在 200 字以内不重复背景信息。 3. 如果问题无法确定明确说明“信息不足”。 4. 不要使用列表以外的修饰性语言。同样的用户问题强提示下的输出 Token 通常会明显下降而且回答更直接。5.2 用“格式模板”替代“详细回答”把“请详细回答”替换成“请按下面的模板输出”是抑制 Token 膨胀的有效方式。# 文件路径prompt_template.py prompt 请根据下面的信息撰写一条 Release 说明。 项目名称{project_name} 版本号{version} 主要变更 - 修复了 ODBC 连接超时问题 - 升级了 Microsoft Visual C Redistributable 运行时 输出模板 ## 版本 {version} ### 新功能 不超过 2 条 ### 修复 按列表输出 ### 注意事项 如果没有则写“无” .format(project_nameDataService, version2.3.1)模板把输出结构固定下来模型不需要通过堆字数来“显得完整”它只需要填槽。这种方式特别适合生成日报、周报、Release Note、接口文档等格式化内容。5.3 长度提示词的效果测试方法判断一段长度约束是否有效不能只看一次结果。建议准备 20 到 50 条测试问题分别运行“有约束”和“无约束”两版 Prompt统计平均输出 Token 数、包含无关背景的比例、用户满意度。测试项无约束版本有约束版本平均输出 Token680210包含冗余开场白比例65%8%用户直接拿到解决方案比例45%82%只有当长度约束没有导致质量下降时才值得正式上线。6. 实战三RAG 场景下的 Token 预算控制6.1 检索内容不能“全都要”在检索增强生成RAG应用里Token 消耗的大头往往不是模型输出而是上下文输入。把 10 篇相关文档全部塞进 Prompt上下文可能要几万 Token不仅花钱还会造成“上下文中海捞针”导致模型注意力分散。一个基本思路是为单次请求设置输入 Token 预算。# 文件路径rag_token_budget.py from typing import List def filter_chunks_by_budget( chunks: List[str], max_input_tokens: int 2000, token_counterNone ) - List[str]: 按输入 Token 预算过滤文本片段。 chunks: 检索模块返回的文本片段 max_input_tokens: 上下文上限 token_counter: 可传入 tiktoken 的 count_tokens 函数 selected [] total_tokens 0 for chunk in chunks: chunk_tokens token_counter(chunk) if total_tokens chunk_tokens max_input_tokens: break selected.append(chunk) total_tokens chunk_tokens return selected这个函数的核心思想是贪心策略按相关性排序后依次加入片段直到预算满载。片段不在多而在于是否覆盖了用户问题中的关键实体和约束条件。6.2 检索块越小控制越灵活如果一段文本本身有 3000 Token即使只检索到 1 段也可能超出预算。所以 RAG 在建模阶段就应该控制文本块大小。常见做法按段落或固定长度如 500 到 800 字切块。切块时保留标题、章节编号等元信息方便拼接。检索后可以根据元信息做进一步压缩比如只保留命中关键词附近的内容。6.3 多路召回后的去重与压缩很多 RAG 系统会同时走关键词召回、向量召回、重排模型三个通道。召回结果之间可能大量重叠直接拼接会产生大量重复 Token。建议增加一个轻量级去重层# 文件路径dedup_chunks.py def dedup_chunks(chunks: List[str], max_len: int 300) - List[str]: 通过文本哈希去重同时截断超长片段。 seen set() result [] for chunk in chunks: # 取前 max_len 个字符作为指纹降低重复率 key chunk[:max_len] if key in seen: continue seen.add(key) result.append(chunk[:max_len]) return result多路召回本身是为了提升覆盖率但去重层能显著降低输入成本同时减少模型被重复内容干扰的概率。7. 如何评估优化效果不要用 Token 数作为唯一标准7.1 定义质量评估维度Token 数下降是否意味着优化成功取决于质量是否保持不变或提升。我建议从四个维度评估维度说明评估方式正确性事实、参数、代码是否准确规则检测 人工抽检完整性是否覆盖问题中的所有子项关键词覆盖 人工格式合规是否符合 JSON / Markdown 等格式要求解析器自动判断可执行性用户按回答能否真正解决问题线上效果 测试集演练7.2 自动化评估脚本示例这里给出一个最简单的“长度 关键词覆盖”双重评估脚本# 文件路径evaluate_output.py import json import re def evaluate_single_case(reference_answers, model_output): 根据参考答案关键词评估单条输出。 output_lower model_output.lower() hit_count 0 for keyword in reference_answers: if keyword.lower() in output_lower: hit_count 1 coverage hit_count / len(reference_answers) token_count len(re.split(r[\s,。;], model_output)) return { keyword_coverage: coverage, word_count: token_count, too_long: token_count reference_answers[max_words], } if __name__ __main__: case { reference_answers: [Named Pipes, 防火墙, 连接字符串], max_words: 200, } output 请检查 SQL Server 的 Named Pipes 协议是否开启同时排查防火墙和连接字符串配置。 print(json.dumps(evaluate_single_case(case, output), ensure_asciiFalse))这只是一个示例思路生产环境建议用更细致的人工评分表或 LLM-as-Judge 方案。但核心原则相同优化前后必须在同一套测试集上对比。7.3 引入用户反馈作为最终标准在线上系统里最终评判标准是用户行为搜索后是否点击、提问后是否重试、客服会话是否减少。如果 Token 数下降了但用户重试率上升那说明优化方向错了反之如果 Token 数下降用户满意度提升说明你正在做正确的优化。8. 常见误区与排查清单8.1 常见误区误区后果正确做法追求输出越长越好成本上升、延迟增加、质量不稳定根据任务类型预设 Token 上限max_tokens 设置过小回答被截断语义不完整在测试集上观察 P95 输出长度Prompt 只写“请简洁”约束不够明确模型依然自由发挥给出模板或格式要求只按 Token 数评估忽略语义质量综合关键词、格式、人工评分把所有文档都塞进上下文输入 Token 爆炸、噪音干扰设置上下文预算并做精排8.2 排查清单当你发现模型输出过长、成本异常时按以下顺序排查检查 max_tokens 是否设置是否过大。检查系统提示词中是否包含“请详细、请深入、尽量多写”等膨胀指令。检查用户输入中是否自带“详细回答”这类诉求。检查是否有多个召回片段重复拼接进上下文。检查是否打开了需要额外输出大量推理过程的设置。在日志中统计平均输出 Token 和 P95 输出 Token确认问题是否普遍。9. 工程实践与最佳实践建议9.1 在代码层固化 Token 约束不要把控制 Token 的希望完全寄托在产品经理或运营同学手工写 Prompt 上而应在代码层固化约束。具体手段包括为每个调用场景设置默认 max_tokens。通过 response_format 强制结构化输出。在网关层统一打印 Token 日志。对超长输出结果做截断或二次处理。9.2 分场景维护 Prompt 版本同一个模型在不同场景下的 Token 策略应该不同。建议把 Prompt 按场景拆成独立文件并用配置中心或环境变量管理。prompts/ ├── qa_short/ │ ├── system.txt │ └── user_template.txt ├── code_review/ │ ├── system.txt │ └── user_template.txt └── summary_report/ ├── system.txt └── user_template.txt这样每一处 Prompt 都能单独做 AB 测试也不会出现“调了一个 Prompt 影响所有功能”的连锁问题。9.3 建立成本看板推荐把每次调用的model、prompt_tokens、completion_tokens、total_cost写入日志系统然后按天、按用户、按功能聚合。当某个功能的 Token 消耗异常增长时可以第一时间发现并定位到 Prompt 或检索策略变化。9.4 不要忽略运行环境大模型应用通常会运行在 Windows 或 Linux 服务器上依赖 Python、tiktoken、openai等库。Windows 环境下经常出现与 Microsoft Visual C Redistributable 相关的运行时问题尤其是安装或升级 Python 依赖时。如果你在安装tiktoken、pydantic等带 Rust/C 扩展的库时看到类似的报错建议先安装最新版的 Microsoft Visual C Redistributable再重新安装依赖。这虽然不是 Token 优化问题但却是实际落地过程中最常见的环境阻塞点。10. 总结“Tokenmaxxing is not what we are optimizing for”这句话的核心并不是“不要节省 Token”而是提醒开发者真正要优化的永远是业务目标。对于问答系统优化目标是让用户更快拿到准确答案。对于代码生成优化目标是让代码可运行、可维护。对于内容摘要优化目标是让信息密度足够高、遗漏足够少。Token 数量更像是汽车仪表盘上的“油耗”而不是目的地。你当然要关注油耗但方向盘指向哪里才决定你是否能到达目的地。如果你正被“模型输出太长、效果却不好”的问题困扰建议从这几步入手先统计 Token 消耗分布再为场景设置 max_tokens 和 stop 参数接着优化 Prompt 约束和检索召回最后用一套固定测试集评估优化效果。如果你对结构化输出、RAG 上下文压缩或 LLM 评估体系搭建有更多问题欢迎在评论区一起讨论。