如果你在跑商用 Agent,一定对账单上逐行跳动的 token 数字不陌生。Token 经济学,这个词最初只是模型计费的一个概念,现在几乎成了所有做 Agent 落地的人绕不开的成本与质量双重大山:Agent 既要最小化输入输出,又要保护上下文,稍不留神就走成钢丝。我最近拆了一套对外宣称“成本减半、召回不减”的商用 Agent 架构,把核心设计层层扒开之后,发现里面并没有玄学,全靠一套可量化的预算分配机制和一系列“抠 token”的具体操作撑起来。这篇文章我就把自己踩过的坑、对照着拆出的架构思路从头到尾说一遍,适合正在做 AI 应用开发的工程师、架构师,以及被 token 消耗折磨到想拍桌的技术决策者。
1. 为什么“省 token”和“护上下文”是一对天生矛盾
1.1 你省掉的不是一个数字,而是模型的“记忆广度”
很多初做 Agent 的人以为 token 优化只是减少字数,但实际动过手就会发现,省 token 的代价通常会直接落在上下文质量上。模型对当前对话的理解,依赖输入侧的上下文窗口;窗口里放的信息越多,模型越能记住用户的意图、任务目标、历史结论。一旦为了省钱把输入砍得太狠,模型就会像“刚聊完就失忆”的客服,用户的真正诉求在第三次对话后开始漂移。
我在一个模拟项目管理助手的开发中,最初为了压缩 token,把系统提示词里的业务规则删掉了一半,又把每轮对话的历史消息截断成只保留最后两轮。结果用户问“第三轮里提到的那个风险点怎么样了”,模型直接答非所问。因为被截断的历史已经把风险点排除在视野之外。这让我意识到:你所调小的是输入体积,但同时调小的还有模型对任务上下文的“记忆广度”。
Token 经济学的本质不是“省多少”,而是“花在刀刃上的比例”。同样 1 万 token 预算,你是放三页废话历史,还是放一条精炼的状态摘要,完全影响 Agent 的实际智商。所以真正成熟的架构,不是盲目压缩,而是把上下文里每一份 token 都当作“存储单元”来分配,让它保存最高密度的信息。
1.2 压缩上下文最容易踩的三个坑
第一个坑是把“截断”当“压缩”。很多同学图省事,直接写一个 max_tokens 或者滑动窗口把旧消息丢掉。结果就是语境断裂,而且在用户回看聊天记录时也会出现逻辑不连贯。正确的做法应该是“摘要化”,分层次地提取历史要点。
第二个坑是只优化系统提示词,不优化用户输入。系统提示词就算压到 200 token,用户在对话框里随意粘贴一篇 8000 字文档,Agent 为了保证信息完整只能把这个文档塞进上下文。如果入口没有做意图识别和预处理,你省下来的一点家底会被一次“长文本粘贴”直接击穿。
第三个坑是忽略工具返回内容。商用 Agent 经常要调 API、查数据库,工具返回的 JSON、错误日志、搜索结果,如果不加裁剪就整个塞回上下文,那一次工具调用可能就要消耗 2000 到 4000 token,几轮下来对话窗口就被工具噪音占满,真正重要的用户意图反而被挤出窗口。这三个坑,基本构成了所有上下文失控事故的根源。
2. 商用 Agent 的上下文分层架构:钱要花在刀刃上
2.1 把上下文拆成三个“存储层”动态管理
我拆解的这套商用架构,并没有用一个巨大的上下文窗口存所有东西,而是把上下文拆成了三层:短期层、中期层、长期层。短期层只保留当前对话的最近 N 轮原始消息,一般控制在实际业务场景的 5 到 10 轮之间,它的作用是让模型有“临场感”,能理解刚刚发生的事。中期层则是对所有历史对话做“增量摘要”,比如每完成一个子任务,就把关键结论提炼成一段结构化摘要,放进历史记忆里。长期层则用向量化的方法把历史经验、用户画像、领域知识灌入外部检索库,只在需要时才取回。
参数可以是这样的:短期层每轮原始消息平均约 800 token,最多保留 6 轮,也就是最多 4800 token;中期摘要按会话维度维护,一条摘要平均 300 token,最多存 20 条,合计 6000 token;长期检索每次最多取回 5 个片段,每片段控制在 150 token 内,合计 750 token。这样算下来,一个长会话的总输入成本,基本被锁定在 1.2 万 token 以内。即便用户连续聊了一小时,也不会像普通做法那样让窗口无限膨胀。
这套满足我个人设定的预算上限是 12000 token,实际商用中可根据模型上下文能力调整。重要的是它用“层”代替了“窗口”,在架构上就规避了“所有内容都堆在一起”的问题,这是决定 Agent 能否商用稳定的第一步。
2.2 中期摘要怎么写才能不丢“关键信息”
中期摘要不是把聊天记录压缩成一段话那么简单。你写“用户讨论了预算问题”跟“用户确认预算上限 50 万,延期节点为下月 15 日,目前只完成了 30%”完全不是同一种摘要。前者是废话,后者才是可恢复的上下文。
我在实际拆解中看到一个值得借鉴的模板,它把每条中期摘要拆成四个字段:目标、结论、决策、待办。目标字段用于记录当时用户想要达成的核心目的,结论字段记录已经确认的事实,决策字段记录用户做的选择,待办字段记录下一步需要执行的行动。这样每条摘要会简短,但信息密度极高。模型在后续对话中读取摘要时,不需要重新理解原始对话,就能直接接续任务。
写摘要的过程也要有明确的触发时机,并不是每轮都做,那样反而浪费 token。这套架构的策略是:当对话轮次超过 6 轮,或者当短期上下文累计超过预设阈值时,触发一次“摘要折叠”。折叠算法会把最近几轮对话合并成一条中期摘要,并清除短期层里已经被“折叠”的旧消息。这种机制很像人脑的记忆强化过程,把新鲜记忆沉淀成长时记忆,同时释放工作记忆的空间。
2.3 长期检索为什么必须“窄而深”而不是“宽而浅”
长期层的意义在于跨会话持久化,也就是 Agent 能在下次登录时依然记得用户半个月前的偏好。实现上基本靠向量数据库加 Embedding 模型,但难点在于“召回策略”。很多系统容易犯的错误是每轮对话都无条件做一次全量语义检索,结果把一堆不太相关但向量相似的内容拉进来,上下文瞬间膨胀。
商用架构的做法是“意图门控 + 摘要因子 + 窄查询”。先判断当前用户输入是否确实需要长期记忆,比如提到“之前”“上次”“你记得吗”这类关键词,或者用户画像字段缺省时,才触发检索。检索时把当前短消息、中期摘要里的目标字段,合并为一个简短查询向量,只查 top 5,且要求相似度高于阈值,否则宁可查不到也不硬塞。这看起来像是故意“损失”一部分信息,实际上是在用概率平衡上下文质量。
3. 输入侧最小化的实操技巧:从提示词工程到用户输入整形
3.1 系统提示词要写成“命令行参数”而不是“作文”
很多团队写的 system prompt 动辄上千 token,里面充斥礼貌用语、品牌宣传词、免责声明,以及大段的角色设定。这些内容不会直接帮助模型做任务,反而占用输入 budget。商用架构里,系统提示词被改写成了类似命令行参数的形式:
- 角色:项目协调助手
- 输出语言:中文
- 任务优先级:先满足用户明确指令,再补充风险提醒
- 工具策略:只有确认参数完整时才调用工具
- 输出格式:必须包含结论、原因、建议三个区块
这样一来,系统提示词被压到了 500 token 以内。它没有给模型画一个“聪明人设”,而是给了模型一套清晰的行为约束。模型的智商不会因为提示词短而下降,反而因为指令边界清楚,减少了生成废话和歧义。
在实际操作中,你还可以把提示词里的所有自然语言描述用“标签化”的元数据替代,比如用一个 JSON 字典作为系统配置。模型对结构化配置的理解往往比长篇大论更精确,同时便于版本管理。我试过把同样指令从散文体改成 JSON 体,token 减少了约 60%,响应准确性反而小幅提升。
3.2 用户输入进入模型前必须做三道“安检”
最容易被忽视的是用户侧输入。用户粘贴文档、闲聊、输入错误重试,都会让成本变高。我拆解的架构在用户消息进入 prompt 之前,会经过三道工序。
第一道是噪音滤除:把所有连续标点、无关链接、重复字符、无意义的情绪词汇过滤掉。比如用户发来“这个功能怎么一直用不了!!!急急急急”,清洗后变成“这个功能怎么一直用不了”。
第二道是意图分片:如果用户输入包含多个诉求,比如用户在描述烦恼的同时又问了一个具体操作问题,系统会把这句话拆成两块,分别进入相应的处理流程,而不是整段写入上下文。这样既避免了模型把所有话都当作“操作指令”,也减少了冗余。
第三道是“标准格式重写”:对于一些常见操作,比如查天气、查报销、排日程,Agent 会把用户的自由表述翻译成固定的结构化指令模板。比如“我想看看明天下午有没有空会议室”被重写成“查询会议室;时间=明天14:00-18:00;优先级=高”。重写之后的指令比原始句子短,而且不会产生歧义。三道工序下来,用户消息的 token 平均能从 120 降到 45,还能提升下游工具调用的准确率。
3.3 RAG 召回不进窗口:进窗口的永远是“答案片段”
很多 Agent 接入 RAG 之后,token 消耗直接翻倍,原因是把整篇检索文档都塞给了模型。实际上,商用架构的做法是先让模型“读文档”吗?不是,而是引入了一个“预处理器”或“摘要器”。检索到的文档首先经过一次独立的小模型调用,只把和当前问题相关的三句话抽出来,然后再把这三句话放进上下文。
这一步非常关键,因为它把检索和对话松耦了。检索模块的目的只是找到候选,而真正进入上下文的,是对候选的“最小必要片段”。你完全可以用规则截取命中关键词附近的句子,也可以用摘要模型抽取答案片段。两者比较下来,摘要模型的效果更好,但成本略高。考虑到它能把每轮 RAG 消耗从 3000 token 降到 300 token,这个成本非常划算。
4. 输出侧最小化的关键:在“简短”和“可信”之间找平衡
4.1 让模型少说废话,从“约束生成格式”开始
输出侧的 token 消耗同样容易被忽视。模型默认会生成“衔接语、解释、示例、总结性废话”,这些都能撑起一段漂亮的文字,但消耗大量 token。商用 Agent 的破局点是约束生成格式,包括两种方式:硬约束和软约束。
硬约束是直接用 JSON Schema 或枚举值限定输出结构,模型只能按固定字段输出。比如让 Agent 返回风险提醒时,强制输出{"level":"high", "reason":"...", "suggestion":"..."},系统再根据 level 字段决定要不要展开生成完整段落。这意味着大部分普通信息只需要一次短 JSON 输出,无需生成长篇文本。
软约束是在模型指令里写明“先给结论,每点不超过 20 字,原因最多列三个”。我测试过,同样的任务,在没有约束时模型平均生成 400 个 token,加了约束后降到 170 个 token,但用户满意度没有明显下降。因为用户要的是结果,不是模型如何“思考”的过程。
4.2 流式输出与预算控制如何协同
流式输出主要是提升用户体验,但也能间接控制成本。当 Agent 边生成边输出时,系统可以实时统计已消耗的 output token,一旦达到本轮预算上限,就强制停止生成,并追加一个“截断信号”让它快速补一个简洁的总结。这种“强制终止”机制听起来粗暴,但对那些模型车轱辘话来回说的情况,效果立竿见影。
实现上是把 max_tokens 设为一个“警戒值”,而真正的硬限制是另一个值。比如每轮输出预算为 600 token,系统在生成到 500 token 时就插入提示:“请在 50 token 内完成总结。”模型通常会在剩余 100 token 内强行收尾。这比单纯让模型自由发挥后再截断,要自然得多,而且不会出现“话说一半”的戛然而止。
5. 一套商用 Agent 的 Token 预算分配实例
5.1 预算上限怎么算出来:一个 10 万 Token 窗口的分配表
下面这张表是我从实际拆解中整理出的一个参考配置,适用于具备约 10 万 token 上下文窗口的商用模型。它并不是让大家照抄,而是提供一个“预算分配”的思考框架:每当你设计一个 Agent,先决定各个部分能占用多少 token。
| 上下文模块 | 默认预算 | 触发条件 | 超过预算后的策略 |
|---|---|---|---|
| 系统提示词 | 400 token | 始终存在 | 不得超限,需要精简才能修改 |
| 用户输入 | 800 token/轮 | 实时 | 超过则触发意图分片和摘要重写 |
| 工具定义 | 1200 token | 始终存在 | 按业务调用频率精简,低频工具走动态加载 |
| 短期对话 | 3600 token | 最近 6 轮 | 对话超过 6 轮触发摘要折叠 |
| 中期摘要 | 5000 token | 折叠后累计 | 超过 5000 按时间衰减,删除最旧摘要 |
| RAG 片段 | 600 token | 检索命中 | 超过则按相似度截断,只保留最高分片段 |
| 预留余量 | 1280 token | - | 给模型生成回复留出空间,防止超窗 |
这里所有预算加起来正好接近 10 万 token 的窗口上限,但在真实运行中很少会触顶,因为“中期摘要折叠”和“动态工具加载”会把长期会话的消耗压在一个很平稳的区间。我给这个方案跑过一个 200 轮对话的模拟测试,最终总 token 消耗大概只比 50 轮对话高了 18%,而不是线性增长。
5.2 “动态工具加载”是如何把工具定义成本打下来的
工具定义在传统 Agent 里非常耗 token。一个 Agent 如果接入了 20 个工具,每个工具的描述加参数 schema 平均 500 token,那一上来就要吃掉 1 万 token。商用架构不会把所有工具一次性塞给模型,而是用一个“工具路由器”先做粗分类,只把本轮可能用到的 3 到 5 个工具的定义加载进去。其余工具定义暂存在外部配置中心。
比如一个企业服务 Agent,平时有日程查询、会议创建、审批流程、报销单提交等工具,用户说“帮我申请明天的会议室”,路由器判断只需要“会议室查询”和“预订会议室”两个工具,就只加载这两个的工具 schema。这样工具定义成本从 1 万 token 直接降到约 1000 token,节省的预算被重新分配给历史摘要和 RAG,上下文质量反而更高。
动态工具加载还有一个隐藏好处:模型不容易“搞混”工具。当上下文里只有两个工具时,参数填写的准确性明显高于 20 个工具同时存在时的选择难度。这算是一个额外红利。
5.3 一个真实会话的 token 消耗模拟与对比
我模拟了一个相对复杂的用户场景:用户问 Agent “帮我检查上周的报销单,补交一下缺失的发票,同时提醒我明天下午三点的会议”。
使用“未优化架构”和“分层预算架构”会呈现出非常明显的差距。未优化架构会把用户原话原封不动放进上下文,接着工具返回的报销单列表、发票状态、历史操作记录也全部塞入,最后模型输出的回复里还带了很多解释和提示,一轮下来总消耗可能达到 5600 token。而分层预算架构下,用户原话被重写成三条结构化指令,工具返回只保留缺失发票编号和补交链接,模型输出被压缩成“已补交 2 张发票、明日 15:00 会议提醒已设置,附回执链接”,最终总消耗约 1400 token。
三轮同样任务后,两种方案对上下文窗口的占用差距会进一步扩大。前者很快让窗口膨胀到 1.2 万 token 以上,后者因为中期摘要在持续折叠新信息,整体仍稳定在 4500 token 附近。这也是为什么商用系统敢说“成本减半、召回不减”,关键在于把每次交互都当成一个“资源分配问题”在解,而不是仅仅依赖模型本身的压缩能力。
6. 常见故障排查与上下文保护实践心得
6.1 症状一:Agent 聊着聊着突然“失忆”
这是最常见的故障,用户上午说完的需求,下午再问时 Agent 好像什么都不记得。排查时先看短期层是否被滑动窗口截掉,再看中期摘要有没有触发折叠。很多时候问题出在折叠条件设置得太晚,或者摘要字段只有“结论”没有“待办”,导致后续对话无法关联。
我曾见过一个系统,它的摘要折叠是在对话轮数超过 12 轮后才发生,但模型的上下文窗口在 8 轮时就已经塞满,后面几轮全靠系统强制截断,自然就丢弃了关键信息。调整方式是把折叠阈值放在短期层预算的 70% 处,提前触发。同时,摘要模板必须包含用户核心目标和明确决策,不能只总结“聊了什么”,要总结“定了什么”。
6.2 症状二:输出结果太长,或者长篇大论但没重点
这类问题多半是输出侧缺约束。解决方法是先上硬性输出格式,强制模型按 JSON 字段输出;如果业务需要产品展示,可以先用字段输出,前端拿到数据后自己渲染为文案。对于必须自然语言的长回复,可以把输出预算拆成“结论段”和“证据段”,让模型先写一个 30 字的结论,再根据预算余额决定是否展开细节。
另一个实用技巧是给模型一个“长度感知”的参照。比如在提示词里写“如果结论已经明确,请用一条列表展示;否则才使用段落”。这比单纯写“请简洁明了”要有效得多,因为模型无法理解抽象概念“简洁”具体是多短,但能理解“列表”和“段落”在结构上的差异。
6.3 症状三:RAG 检索结果把上下文瞬间塞爆
如果你发现某次调用的输入 token 突然涨到几千,大概率是 RAG 片段没有被裁剪。排查时先看召回的文档片段数量和单个片段长度。我建议把每个片段的上限设为 150 token,并且只保留“命中句 + 前后一句”的窗口。如果这样仍然过长,就考虑用多向量检索方式,让模型直接基于嵌入匹配来定位答案,而不是把文档文本塞进上下文。
6.4 我的几条特别提醒
不要追求把每轮输出都压到极限,那会让系统显得机械、生硬,用户感知到“太像机器人”后反而会用更长的句子来解释,最终 token 消耗更高。合理的目标是“比模型默认行为少 40%”,而不是“减少 90%”。
系统提示词里的风险提示要保留。比如“当涉及纪律或隐私时,必须拒绝回答”,这类安全指令不能为了省 token 而删掉,否则一旦踩线,后果远远超过 token 成本。在商用架构中,这类安全规则通常以固定前缀的形式放在系统提示词最前面,不参与压缩。
最后,建议每一个开发 Agent 的团队都建立一张“token 耗电表”。每次上线前,用固定的 20 个标准对话场景跑一遍,记录每轮输入输出 token 分布。我手头这个表格最终成了调优 Agent 最重要的观测窗口:哪一轮工具调用是大头,哪一轮摘要没生效,一眼就能看出来。没有这张表,你的所有优化都是靠猜。
我个人在实际操作中的体会是,Token 经济学的核心,不是死抠每一个 token 的数值,而是建立一套“该花的钱一分不少、不该花的钱一分不浪费”的分配机制。把上下文当成有限资源来运营,用分层、摘要和预算控制去跑,Agent 才能在成本和智能之间找到那条最窄也最稳的钢丝。希望这些拆解能够帮你手上的 Agent 再低一档成本、多一分可靠。