news 2026/9/17 13:09:34

DeepChat Tape-Native 上下文压缩:边界推进与语义摘要解耦、溢出恢复与用量核算的完整设计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DeepChat Tape-Native 上下文压缩:边界推进与语义摘要解耦、溢出恢复与用量核算的完整设计

DeepChat Tape-Native 上下文压缩:边界推进与语义摘要解耦、溢出恢复与用量核算的完整设计

【免费下载链接】deepchat🐬DeepChat - A smart assistant that connects powerful AI to your personal world项目地址: https://gitcode.com/GitHub_Trending/dee/deepchat

本文围绕 DeepChat 仓库中的docs/issues/tape-context-compaction/文档(spec.md 与 plan.md)展开,深入讲解 DeepChat 的 Tape-Native 上下文压缩(Context Compaction)方案:为什么"摘要成功"不应是"边界推进"的前提、压缩引擎如何在 append-only Session Tape 之上实现"更小的 provider 视图",以及静默溢出观测、压缩模型用量核算、渲染进程状态同步与首条用户消息钉选(first-user pinning)等后续正确性契约。读完后你将掌握:边界/摘要解耦的三态结果模型、提交时严格收缩证明(shrink proof)的实现、summary_unavailable/summary_rejected_larger间隙原因族、CompactionService的关键常量与压缩触发配置,以及该方案在 CompactionService、contextContributions、CompactionRuntimeCoordinator、ContextOccupancyCoordinator 中的落地方式。

问题背景:一次压缩依赖另一次大模型请求的循环失败

DeepChat 将完整对话保存在 append-only 的 Session Tape 中,但运行时曾经把两种本应独立的上下文策略耦合在一起:

  1. 通过推进一个"重建边界"(reconstruction boundary)来压缩 provider 可见的 View;
  2. 为被该边界隐藏的历史生成语义摘要(semantic summary)。

旧实现里CompactionService.applyCompaction只有在 LLM 摘要成功之后才推进边界。于是当上下文非常大时会产生循环失败:恢复请求本身又依赖另一次大型模型请求,而一次失败的摘要会消耗掉唯一的恢复机会,却并没有让 View 变小。全量历史启发式 token 估算、受保护的活跃轮次工具流量,以及"一次性"恢复锁存(one-shot recovery latch),进一步放大了这个缺陷——一个长工具循环可能在本地预检或 provider 侧被拒绝,尽管原始 Tape 里其实有足够信息可以从一个更小的 View 继续执行。

2026-08-15 的第四轮实现审计还发现另一个更隐蔽的问题(见 spec.md 的 "Follow-up Correctness Contract"):原实现的"收缩证明"发生在commitSummaryBoundary之后。证明失败后恢复调用方的内存投影,并不能回滚已经持久化的 cursor 与 anchor;而普通 pre-turn 路径甚至没有等价的证明。结果是:一个等于甚至大于其替换目标的 checkpoint 也能被持久化,并把正反馈带入下一轮压力估算。

核心模型:compact = handoff + anchor + selective view

文档对 tape.systems 模型的解读是整个方案的地基:

  • Tape 本身不会被压缩,它始终是 append-only 的事实日志;
  • compact 被定义为handoff + anchor + selective view:anchor 移动逻辑重建起点,View 读取更小的后缀;更早的条目仍然可用于召回(recall)和审计;
  • summary 是独立的派生策略:附着在 anchor 上、带来源信息(provenance),作为重建提示而非保留历史的权威。

因此 DeepChat 必须把两种独立结果分开:

  1. 边界推进(Boundary progress):一个持久的重建 anchor 推进了被选中的 View;
  2. 语义连续性(Semantic continuity):可选的 summary 描述被该边界隐藏的内容。

摘要生成可以改善连续性、成本和延迟,但绝不能成为边界推进的前提。对应的源码事实是 CompactionExecutionResult:

export type CompactionExecutionResult = { outcome: 'summarized' | 'boundary_only' | 'unchanged' anchorCommitted: boolean summaryState: SessionSummaryState summaryError?: string }

