
1. 为什么 Token 经济学是商用 Agent 的第一道生死线前两年大家聊 Agent聊的是“能不能跑通”一个智能体能把工具调对、把步骤跑完就够发一篇技术分享了。等到真正往商用方向做摆在面前的第一座山根本不是模型能力而是 Token。 token 经济学这个说法听起来像是成本核算实际上它同时决定了三件事单次请求的响应延迟、上下文窗口的有效利用率、以及整个系统的毛利空间。以一个实际的商用客服 Agent 为例一次普通查询如果让系统提示词加上历史记录冲到 8000 token在主流模型上的推理时间会肉眼可见地慢下来用户等上三四秒就会流失而每一轮对话背后都是实打实的账单。这个账不算清楚架构再漂亮也活不过测试期。我见过不少团队踩同一个坑前期 Demo 阶段用长上下文模型什么历史都往窗口里塞效果确实好开会演示很顺利。一上灰度发现并发一起来成本呈线性甚至超线性上涨某些极端请求甚至能把 128K 窗口直接打满然后模型开始“失忆”最早的信息全部被挤出去回答质量断崖式下跌。这个时候再回头做优化等于把架构推倒重来。所以现在做商用级 Agent第一原则就是在设计阶段把 Token 当作一等公民来对待而不是等出问题了再补救。这篇文章会从 Token 的流向拆起把输入输出的每一分消耗讲清楚然后给出最小化输入、保护上下文的具体策略最后聊一套我实际在用的分层架构。适合正在做 Agent 落地、被成本或者上下文问题折磨过的工程师也适合刚入门、想避开常见大坑的开发者。2. 先搞清楚 Token 流向了哪里Agent 的 Token 消耗全景拆解做优化之前得先知道钱花在哪了。一个典型的 Agent 请求Token 消耗远不止“用户问题 模型回答”这么简单。商用 Agent 的输入 Token 至少包含五个部分系统提示词、历史对话、工具定义、检索结果、用户输入。输出 Token 至少包含三部分推理中间步骤、工具调用参数、最终回答。其中任何一部分失控都会拖垮整个系统。2.1 输入端的五个隐形消耗源系统提示词是第一个容易被忽视的地方。很多人写系统提示词喜欢把角色设定、业务规则、回答风格、禁忌事项全部堆进去动辄两三千 token。我见过最夸张的一份系统提示词写了 6000 多 token里面光是“你是一个专业的客服助手”就换着花样说了八遍。这种冗余在一两次调用里看不出问题但在日均百万请求的商用场景下每多 1 token 都是纯成本而且系统提示词占据的空间直接挤压了真正有用的对话历史。历史对话的膨胀速度比想象中快得多。一个多轮客服场景用户来回追问五次中间穿插工具调用记录历史可能就超过一万 token。更麻烦的是很多 Agent 框架默认把工具调用的完整输入输出塞回历史里比如一次数据库查询返回了 80 行记录这 80 行全部留在上下文里后续每一轮都要重新计算。这是典型的“垃圾进、垃圾出”既消耗 Token 又干扰模型注意力。工具定义是另一个容易被低估的消耗点。现代 Agent 依赖 function calling每个工具都要写清楚名称、描述、参数 Schema。一个中大型系统可能挂了几十个工具光工具定义就能轻松占掉三四千 token。如果工具描述写得啰嗦每个参数都附一大段说明消耗会进一步飙升。而工具定义是每次请求都必须携带的基础开销用户还没说一句话几千 token 已经烧掉了。检索结果取决于你的 RAG 方案。很多系统为了“确保召回全面”每次把 Top 10 文档片段拼进上下文每个片段几百 token加起来又是两三千的消耗。但实测下来真正对回答有帮助的可能只有其中两三段。检索结果不做过滤和重排输入端的浪费会非常可观。用户输入本身反而是最小的一块但也存在优化空间。用户习惯把前情提要复述一遍或者一次性粘贴一大段文本这些都是不可控的输入成本能做的只能是限制最大长度和做预处理裁剪。2.2 输出端的三个隐性放大器很多人只盯着输入端的 Token忽略了输出端。商用 Agent 的输出 Token 消耗往往比想象中大得多原因在于 Agent 不是一次生成就结束而是多次调用模型。每一次工具调用前后模型都要先生成一段推理文本比如“用户想查询订单状态我需要先调用查询接口”这段思维链即使最终不展示给用户也是要计入成本的。工具调用参数是另一个消耗点。模型需要生成符合 Schema 的 JSON 参数这个过程中偶尔会出现“思考半天、反复修改、最后生成一段无效 JSON”的情况。无效生成意味着这一轮的所有 Token 都白花了还得再加一轮让模型自我纠正。最终回答反而是相对可控的部分。只要在参数里限制好 max_tokens回答长度基本能稳定住。但有一个隐藏问题如果前面几轮已经烧掉了大量 Token剩余窗口不足以让模型好好组织回答模型会“敷衍”——草草给一个简短回答结束任务。这不是模型变笨了而是上下文空间被压缩后的自然退化。2.3 实测数据一次真实请求的 Token 账本我之前做过一次埋点统计用的是一套中等复杂度的客户支持 Agent挂了 8 个工具系统提示词大约 800 token。以下是某一次真实请求的 Token 分解消耗来源Token 数占比系统提示词8208.1%历史对话5轮2次工具调用520051.5%工具定义8个165016.3%检索结果3段文档109010.8%用户输入2102.1%模型推理工具调用输出8508.4%最终回答2802.8%合计10100100%这还只是一次单轮请求。如果用户连续问五个问题每一轮都要重新发送全部输入历史越滚越大Token 消耗不是五倍而是更多因为前面几轮的输出也会变成后续请求的输入。看清这个账本之后再谈优化就有了明确的方向历史对话是大头工具定义是固定开销系统提示词是纯冗余重灾区。接下来要做的就是对这三块开刀。3. 最小化输入输出的核心战术从压缩到瘦身的组合拳我见过不少团队说要做优化上来就问“有没有一个参数能全局压缩 Token”。很遗憾没有银弹。Token 最小化靠的是多层战术的叠加每一层省一点合起来效果就非常可观。以下这些方法都是我在商用项目中实际验证过、能直接落地的。3.1 系统提示词的瘦身手术显式指令优于长文本描述很多系统提示词臃肿的根源是开发者不信任模型试图用大量的描述性文字“教育”模型。实际上现代模型对简洁、明确的指令理解得更好。把“你需要像一个专业的、耐心的、友善的客服人员一样在回答用户问题时注意语气温和同时要保证信息的准确性不要编造你不知道的信息”压缩成“你是客服。语气专业。不确定就说不确定”效果反而更好Token 直接从几十降到个位数。我建议的系统提示词结构是分层级的。第一层是固定核心层包含角色、全局规则、安全边界这部分尽量压缩到 300 token 以内第二层是业务层根据当前对话场景动态加载比如用户进入售后流程时才加载售后规则平时这部分为零第三层是实例层存放本次对话的临时状态和上下文摘要。这样的分层结构能把系统提示词的整体体积砍掉一半以上。另外要特别注意系统提示词中的 few-shot 示例。很多人喜欢在系统提示词里塞三五个示例对话每个示例几百 token目的是让模型学会调用格式。这在早期模型上确实必要但现在的模型对工具调用的理解已经很强大部分场景删掉示例完全不影响效果。真要保留示例最多留一个最短的而且一定要用真实案例来写别编造那些“理想化”的对话——模型会模仿示例的语气和长度示例写得多啰嗦回答就有多啰嗦。3.2 工具定义动态裁剪只给 Agent 够用的工具工具定义占用的 Token 几乎是纯浪费因为它大多数时候都不会被调用。比如一个系统挂了订单查询、物流跟踪、退款处理、发票开具等 20 个工具但用户这次只是问“你们几点下班”模型根本不需要知道退款参数怎么填写。只要模型能看到全部工具它就需要处理这些定义输入端就会膨胀。解决方案是给工具做一层路由预筛选。在 Agent 入口增加一个轻量级的意图识别环节根据用户输入判断可能涉及的功能域只把相关工具的定义注入当前请求。比如用户提到“退款”就加载退款和订单相关工具其他工具全都不带。实测下来这种动态裁剪能把工具定义 Token 从 1650 降到 400 左右效果非常明显。工具描述的写法也有讲究。每个工具的描述要控制在两句话以内第一句说清楚功能第二句说清楚适用条件。参数 Schema 要精简只保留必填参数可选参数尽量用默认值兜住。我见过一些团队把工具描述写成小作文光一个工具的说明就有三百 token完全没有必要——模型理解工具靠的是参数名和类型描述只是辅助信号。3.3 输出端约束用结构化输出管住模型的嘴输出端最重要的优化是限制思维链的长度。很多 Agent 框架默认会引导模型“先思考再调用工具”但思考的详细程度是可调的。把系统提示词里的“请逐步分析用户的意图”改成“直接调用合适的工具”模型就会大幅减少废话输出。如果业务场景确实需要推理过程可以让模型只输出结论式的简短推理比如“需要查询订单”而不是一小段完整的心路历程。对于需要结构化输出的场景比如让模型填一个 JSON 对象现代模型普遍支持 response format 约束。开启这个功能后模型会严格按照给定 Schema 生成结果不会再输出多余的 Markdown 代码块、解释性文本或者“以下是结果”这种废话。这不仅是格式规范问题更是 Token 节省的利器——每一轮工具调用能省下 20% 到 30% 的无效输出。还有一个常被忽略的参数max_tokens 的精细设置。很多人习惯给一个很大的上限比如 4096模型在生成最终回答时往往真的会写到接近上限。其实大部分客服回答三四百 token 足够了把 max_tokens 压到合理范围模型会自己调整回答的详略程度。这里有一个技巧max_tokens 不能太小否则模型可能在回答中途被截断反而触发重试机制导致更多消耗。合理的做法是先统计历史回答的 P95 长度然后设定在这个数字的 1.5 倍左右。3.4 输入修剪的技术细节缓存、长度控制与分段加载谈到输入最小化还必须提一下现阶段的 Prompt 缓存机制。目前主流模型几乎都支持自动缓存历史对话中相同的部分按较低价格计费缓存的命中率直接决定了长期成本。想让缓存命中率高就不能在对话中途随意修改系统提示词。系统提示词的任何一点改动哪怕只是加了一个标点都会让缓存完全失效整段重新计费。所以系统提示词应该尽量保持静态动态信息通过消息序列的方式追加而不是直接改提示词本身。历史对话的长度控制也是必须做的。一个简单的策略是维护一个 token 计数器超过阈值就触发截断或摘要。具体来说把对话历史切成两部分最近 N 轮对话保持原样保留更早的内容先交给模型做一次摘要压缩摘要的 token 量控制在原文的十分之一左右。这样既保留了关键信息又不会让早期对话无限膨胀。有些框架提供了自动消息剪枝能力但不建议直接依赖自己掌控摘要逻辑更可靠。输入端的最后一道防线是长度预警。每次请求发送前先计算本轮总 token 数如果超过预设的安全阈值比如窗口大小的 60%就触发降级策略优先压缩历史、裁剪工具定义实在不行就引导用户开启新会话。这套逻辑做成中间件之后线上再也没有出现过上下文打满导致回答崩溃的故障。4. 保护上下文的战略设计不把鸡蛋放在一个篮子里最小化输入输出解决的是“怎么省”的问题但省下来的空间如果全被历史对话占满照样没法用。保护上下文的核心思路是让 Agent 永远只持有当前任务真正需要的信息其余内容放到窗口之外的可检索存储中。这不是一个技巧而是一套架构思维。4.1 上下文不是保险箱理解窗口的有限性与注意力衰减很多人对上下文窗口有一个误解128K 的窗口很大足够装下一整本小说Agent 应该能记住所有细节。但实际使用时模型对窗口内不同位置的注意力分布很不均匀。中间位置的信息最容易在长上下文中被“稀释”系统提示词和最新对话占据的注意力权重最高中间的早期历史常常形同虚设。这就是为什么有些对话中模型会突然忘记用户五分钟前说的关键信息不是模型坏了是注意力机制下的正常现象。所以保护上下文的本质不是“塞得更多”而是“让重要信息始终处于高注意力区域”。两个主要手段一是把最重要的指令放在系统提示词和最新消息这两个高注意力位置二是把不再需要的高频低importance信息移出窗口。理解了这一点就不会被“128K 就是 128K”的表象迷惑。4.2 记忆分层工作记忆、短期记忆与长期记忆我在实际架构中把记忆分成三层对应的处理策略完全不同。工作记忆相当于当前任务进行中的临时信息比如“用户正在对比两款产品的价格”。这部分必须完整保留在窗口内因为 Agent 推理时需要即时访问。工作记忆的维护策略是只保留当前任务的必要信息任务结束立即清除。短期记忆指当前会话中已经发生过、可能还会用到的信息比如用户之前提供的收货地址、偏好说明。这部分可以通过摘要的方式保留。摘要不是简单截断而是提炼出关键事实比如“用户地址某市某区某街道 5 号要求发货前电话确认”。一段五百 token 的原始对话压缩后可能只需要五十 token信息密度提升十倍。长期记忆指跨会话的信息比如用户的历史订单记录、之前投诉过的内容。这部分永远不应该直接塞进上下文窗口而是存到外部的向量数据库中。每次用户发起新会话时通过检索只召回最相关的几条记忆注入窗口。这套三层记忆体系的核心原则是尽可能让上下文窗口里只装当前任务的真信息其余全部外包。4.3 上下文压缩的正确姿势摘要、蒸馏与关键信息提取说到上下文压缩大部分人第一反应是“让模型总结一下前面的对话”。这个方向对但细节里全是坑。朴素做法是每次对话超长就直接丢给模型“请总结以上内容”得到一段泛泛的梗概结果后续 Agent 真正需要的具体信息全丢了。比如用户之前留下了一个退款单号通用摘要会写成“用户咨询退款问题”单号被吞得干干净净。正确的压缩方式是指定摘要的 schema强制模型输出结构化要点而不是自由文本。我常用的摘要格式是 JSON包含以下字段用户的明确意图、待办的未解决问题、已确认的关键信息订单号、地址、金额等、涉及的工具调用记录、应该继续推进的下一步。把摘要的格式固定下来之后压缩结果就从“散文”变成了“结构化数据库记录”后续 Agent 使用时可以直接提取字段信息丢失率大幅下降。压缩的时机也有讲究。不要等窗口快满了才压缩那样压缩过程的输入本身就可能超限。建议设置一个水位线当 token 占用超过窗口的 50% 时启动一次压缩把最旧的 30% 历史交给摘要模型处理。压缩过程本身也要计入成本所以摘要模型要选便宜的型号而不是用主模型。主模型负责复杂推理摘要模型只需要做信息提取两者职责分离单位成本差距可能是十倍以上。4.4 滑动窗口、全量摘要与混合策略的取舍目前业界常见的上下文管理策略有三种滑动窗口、全量摘要、滑动窗口加摘要混合。滑动窗口实现简单只保留最近 N 轮对话但代价是早期信息必然丢失。全量摘要把所有历史全部压缩成一段摘要信息密度高但实现复杂而且摘要与实时对话的衔接容易出问题。我实际在用的是混合策略最近 5 轮对话完整保留滑动窗口5 轮之前到更早的内容做摘要摘要层再往前的跨会话信息走向量检索。这个策略的实现细节在于摘要频率的控制。每轮对话结束新消息进入窗口累计出现三条新消息且窗口占用超过水位线就触发一次增量摘要把最老的一轮对话并入现有摘要中。通过这样的滚动更新摘要始终保持最新不用等到超长再一次性压缩单次压缩的成本也更低。混合策略的另一个关键点是要给摘要层预留一份“原始线索索引”。比如订单号、日期、金额这类具体数据摘要里保留同时额外存一份键值索引后续如果需要精确值直接从索引里查不依赖模型从摘要文本中猜测。这个设计在实践中帮了大忙很多次用户追问“我当时说的收货地址是什么”Agent 都能精确回答而不是给出一个模糊的位置描述。5. 商用最强 Agent 架构的实战剖解一套可复用的分层系统前面的章节讲的是战术这一节把这些战术组装成一套完整的架构。这个架构来自我为某中型电商团队设计的商用量产 Agent经历了日均几十万次请求的检验我把它整理成一套可以直接套用的模式。5.1 总体架构路由层、上下文管理层、执行层三层拆解整个系统从入口开始就分流。第一层是路由层负责理解用户意图判断应该走哪个业务 Agent。第二层是上下文管理层负责维护和优化每一路请求的上下文窗口。第三层是执行层由多个按业务域划分的子 Agent 组成比如订单助手、售后助手、产品顾问每个子 Agent 只持有自己的工具和上下文。分层架构带来的直接好处是上下文隔离。用户同时在咨询订单问题和退款问题如果只有一个 Agent 处理两个业务域的历史会互相干扰Token 也会叠加。拆成两个子 Agent 之后每个 Agent 的窗口里只装自己域的内容总消耗反而大幅下降。路由层本身非常轻量只需要一次意图分类输入输出 Token 都控制在很小的范围。路由层的设计要特别注意一点路由错误会导致用户走错业务 Agent整个对话要从头开始。所以路由分类的置信度要高不确定时宁可让用户确认一下也不要直接反向分发。我在实际项目中加入了一个兜底逻辑路由层输出低置信度结果时走通用 Agent 而不是强行分流通用 Agent 可以在对话过程中将用户重定向到正确的子 Agent。5.2 上下文管理层把 Token 预算做成可观测、可干预的资源上下文管理层是这个架构里最核心的部分。它不是一个单纯的“记住历史”的模块而是一个持续运行的状态机管理着每个会话的 Token 预算。我给它设定了几条硬规则第一每个子 Agent 的窗口占用率不允许超过 70%超了就触发压缩第二单次请求的总消耗不允许超过设定的业务预算超了就降级模型第三所有压缩动作必须留有审计日志方便事后排查信息丢失问题。Token 预算的表达方式不能是抽象的数字而是跟业务指标挂钩。比如我的做法是给每个客服会话分配一个成本上限大约相当于 0.02 元。系统实时统计每一轮请求消耗的费用一旦逼近上限就自动切换策略关闭工具调用改用直接回答或者把主模型切换为便宜的轻量模型确保单个会话永远不会亏损。这种硬性预算机制倒推着系统把每一分 Token 用到刀刃上。上下文管理层还要负责工具上下文的组装。前面的路由层确定了业务域之后上下文管理层就从这个域的工具清单里过滤出本次请求需要的工具再拼进系统提示词。这一步看似简单却是整个架构里对 Token 节省贡献最大的环节之一。5.3 一个完整的请求生命周期示例为了讲清楚这套架构怎么协同工作我以一个真实场景为例用户发来一条消息“我上周买的耳机左边没声音了想退货”。请求经路由层分类判定为售后意图置信度较高分发到售后子 Agent同时附加一个标签用户可能处于退货流程。售后 Agent 的系统提示词由三部分拼装全局核心规则约 200 token加上售后业务规则约 300 token加上退货流程专属说明临时加载约 150 token。工具定义只加载售后域下的订单查询、退换货申请、物流查询三个工具共约 400 token。上下文管理层检查该会话的历史发现之前有一次用户咨询过产品使用问题约 1200 token 的历史与本次退货需求不直接相关于是触发摘要压缩把这段历史压缩成 120 token 的结构化摘要。当前窗口中保留的完整对话只有最近两轮。因此本次请求的总输入约为650提示词加上 400工具加上 120历史摘要加上 40用户消息总计大约 1210 token相比未优化时的上万 Token压缩率接近九成。执行层拿到输入后模型调用工具查询订单信息确认订单在退货期内然后生成退货指引。整个过程的输出 Token 控制在 600 以内。这笔请求的全部成本大约是未优化场景下的八分之一到十分之一响应时间也大幅缩短。这组数据不是我编造的而是真实压测环境下统计到的典型值。5.4 模型分层选型什么任务用什么模型省一半的账模型选型直接决定了 Token 单价的基准。现在很多商用 Agent 主打一个模型打天下功能都能做但贵。我在架构里把模型分成三层底层负责路由分类和意图识别用最便宜的轻量模型就足够中层负责摘要压缩和实体抽取用中价模型顶层负责复杂推理、工具调用和最终回答生成用最强的主力模型。一层简单的分流就能让成本结构发生质变。实测中路由和摘要占全部请求的 40% 以上但这两块用轻量模型处理单价可能只有主力模型的十分之一。整体算下来Token 成本能再降低三成左右。不过模型分层有一个要避开的坑消息格式不兼容。不同厂家模型的 tool calling 参数格式不一样如果路由模型和主模型来自不同厂商消息拿过来直接用可能解析出错。稳妥的做法是统一封装一层适配器把不同模型的输入输出格式都转成内部标准格式。我用过两种方案一是自己做轻量转换层二是直接用兼容性较好的统一 API。两类方案都可行关键是要在早期就确定下来避免后期切换成本过高。6. 常见问题与排查技巧实录我在 Token 治理路上踩过的坑这部分是真正的实战记录。以下问题几乎每个商用 Agent 团队都会遇到我按出现频率和破坏力排序整理成表并给出我的处理方法。现象根因解决方案对话越长回答越差历史对话挤占窗口注意力稀释设置水位线触发压缩保留最近轮次工具调用频繁失败工具定义裁剪太狠模型不理解关键工具禁止裁剪保留完整描述用户追问早期信息答不出压缩摘要丢失具体字段摘要强制结构化建立键值索引成本突然飙高缓存失效系统提示词被改动提示词静态化动态内容走消息层模型输出长期超长max_tokens 设置过大按历史长度统计设定合理上限路由判断错误意图分类模型过弱低置信度走通用Agent兜底第一个坑我必须单独拿出来说。项目上线初期我为了追求极致的 Token 节省把工具定义裁剪得非常狠——只保留工具名和两个必填参数描述全部不要。结果模型在调用工具时频繁生成错误参数系统反复重试每轮重试都在烧 Token最终算下来比不裁剪还贵。这个教训让我明白了一个原则Token 优化不能牺牲任务成功率。工具裁剪的底线是保证模型能正确调用砍到哪里需要小流量验证而不是直接一把梭。第二个值得记录的坑是摘要压缩的“过拟合”。一开始我让摘要模型输出自然语言总结测试的时候看摘要还挺像回事模型也能读懂。但产品上线后发现一个隐蔽问题摘要中的具体数字经常被模型“脑补”——订单号从 123456 变成了 123450日期从 5 月 12 日变成了 5 月 20 日。这种幻觉在自由文本摘要里几乎无法避免所以才有了前面提到的结构化摘要和键值索引方案。从那以后凡是关键业务字段一律走枚举和索引绝不让摘要模型自由发挥。第三个坑是关于缓存的设计。早期为了动态适配业务规则我经常在系统提示词里插入一些临时指令比如这次大促加一条“满 300 减 50 优先推荐”。结果每条临时指令都导致缓存前缀失效全量重新计费日成本瞬间翻倍。后来我改成把临时指令作为用户消息前缀追加而不是修改系统提示词缓存命中率重新回到 90% 以上。从架构设计的第一天起就要把系统提示词当作不可变资产来维护任何动态内容都不要往里面塞。7. 回顾与补充把这些经验落到自己的项目里如果你正在规划或者维护一个商用的 Agent 系统我最想强调的不是某一个具体的压缩算法或框架而是一个整体视角Token 经济学不是一个优化环节而是一个贯穿架构设计的底层约束。从选择模型、设计提示词、划分工具集到规划路由逻辑、决定状态存储方式每一步都在影响 Token 的流向。在项目早期就建立预算意识、可观测的监控面板和自动压缩机制后期能避免大量的返工成本。根据我在多个项目中的实操摸索最推荐的落地顺序是先埋点统计 Token 流向搞清楚钱花在了哪里再砍掉最大的浪费源通常是系统提示词和工具定义然后建立上下文管理层引入摘要压缩与水位线最后做模型分层和缓存优化。每一步都通过压测和灰度验证效果而不是一次性推到全量。这个顺序能让你在最短时间内看到成本下降同时保持系统的稳定。最后再分享一个小细节Token 优化无止境但到了一定程度之后边际收益会迅速递减。我最开始优化的时候把单次请求从 10000 token 压到 2000 token成本下降八成费了很大劲。再往后想从 2000 压到 1500付出的工作量几乎一样多收益却不明显。做任何优化都要设置一个合理的止损点比如“单次请求控制在 2000 token 以内且回答质量不下降”达到了就收手把精力放到系统稳定性、数据安全和用户体验上。说到底Agent 的价值在于解决真实问题Token 只是实现这个价值路上的一段桥桥修好了能过去没必要雕花。