Grok Build 是如何工作的(三):compact 与会话减负

阅读顺序:四份历史数据 → 四类减负机制 → 摘要 compact 的 two-pass → compaction mode → 时间线与速查。

术语:

含义
soft-trim 超长 tool 正文保留文首 + 分隔标记 + 文尾,中间删除
hard-clear tool 正文整段换成固定占位句(如 [Tool result omitted — too old]
请求体 序列化后发往模型服务的 HTTP 载荷(含对话、tools、参数等)及其字节体积
请求副本 组装当次请求时,从内存对话历史 clone 出的条目列表;可只改这份 clone,不改内存真值

1. 四份与会话历史相关的数据

名称 是什么 用途与更新方式
内存对话历史 ChatState 中的 conversation 运行时真值。L2/L3 写入与读取。组装模型请求时从这里复制。可被摘要替换为更短的当前历史
chat_history 磁盘上的对话列表文件 内存历史的镜像:追加则 persist;整表变化则 replace。无独立裁剪逻辑
updates.jsonl 按时间追加的过程日志 与内存历史、chat_history 独立维护。供 replay、搜索索引等。内存历史变短或变摘要时,不要求本文件改写成同一列表
请求副本 当次调用用的条目 clone 从内存历史复制;随本次请求结束丢弃。模型在当次调用中只看见经 backend 映射后的这份列表

chat_history 与内存历史:逻辑上同一份当前对话列表(磁盘 / 内存)。落盘可异步,崩溃瞬间磁盘可能略落后于内存。

updates.jsonl 与前两者:前两者是当前对话列表;updates.jsonl 是过程中按时间记过的更新。

本节只定义数据位置。对它们做 soft-trim、hard-clear、去图、摘要替换的规则见下一节。

2. 四类减负机制

机制 是否称 compact 是否调摘要模型 改谁
请求副本 tool 裁剪 仅请求副本
内存 hard-clear 内存历史,并同步 chat_history
请求体体积控制(旧图) 仅请求副本
摘要 compact 是(/compact、auto-compact、超窗等) 通常是 内存历史,并同步 chat_history

请求副本 tool 裁剪

  • 何时:每次组装请求时,若 total_tokens > context_window / 2
  • 做什么:在请求副本上按 tool 所属 turn 龄期(从尾向前数 User)处理 tool result。默认:最近 3 个 turn 不动;中等龄且正文超过约 4000 字 → soft-trim(文首/文尾各约 1500);龄期 ≥ 约 10 → hard-clear。
  • 不做什么:不改内存历史、chat_historyupdates.jsonl。不调用摘要模型。

内存 hard-clear

  • 何时:每次用户消息写入内存历史之后。与是否过半窗、是否 auto-compact 无关。
  • 做什么:对龄期 ≥ 约 10 个真实 user turn 的 tool result,在内存历史上 hard-clear,并同步 chat_history。只 hard-clear,不做 soft-trim。合成 user(如 system-reminder)对龄期的影响由实现校正。
  • 目的:限制长 session 进程内存。
  • 不做什么:不改 updates.jsonl 已写原文。不把整段对话换成摘要。

请求体体积控制(旧图)

  • 何时:组装请求时,对话序列化体积接近代理/服务上限(实现上约 50MB 硬顶下留余量触发)。
  • 做什么:在请求副本上移除较早 inline 图,换成说明文字。
  • 不做什么:不改内存历史。与“token 过半窗才做 tool 裁剪”的条件相互独立。模型调用层若仍收到 413,还可能再剥图重试(发送路径,不改内存历史策略)。

摘要 compact

  • 目的:用摘要替换内存历史中的当前对话列表,降低后续上下文占用。
  • 触发(并列入口,共用内核):
    • 用户 /compact
    • auto-compact:估算用量 ≥ 配置百分比(代码侧常见约 80%–85%,可配置、可按模型与托管覆盖)
    • 超窗 / 溢出预检 / 部分换模型导致窗口变小等恢复路径
  • 成功后:内存历史变为摘要后结构,chat_history 同步。可写 checkpoint,供 rewind 跨压缩点。updates.jsonl 不因此被改写成与内存历史同一列表。
  • 与请求副本 tool 裁剪的阈值:tool 裁剪在 token 过半窗时作用于请求副本;auto-compact 使用单独的百分比阈值(常见约 80%–85%)。两套条件,分别触发。

3. 摘要 compact 内核:single-pass 与 two-pass

触发:  /compact  或  auto-compact / 超窗等
              \          /
               \        /
            compact 内核
                 │
    two-pass 开启且 NOTE₁ 有效 → Pass 2
    否则 → single-pass(一轮摘要)
                 │
         写回内存历史(同步 chat_history)
                 │
         按 compaction mode 附加回捞说明(可选)

切片与摘要的输入来自内存历史快照。请求副本与 updates.jsonl 全量不是该 split 的输入。

single-pass

一次调用摘要模型(或等价路径),把当前需压缩的历史压成摘要,写回内存历史。无前置缓存时走这条;two-pass 失败或关闭时也回退到这里。

two-pass

摘要 compact 内核内部的可选执行方式:用两轮摘要代替一轮。开关关闭则始终 single-pass。触发入口仍只有 /compact、auto-compact、超窗等。

Pass 1 在后台摘要历史前缀;Pass 2 在正式 compact 时用该前缀摘要加上较短尾部再摘要,从而缩短主路径上单次摘要的输入长度与等待时间。

步骤 名称 何时 输入 输出 是否改内存历史
Pass 1 prefire 用量 ≥ auto-compact 阈值 − 提前量(默认提前约 10 个百分点);后台 内存历史快照按 token 重量切开后的前缀(默认约前 95%;不拆开 tool_call 与对应 tool_result) NOTE₁:前缀摘要文本 + 前缀指纹
Pass 2 正式 compact 已进入 compact 内核,且 NOTE₁ 仍有效 NOTE₁ + 仍较新的尾部(默认约后 5%) 最终摘要,写回内存历史

NOTE₁:Pass 1 缓存的前缀摘要文本,附带前缀指纹。前缀因 edit / rewind / 分支等变化导致指纹不匹配时,NOTE₁ 作废,改走 single-pass。

Pass 1 其它退出:对话过短、切开结果空、摘要调用失败、空 NOTE₁、开关关闭 → 不产生可用缓存。

何时跑

  • Pass 1:two-pass 开启,且用量 ≥ auto-compact 阈值 − 提前量。后台写 NOTE₁,不改内存历史。
  • Pass 2:已进入 compact 内核,且 NOTE₁ 仍有效;否则 single-pass。/compact 与 auto-compact 都进该内核,故都能用 Pass 2。只有自动用量路径会启动 Pass 1。

4. compaction mode(摘要 compact 成功之后)

仅在摘要 compact 已成功写回内存历史与 chat_history 之后生效。决定摘要正文外是否附带“compact 前细节可从某路径读取”。不改变请求副本 tool 裁剪、内存 hard-clear、请求体去图的行为;也不取消“当前历史已被摘要替换”的结果。

mode 摘要外附加 回捞对象
summary 无路径 仅摘要本身
transcript 指向 updates.jsonl 读过程日志拿 compact 前原文
segments 指向 session 下 compaction/ 读该次 compact 时另写的 markdown 分段(见下)

segments 模式落盘内容

路径在 session 目录下的 compaction/(与 chat_historyupdates.jsonl 并列)。

文件 内容
INDEX.md 目录表。每成功 compact 一次追加一行:段号、文件名、turn 数、约略字节、关键词。供先扫目录再打开具体段
segment_NNN.md(如 segment_007.md 这一次 compact 从内存历史切出去、即将被摘要替换掉的那一段对话,渲染成可读 markdown

单个 segment_NNN.md 大致结构:

  1. Segment metadata:段号、条目数、时间戳
  2. Turn statistics:角色计数、用过的 tool 名与次数、工具参数里出现过的路径、tool 错误数、末条 assistant 摘录等
  3. Summary:本次 compact 生成的摘要正文(与写回内存历史的摘要同次产物)
  4. 对话正文区(详略由 compaction_detail 配置,默认 verbose):
    • verbose:按条列出 Human / Assistant / Function 等,含正文、tool 名与参数、tool 返回全文(单文件有约 512KB 截断上限)
    • balanced / minimal / none:参数与返回逐渐缩短,直至只有统计+摘要、无逐条正文

segments 回捞的是 compact 时专门导出的段落快照(统计 + 可选全文)。读的不是 updates.jsonl 事件流,也不是已经变成摘要后的 chat_history

配置解析顺序通常为:环境变量 → 用户配置 → 托管 managed_config[features].compaction_mode → 代码枚举缺省。

  • 代码枚举缺省:summary
  • 托管 features 可设为 segmentstranscript。未设用户覆盖时,以托管与解析结果为准。

组装当次请求时仍只发送请求副本。updates.jsonlsegment_*.md 全文不会自动并进请求;需模型在后续 tool 轮次按摘要中的路径自行读取。

5. 同一次 turn 内的相对顺序

下列步骤不必每步都发生:

  1. L2 将用户消息写入内存历史 → 内存 hard-clear(可能)→ 同步 chat_history;事件可追加 updates.jsonl
  2. 主模型调用前:若 two-pass 开启且用量达到 prefire 水位 → 可后台 Pass 1。若达到 auto-compact 阈值(或 force 等)→ 摘要 compact(Pass 2 或 single-pass)→ 按 compaction mode 附加说明。
  3. 组装请求:内存历史 → 请求副本;体积过大 → 请求体体积控制去旧图;token 过半窗 → 请求副本 tool 裁剪;可选仅本请求的 memory reminder。
  4. 发出请求体;413 等可在发送路径再剥图。
  5. 调用失败且判定上下文超限,或工具输出使估算 token 顶破整窗(preflight)→ 可再做摘要 compact,然后重新组装请求副本再调用。
  6. 成功路径:结果写回内存历史(同步 chat_history)。

6. 机制对照(速查)

条件 行为
token > 窗 / 2 请求副本 tool 裁剪
每次 push user,tool 够老 内存 hard-clear(同步 chat_history
请求体字节接近上限 请求副本上去掉较早 inline 图
用量 ≥ auto 阈值 / 超窗 / /compact 摘要 compact 替换内存历史
two-pass 开且近阈值 后台 Pass 1 → NOTE₁
已进 compact 内核且 NOTE₁ 有效 Pass 2;否则 single-pass
摘要 compact 成功后的 mode 是否写回捞路径 / 是否写 compaction/
对象 请求副本 tool 裁剪 内存 hard-clear 请求体去图 摘要 compact
内存历史 不改 hard-clear tool 不改 换成摘要
chat_history 不改 随内存历史 不改 随内存历史
updates.jsonl 不改 不改已写正文 不改 不整表替换;transcript 可指向它
请求副本 soft-trim / hard-clear 起点可能已是 hard-clear 后内容 去旧图 不单独跑;clone 自 compact 后的内存历史

compact-flow

作者的邮箱:tokamak9000@163.com。如有问题,欢迎讨论

posted @ 2026-08-05 22:59  tokamak9000  阅读(2)  评论(0)    收藏  举报