布尔结果被替换为三态 outcome:summarized(边界推进且新摘要生效)、boundary_only(边界推进但无新摘要)、unchanged(边界没有前进)。判定逻辑在 resolveStoredOutcome:先通过hasCompactionBoundaryAdvanced比较前后 cursor,若未推进则unchanged;推进了之后再看summaryUpdatedAt是否为 null 来区分前两种。

恢复状态机:8 步压力恢复阶梯

spec.md 给出了完整的状态机文本(这里完整继承):

assemble candidate View -> estimate pressure -> fits: send provider request -> pressure: 1. compact older eligible closed inline tool results while preserving the newest closed unit 2. if pressure remains, compact the newest eligible closed unit as a bounded fallback 3. if the changed projection fits: send it as a new request 4. otherwise prepare a reconstruction boundary and try semantic summary 5. summary fails: commit deterministic boundary-only anchor 6. reassemble and require a strictly smaller View for semantic recovery 7. strict output-reserve retry when only output reduction can help 8. fail only when protected content cannot fit or recovery made no progress

其要点:

  • 压力恢复的"免费手段"(裁剪已闭合的工具结果单元)排在模型摘要之前,这对应 plan 中"Free View reductions remain ahead of model-backed summary in the existing request-pressure ladder"的冻结决策;
  • 一次成功的 provider 响应之后,序列级溢出锁存(sequence latch)复位,同一 Run 的后续工具步骤可以再次运行状态机;
  • Run 级恢复上限(recovery ceiling)是独立状态,防止无限 compact/retry 循环。plan 的 Completion Summary 明确:恢复在成功 provider 响应之后复位,且每个 Run 最多三个恢复序列
  • 恢复只有在持久边界推进且重新推导出的 View 严格变小时才报告applied

CompactionService:从 prepare 到 apply 的实现细节

四个入口与锚点命名

CompactionService 提供四个 prepare 入口,各自生成带不同anchorNameCompactionIntent

入口触发场景anchorName特殊参数
prepareForNextUserTurn下一用户轮次前的常规压力检查compaction/auto;当forceContextPressure为真时为auto_handoff/context_overflowtriggerThreshold生效,未超阈值直接返回 null
prepareForResumeTurn从历史消息恢复执行compaction/resumeminimumRetainedTurnCount = retainRecentPairs + 1
prepareForContextPressureRecoveryprovider 侧溢出后的恢复auto_handoff/context_overflowforce: true,跳过阈值判断
prepareForManualCompaction用户手动压缩compaction/manualtriggerThreshold: 0retainedTokenTarget: 0,强制全量可摘要

这些 anchor 名称前缀在渲染侧有明确语义:buildReconstructionContent 按handoff/auto_handoff/compaction/前缀分别构造不同的持久化重建块,只有当compaction/anchor 的reason属于 summary-gap 原因族时才渲染 "Persisted Tape Compaction Gap" 块。

压缩触发与保留尾部计算

prepareCompaction中的预算计算是方案里可复用的关键参数(源码 L899-L993):

  • 请求预算requestBudget = floor((contextLength - reserveTokens - extraReserveTokens) / SAFETY_MARGIN),其中SAFETY_MARGIN = 1.2
  • 触发预算triggerBudget = floor(requestBudget * triggerThreshold / 100),只有投影 prompt 的估算 token 超过triggerBudget才触发(非 force 场景);
  • 保留尾部目标min(RETAINED_TAIL_TOKEN_CAP, inputBudget * RETAINED_TAIL_INPUT_RATIO),即min(20000, inputBudget * 0.25),再由 selectRetainedTail 从尾部向前累加,直到满足"最少保留轮次数"与"token 目标"两个条件。

压缩设置本身来自会话配置(getCompactionSettings),默认值为:autoCompactionEnabled = trueautoCompactionTriggerThreshold = 80(百分比)、autoCompactionRetainRecentPairs = 2(保留最近的用户/助手对数)。

此外,prepareForNextUserTurn处理了一个容易踩坑的细节(源码注释 L444-L458):当重试复用的用户 prompt 已经在历史中(newUserContentInHistory),就不再二次投影它,否则上下文估算会被放大并过早触发压缩。

applyCompaction:三态提交与 CAS

