Token优化是四件事:先用模型tokenizer度量、shape压缩后再送请求、相同内容缓存只付一次费、最后用配额和输出限制兜底。SmartGate实现全部四步并给出具体数字。
简短回答:AI 应用的 Token 优化是同一条请求链路上的四项 Disciplines(纪律):在消耗 Token 之前先计量、在模型看到请求之前先塑形和压缩、缓存和路由以避免同一段内容被重复计费、以及用配额和输出限制封顶循环。SmartGate 在网关代码中实现了全部四项,本文将展示背后的机制和数据。
使用模型自身的分词器来计量。返回整数的结果才可被配额比较;字符估算无法做到。
先塑形再封顶。压缩和去重减少了模型需要读取的内容,这比请求构建完成后拒绝它更划算。
每个客户端一个 URL。托管的 MCP endpoint 替代了每个工具对应的私钥,主机配置是网关生成的简短 JSON 文件。
缓存重复内容而非决策。预算快照的 45 秒窗口是可以接受的;但缓存授权决策则不行。
统计节省量。两个审计字段将"我们压缩了某些内容"转化为财务团队能理解的数字。
最后一道防线是封顶。当塑形、缓存和路由都不足以控制成本时,每分钟速率限制、每月 Token 配额和输出限制作为最终保障。
本文中的每种技术都属于四个杠杆之一,它们的优先级依次递增。塑形在调用点决定:让更少的字节离开你的进程。缓存则完全消除调用,而非单纯降低成本。路由改变响应的模型及其价格。封顶则是前三者失效时的最终保障。
大多数团队从封顶开始,这是成本最高的方式。每月配额只能告诉你账单过高,却无法说明前三个更经济的杠杆本可以如何规避。
四个杠杆的失效方式各不相同,这正是顺序重要的原因。塑形改变了模型读取的内容。缓存改变了是否需要读取。路由改变了剩余调用的价格。封顶决定了其他三者都不足时会发生什么。代理循环每轮都追加自己的转录,这会同时击败塑形和缓存,所以计量必须优先:你无法判断哪个杠杆缺失,直到你能看到具体数字。
Token 效率表面上是 Prompt 写作习惯,实际上是流量问题。单次代理的成本并非用户的提问本身,而是提问加上宿主机发送的每个工具定义、循环累积的每个结果,以及每次重试。2026 年对相同十轮代理对话的测量显示,无 MCP 服务器时每轮 2,400 Token,连接三个时为 18,700 Token,五个时为 31,200 Token(MCP 的脏秘密)。另一个来自 22 个团队的 2026 年 Q1 数据集显示,MCP 输入 Token 占编码代理总消耗的 41–58%(MCP 网关经济学)。
这些运行中 Prompt 本身没有任何变化。变化的是工具表面,这就是为什么计数必须在流量所在处进行,而非在文本编写处。而且计数本身有一个微妙的细节,决定了是否有人会继续进行计数。
get_token_length 是该计量路径:文本输入,整数输出,调用者决定如何处理。有两个细节值得注意。首先,一个调用背后有两个分词器家族,函数会选择匹配的那个,所以团队在切换宿主机模型时无需切换其预算计算方式。其次,它调用 tokenizer.tokenize 并单独添加特殊 Token 计数,而不是调用分词器自身的 __call__,因为后者在输入超过模型最大长度时会发出警告并执行更多操作——而这恰恰是 fetch 工具产生的输入形式。对每个大文档都产生警告的计量方式是不会有人在热路径上运行的,而未被计量的路径才是产生惊人账单的路径。
# backend/smartgate/modules/context_gate/algorithm.py — source lines 987–1003 (token count)
def get_token_length(
self,
text: str,
add_special_tokens: bool = True,
use_oai_tokenizer: bool = False,
):
if use_oai_tokenizer:
return len(self.oai_tokenizer.encode(text))
else:
# tokenize + special token count avoids tokenizer.__call__ on megabyte
# texts (transformers warns when len > model_max_length).
n = len(self.tokenizer.tokenize(text))
if add_special_tokens and hasattr(
self.tokenizer, "num_special_tokens_to_add"
):
n += self.tokenizer.num_special_tokens_to_add(pair=False)
return n
特殊 Token 是团队最先忽略的细节,而忽略它们导致每个请求产生一个恒定的误差:单次不可见,但在一个月代理流量累积下就很显著。将计数与决策分离是设计的另一半。函数返回一个整数;配额检查、仪表板和审计行稍后都消耗同一个数字,因此计量无需为每个调用者重新实现。
对网关的实际反对意见是配置蔓延:每个宿主机都想要自己的文件、自己的密钥和自己的传输设置。解决方案是将主机配置变成生成的产物,而非每个开发者手动转录的文档,并让每个宿主机指向一个 endpoint。
下面的摘要是构建一个宿主机的方式,故意写得很简短。entry 类型是 streamable-http 而非 command,所以本地不会产生任何进程;serverUrl 是单一的 MCP URL;授权 header 从占位符写入,而非从真实密钥,所以意外提交的 config 不会携带凭证。最后一行的 platform 常量不是装饰:它使得在回读活动日志时能将请求归因于发送它的宿主机。
# lib/connect/mcp-config-templates.ts — source lines 99–116 (host config)
function buildWindsurfMcpConfigJson(
mcpUrl: string,
apiKeyPlaceholder: string = API_KEY_PLACEHOLDER,
): string {
return JSON.stringify(
{
mcpServers: {
smartgate: {
type: "streamable-http",
serverUrl: mcpUrl,
headers: buildMcpAuthHeaders(apiKeyPlaceholder, PLATFORM_AGENT_ID.Windsurf),
},
},
},
null,
2,
);
}
对 Token 账单的两个影响。首先,传输决策不再成为每个开发者的选择:如果宿主机使用 Streamable HTTP,相同的 endpoint 可以服务 Cursor、Claude Desktop、Windsurf 和 CI job,所以压缩或缓存的变更能一次性触达每个客户端,而非只落入某个编辑器。其次,工具表面保持在同一处,这是保持其精简的唯一方法。五个手动配置的服务器会为每个请求添加工具列表;一个 endpoint 可以暴露有限集合并在服务器端路由其余部分。网关为你连接的宿主机生成代码片段,连接页面则列出当前的宿主机。
压缩是 effort 与 Token 比值最佳的杠杆,也是静默破坏质量最严重的。它分为两个家族。
机械压缩移除不携带信息的字节:检索文档中的重复段落、你想要的段落周围的导航 chrome、重复的空白和样板代码,以及工具输出序列化为 prose 而非表格。这种家族实际上是无损的,默认启用是安全的,这就是为什么它应该是团队首先开启的东西。
学习压缩重写 Prompt 本身。LLMLingua 的方案是一个预算控制器设置可以削减多少,以及一个 token 级别的压缩传递,保持剩余 token 相互依赖,所以压缩后的 Prompt 不是一组关键词(LLMLingua, paper)。预算控制器是大多数实现跳过的部分,而跳过它正是压缩变成静默质量回归的方式:没有既定预算,压缩器会削减到适合为止,而非削减到答案能存活为止。
三个规则保持压缩的诚实。让 instruction 块远离压缩区域;压缩检索到的证据,而非问题。按调用记录比率而非按周,这样回归可归因。按任务类别决定损失预算,因为摘要任务比代码编辑能容忍更多削减。同一问题的代码敏感部分——当上下文紧张时哪些 token 存活——在上下文窗口管理技术中。
代理栈需要三种不同的缓存,混为一谈正是缓存口碑不好的原因。
Response caching(响应缓存)将完整的模型回答以精确的 prompt、模型和参数组合作为 key 存储起来。只有在 key 完全精确时,缓存才是正确的——一个能回答「相似」prompt 的缓存是一个命中率很好但存在正确性缺陷的 bug。
Tool-result caching(工具结果缓存)在一个短时间窗口内存储 fetch 或检索操作对某个 URL 或查询的返回结果。这是通常节省最大的地方,因为 AI 智能体循环会重新读取它们在三个步骤之前就已经读取过的页面。
Decision caching(决策缓存)存储对廉价但高频问题的回答,比如团队是否在预算范围内。SmartGate 默认将该快照缓存 45 秒:TTL 是一个可以通过环境变量覆盖的值,而非有限或非正数的值会回退到 45 秒,而不是变成一个无限窗口。这是一种明确的权衡——一波工具调用共享一次预算检查,且上限最多可能有 45 秒的延迟。这个权衡适合额度检查,但不适合授权决策,这也是为什么工具调用的授权是逐请求评估的。
两个原则决定了缓存和泄漏之间的差别。每个条目都需要一个 TTL,而不仅仅是驱逐策略,因为一个永不过期的陈旧条目和一个错误的条目是无法区分的。每个触达用户的缓存响应都需要一个包含租户的 key:跨团队共享的缓存最终会把一个团队的数据返回给另一个团队。
Cloudflare AI Gateway 是模型提供商前端的一个托管控制点,其功能列表读起来就像是四个杠杆的化身:响应缓存、速率限制、护栏、动态路由与兜底、逐请求日志,以及 token 和成本分析(AI Gateway)。动态路由是路由杠杆的具体实现:规则组合了提供商、模型、配额和条件,一个请求如果失败或超出其条件,会落到下一个目标而不是让这一轮失败(dynamic routing)。
在假设它能解决工具流量问题之前,仔细阅读其作用范围。AI 网关管理的是模型调用:你的应用请求的 completion。上面测量到的 token 放大发生在更早的一层——在填充 context 的工具调用中,而这些是由 MCP 网关管理的。这两个层是组合关系:路由和缓存 completion,压缩、授权和计量为它提供数据的工具。如果这个区别是新的,AI gateway 与 API gateway 是更短的阅读材料。
在 AWS 上托管一个 MCP Server 是一个有多种答案的已解决问题:负载均衡器后的容器、用于不频繁工具调用的 Lambda 函数,或托管网关。Amazon Bedrock AgentCore Gateway 是最后一种形态的托管版本——AI 智能体流量的一个安全入口点,路由到工具、其他 AI 智能体和模型,MCP Server 声明为网关目标,认证、策略执行和可观测性在端点处统一(gateway targets、gateway overview)。
与 token 相关的要点是托管不改变什么。服务器运行在哪里影响延迟、冷启动、出口流量和运维面,但一次调用消耗多少 token 是由服务器返回的载荷和主机重新发送工具定义的频率决定的。一个服务器从笔记本电脑迁移到托管网关产生的是相同的 context,除非迁移同时也把压缩、缓存和计量放入了请求路径。所以根据部署情况选择运行时,把计费作为请求路径的属性而不是主机的属性。更广泛的部署问题——网关层应该拥有什么、应用应该保留什么——在 enterprise AI gateway architecture 中有覆盖。
工具测试通常断言正确的内容返回了。对于一个 token 成本问题这只是半个测试套件,因为一个服务器可以用最昂贵的可能形式返回正确的文档。值得写的断言是成本回归会失败的那些:
长输入,稳定计数。 一个非常大的文本应该产生一个在参考值小误差范围内的 token 计数,这样 tokenizer 更换或截断 bug 会作为测试失败而不是账单出现。
按 token 分块,而不是按字符。 一个按字符测量的分割器在不同语言和 markdown 中会产生不同的片段,而片段才是被压缩的东西。
显式降级。 一个未知的模型名应该以一种定义好的方式降级,而不是在热路径上抛异常;它的计费应该明显为零而不是缺失。
退化输入。 单 token 输入和空结果是打破比率计算的输入。
节省字段是把压缩从声称变成数字的关键,下面的摘录展示了它们是如何附加的。该函数从工具结果中读取原始和压缩后的 token 计数,并将它们添加到审计参数中——但仅在原始计数大于零时,且当结果不是它期望的字典形状时返回未修改的参数。这个守卫就是全部要点:一次失败的压缩不能写入一个虚假的节省,因为节省聚合才是账单计算的基础。
# backend/smartgate/core/audit_params.py — source lines 4–15 (savings fields)
def enrich_compress_audit_params(
params: dict,
result_data: object,
) -> dict:
"""Add raw_tokens / compressed_tokens for savings aggregation (spec §4.1)."""
if not isinstance(result_data, dict):
return params
origin = int(result_data.get("origin_tokens") or 0)
compressed = int(result_data.get("compressed_tokens") or 0)
if origin > 0:
params = {**params, "raw_tokens": origin, "compressed_tokens": compressed}
return params
同样的模式可以推广到任何计量工具:保留原始计数,保留处理后的计数,并将两者附加到该调用的审计记录上。每调用两个整数才能使月度报告可对账,也只有这样才能让压缩变更基于证据而不是基于对响应质量的感觉来评估。
Model Context Protocol 只定义了两种标准传输:stdio,客户端将服务器作为子进程启动并通过标准输入和输出交换 JSON-RPC 消息,以及用于远程服务器的 Streamable HTTP。规范的建议是客户端应尽可能支持 stdio(transports),对于开发者工具来说这是正确的默认值:无端口、无证书、无认证握手。
从 token 角度看,这个选择比看起来更窄。stdio 服务器仍然向主机声明其工具,主机仍然将这些定义序列化到每一轮的 context 中——第一部分测量的放大在本地服务器上同样会发生。stdio 改变的是运维,而不是载荷:进程是你的,数据留在机器上,没有什么需要授权。远程端点改变的是相反的方向,而杠杆就在那里:托管端点可以在返回前压缩响应、缓存 fetch,并按团队对调用计费。实际规则是根据你实际拥有的部署选择传输方式,然后确保 token 控制位于两者都会调用的层。修订历史在这里很重要,因为远程传输已经变过一次。
经典检索增强生成检索一次并将最相关的段落随问题一起发送:一次检索、一次 completion,可预测的载荷。AI 智能体 RAG 让模型选择其检索策略,所以跳数成为一个运行时决策——而每一跳都会重新发送到目前为止累积的 context,包括上一跳的工具输出(agentic RAG survey)。
因此账单随跳数而非文档数增长。在同一页上两次检索比跨两页一次检索花费更多,因为第二次调用在其 context 中携带了第一次的结果。这就是四个杠杆不再独立的点:压缩一个检索到的段落收益翻倍——一次是在段落被获取时,另一次是在之后包含它的每一跳。经典与 AI 智能体的权衡以及在哪里停止循环在 RAG versus agentic RAG 中有覆盖;压缩方面在上面。
对于预算来说,有用的做法是把一跳当作一个计量单位。为循环设置一个跳数上限和每跳 token 限额,然后事后比较两者。先达到跳数上限但未达到 token 限额的是推理;先达到 token 限额的是重读。
限制有三个层级,完整的配置会同时使用这三层。每次调用的输出上限约束最昂贵的意外,因为生成的 token 会记入你的账户,而失控的生成过程在结束前是不可见的。每分钟速率限制约束突发流量:它决定了循环能以多快的速度消耗配额。月度配额约束整月,是团队实际做规划的数字。
SmartGate 的目录将这些层级显式化,而不是隐藏在一个单一数字中。月度 token 限额在各计划中逐步递增为 2M、20M、100M 和 200M,速率也随之阶梯上升:
作为预算来解读,有意义的列是最后两列:per-key 限制阻止了一个配置错误的客户端,team ceiling 阻止了十个正确客户端同时到达。实现细节——如何在每个团队层面强制配额、边界处发生什么、决策如何传递到工具调用——在 enforcing a token quota per team 中有详细说明。
网关类别按请求路径上的组件划分。SmartGate 比"AI gateway"更窄:它管理工具流量,其计费只在节省了成本之后才参与进来。
这张表有两种诚实的解读。如果你的唯一问题是某个长文档不断填满编辑器的上下文,本地压缩服务器是一个合理的起点:它是免费的,且不接触你的网络。如果问题是强制执行——谁可以调用什么、调用多少、在哪个预算下、有什么审计跟踪——压缩本身回答不了,而网关可以。表的最后一行也需要读两遍:本地安装的服务器方便且不计量,换句话说就是没有人能告诉你它节省了多少。
七个工具本身记录在 MCP tools reference 中,使节省量可共享的按请求计量在 execution-cost breakdown 中。
连接一个客户端。为 Cursor、Claude Desktop、Windsurf 或你自己的主机生成配置,粘贴进去,确认七个工具出现在工具列表中。这一步用一个 URL 替代了每个工具一个密钥。
在限制之前先开启塑形。对你已有的工作流——竞品页面、文档、issue 线程——运行一次 fetch、一次检索和一次去重,观察用量报告中压缩后与原始 token 数的对比。如果比率没有变化,说明载荷本来就很小,限制不是你的问题。
然后强制执行。用预算检查和记录调用包装循环,设置团队的月度上限,给需要长研究形状的工作一个 pipeline 调用,让四个步骤变成一个被审计的请求而不是四个。
从免费计划开始——每月 2M token、全部七个工具、无需信用卡——点击 start free,然后在定价页上根据你自己的工作负载检查限制。
在这里什么算作 token 优化?四个杠杆作用于一条请求路径:用模型自己的 tokenizer 计量、用压缩和去重塑形载荷、缓存和路由使重复字节不被计费两次、用输出限制、速率限制和月度配额限制循环。
SmartGate 替代我的模型或网关吗?不。你的智能体仍然与它的宿主模型对话,AI 网关仍然管理补全。SmartGate 位于工具流量上——那些在请求补全之前填充上下文的内容——并对这些调用进行计量、压缩、授权和计量。
为什么要将预算检查缓存 45 秒而不是始终实时读取?因为检查位于每个工具调用的路径上,而底层快照在突发期间很少变化。45 秒窗口是一个环境覆盖值,非正值会回退到它,权衡也很清楚:最多 45 秒的配额陈旧度,换来的是每个突发一次检查而不是每次调用一次检查。授权决策不会以这种方式缓存。
我怎么知道压缩节省了任何成本?该调用的审计行带有原始 token 数和压缩后的 token 数,只有当原始计数大于零时才会写入节省字段。如果某次调用没有报告原始计数,就不会为其声称节省,这保证了汇总数据是可对账的。
stdio 服务器避免 token 放大了吗?没有。本地服务器的 tool 定义仍然被序列化到每个 turn 中。stdio 买来的是本地性、无需端口和无认证握手;它本身并不会缩小上下文。
我需要 MCP 客户端才能使用这些控制吗?这些工具是 MCP 原生的,相同的模块也可以通过 REST 访问,因此 CI 作业或后端服务可以在没有智能体参与的情况下获得相同的计数、相同的配额决策和相同的审计行。
压缩是有损的。分割并压缩长载荷会丢失你原本想要的内容。在依赖它之前用你自己的语料库测试比率,并将指令块保持在被压缩区域之外。
决策缓存用新鲜度换取成本。45 秒窗口意味着配额读数最多可能落后 45 秒。这对配额来说是刻意的权衡,但对授权来说是错误的权衡。
这里的数字是测量值,不是保证。每个 turn 的放大系数来自一个特定的智能体、一个特定的宿主和一组特定的服务器;你的工具面决定了你的数字。
网关不是沙箱。管理哪些工具可以被调用并不会让不安全的工具变得安全。将其与最小权限密钥、角色检查以及对你智能体被允许访问的内容的审查结合使用。
Model Context Protocol specification, Transports (stdio and Streamable HTTP): https://modelcontextprotocol.io/specification/2025-06-18/basic/transports
Cloudflare AI Gateway, feature overview (caching, rate limiting, guardrails, dynamic routing): https://developers.cloudflare.com/ai-gateway/
Cloudflare AI Gateway, dynamic routing and fallbacks: https://developers.cloudflare.com/ai-gateway/features/dynamic-routing/
Amazon Bedrock AgentCore Gateway, MCP servers as targets: https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-target-MCPservers.html
Amazon Bedrock AgentCore Gateway overview: https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway.html
LLMLingua: prompt compression with a budget controller: https://llmlingua.com/ · https://arxiv.org/abs/2310.05736