在真实智能体开发里,最容易被忽略的往往不是模型能力,而是执行上下文。无论 Agent 是在写代码、查资料,还是调用多个工具完成任务,模型真正能用来推理的并不是数据库或知识库里所有内容,而是当前请求里被压缩进上下文的这批 token。腾讯发布的 ContextPilot,用细粒度 RL 训练智能体主动管理工作上下文,这个方向正好击中了很多 Agent 项目在长任务、多工具场景下的核心痛点。
要理解 ContextPilot,不能只看“压缩上下文”这四个字。它背后的关键变化在于:把上下文管理从“规则截断”升级成“模型决策”。传统做法是上下文快满时,按时间或长度丢弃旧消息;ContextPilot 的方向则是让 Agent 自己判断哪些信息值得保留、哪些可以合并、哪些必须主动重新获取,并把这个判断过程放到细粒度强化学习里训练。下面从工作上下文的本质开始拆解,再看看如果要落地类似机制,工程上应该怎么设计、验证和排错。
1. 先理解工作上下文为什么会被塞满
1.1 工作上下文不是 Prompt,而是智能体的短时工作台
很多人会把 Prompt 和上下文混在一起。实际上,Prompt 只是开发者写给模型的那部分固定指令,工作上下文则是 Agent 在某一次任务执行过程中真实看到的全部 token,通常包含系统指令、用户需求、历史对话、检索文档、工具返回结果、中间思考和错误日志。
可以把它理解成开发者的短时工作台。开发者会把自己正在处理的关键文件、编译信息、报错日志放在桌面上,而不是把整个仓库都摊开。同样,模型每一步推理能依赖的也只有上下文工作台里的东西。工作台太小,任务做不完;工作台摆放混乱,模型会把重要信息和无关信息混在一起,最终只能靠猜。
LangGraph、Dify、Coze 等平台里的会话记忆、状态管理和工具返回内容,都属于这个范畴。很多开发者在使用这些平台时发现,会话一长,模型回答开始变差,或者请求直接报“上下文超限”,就是因为工作台上的内容缺乏管理机制。
1.2 上下文超限会引发的不只是报错
上下文塞满之后,最直接的表现是请求失败。因为模型 API 对输入 token 有上限,超过后无法继续执行。但在超过上限之前,更隐蔽的问题是性能劣化。
当上下文里堆满中间过程时,模型很难把注意力放在真正关键的信息上。检索到的文档可能有大量重复内容,工具返回结果可能包含几十页原始数据,历史对话里可能积累了十几轮无效澄清。这些内容不仅增加费用和延迟,还会挤压关键信息的位置。很多模型在超长上下文里会出现“中间信息丢失”的现象,也就是开头和结尾的内容被关注,中段的关键结论被忽略。
因此,工作上下文管理的目标并不只是让请求不报错,而是让有限的 token 空间始终保持高信噪比。
下表是几种常见上下文状态的对比。
| 上下文状态 | 对模型效果的影响 | 对成本和延迟的影响 | 是否需要管理 |
|---|---|---|---|
| 信息过载,保留大量重复文档 | 关键信息被淹没,回答不准确 | 成本高,首字延迟高 | 必须管理 |
| 相关但过期,保留旧指令 | Agent 做出错误决策 | 中高成本,浪费预算 | 必须管理 |
| 按长度硬截断,丢失关键链路 | 后续步骤无依据,任务断层 | 成本可控,但返工率高 | 需要更细策略 |
| 主动压缩和保留摘要 | 关键语义仍可复用 | 成本低,执行稳定 | 理想状态 |
1.3 Agent 需要主动管理,而不是被动截断
过去大部分方案是“被动管理”:当 token 超过阈值时,丢掉最早的消息,或者对整个历史做一次 summary。这种方式能在短任务里工作,但在复杂工具链中问题很明显。
假设 Agent 先查看了一个 JSON 配置文件,然后调用了接口,接口返回又依赖配置里的某个字段。如果系统只是按时间截断了配置文件的原文,后续模型就失去了判断依据。它可能在下一个动作里重新读取文件,也可能直接凭印象猜一个值,产生非常隐蔽的错误。
ContextPilot 强调的“主动管理”,本质上是要在正确的时间点决定:哪些原始内容需要进入当前窗口,哪些内容只保留摘要,哪些内容可以从本地索引或外部存储延迟加载。这个决定不能在所有任务里都一刀切,必须根据任务状态动态调整。
2. ContextPilot 的方向:把上下文管理变成 RL 决策问题
2.1 为什么不能用固定规则完成主动管理
固定规则可以解决一部分问题,但解决不了所有问题。举个例子:工具返回了一份 1000 行的日志,Agent 正在排查接口超时。规则可以设定“只保留最后 50 行”,但真正可能导致问题的是第一行里的超时配置,或者中间某一行里的报错码。固定规则无法知道哪一行对当前任务最重要。
如果让模型自己决定,模型又可能为了减少风险而保留所有内容,或者为了节省 token 而过度压缩。这里的本质是一个决策问题:在每一个执行步骤,是否压缩、压缩哪部分、压缩到什么程度、是否需要重新检索,这些动作会影响后续所有步骤的成败。
ContextPilot 的切入点是用细粒度 RL 来训练这个决策过程。RL 关心的是“状态-动作-奖励”。状态是当前执行上下文,动作是某种上下文编辑操作,奖励则来自任务成功率和上下文使用效率的综合评估。让模型在大量 Agent 任务中试错,才能真正学会在“保留细节”和“节省上下文空间”之间做权衡。
2.2 细粒度 RL 的“细”体现在哪里
细粒度 RL 是相对任务级 RL 而言的。常规 RL 训练 Agent 时,往往只看最终任务是否成功,然后给一个整体奖励。这种信号太稀疏:一个任务可能有 50 步工具调用,如果中间 40 步都犯了错,最后一步成功,模型很难判断哪一步的上下文管理是对的。
细粒度 RL 会把任务过程拆开,尽可能对上下文编辑行为本身给出信号。压缩一个重要信息后导致任务失败,当前这个压缩行为应该得负分;压缩一段无关日志但没有影响后续任务,当前行为应该得正分;主动重新读取了被遗忘的关键配置,也应该获得正向反馈。
这种拆分后的信号更接近“教练逐回合指导”,而不是“只看整场比赛输赢”。在上下文管理任务里,细粒度信号尤其重要,因为压缩动作本身不会立刻产生可观察结果,它要到后续几步才会显现出价值。如果只用最终奖励,很难把失败归因到某一次不当压缩。
2.3 可训练的动作空间设计
要让 RL 策略真正起作用,必须先定义一套上下文编辑动作。ContextPilot 的具体动作集没有公开完整细节,但从上下文管理任务的一般规律来看,动作至少应该覆盖以下几类:
- 保留原始内容。
- 对指定消息做摘要。
- 折叠工具返回的详细结果。
- 标记某段对话为可过期内容。
- 从存档中重新加载关键上下文。
- 主动删除无关的中间观察。
- 调整系统指令和任务目标的展示顺序。
每个动作最好能附带细粒度的对象信息。例如动作是summarize,对象是某一次工具返回结果,目标是“在保留关键字段的前提下压缩内容”。模型需要知道它操作的是哪一段数据,否则策略即使学到,也无法稳定应用。
下面是一个动作空间示例,仅用于说明数据结构,不代表 ContextPilot 官方接口。
{ "action": "summarize", "target": "tool_result_32", "reason": "日志主体无异常,只需要保留错误码和超时时间", "params": { "max_tokens": 400, "keep_first": true, "keep_last": true } }有了统一动作结构,RL 策略、规则兜底和人工调试才能共用同一套日志和回放逻辑。
3. 上下文管理器需要的工程组件和策略接口
3.1 对上下文做分层建模
如果只是修改当前 prompt,很难做好上下文管理。工程上更稳妥的方法是把上下文分成几个层次。
- 工作层:当前真正进入模型的 token,也叫 active context。
- 存档层:已经发生但不需要立即展示的完整记录。
- 摘要层:对历史记录、工具结果、长文档生成的语义压缩。
- 检索层:当任务需要更多细节时,可以从哪取回原文。
可以理解成一个渐进式的归档系统。当前需要的内容放在桌面上,暂时不用的放进抽屉,抽屉里放一份便利贴说明“这个抽屉是什么”。如果后续工作需要某个抽屉里的细节,再打开抽屉读取,并重新决定是不是要占用桌面空间。
{ "session_id": "session_test_001", "active_context": [ {"role": "system", "content": "你是代码调试助手"}, {"role": "user", "content": "请帮我排查订单超时问题"}, {"role": "tool_result", "tool": "read_file", "content": "日志片段摘要,保留错误码"} ], "archive": { "tool_result_32_raw": "完整日志路径或分页存储标识" }, "summary_index": { "read_file_12": "用户要求查看 nginx 访问日志,定位 504 错误", "api_call_09": "订单服务返回超时,上游库存服务耗时 3 秒" }, "budget": { "max_tokens": 16000, "reserved_tokens": 1200, "system_instruction_tokens": 800 } }这种分层结构的好处是,任意时刻模型看到的只是 active_context,但所有历史信息并没有被真正删除,只是被挪到了更便宜、不占用当前注意力的存储层。一旦 RL 策略决定需要细节,可以通过 retrieval 动作把存档内容重新拉回工作层。
3.2 策略接口应当独立于具体模型
实际编写 Agent 时,最好不要把上下文管理逻辑散落在业务代码里。建议单独抽象出 ContextManager,它负责更新状态、选择动作、执行压缩、记录日志。
from dataclasses import dataclass from typing import Callable, List, Dict @dataclass class ContextAction: action: str target: str params: Dict class ContextManager: def __init__(self, policy: Callable[[Dict], ContextAction], summarizer: Callable[[List[Dict]], str], estimate_tokens: Callable[[str], int], max_tokens: int = 8000): self.policy = policy self.summarizer = summarizer self.estimate_tokens = estimate_tokens self.max_tokens = max_tokens self.active_context: List[Dict] = [] self.archive: Dict[str, Dict] = {} self.summary_index: List[Dict] = [] self.action_log: List[Dict] = [] def observe(self) -> Dict: return { "active_context": self.active_context, "summary_index": self.summary_index, "used_tokens": self._used_tokens(), "max_tokens": self.max_tokens, "last_actions": self.action_log[-5:] } def step(self, new_message: Dict) -> ContextAction: self.active_context.append(new_message) observation = self.observe() action = self.policy(observation) self.action_log.append({"obs": observation, "action": action.__dict__}) return action def execute(self, action: ContextAction): if action.action == "summarize": target_message = self._find_target(action.target) summary = self.summarizer([target_message]) self.summary_index.append({ "target": action.target, "summary": summary, "time": action.params.get("time") }) self._replace_with_summary(action.target, summary) elif action.action == "drop": self.archive[action.target] = self._find_target(action.target) self.active_context = [ m for m in self.active_context if m.get("id") != action.target ] elif action.action == "reload": raw = self.archive.get(action.target) if raw is not None: self.active_context.append(raw) self._compact_if_needed() def _used_tokens(self) -> int: return sum( self.estimate_tokens(m.get("content", "")) for m in self.active_context )这段代码没有真正训练模型,但它把“策略决策”和“业务逻辑”分开了。policy 可以是任意函数,前期可以先写规则,例如“当 used_tokens 超过 max_tokens 的 80% 时,对整个工具结果进行摘要”;后期换成 RL 模型时,只需要替换 policy 的实现,不需要重写执行逻辑。
3.3 预算管理是 RL 训练的必要约束
上下文管理器不能无限制执行动作。每个任务都应该有明确的 token 预算。预算可以分给系统指令、压缩后的历史、当前工具结果、最终答案留白。建议保留一部分 token 给模型生成回复,否则压缩后的上下文可用,但最后输出超限仍然会失败。
参数设计时需要衡量两个方向:
| 参数 | 含义 | 调大后的影响 | 调小后的影响 |
|---|---|---|---|
| max_context_tokens | 当前工作层可用的最大 token 数 | 能保留更多原始信息,但成本和延迟上升 | 节省成本,但频繁压缩容易丢失细节 |
| reserved_output_tokens | 给最终回答保留的 token | 输出更稳定,但压缩发生得更早 | 可用空间变大,但回答可能被截断 |
| compression_threshold | 触发压缩决策的上下文使用率 | 触发少,上下文压力大 | 触发频繁,决策成本高 |
| summarize_max_tokens | 摘要允许的最大长度 | 摘要更完整,但占用上下文 | 摘要更短,容易丢细节 |
训练细粒度 RL 策略时,可以把“是否遵守预算”作为硬约束,再在预算内学习如何分配每个模块的空间。不能让模型牺牲任务成功率去追求上下文占用率低,也不应该为了任务成功率无限制保留所有中间结果。
4. 一个最小可运行的验证原型
4.1 明确目标:先验证上下文压缩是否影响任务
ContextPilot 级别的完整训练需要大量算力和 Agent 环境。普通开发者可以先做一个简化版原型,用来回答一个问题:同一个任务,在同样的模型能力下,加入主动上下文管理后,结果是否会变好。
这个原型不直接复现腾讯内部模型,而是用当前可用的模型 API 做 summarizer,用规则或轻量策略做 policy。重点是把“上下文管理器”这套机制跑通,并留下行为日志。
4.2 准备环境
需要准备一个能调用模型 API 的 Python 环境,以及一个长文档阅读理解任务。比如让 Agent 读一份包含产品列表、价格、库存和用户评价的长文档,回答“哪些商品适合补货”。原始文档可能超过模型窗口,或者接近窗口限制,导致 Agent 回答不稳定。
建议使用下面的最小环境:
- Python 3.10 及以上。
- 一个模型 API 客户端。
- 一个用于生成摘要的函数。
- 一个简单的 token 估算函数。
如果原始项目中已经接入了 LangGraph、LlamaIndex 或其他 Agent 框架,不需要额外引入框架,可以直接在调用大模型之前加一个 ContextManager 层。
4.3 实现上下文压缩逻辑
先实现一个简单的 summarize 触发:
def estimate_tokens(text: str) -> int: # 中文可以按字符数估算,中文约 1.5 到 2 token/字 return int(len(text) * 1.5) + 8 def make_summarizer(llm_chat): def summarize(messages): content = messages[-1]["content"] if len(content) < 1000: return content prompt = f"请压缩以下内容,保留所有关键数字和结论:\n{content}" reply = llm_chat([{"role": "user", "content": prompt}], max_tokens=200) return reply return summarize这里的summarize并不完美,只做一个 baseline。真实上下文管理器中,摘要需要按信息来源分别压缩,避免把工具结果和用户意图混在一起。
然后组装验证流程:
def run_agent_with_context_manager(raw_document, user_question, llm_chat): summarizer = make_summarizer(llm_chat) cm = ContextManager( policy=lambda obs: ContextAction( action="summarize", target="doc_long", params={"max_tokens": 500} ) if obs["used_tokens"] > 5000 else ContextAction( action="keep", target="", params={} ), summarizer=summarizer, estimate_tokens=estimate_tokens, max_tokens=6000 ) cm.step({"id": "user_question", "role": "user", "content": user_question}) cm.step({"id": "doc_long", "role": "user", "content": raw_document}) action = cm.execute(cm.policy(cm.observe())) final_messages = cm.active_context return llm_chat(final_messages, max_tokens=800), cm.action_log实际运行前要在日志里记录:原始文档多少 token,压缩后多少 token,摘要是否保留了用户问题需要的字段。
4.4 运行结果怎么看
预期结果是,在长文档任务中,ContextManager 可以把输入从 8000 token 降到 2000 token 左右,同时仍能回答出关键信息。但因为摘要函数比较粗糙,可能出现以下问题:
- 摘要丢弃了某个价格字段,导致 Agent 回答“库存充足”但无法给出准确数量。
- 原始文档里数字较多,压缩后模型开始编造缺失的数字。
- 每次都重新对全文做 summary,导致调用成本反而上升。
因此,最小原型验证的不只是“能不能跑通”,而是“压缩之后任务效果是否保持一致”。如果 baseline 压缩导致回答质量明显下降,说明简单摘要不够,下一步才需要引入更细粒度的 RL 决策。
5. 如何评估模型真的学会了主动管理上下文
5.1 离线评测指标
评估上下文管理策略时,不能只看 token 节省量,还要看任务成功率。我建议把指标分成三层。
第一层是任务效果,包括最终回答准确率、工具是否成功执行、用户需求是否被满足。第二层是上下文效率,包括平均每次请求 token 数、主动压缩次数、上下文超限报错次数。第三层是压缩行为质量,包括摘要是否需要反复重读、关键字段是否被保存、被压缩内容是否真的不再被后续步骤需要。
在批量评估时,可以分别记录使用原始上下文、使用硬截断、使用固定摘要、使用 RL 策略四组的差异。
| 评测指标 | 原始上下文 | 硬截断 | 固定摘要 | RL 策略 |
|---|---|---|---|---|
| 任务成功率 | 高但受窗口限制 | 低,明细丢失 | 中等 | 目标最高 |
| 平均 token 消耗 | 最高 | 低 | 中 | 低 |
| 中间重读次数 | 少 | 多 | 中 | 少 |
| 上下文超限率 | 高 | 低 | 低 | 低 |
| 可解释性 | 无需解释 | 较差 | 中等 | 可用日志解释 |
如果一味的 token 节省导致任务成功率大幅下降,说明策略过度压缩。反过来,如果任务成功率很高但 token 用量和原始上下文几乎一样,说明策略没有真正学会管理。
5.2 测试集要覆盖关键决策点
RL 策略训练结束后,还需要一套专门用于验证上下文管理能力的数据集。测试数据不能只给普通问答,应该设计包含上下文压力的任务。
可以复用下面几类任务:
- 长文档单轮问答,文档中有重复段落和关键结论。
- 多工具连续调用任务,必须保留中间步骤的输出结果才能继续下一步。
- 长会话历史任务,前 20 轮信息与最终问题相关,但中间有一轮误导信息。
- 超长错误日志任务,需要从 full log 中定位根因。
每类任务中都应标记“关键信息点”。评测时自动检查最终回答有没有包含这些关键点,同时统计模型是否在调试日志中访问过对应的原始片段。
5.3 奖励函数拆解到行为级
细粒度 RL 的奖励设计需要细化到行为级。一个朴素奖励函数可以这样理解:
def compute_step_reward(task_success_so_far, action, before_tokens, after_tokens, key_info_preserved, reload_required): reward = 0.0 if key_info_preserved and after_tokens < before_tokens * 0.5: reward += 1.0 if reload_required: reward -= 1.0 if action == "summarize" and task_success_so_far: reward += 0.2 return reward这里没有使用最终任务一个分数,而是对每个压缩动作单独打分。key_info_preserved表示摘要后还能不能通过检索或后续回答找到关键信息,reload_required表示后续步骤是否必须重新加载原文。如果策略频繁压缩后又频繁重读原文,单次压缩看似节省了 token,整体却增加了调用次数和时间,应该在奖励里体现负分。
6. 实际调试中的常见坑和排查链路
6.1 模型学会了压缩,但任务结果变差
现象:token 用量确实下降了,但 Agent 最终回答错误率上升,尤其在需要精确数字时经常漏字段。
原因:奖励函数偏向“节省 token”,没有足够强调关键信息保留。摘要函数又是一个独立模型,压缩内容时的错误没有反馈给 RL 策略。
检查方式:打开 action_log,看每次压缩动作前后的目标文本,检查摘要里是否保留数字、名称、代码字段、错误码。如果十次压缩有八次丢掉关键字段,问题通常出在摘要质量和奖励权重上。
处理建议:不要直接对整段原始数据做一句摘要,先把文本按结构切块,对每个块做“是否关键”的判断。奖励函数中对结构字段的保留单独加分。
6.2 上下文管理器频繁触发,导致延迟和成本上升
现象:任务并不长,但系统每隔几步就调用一次摘要模型,整体耗时比直接处理完整上下文还要高。
原因:压缩阈值设置过高,或策略认为任何活跃消息都该被压缩。摘要动作本身也要消耗模型调用和 token,如果不把决策成本纳入奖励,策略会做出“过度管理”的行为。
检查方式:统计每个任务的平均压缩次数和压缩耗时。如果一个 5 步任务主动压缩了 8 次,明显异常。
处理建议:调低压缩频率不是唯一办法,更好的方式是给每个动作增加成本惩罚。同时在策略入口加冷却时间,比如同一类摘要动作至少间隔 N 步。
6.3 压缩后 Agent 找不到工具结果
现象:Agent 执行了一个工具调用,随后要求“查看返回结果”,但上下文中只保留了摘要,没有原始数据,导致后续指令无法执行。
原因:上下文管理器把工具返回结果压缩成摘要,但没有保留工具结果 ID 和读取接口。Agent 只知道摘要,不知道从哪里重新获取原文。
检查方式:在 action_log 中查找summarize动作,确认目标工具结果是否归档到可检索存储。再模拟一次用户询问“根据刚才日志里的具体报错行继续排查”,看 Agent 是否有能力 reload。
处理建议:压缩工具结果时,摘要内容必须包含原始结果的来源标识。Agent 上下文里要有一个可用的 reload 动作,不能只允许删,不允许取回。
6.4 RL 训练收敛慢,策略几乎不采取压缩动作
现象:在训练早期,模型发现压缩后偶尔会丢信息,于是策略逐渐变成“不压缩任何东西”,最终表现为任何上下文管理动作都不触发。
原因:这是典型的策略坍缩。RL 对动作的负反馈过于敏感,模型最终选择保守策略来避免负分。如果默认动作keep的预期收益高于其他动作,模型不会主动探索压缩。
检查方式:看训练日志中动作分布,确认keep是否占比超过 95%。同时看奖励曲线,如果奖励上升完全来自任务成功,而不是来自上下文效率,说明细粒度信号没有真正生效。
处理建议:在 RL 训练一开始,给上下文效率目标加上一个较大的正向系数,或者使用课程学习:先只训练“删除明显无关内容”,再逐步引入“摘要完整内容”。这也提醒我们,不是所有压缩策略都适合一步到位。
下表总结了这四类常见问题。
| 问题现象 | 可能原因 | 检查方式 | 处理建议 |
|---|---|---|---|
| token 下降但任务变差 | 奖励偏好压缩,摘要丢失关键信息 | 查看摘要文本和关键字段保留率 | 按结构化切块逐块压缩,奖励中加入关键信息保留分 |
| 压缩次数过多 | 摘要调用成本未纳入决策 | 统计每一步压缩耗时和次数 | 给动作添加成本惩罚,加入压缩冷却期 |
| 后续无法获取工具详情 | 压缩时丢失原始来源标识 | 检查 action_log 和存档层 | 摘要保留来源 ID,提供 reload 机制 |
| 策略从不压缩 | RL 对压缩负反馈过度敏感 | 看动作分布和奖励分解 | 调整动作奖励系数,使用课程学习从无关内容删除开始 |
7. 生产环境落地建议与后续扩展
7.1 学习环境与生产环境的差异
在实际项目里,ContextPilot 这类思路最忌“在一个短任务里测不出差异,就以为机制无效”。学习环境里可以用几百 token 的小任务快速验证上下文管理器是否安全,但生产环境需要额外考虑以下内容:
- 上下文动作日志必须保存,否则 RL 训练和问题归因都没有数据。
- 摘要和压缩动作要可回滚,必要时能手动在调试面板里恢复被折叠的原文。
- 策略服务必须设置降级路径,RL 策略不可用时自动回退到固定摘要规则。
- token 估算应使用真实 tokenizer,而不是简单按字符数估算。
- 需要监控上下文管理动作带来的额外延迟和成本。
区分环境很重要。生产环境不要在每次请求都动态调用大模型做摘要,建议增加缓存层。同一份长文档第一次摘要后保存 key,后续直接复用。如果文档被修改,再更新缓存。
7.2 适合先试点上下文管理的 Agent 场景
不是所有 Agent 都需要复杂的上下文管理器。如果用户只是做简单问答,当前对话只有两三轮,直接透传即可。下面几类场景更适合先试点:
- 销售智能体需要读大量客户资料和产品手册,回答中还要不断引用不同来源。
- 代码调试 Agent 需要保留代码文件、编译日志和上次修复动作,任务跨越多轮。
- 数据分析智能体需要调用 SQL 或图表工具,每次返回都占大量 token。
- 工作流 Agent 塞满会话后需要继续执行后续节点,例如配置了多个工具的综合流程。
这些场景的共同点是:任务越长,单轮成功率越低;信息一旦被截断,Agent 无法重新通过对话找回;上下文里存在大量“相关但当前不需要”的内容。
7.3 一条可复用的落地清单
如果在自己的项目里引入 ContextPilot 类似思路,可以从下面这份清单开始检查:
- 是否定义了 active context、archive、summary index 三层结构。
- 是否所有消息都有唯一 ID。
- 是否记录每一条压缩动作的 reason、target、before_tokens、after_tokens。
- 是否能在摘要后重新加载原始内容。
- 是否保留足够空间给模型最终输出。
- 是否固定规则兜底,避免 RL 策略完全不可用。
- 是否用真实 tokenizer 统计长度。
- 是否有离线数据集衡量压缩后的任务成功率。
- 是否对摘要缓存,避免重复调用模型。
- 是否把上下文效率纳入最终评估指标,而不只看任务成功。
如果每一项都能明确回答“是”,一套可观测、可回滚、可扩展的上下文管理机制基本就成型了。
7.4 从摘要到细粒度 RL 的扩展路径
对于刚接触这个方向的开发者,建议不要一开始就写强化学习训练脚本。先实现固定的摘要策略,再把它升级成“基于上下文占用率触发的规则策略”,然后收集大量行为日志,最后再用这些日志设计 RL 状态和奖励。这样做的好处是,每一步都有可对比的 baseline,也能在训练失败时快速定位是状态设计问题还是奖励函数问题。
ContextPilot 把“上下文管理”从工程技巧提升到大模型决策问题,这是 Agent 长任务落地的重要一步。它本质上在说:不要让上下文窗口决定 Agent 能做什么,而要让 Agent 学会在有限的窗口里精准组织自己的工作台。接下来最值得做的不是等待一个新模型发布,而是先在当前项目里补上上下文日志、压缩动作和回读能力,积累自己的最佳实践。