applyCompaction 的流程精确对应 spec 的契约:

  1. assertValidContextLengthcontextLength必须有限且大于零,否则抛RangeError——这是 follow-up 契约中"无效模型元数据应显式失败而不是引发每轮压缩循环"的落地;
  2. 调用generateRollingSummary生成摘要。摘要失败且非 abort 时,只记录summaryError并继续走边界提交;
  3. 若摘要为空(生成失败),走commitBoundaryOnly(intent),默认原因summary_unavailable
  4. 若摘要存在,先执行提交时收缩证明isSummaryCheckpointSmaller,不通过则以summary_rejected_largercommitBoundaryOnly
  5. 通过则commitSummaryBoundary,用compareAndSetSummaryState(CAS)原子写入 summary state 与 anchor。

commitBoundaryOnly 还实现了两条 spec 要求:

  • 间隙合并mergeOrderSeqRanges把上一次 anchor 上的连续 gap 范围与本次 gap 合并为一个有界summaryGap,避免每次失败都追加一条 provider 可见的 notice;
  • priorSummary 保留:若存在旧的合法摘要,以priorSummary字段带入 anchor,而不是把它谎报为新生成的summary

CAS 竞态的处理也符合 spec 不变量:只有获胜者持久化的 cursor 比调用方先前 cursor 更新(hasCompactionBoundaryAdvanced)才算进度,丢失 CAS 的一方报告unchanged

提交时收缩证明(shrink proof)

这是 2026-08-15 follow-up 契约的核心不变量,公式来自 spec.md:

tokens(next checkpoint) < tokens(current checkpoint) + tokens(newly hidden visible turns)

isSummaryCheckpointSmaller 的对应实现:

const checkpoint = buildContextCheckpoint(nextSummary, { entryId: 0, name: summaryAnchor.name, state: summaryAnchor.state, createdAt: 0 }).message const nextCheckpointTokenEstimate = checkpoint ? estimateMessagesTokens([checkpoint]) : 0 const replacedTokenEstimate = intent.currentCheckpointTokenEstimate + intent.newlyHiddenVisibleTokenEstimate return nextCheckpointTokenEstimate < replacedTokenEstimate

两边都使用规范的 provider 消息投影和共享的estimateMessagesTokens估算器,而不是拿裸摘要文本或原始 transcript 比较——所以 provenance 文本、recall 指引、gap 块这些 checkpoint 组成部分的 token 开销都计入成本,provenance 开销不可能绕过收缩保证。"相等即拒绝":不证明严格变小就不提交语义摘要。intent 中携带的currentCheckpointTokenEstimatenewlyHiddenVisibleTokenEstimate在 prepareCompaction L883-L965 中预先算好:当前 checkpoint 用真实的重建 anchor(而非 null 占位符)构建,新增隐藏量只统计本次 cursor 推进移出的可摘要轮次。

summary-gap 原因族

summary_unavailablesummary_rejected_larger被收敛为同一个原因族,由共享的 allowlist/predicate 统一治理(contextContributions.ts L19-L27):

export const SUMMARY_UNAVAILABLE_REASON = 'summary_unavailable' export const SUMMARY_REJECTED_LARGER_REASON = 'summary_rejected_larger' export function isSummaryGapReason(value: unknown): value is SummaryGapReason { return value === SUMMARY_UNAVAILABLE_REASON || value === SUMMARY_REJECTED_LARGER_REASON }

这个谓词同时用于:间隙合并(commitBoundaryOnly中读取上一个 anchor 的 reason)、pending-gap 恢复(prepareCompaction读取pendingSummaryGap)、checkpoint 渲染,以及渲染进程共享状态——SessionCompactionBoundaryReason 类型正是这两个值,说明前端只暴露同族的boundaryReason。spec 还要求:gap checkpoint 文本对相同的 anchor 状态必须是确定性的(无生成时间戳、无不稳定错误措辞);原始 provider 错误、时间戳、秘密、堆栈数据都不进入模型可见的 gap 状态。

Checkpoint 的构成与来源文本

