
1. 从报告 A这个标题说起一个被低估的上下文管理命题第一次看到报告 A这个标题配合着Agent Context Server、上下文管理、微服务、LLM、工具结果压缩这组关键词我脑子里蹦出来的第一个念头是这大概率是一个关于智能体上下文服务的工程实践项目而且报告 A很可能只是某个内部代号或者脱敏后的项目名。真正有价值的信息藏在关键词里——它指向了一个当下 LLM 应用落地过程中最容易被忽视、却又最致命的环节上下文Context的生命周期管理。为什么说它容易被忽视因为大多数人做 LLM 应用注意力都放在模型选哪个提示词怎么写工具怎么接上很少有人认真思考一个问题当 Agent 连续调用十几个工具、每个工具返回几千字的 JSON、对话轮次累积到几十轮之后那个塞进模型窗口的 context 到底长什么样它是不是已经膨胀到把真正重要的信息挤出去了它是不是因为工具返回结果里一堆无用的字段而浪费了大量 token报告 A这个项目从关键词组合来看要解决的就是这个问题。它把上下文管理从应用代码里随手拼字符串提升为一个独立的服务——Agent Context Server用微服务的思路来治理 LLM 的上下文。这个思路本身就值得展开聊。我见过太多团队前期用几十行 Python 就把 Agent 跑通了到了生产环境发现上下文爆炸、成本失控、响应变慢、模型开始胡言乱语回头再改架构代价极大。这篇文章我会围绕这个项目的核心命题展开如何用服务化的方式管理 Agent 的上下文尤其是工具调用结果的压缩与治理。我会拆解为什么需要独立的 Context Server、工具结果压缩到底怎么做才不丢信息、微服务架构在这里是过度设计还是必要之举以及我在类似实践中踩过的坑。不管你是刚接触 LLM 应用开发还是已经在做 Agent 平台的工程负责人应该都能从中找到可以直接抄作业的部分。2. 为什么上下文管理值得单独抽一个服务出来2.1 上下文膨胀的真实成本账先算一笔账这样后面讨论架构才有依据。假设你做一个客服 Agent用户一次咨询平均触发 5 次工具调用查订单、查物流、查库存、查优惠券、查历史工单。每个工具返回的原始 JSON 平均 800 token这已经算克制的了很多内部 API 返回一堆嵌套字段和 null 值。5 次就是 4000 token。再加上系统提示词 500 token、工具定义 schema 1500 token、对话历史每轮 200 token 累积 10 轮 2000 token一次请求的输入轻松突破 8000 token。如果这个 Agent 每天处理 1 万次咨询按主流模型输入价格每百万 token 几块钱到几十块钱不等来算光输入成本一天就是几十到几百块一个月下来是笔不小的开支。更关键的是延迟输入 token 越多首 token 响应时间越长用户体感越差。而且当上下文接近模型窗口上限时模型对中间位置信息的注意力会下降这就是所谓的lost in the middle现象——你塞进去的信息模型未必真的看到了。所以上下文管理不是优化项而是生存项。它直接决定了你的 Agent 能不能在成本、延迟、效果三者之间找到平衡点。2.2 把上下文逻辑塞在应用层的三个死结我早期做 Agent 的时候上下文拼接逻辑就写在业务代码里一个build_context()函数几百行各种 if-else。跑起来之后发现三个绕不开的问题。第一个死结是逻辑复用困难。你有客服 Agent、有代码助手 Agent、有数据分析 Agent每个都要做上下文裁剪、工具结果压缩、历史摘要结果就是每个项目复制一份改一处要改五处还容易漏。第二个死结是状态无法集中观测。上下文到底是怎么一步步膨胀起来的哪次工具调用贡献了最多的 token压缩策略到底省了多少这些在应用层散落各处的逻辑里根本统计不出来。出了问题只能靠打日志一点点扒。第三个死结是多实例部署时状态不一致。Agent 服务水平扩容后同一个会话的上下文可能落在不同实例上如果上下文存在本地内存就会出现这次请求记得上一轮下次请求失忆的诡异现象。这三个死结指向同一个结论上下文管理是一个有独立生命周期的领域问题它值得有自己的服务边界。这就是 Agent Context Server 存在的理由——把上下文的存储、组装、压缩、观测收敛到一个服务里让 Agent 应用只关心我要什么上下文而不关心上下文怎么来的、怎么瘦身的。2.3 Context Server 的职责边界该怎么划抽服务最怕边界划不清划不清就会变成分布式单体。我理解 Context Server 的核心职责应该收敛在四件事上上下文组装根据会话 ID 和当前请求把系统提示、工具定义、历史消息、当前输入按策略拼装成最终 payload。工具结果压缩对工具返回的原始结果做结构化裁剪、摘要、字段过滤在保留语义的前提下降低 token 占用。上下文窗口管理当总长度逼近阈值时决定丢弃什么、摘要什么、保留什么。可观测性记录每次组装的 token 分布、压缩比、命中策略供后续调优。而它不应该承担的业务逻辑判断、工具的实际执行、模型的调用。这些留在 Agent 应用层。边界清晰了服务才不会腐化。3. 工具结果压缩整个项目里最见功力的部分3.1 为什么工具结果是上下文里的重灾区前面算账时提到工具返回结果是 token 消耗的大头。原因很现实内部 API 的设计初衷是给前端或后端程序消费的不是给 LLM 消费的。一个查询订单的接口可能返回这样的结构订单基本信息、用户信息、商品列表每个商品又有十几字段、支付信息、物流轨迹几十个节点、各种时间戳和状态码。前端只需要其中几个字段展示但 LLM 拿到的是全量。更麻烦的是很多字段对 LLM 推理毫无价值内部 ID、数据库版本号、创建人、更新人、各种null、空数组、布尔标志位。这些字段不仅占 token还会干扰模型注意力让它在无关信息里迷失。所以工具结果压缩的本质是做一次面向 LLM 语义消费的信息蒸馏。注意关键词是语义消费不是数据压缩。你不能简单地把 JSON 转成紧凑格式或者 gzip那对 token 没用。你要做的是理解这个工具结果里哪些信息对当前任务真正有用。3.2 三种压缩策略的适用场景与取舍我在实践中总结出三种层次的压缩策略它们不是互斥的而是可以叠加使用。第一种是结构化裁剪Schema-based Pruning。针对每个工具预先定义一份LLM 可见字段白名单Context Server 拿到原始结果后只保留白名单里的字段其余全部丢弃。这种策略的优点是零信息损失风险因为白名单是人工确认过的、压缩比稳定、实现简单。缺点是灵活性差同一个工具在不同场景下需要的字段可能不同。第二种是语义摘要Semantic Summarization。对于文本类、列表类的结果比如物流轨迹、评论列表用一个小模型或者规则引擎做摘要。比如 50 条物流轨迹压缩成包裹于 X 日发出途经 A、B、C 三个中转站预计 Y 日送达当前状态派送中。这种策略压缩比极高但引入了信息损失和额外的模型调用成本需要权衡。第三种是动态字段选择Dynamic Field Selection。根据当前用户 query 的意图动态决定保留哪些字段。比如用户问我的订单什么时候到那就重点保留物流相关字段用户问我买了什么那就重点保留商品列表。这种策略效果最好但实现复杂度最高需要意图识别能力。我的建议是从结构化裁剪起步覆盖 80% 的场景对少数文本密集型工具引入语义摘要动态字段选择作为进阶优化不要一上来就做。下面这张表可以帮你快速判断策略压缩比信息损失风险实现成本适用场景结构化裁剪中30%-60%低低字段固定的结构化 API语义摘要高70%-90%中中长文本、列表类结果动态字段选择高60%-85%低高意图明确、字段需求随场景变化3.3 压缩不能丢的那条底线可追溯性这里要敲一个重点压缩后的结果必须可追溯。什么意思当模型基于压缩后的上下文做出了一个错误决策你需要能回答它当时看到的是什么。如果压缩过程是无损可逆的还好但语义摘要是有损的你必须把原始结果和压缩结果都存下来并且记录用了哪个策略、压缩比多少。我踩过一个坑早期做摘要压缩时为了省存储只存了摘要不存原文。结果有一次模型回答错误我怀疑是摘要丢了关键信息但原文已经找不到了只能靠猜。后来改成原文和摘要都存用会话 ID 工具调用 ID 关联排查效率提升了一个数量级。这个存储成本相对于排查成本来说完全不值一提。提示压缩策略一定要做成可配置、可灰度的。不同工具、不同业务线的最优策略不一样硬编码一种策略迟早要返工。4. 微服务架构在这里是必要还是过度设计4.1 什么时候该拆什么时候不该拆微服务这个词现在有点被滥用了很多项目为了微服务而微服务最后搞出一堆分布式问题。所以我要先泼盆冷水如果你的 Agent 应用只有一两个、QPS 很低、团队就三五个人那 Context Server 完全可以作为一个模块存在不必独立部署。模块化是目的微服务只是手段之一。那什么时候值得拆成独立服务我判断有三个信号多 Agent 复用你有超过 3 个 Agent 应用需要共享上下文管理能力拆出去能显著减少重复建设。独立扩缩容需求上下文组装和压缩是 CPU/内存密集型操作尤其涉及摘要模型时它的扩缩容节奏和业务 Agent 不一样混在一起会互相拖累。团队边界清晰有专门的平台团队负责 Context Server业务团队只管调用。组织架构决定系统架构这话在微服务语境下尤其成立。如果这三个信号你一个都不满足那就老老实实做成一个库或者模块别给自己找麻烦。4.2 Context Server 的服务拆分粒度假设你决定拆了那拆成几个服务我的经验是两个就够一个Context Assembly Service负责组装和窗口管理一个Tool Result Processor负责工具结果压缩。为什么把压缩单独拆因为压缩可能涉及模型调用语义摘要它的资源特征、依赖、失败模式都和组装不一样。组装是纯内存操作快且稳压缩可能慢、可能失败、可能需要降级。分开之后压缩服务挂了可以降级为不压缩直接透传不至于整个上下文服务不可用。至于存储层会话上下文建议用 Redis 这类带 TTL 的内存存储工具结果原文用对象存储或文档数据库。不要用关系型数据库存上下文写入频率太高扛不住。4.3 服务间通信与数据一致性Context Server 和 Agent 应用之间我推荐用同步的 RPC 调用gRPC 或 HTTP因为组装上下文是请求链路里的关键路径必须同步拿到结果。而工具结果压缩如果耗时较长可以考虑异步预压缩工具执行完就把结果丢给压缩服务Agent 需要时直接取压缩好的。但这引入了压缩还没完成怎么办的问题需要设计好等待和降级逻辑。数据一致性方面最大的坑是会话上下文的并发写。同一个会话可能同时有多个请求进来比如用户快速连发消息如果两个请求都去更新上下文可能互相覆盖。解决方案是用乐观锁或者把同一会话的请求串行化。我倾向于后者简单可靠代价是同一会话的并发度受限但实际场景里用户很少真的并发发消息。5. 上下文窗口管理的策略与踩坑实录5.1 窗口快满时的四种处理手段当组装好的上下文逼近模型窗口上限你必须做取舍。常见手段有四种我按推荐优先级排列第一工具结果压缩前置。这是最优先的因为工具结果里冗余最多压缩它信息损失最小。理想情况下压缩做完根本不会触发窗口告警。第二历史消息摘要。把较早的对话轮次用模型摘要成一段话替换掉原始多轮消息。这里要注意摘要的粒度太粗会丢关键信息太细省不了多少 token。我的经验是每 5-10 轮做一次滚动摘要。第三丢弃低价值消息。比如工具调用的中间确认消息、重复的系统提示。这个要谨慎丢弃规则设计不好会破坏对话连贯性。第四截断最老的消息。这是最后手段简单粗暴但会直接导致失忆。不到万不得已不要用。5.2 一次线上事故的完整排查链路说个真实经历。有段时间客服 Agent 频繁出现答非所问用户问退款进度它回答商品推荐。排查过程是这样的第一步看 Context Server 的组装日志发现出问题的那几次请求上下文里商品推荐工具的结果占了 60% 的 token而退款工具的结果被挤到了很靠前的位置因为窗口管理策略是保留最新的。第二步追为什么商品推荐结果这么大。发现那个工具的返回里带了一个推荐理由字段每条推荐理由是一段 200 字的营销文案10 条推荐就是 2000 字。这个字段对当前任务完全无用但没被裁剪掉。第三步根因清楚了结构化裁剪的白名单没覆盖这个新加的工具。工具是业务团队新上的Context Server 的配置没同步更新导致新工具的结果全量透传。修复方案有两层短期给这个工具补上白名单配置长期建立工具注册与 Context Server 配置的联动机制新工具上线必须同步提交裁剪规则否则默认只透传核心字段。这个事故给我的教训是上下文管理是一个需要和工具生态同步演进的系统任何配置滞后都会直接转化为线上问题。所以后来我们做了配置的自动化校验工具 schema 变更时自动告警。5.3 窗口阈值该设多少才合理很多人把阈值设成模型窗口的 90% 甚至 95%觉得能塞就塞。我不建议这么干。原因有二一是要给输出留足空间很多模型输入输出共享窗口二是接近上限时模型效果会下降。我的经验值是输入控制在窗口的 60%-70%。比如 128K 窗口的模型输入控制在 80K 以内。这个比例下模型对上下文的利用率最高延迟也可控。当然具体数值要压测不同模型表现不一样。6. 落地这套方案时我踩过的坑和总结的技巧6.1 工具结果压缩的三个反直觉发现第一个发现压缩比不是越高越好。我曾经追求极致压缩把工具结果压到原来的 10%结果模型开始频繁幻觉因为它拿到的信息太少了只能靠猜。后来把压缩比控制在 40%-60%效果反而最好。压缩的目标是去掉噪声不是榨干信息。第二个发现保留字段的顺序会影响模型理解。JSON 字段的顺序在程序看来无所谓但模型是顺序读的。把关键字段放在前面模型更容易抓住重点。所以裁剪之后我会按重要性重排字段顺序。第三个发现空值和错误信息要区别对待。字段值为null通常可以丢但工具返回的错误信息绝对不能丢而且要放在显眼位置。我有次把错误信息当普通字段裁掉了模型以为工具调用成功了基于空结果继续推理错得离谱。6.2 观测指标怎么设计才有用Context Server 如果不做好观测就是个黑盒。我建议至少埋这几类指标每次组装的 token 分布系统提示、工具定义、历史、工具结果各占多少。这个能帮你快速定位谁在膨胀。压缩比分布按工具维度统计找出压缩效果差的工具。窗口告警次数触发窗口管理的频率频率高说明压缩策略需要优化。上下文命中率模型实际引用的上下文片段占比这个需要结合模型输出分析但价值极高。这些指标用 Prometheus Grafana 就能搞定投入不大收益极高。6.3 给不同阶段团队的建议如果你刚起步我的建议是先别拆服务把上下文管理写成一个独立的模块接口设计好压缩策略从结构化裁剪做起。等业务量上来、Agent 数量多了再考虑拆成服务。如果你已经在生产环境跑着上下文开始失控那优先做两件事一是给所有工具结果加裁剪白名单二是把上下文组装逻辑收敛到一个地方。这两件事做完成本能降一大截。如果你在做平台要支撑很多业务方那 Context Server 的配置化能力是核心。让业务方自己配裁剪规则、自己看观测指标平台团队只维护框架和兜底策略。最后分享一个我一直在用的小技巧给每个工具结果打一个信息密度标签。高密度的比如精确的数值、状态优先保留低密度的比如大段描述性文本优先压缩。这个标签可以人工标注也可以用规则自动生成。有了它窗口管理时的取舍就有了依据不用拍脑袋。这套东西说到底核心就一句话LLM 的上下文是稀缺资源得像管理内存一样管理它。谁把这个管理做扎实了谁的 Agent 就能在成本、延迟、效果上同时占优。