跳到正文

Skills

chimera-budget-the-context

按低于真实窗口的预算来花,并把你每一步都重新发送的工具 schema 算进去——它们是压缩触及不到的地板。

模式来源: clean状态: activev0.1.0 · Apache-2.0

由读过该卡片的评审者赋予,而不是文件自我声明的。智能体在处理不可信内容的运行中提炼出的卡片,生来即被标记为受污染,在被检索之前会一直等待评审。

何时会想到它

  • 上下文溢出导致运行中断
  • 调高 max-steps
  • 智能体忘了自己在做什么
  • 再接入一个 MCP 服务器
  • 决定提示词里删掉什么

价值通常在「避免」和「检查」里。「该做」是人人都会写的那一节。

上面的卡片正文是译文。英文原文才是 CLI 导入的内容、智能体运行时读取的内容,也是下方哈希所证明的内容。

触发

你在跑一个每一步都往消息列表里追加内容的循环——一个 ReAct agent、一轮编码、一个会调用工具的助手——而这个列表只增不减。症状是:提供方(provider)因上下文长度报错,或者运行没有崩,但跑了很长一段之后开始在错误的文件上干活。

这条不适用于你自己组装好、可以一次性量完的单次调用。什么都不会累积的时候,就没有淘汰策略(eviction policy)需要设计。

该做

  1. 在动这个循环之前,先写下两个数字:模型宣称的窗口大小,以及你打算把其中多大比例花在提示词上。Chimera 花 0.6(chimera/core/context_budget.py 里的 DEFAULT_BUDGET_FRACTION)。剩下的部分用来支付补全(completion),以及你的 token 估算和提供方真实计数之间的差额。
  2. 预算的某个比例上触发压缩(compaction),而不是在窗口的某个比例上——Chimera 在预算的 0.8 处触发。压缩需要有地方可以压进去;把触发点设在窗口上,等它触发时已经没有空间了。
  3. 把固定的地板和会增长的部分分开测量。系统消息加上 tools= 载荷在每一步都会被重新发送,任何消息压缩都碰不到它们。在你假设历史记录才是贵的那部分之前,先跑 chimera schema-bench(或者自己数一遍 JSON)。一次啰嗦的 MCP 或 OpenAPI 导入,可能给这次运行的每一步都压上数万个 token。
  4. 如果地板本身是问题,那就削地板:剥掉只用于注解的 schema 键(examplestitledefault$comment),把参数说明裁到第一句,同时保持 typepropertiesrequiredenum 原样不动,这样工具选择和参数有效性都不会变。chimera/tools/schema_compact.py 做的就是这件事。如果还是太大,就少登记几个工具。
  5. 把淘汰顺序明确定死:系统消息永不淘汰,最近的若干轮原文保留(Chimera 保留 6 轮),更早的那一段用摘要或者一条事实性记录替换掉。绝不要重写系统消息——它是提示词缓存所依赖的稳定前缀,改它会让它后面的每一轮缓存全部失效。
  6. 压缩之后,把这次运行要维持自身所需的东西重新注入回去:任务原文、计划、带状态的任务清单,以及当前正在编辑的那个文件。文件要从磁盘重新读取,而不是还原一份记忆中的副本。
  7. 当你自己估算 token 大小时,除了 content 之外也要把 tool_calls 载荷算进去。工具参数是挂在 assistant 消息上的,不在 content 里;一个只读 content 的体积估算,恰好会低报那些真正变大了的消息。

避免

因为任务没做完就调高 --max-steps。这是最顺手的动作,也正是杀死这次运行的那个动作:步数更多,意味着在同样大小的窗口里塞进更长的消息列表。

丢掉任务陈述。它作为一条用户消息排在最前面,所以它是一个天真的压缩器第一个淘汰掉的东西,也是 agent 最不能没有的东西。结果就是一个 agent 在执行一份目的已经被删掉的计划——依然自信,依然在产出编辑,哪里都没有报错。文件它可以重新读;指令它读不回来。

把一条 tool 消息留在保留尾段的开头:

older, recent = body[:-keep_recent], body[-keep_recent:]   # 可能让一条 tool 结果变成孤儿

对比

older, recent = body[:-keep_recent], body[-keep_recent:]
while recent and recent[0].get("role") == "tool":
    older.append(recent.pop(0))                            # 尾段从一个合法的轮次开始

大多数提供方会拒绝一条其配对的 assistant tool_call 已经不在的 tool 消息,于是本该拯救这次运行的压缩,反而成了终结它的东西。

还要避免一上来就为最大压缩率去调参。要以召回优先来校准:保留太多花的是 token,那是一笔账单;删掉太多丢的是后面还要用的上下文,而那些消息已经没了。一个是成本,另一个不可恢复。

检查

故意把窗口设小——把预算指向一个 4K 的假窗口,或者跑一个你知道很长的任务——然后确认三件事:压缩触发了、运行越过压缩继续跑了、以及紧随其后的那条消息里含有原始的任务字符串。压缩之后,在组装好的提示词里 grep 任务中一句有辨识度的话。如果它不在,那还原就是没在工作,不管日志怎么说。

然后用一个二元问题检查地板:在历史为空的情况下,单独一步的提示词是不是已经超过了你的阈值?如果是,压缩永远帮不上忙——compact() 在一个它压不动的列表上会返回 changed=False,而对一次空操作的诚实解读是"这没起作用",不是"再撞一次同一堵墙"。

风险

预算设得太低,会去压缩那些本来根本不需要压缩的运行,而每一次压缩都会重写提示词的后缀,把它后面的缓存命中全部扔掉。在一次长时间的编码会话里,这是一笔真金白银的账单,付出去只为了躲开一次根本不会发生的溢出。

schema 压缩有它自己的边界:把参数说明裁成一句话,对参数有效性来说是安全的,但可能会删掉那句告诉模型何时该用这个工具的话。它改变了选择行为,却没有改变任何校验器会检查的 schema,所以它的失败形态是工具选得略差一点,而不是报错。要把它当成一次 A/B 来测量,不要因为它省 token 就打开它。

而且,如果任务对这个模型来说本来就太大,整套做法什么也换不来。做预算是把硬天花板变成软天花板;它变不出本来就不存在的空间。

如何使用

卡片就是数据。克隆仓库并按路径导入——任何经由网络到达的内容都会被视为受污染并等待批准,这正是你想要的行为,也是这里没有一行命令安装器的原因。

git clone https://github.com/brcampidelli/chimera-agent.git
chimera skills-import chimera-agent/skills/chimera-budget-the-context/SKILL.md

完整性

文件发布版本的 SHA-256。导入方可以据此核对收到的内容与本页展示的一致。

63f202117c1ffb79dcc016edf37d12760ef2edd00274900bf5177dc1ee6b33f2

在仓库中阅读该卡片