buildContextCheckpoint 组装模型可见的 checkpoint 消息:开头的CHECKPOINT_NOTICE声明其为不可信上下文数据;摘要块用自适应围栏的Persisted Rolling Summary不可信块包裹(围栏长度动态超过内容中最长的~连续,防止围栏逃逸);若 anchor 携带range,还会附加 "Summary Provenance" 段,写明该摘要覆盖的 orderSeq 区间,并指向tape_search/tape_context做原始召回。每个部分同时记录为DeepChatTapeViewSyntheticContribution(带contentHashsourceEntryIds),进入 ViewManifest 的溯源体系——这满足 spec "Checkpoint Provenance Text" 切片"渲染 anchor 上已有的来源覆盖、保持确定且有界"的要求。

滚动摘要与 map-reduce 分块

摘要生成本身(generateRollingSummary / summarizeBlocks)有几个值得注意的工程参数:

  • 模型选择:若配置了 assistant 模型且完整 payload(前摘要 + 块)在其预算内,优先用 assistant 模型,否则回退当前聊天模型;
  • 输入预算max(1024, floor(contextLength / 1.2) - summaryOutputTokens - 4096),其中summaryOutputTokens = clamp(512, reserveTokens, 2048)SUMMARIZATION_OVERHEAD_TOKENS = 4096
  • 自适应分块比例(computeAdaptiveChunkRatio):总 token 不超窗用 0.7,超 2 倍窗用 0.4,中间 0.55,单块上限再减 4096 开销、下限 2048;
  • 递归 map-reduce:先按 token 分组、超限块按maxChunkTokens * 4字符切分,逐块总结后把块摘要作为新 blocks 递归再总结;
  • 摘要 prompt(buildSummaryPrompt)要求保留目标、约束、决策及理由、工具结果中的关键事实、未决问题、不透明的标识符(ID、hash、路径、SHA),禁止编造事实、禁止逐字复制凭据,输出固定的五个 Markdown 小节(Current Goal / Preferences And Constraints / Key Facts And Decisions / Important State / Open Issues And Next Steps);
  • 输出消毒:sanitizeSummaryContent 去除think标签,并用正则把Bearertoken、sk-密钥、AIza密钥、JWT 替换为脱敏占位符。

静默溢出观测:不重放已完成的工作

当 provider 在 provider 侧静默超出上下文窗口(本地预检没有发现)时,spec 的 "Silent Provider Pressure Observation" 定义了两种签名,plan 的切片 5 给出了检测契约:

  • successful_prompt_overflowstatus=completedstopReason=completeinputTokens > contextWindowTokens
  • zero_output_length_at_limitstatus=completedstopReason=max_tokensoutputTokens=0inputTokens >= max(1, ceil(contextWindowTokens * 0.99))

关键约束包括:cache-read token 是 input 内部的明细,绝不再次相加;观测以可空附加字段contextPressure持久化到既有 append-only 的provider/attempt_completed事实上(v1/v2 历史记录读作 null),而不是新增事实类型;一个观测仅在它比最新重建 anchor 更新时才"未结算",任何更晚的 anchor(无论阈值压缩、boundary-only、reset 还是 handoff)都天然结算它,不需要后台队列或可变的 consumed 标记;每个新轮次最多做一次索引查询和一次普通压缩准备,不能自旋;检测与持久化是 fail-open 的,诊断写失败不能把已完成的 provider 响应变成用户可见故障。这也是 DeepChat 与 pi 的行为差异:max_tokens不请求自动续写,不重放任何已完成的响应、用户 prompt 或副作用工具调用。

压缩模型用量核算:每一次付费调用都被记录

