10 KiB
基于决策模型的上下文压缩
长任务会积累大量工具调用:读过的源码、过期的搜索结果、重复查询的日志、已经结束的支线任务。
compact_context 根据下一步要做什么,判断旧工具调用是否仍然有用,以及它的完整输出是否必须保留。
它返回一份建议的消息快照和逐调用决策,由宿主决定是否应用。
这一流程通过 as_decision_model 接口调用概率决策模型。当前 agentscope 适配器使用 AgentScope 的
TypeSafe/Jev 实现;替换供应商时,Job 和压缩策略仍然使用同一个接口。
一次压缩如何工作
- 宿主先归档原始历史。 宿主提供 AgentScope 2.x 的 JSON 消息快照、当前
goal、允许处理的工具名和保护列表。 ReMe 不负责归档,也不会替宿主更新运行中的 Agent 状态。只有原始记录可恢复时,宿主才应应用删减建议。 - 用确定性规则挑选候选。 按调用 ID 配对
tool_call与tool_result。调用必须为finished,结果必须为success,工具必须在显式允许列表中,输出必须全部是文本。重复 ID、缺失配对、反向配对和非法 JSON 输入不会参与决策。 - 建立有限的观测视图。 发送当前目标、对话文本、工具名、截短后的输入和结果字符数。工具输出正文与 thinking 不进入决策请求。观测超预算时,逐步缩短输入和旧文本、移除旧的纯文本消息或合并旧调用记录;返回的会话原文不因此改变。
- 每个候选问两个二分类问题。
call_<id>判断“调用及其输入对下一步是否仍然重要”,result_<id>判断 “完整输出是否必须原样保留,之后再检索是否不够”。问题成对分批,每批携带相同观测视图,在并发和总超时约束内执行。 - 全部批次成功后重建快照。 校验每个答案的类型和概率范围,再在消息的深拷贝上应用决策。缺少答案、非法概率、 任意批次失败或超时都会使调用失败,不返回部分压缩结果。宿主应继续使用已保存的原始快照。
两个概率如何变成动作
设保留阈值为 t,默认 0.5。先判断结果,再判断调用:
| 条件 | 动作 | 对返回快照的影响 |
|---|---|---|
p_result >= t |
keep |
保留调用及完整结果,即使 p_call 较低 |
p_result < t 且 p_call >= t |
drop_result |
保留调用,将长文本结果替换为前缀和省略标记 |
两个概率都 < t |
drop_call |
同时移除调用和结果;仅移除因此变空的消息 |
drop_result 的默认前缀为 300 个字符,标记提示从归档历史恢复全文。只有新文本更短时才替换,所以该动作对短输出可能不产生变化。
用户文本、assistant 文本、thinking 和未被修改的块字段保留原样。
以下内容优先受规则保护,不受概率阈值影响:
- 第一条消息、最近
preserve_recent_messages条消息,以及protected_message_ids指定的消息。配对的任一端受保护,整对保留。 protected_call_ids指定的调用,以及不在eligible_tool_names中的工具。默认允许列表为空,因此默认不会压缩任何工具。- 未完成或失败的调用、非纯文本输出、工具名不一致的配对。重复或缺失 ID 的块也不会删除,但不一定出现在
decisions中。
允许列表应由宿主限定为安全的只读工具,ReMe 不会根据工具名自动识别副作用。 对于必须保留的审计记录、变更回执或关键证据,宿主应显式保护,不能只依赖语义概率。
配置与服务调用
安装并配置凭证:
pip install "reme-ai[core,decision]"
export DECISION_MODEL_API_KEY=your-typesafe-api-key
export DECISION_MODEL_BACKEND=agentscope
# 可选:DECISION_MODEL_NAME、DECISION_MODEL_BASE_URL
.env 也可以配置这些变量。旧的 CLASSIFIER_* 名称需按配置迁移说明改为
DECISION_MODEL_*;backend 应为 agentscope。省略模型名或配置为 null 时使用适配器的 SDK 默认模型。
在一个终端启动服务:
reme start config=decision_compaction
在另一个终端调用。以下短示例展示请求格式;复杂样例见本文后面的集成用例:
reme compact_context \
goal='修复支付重试逻辑,之前完成的图标搜索已无关' \
eligible_tool_names='["search_code"]' \
options='{"preserve_recent_messages":1}' \
messages='[{"id":"m0","role":"user","content":[{"type":"text","text":"保留支付代码,清理旧图标搜索"}]},{"id":"m1","role":"assistant","content":[{"type":"tool_call","id":"c1","name":"search_code","input":"{\"pattern\":\"logo\",\"path\":\"web/icons\"}","state":"finished"},{"type":"tool_result","id":"c1","name":"search_code","output":"旧任务的图标路径列表","state":"success"}]},{"id":"m2","role":"user","content":[{"type":"text","text":"现在只处理支付重试"}]}]'
decision_compaction 继承默认服务配置和其他 Job,因此常规后台任务也会启动。
需要嵌入宿主进程时,可像集成测试一样只装配 compact_context Job 和它的决策组件,不启动其他工作流。
标准 Response 的 answer 包含:
schema_version、messages:版本与建议快照;changed、reason:是否实际改变,以及compacted/no_change/no_candidates。decisions:内部配对 ID、原始call_id、动作、原因,以及参与推理时的keep_call/keep_result概率。stats:前后消息数和字符数、候选与保护配对数量、观测视图的估算 token 数及缩减阶段、请求数、供应商 usage 和耗时。 同一份统计也位于response.metadata.compaction。
宿主应检查 success,使用自己的 tokenizer 重新计算最终上下文预算,再选择应用建议、继续压缩或恢复原始记录。
压缩不会自动生成摘要、写入长期记忆或执行历史中的工具。
预算、并发和超时
options 字段 |
默认值 | 作用 |
|---|---|---|
keep_threshold |
0.5 |
两个问题共用的保留阈值 |
preserve_recent_messages |
6 |
原样保护最近的消息,按消息而非轮次数计数 |
max_state_tokens |
25000 |
观测视图的估算 token 上限 |
max_request_tokens |
30000 |
每批观测与问题的估算 token 预算,包含 256 token 的开销预留 |
truncate_head_chars |
300 |
drop_result 保留的文本前缀长度 |
max_concurrency |
4 |
同时运行的决策请求上限,范围 1–32 |
total_timeout_seconds |
30 |
所有决策请求及其排队等待的总超时 |
组件层的 timeout、max_retries、retry_delay 控制单次供应商请求及重试。
内置压缩配置分别为 10 秒、1 次重试、0.5 秒初始退避。预算使用本地估算器,不等于供应商计费 token,也不等于宿主模型的上下文预算。
观测无法装入预算,或一对问题也放不进单批请求时,调用失败,由宿主保留原始快照。
两个真实模型集成场景
集成测试源码 提供两个合成的长任务场景。工具调用及其返回值均为测试数据,历史中的部署、回滚、数据库查询不会实际执行; 只有决策请求使用真实的 TypeSafe/Jev API。
| 场景 | 当前任务与关键候选 | 干扰与保护边界 |
|---|---|---|
| 支付重试缺陷修复 | 下一步根据已读源码和测试原文生成精确补丁,验证相关源码与测试结果被保留 | 已完成的主题 CSS、图标搜索、过期库存查询应有可淘汰项;显式保护账单证据与审批回执,保留失败、运行中、重复 ID 和最近消息 |
| 数据库复制延迟排障 | 下一步引用事件日志及 WAL 位点原文编写根因报告,验证关键日志与数据行被保留 | 混入历史营销报表、旅行天气和退役系统压测;保护审计审批、回滚回执、非文本图表、失败查询和最近消息 |
两个用例都检查:真实推理按批执行、至少移除一个无关调用、关键候选完整保留、受保护记录和会话文本不变、 原始输入与临时归档不变,以及输出字符数实际下降。模型具有不确定性,语义断言可能揭示模型或配置的变化;测试不会伪造概率来保证通过。
2026-10-15 使用本地配置的 TypeSafe/Jev 端点实测,两例均通过,结果如下。数字按 JSON 字符数统计,不是 token 节省率:
| 场景 | 压缩前字符数 | 压缩后字符数 | 减少比例 | 被移除的无关调用 | 决策请求数 |
|---|---|---|---|---|---|
| 支付重试缺陷修复 | 39,438 | 12,738 | 67.7% | 3 | 2 |
| 数据库复制延迟排障 | 51,485 | 12,828 | 75.1% | 4 | 2 |
显式授权真实 API 调用后运行:
REME_RUN_DECISION_INTEGRATION=1 \
pytest tests/integration/test_decision_compaction.py -v -s
测试读取环境变量或仓库根目录 .env,环境变量优先;未显式启用时直接跳过,未配置 API key 时也跳过。
输出仅包含合成场景的动作、概率、字符数和 usage;工作区及原始快照放在 pytest 的临时目录中。
实际节省比例依赖任务历史、目标和模型判断,不能由这两个用例推导通用收益。
适用边界
决策模型只能看到有限观测视图,无法核查被省略的工具输出内容。目标写得不完整或工具描述不足时,判断可能遗漏重要信息。 宿主需要给出明确的下一步目标,为不可丢失的信息设置保护,并在应用后继续保留可恢复的原始历史。 该策略适合减少旧工具轨迹的体积;它不提供自动触发、最终 token 预算保证、摘要生成或归档存储。
接口与实现分别见 Compaction schema、 候选配对与重建、 观测与分批 和 Job Step。