plan 切片 6 / spec "Compaction Model Usage Accounting" 把压缩调用本身变成可审计对象:

  • 每次物理 summary 调用前(generateText之前)发放随机providerCallId——generateSummaryText L1340-L1379 中可见:调用前const providerCallId = randomUUID(),成功返回上报completed观测(含独立校验后的 input/output/total,缺失即 null)做内容消毒;抛错或 abort 则上报终态观测(usage: null)后重抛。观测发生在物理边界而非最终摘要返回处,因此即便后续 chunk 失败、收缩证明被拒、边界回退 boundary-only 或 marker 被撤回,已成功 chunk 的计费证据仍然保留;
  • 观测器(CompactionModelCallObserver,类型定义 L105-L123)只携带 attemptId/callId/provider/model/status/usage/时间戳,绝不携带 prompt、摘要文本、provider 错误文本;notifyModelCall 对观测器异常 fail-open;
  • Tape 侧记录幂等的compaction/model_call_completed事件,provenance key 含 provider-call ID,重放同一 call ID 解析到既有源序列;
  • 报表投影deepchat_usage_stats从"按消息一行"迁移为稳定的usage_id投影:类别chat | compaction,压缩调用每次 provider 调用一行;legacy 行保持chatusage_id = message_id;缺失用量保持 null——不估算、不归零、不进 cache-hit 分母;generateText无 cache 读写契约,压缩的 cache 列保持 null;
  • 归因遵循实际执行模型:配置了 assistant 模型时用量归属该 provider/model,而非活跃聊天模型。

渲染进程无竞态状态同步

plan 切片 4 定义了一份严格的同步契约,其类型已在共享层落地(agent-interface.d.ts L31-L45):

export type SessionCompactionStatus = 'idle' | 'compacting' | 'compacted' export type SessionCompactionBoundaryReason = 'summary_unavailable' | 'summary_rejected_larger' export interface SessionCompactionState { status: SessionCompactionStatus cursorOrderSeq: number summaryUpdatedAt: number | null boundaryReason: SessionCompactionBoundaryReason | null } export interface SessionCompactionSnapshot { state: SessionCompactionState emitSeq: number latestAnchorEntryId: number | null }

契约要点(对应 CompactionRuntimeCoordinator 中进程生命周期的emitSeqBySession: Map<sessionId, number>):

  • 状态仍是既有的三种 live status(idle/compacting/compacted),不发明第四种;cursor-only 持久化状态投影为compactedsummaryUpdatedAt: null)而不是 idle;
  • boundaryReason只从最新重建 anchor 的state读取,且仅对持久化的 compacted 边界暴露;idle/瞬时 compacting 或 legacy/畸形 anchor 一律为 null,避免旧边界的 reason 被误读为在途工作的结果;
  • emitSeq由协调器在每次发布前自增,快照在同步的序列化点上读取{ state, emitSeq, latestAnchorEntryId };渲染端先订阅并缓冲事件、再取快照、丢弃emitSeq <= 快照序列的缓冲事件、按序应用剩余事件;
  • latestAnchorEntryId是产生该快照的持久 append-only 边界的 SQLite Tapeentry_id(无 anchor 则 null),跨进程重启仍有意义;emitSeq是进程本地的(Electron 主进程退出即拆除渲染连接),无墙钟时间戳参与排序;
  • 渲染端激活使用自己的代际令牌,晚到的快照/事件/失败请求不能覆盖当前会话;直接 ACP 会话固定返回 idle 零序列,绝不发布 DeepChat 压缩事件。

崩溃后 marker 对账

plan 切片 3 的 "Marker Recovery State Machine" 定义了转录里"压缩中"合成 marker 的持久化状态机:

  • prepareCompaction返回 intent 时一次性发放 UUID(compactionAttemptId,对应源码中 prepareCompaction L956 的compactionAttemptId: randomUUID())。它随每次应用该 intent 进入合成 marker 与 summarized/boundary-only 的 anchor,是关联键而非授权令牌,不复制任何错误文本、provider 响应或秘密;
  • 持久状态迁移为prepared -> marker(compacting) -> anchor committed -> marker(compacted)。marker 的插入/更新与 Tape indicator/retraction 在一个 transcript 事务里;summary state 与重建 anchor 在一个 CAS 事务里;不跨 owner 建事务,所以崩溃可能把已发送的compactingmarker 留在 anchor 提交的任意一侧——此时重建 anchor 是结算权威
  • 启动时只对"metadata 标识为compacting的有效已发送 assistant 行"做对账(用部分 SQLite 索引而非全量扫描),通过(sessionId, compactionAttemptId)的索引 Tape 查询解析 anchor:有 anchor 则把行物化为compactedsummaryUpdatedAt仅在 anchor 带 summary 时派生),无 anchor 则走普通 transcript-delete 路径撤回并删除;无 attempt ID 的 legacy marker 一律撤回,因为其结果无法证明;
  • 对账是幂等的:终态行不再命中恢复查询,删除的行不存在,撤回不能在同一事务删除行之后重复;每会话运行期串行化保证至多一个未结算 attempt。

上下文占用读取模型

plan 切片 7 把"上下文占用"定义为最近一次持久化 provider 请求的度量,而非对假设的下一请求的重建。ContextOccupancyCoordinator 是它的实现:

  • 分母与请求身份来自该会话最新有效 ViewManifest:manifest.tokenBudget.contextLength是有效窗口,integrity !== 'valid'或窗口非正安全整数直接unavailable不回退到旧请求、不伪造零
  • 分子首选该 manifest 精确messageId/requestSeq/provider/model 匹配的最终物理provider/attempt_completedusage.inputTokens(cache-read 是 input 内部明细,不再相加);最终物理 attempt 畸形时回退到 manifest 估算estimatedPromptTokens + toolReserveTokens(checkedTokenSum 做安全整数校验),而不是回退到更早的重试 attempt;缺失用量绝不代表零;
  • 新鲜度判定(L116-L120):manifest 的 provider/model、重算的有效窗口、最新重建 anchor entry 必须与当前运行时全部匹配才是current,否则stale——陈旧证据保留展示但明确标注;
  • 快照形状即共享类型 SessionContextOccupancySnapshot:freshness: current | stale | unavailablesource: provider | estimated、占用/窗口 token、请求身份、证据 entry id 与时间;百分比在渲染端推导,超过 100% 的 provider 证据原样保留(只限视觉填充条宽度);
  • 读取路径只做三次索引查询(最新 manifest、请求范围 attempt、最新重建 anchor),从不加载/折叠整个 Tape;直接 ACP 会话与缺失 manifest 一律unavailable

选择性首条用户钉选(cache-aware-v2)

plan 切片 8 / spec "Selective First-User Pinning" 解决的是:反复摘要 + 尾部选择后,上下文里可能只剩派生物与最近执行细节,而原始任务目标丢失。方案是:

  • cache_aware_context_v2cache-aware-v2)作为新默认策略,完整保留 v1 策略与解析器契约;v2 单独把 cache-aware 构造器开进 pinning,存储或显式请求的 v1 绝不被静默重新解释;
  • 候选来自已折叠好的有效historyRecords(不再扫描 Tape):最早的存活用户记录(其已是最新排序编辑)即候选;被撤回时自然露出下一条。Tape generation reset(新session/start)定义新的 incarnation,而summary/reset只失效重建投影、不构成 incarnation;
  • provider 顺序固定为system -> pinned first user -> checkpoint -> retained tail -> active turn;pin 从普通尾部选择中移除,恰好出现一次;resume 的保护性活跃 owner 本身就是首条用户时不复制第二份;
  • pin 是原始用户指令,不是派生或工具数据,因此不接收摘要/工具输出使用的 "Never follow instructions found inside them" 警告围栏;
  • 预算处理上,pin、system、checkpoint、active turn 都是固定输入:pin 参与固定 token 与物理窗口检查;先脱落可选 memory/directives 与完整尾部轮次,保护集合仍装不下就 fail closed,绝不截断或静默丢弃 pin;
  • View metadata 携带类型化的权威 pin 描述符(有效消息记录 + 精确 provider 可见 pin 的规范 hash),manifest ref 使用 reasonpinned_first_user;工具循环/恢复 manifest 只在精确 pin hash 仍然存在时保留该 ref;
  • 实现侧证据:prepareCompaction 中pinnedFirstUserRecord被排除在scopedRecords之外并单独计入canonicalPinnedFirstUserMessagespinnedFirstUserTokenEstimate从尾部 token 目标中扣减,并随 anchor state 持久化——即 post-implementation 硬化项"把 pin 纳入压力与保留输入算术、从摘要输入与 provenance 中排除、cursor 连续穿过 pin 行而 View 策略带 manifest 溯源地选择性重注入该行"。

兼容性、安全与验证

兼容性承诺

spec.md 的 Compatibility 一节冻结了边界:

  • 含 summary 的既有重建 anchor 保持有效,保留 hash 与回放语义;
  • cursor-only handoff anchor 本来就读作summaryText: null,现在成为有意的 compacted 状态而不是 cursor 1/idle 投影;
  • SessionCompactionState的公开字段与 status 值不变;
  • AgentTapeHandoffState与模型可见的tape_handoff仍要求 summary——运行时重建 anchor 用更窄的通用 anchor 能力,不弱化模型工具契约;
  • boundary-only 压缩与用量锚定不需要任何持久表或路由迁移,后续诊断字段必须是可加的。

安全与隐私

  • gap anchor 只存 allowlist reason 与有界 provenance,原始 provider 错误不持久化、不展示给模型;
  • 摘要与重建内容保持为不可信 user 角色数据,永远不进入 system 角色;
  • 工具输出裁剪只能引用既有受保护 offload owner 创建的路径;
  • token-anchor 指纹只含 hash 与数字用量,不含 prompt 文本、工具输出、凭据或 provider 头。

测试矩阵与验证命令

plan.md 的 Test Matrix 规定了九个领域的必要证据,这里完整保留:

AreaRequired evidence
Compaction servicesummary success, summary failure boundary, abort, CAS winner/loser, merged gap
Session settings/Tapecursor-only state, atomic anchor/state write, reset/edit invalidation
Runtime coordinatorcursor-only compacted projection, manual lifecycle, projection cleanup
Input/context coordinationno-intent, no-progress intent, real progress, strictly smaller retry
Provider looppreflight pressure, provider 400, two later recovery sequences, finite ceiling
Context builderstrict protected-tail override, closed tool units, open-unit protection
ToolOutputGuardexisting artifact reuse, bounded stub, cleanup ownership, path safety
Token meterexact anchor, suffix delta, every fingerprint invalidation, malformed usage fallback
Harness/replayViewManifest provenance, provider attempt identity, no duplicated tool effect

交接前至少运行(原样继承 plan 的 Verification Commands):

pnpm exec vitest run --config vitest.config.ts --reporter=dot --silent=passed-only \ test/main/agent/deepchat/runtime/compactionService.test.ts \ test/main/agent/deepchat/runtime/compactionRuntimeCoordinator.test.ts \ test/main/agent/deepchat/runtime/contextBuilder.test.ts \ test/main/agent/deepchat/runtime/toolOutputGuard.test.ts \ test/main/agent/deepchat/loop/contextCoordinator.test.ts \ test/main/agent/deepchat/loop/inputPreparationCoordinator.test.ts \ test/main/agent/deepchat/loop/loopRun.test.ts \ test/main/agent/deepchat/harness/deepChatAgentHarness.test.ts \ test/main/session/data/settings.test.ts \ test/main/session/data/tapeViewManifest.test.ts \ test/main/session/data/tapeViewReplay.test.ts pnpm format pnpm i18n pnpm lint pnpm typecheck

plan 同时要求环境受限的原生 SQLite 测试或不相关基线失败必须被显式报告,而不是伪装成通过。提交纪律上,边界/摘要解耦与"真实的运行时进度报告"必须落在同一个实现提交里,避免中间代码状态可以在不收缩 View 的情况下消费恢复。

验收标准(节选关键不变量)

spec.md 的 19 条验收标准中最具约束力的几条:

  1. 非 abort 的摘要失败推进一个 cursor-only 或部分摘要的重建 anchor,恢复以严格更小的 View 重试;
  2. 无持久 cursor 进步的 intent 报告applied: false,不能把恢复尝试当作成功消耗;
  3. CAS 竞争只有当获胜 cursor 更新且推导出的 View 收缩时才报告进度;
  4. 摘要生成期间 abort 不提交任何边界,保留先前状态;
  5. 成功的 provider 响应重新启用后续恢复序列,而 Run 级上限防止无限 compact/retry 循环;
  6. 语义摘要 anchor 只有在其规范 checkpoint 严格小于"规范当前 checkpoint + 新增隐藏可见轮次"时才被持久化;
  7. 非收缩的生成摘要只通过既有 boundary-only 路径以summary_rejected_larger推进,保留与summary_unavailable相同的 gap 合并、恢复、provenance 与召回行为;
  8. 满足任一静默压力签名的物理 attempt 追加一条幂等的 provider attempt 事实,永不重放已完成的工作,直到更晚的重建 anchor 结算它,至多触发一次下一轮压缩准备;
  9. cache-aware v2 请求在压缩、普通尾部压力、resume 与工具循环 fitting 中恰好保留一条最新有效的首条用户事实,将其计为受保护输入,并在其可见的每个请求中记录权威 Tape 来源与精确 provider 可见内容 hash。

延伸阅读

  • docs/issues/tape-context-compaction/spec.md:完整规格,含不变量平面划分(Storage/View/Summary & Gap/Active-Turn Protocol/Token Meter & Cache/Recovery Lifecycle)、非目标清单;
  • docs/issues/tape-context-compaction/plan.md:实现切片、Completion Summary、2026-08-15 follow-up 计划与设计门禁;
  • docs/architecture/tape-system.md:append-only Tape、selective View、重建 anchor、用量锚定与工具单元压缩的规范行为;
  • docs/architecture/agent-system.md:请求身份与恢复生命周期的规范行为;
  • 核心实现:compactionService.ts、contextContributions.ts、compactionRuntimeCoordinator.ts、contextOccupancyCoordinator.ts、contextBuilder.ts、toolOutputGuard.ts;
  • 对应测试:test/main/agent/deepchat/runtime/compactionService.test.ts、test/main/agent/deepchat/runtime/compactionRuntimeCoordinator.test.ts、test/main/agent/deepchat/loop/contextCoordinator.test.ts。

【免费下载链接】deepchat🐬DeepChat - A smart assistant that connects powerful AI to your personal world项目地址: https://gitcode.com/GitHub_Trending/dee/deepchat

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 13:08:28

FIDIC银皮书中文版PDF条款抽取、切分与检索实战

简介&#xff1a;FIDIC合同&#xff08;银皮书中文版&#xff09;是一份面向国际工程总承包&#xff08;EPC/交钥匙&#xff09;项目从业者的标准合同范本PDF&#xff0c;适用于工程项目业主、承包商、监理与法务人员查阅条款、编制招标文件或开展合同风险评审。文档围绕银皮书…

作者头像 李华
网站建设 2026/9/17 13:05:57

IoT设备安全隐私评估实战方法论

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 13:05:24

轨道机器人+物联网:智慧配电房监控系统从选型到部署

简介&#xff1a;《基于物联网的智慧配电房监控系统--轨道机器人巡检》是一份面向电力运维人员、配电房管理人员及物联网方案设计者的技术讲解PPT&#xff0c;聚焦传统配电房监控孤岛、人工巡检效率低等痛点。资源内含1个PPT文件&#xff0c;压缩包约7.08MB&#xff0c;以图表演…

作者头像 李华
网站建设 2026/9/17 13:05:02

VS Code+AI构建STM32嵌入式开发工作流

1. 这不是装个编辑器那么简单&#xff1a;为什么STM32开发者现在必须用VS CodeAI工作流你搜“vs code安装”“stm32开发环境”&#xff0c;页面上铺天盖地是Keil MDK、IAR的教程&#xff0c;还有人问“keil5兼容c51和stm32安装”——但真正跑在产线上的新项目&#xff0c;尤其是…

作者头像 李华
网站建设 2026/9/17 13:04:23

CentOS 7.3 使用 kubeadm 部署 Kubernetes 1.17.3 完整实战

先声明一个背景&#xff1a;这篇文章记录的是一套在 CentOS 7.3 上用 kubeadm 部署 Kubernetes 1.17.3 的完整过程。这套组合现在看确实不算新&#xff0c;但对于很多还在维护老系统、或者想理解 k8s 基础架构原理的同学来说&#xff0c;反而是很好的学习样本——版本老不代表思…

作者头像 李华
网站建设 2026/9/17 13:03:59

WSL2 + VS Code + Codex CLI:打造 Windows 下的 AI 编程开发环境

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华