DeepSeek Harness 路由式模型上下文与压缩策略:适配器权威容量与定向压缩策略的实现解析
【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness
本篇技术指南解析 DeepSeek Harness 中"按路由解析模型上下文容量 + 定向压缩策略"的架构设计(对应架构笔记 2026-07-20-routed-model-context-and-compaction-policy.md)。当同一进程将请求路由到不同容量的模型、相同模型 id 出现在多个提供方、且适配器可能接受目录之外的动态 id 时,一个全局上下文窗口无法安全驱动压缩(compaction)。读完本文你将掌握:容量事实如何由 LLM 适配器权威发布、token 计量为何保持模型无关、compaction-basic 如何通过modelPolicies实现逐路由的阈值/保留/摘要/重试策略,以及加载期与运行期的全部校验规则。
问题:全局上下文窗口为什么不再安全
当一个进程把请求路由到不同容量的模型时,压缩不能安全地应用同一个全局上下文窗口:
- 容量差异:不同模型有不同上下文窗口,单一容量值要么让压缩触发过晚(造成本可避免的溢出),要么触发过早(丢弃有用上下文)。
- 模型 id 不唯一:相同模型 id 可能存在于多个提供方(provider)之下,只按模型名匹配容量会串台。
- 动态 id:适配器可能接受不在建议目录(
listModels()结果)中的动态 id,目录之外的路由同样需要正确容量。
文档还指出,两个"直观"的配置归属方都无法独立解决:
- compact-basic 是可选插件,它不知道适配器接受哪些模型,无法自行断言容量;
- LLM 适配器拥有模型路由,但不能反向依赖一个可选的压缩插件,也不应吸收消费方专用的阈值、保留、摘要器与重试策略。
因此设计目标被收敛为两条:一个权威的容量事实,以及一个可选的逐目标压缩策略,同时不建立第二套模型注册表。
决策总览:容量归适配器,策略归插件
整个方案围绕三个组件的职责切分展开,以下为实现路径(packages/compaction/compaction-basic/src/index.ts、packages/llm/llm/src/index.ts):
| 组件 | 职责 | 关键机制 |
|---|---|---|
LlmAdapter(LLM 层) | 精确路由容量的唯一权威来源 | resolveModel(provider, model, signal?)返回带可选context的聚合元数据 |
dsh-token-meter | 模型无关的绝对 token 压力估算 | 固定回放折叠,无模型 profile、无容量配置 |
dsh-compaction-basic | 消费方压缩策略(阈值/保留/摘要/重试) | 顶层默认 +modelPolicies精确覆盖,每次检查按最新路由解析 |
LlmAdapter.resolveModel:精确路由容量的权威来源
契约与验证
LlmAdapter抽象类在 packages/llm/llm/src/index.ts 中声明了默认实现:
resolveModel( provider: string, model: string, _signal?: AbortSignal, ): Promise<LlmResolvedModelInfo> { return Promise.resolve({ provider, id: model, name: model }) }默认实现不携带任何能力元数据,表示"该路由没有可声明的容量"。返回的LlmResolvedModelInfo可在可选的context字段下携带LlmModelContext(即{ contextWindow: number })。
消费侧由LlmRuntime.resolveModelInfo()(packages/llm/llm/src/index.ts)完成三步工作:
- 通过
registration(provider)选择该路由的注册适配器; - 调用适配器的
resolveModel; - 由
normalizeModelInfo验证并"脱离"(detach)元数据。
验证逻辑的关键在 normalizeModelInfo:contextWindow必须是正整数(Number.isInteger(contextWindow) && contextWindow > 0),否则抛出INVALID_MODEL_CONTEXT;同时校验provider、id、非空name。返回的对象是重新构造的普通对象({ ...context === undefined ? {} : { context: { contextWindow: context.contextWindow } } }),不持有适配器内部对象引用,避免下游被适配器内部状态变化影响。
独立于 listModels():目录只是建议
文档强调:该查询独立于listModels()。两处实现证据:
listModels()的 JSDoc 明确注明 "The result is advisory: an adapter may accept unlisted model ids, and consumers must not turn absence into request rejection"(packages/llm/llm/src/index.ts);resolveModelInfo的 JSDoc 注明 "catalog membership remains advisory and does not control request routing"(packages/llm/llm/src/index.ts)。
语义推论:不在目录中的动态模型可以拥有容量元数据;而缺失context只表示适配器无法描述容量——该路由依然是合法的 LLM 路由,只是压缩无法对其进行主动压力检查(详见后文"目标专用压力错误的降级")。
DeepSeek 适配器:逐模型 contextWindow 与适配器级默认值
模型条目与容量字段
DeepSeek 适配器在 packages/llm/llm-deepseek/src/adapter.ts 中定义了可配置目录条目DeepSeekCatalogModel,其中:
contextWindow?: number—— 该模型已知的请求/响应合并上下文容量;部署元数据不可用时省略;- 另有
maxTokens(每请求输出上限)、inputModalities等字段。
连接级配置DeepSeekConnectionOptions携带defaultContextWindow: number,其 JSDoc 为 "Positive context capacity used when the selected model has no exact value"(adapter.ts)。
解析优先级
modelInfoFor 实现了文档所述的继承规则:
const configured = connection.models.find(entry => entry.id === model) const contextWindow = configured?.contextWindow ?? connection.defaultContextWindow即:精确模型容量优先;未提供容量的模型项与未列出的透传(pass-through)id 都继承适配器级defaultContextWindow。由于context字段总是被构造(context: { contextWindow }),只要defaultContextWindow存在,任何动态 id 也能获得容量。若部署完全不配置该值,则context缺失。
内置模型与默认值:以当前源码为准
架构笔记成文时记录"两个内置模型项都公开精确的 256,000-token 容量",但当前仓库源码已演进:DEFAULT_CONTEXT_WINDOW = 1_000_000(packages/llm/llm-deepseek/src/adapter.ts),且内置目录在 packages/llm/llm-deepseek/src/index.ts 中声明了三个模型条目(deepseek-v4-flash、deepseek-v4-pro、deepseek-v4-flash-vision-exp),三者都使用DEFAULT_CONTEXT_WINDOW作为精确容量。插件级Config.defaultContextWindow的默认值同样为 1,000,000,注释为 "Positive context capacity used when the selected model has no exact value (default 1,000,000)"(index.ts)。如需自定义,可在llm-deepseek配置中覆盖:
# apps/cli/config 下的 llm-deepseek 配置片段(字段均可选) - name: llm-deepseek config: defaultContextWindow: 200000 # 未配置精确容量的模型与未列出 id 的兜底值 models: - id: deepseek-v4-flash contextWindow: 128000 # 精确容量,优先于 defaultContextWindow - id: my-custom-id # 动态/私有模型,可无 contextWindow注意contextWindow必须是正整数,插件加载校验见 packages/llm/llm-deepseek/src/index.ts。pi-ai 适配器则从同一份"权威解析请求模型"的目录描述符解析容量,保证请求模型与容量永远来自同一来源(测试见 packages/llm/llm-pi-ai/tests/adapter.spec.ts)。
Token 计量保持模型无关:dsh-token-meter
文档明确:dsh-token-meter没有模型容量配置,也没有模型 profile。它拥有一个固定回放折叠,返回绝对估算 token 压力,以及按位置排列的表层节点(surface node)token 估值。
这样做有两个直接收益(packages/llm/token-meter/README.md 与架构笔记一致):
- 可复用性:未加载 compaction-basic 时计量依然可用——计量不依赖任何消费方;
- 避免第二个模型注册表:回放核算(replay accounting)不会因为逐模型折叠而复制状态、变成又一套容量登记处。
从源码结构看,计量以"单例折叠"贯穿所有定价决策:压力(pressure)、近期尾部保留(retention)、范围选择(range selection)与收缩校验(shrink validation)全部使用同一个ctx.tokenMeter的measure(session)结果(packages/compaction/compaction-basic/src/index.ts)。文档同时注明:移除全局容量后,本设计取代了 回放式 token 计量服务 Agent Note 中的"全局容量"与"无模型策略"部分,单折叠计量决策保持不变。
Compact-basic 解析目标规格:配置面全解
完整配置表
compaction-basic 的完整策略面(packages/compaction/compaction-basic/README.md 与 types.ts 一致):
| 字段 | 默认值 | 含义 |
|---|---|---|
thresholdRatio | 0.8 | 在floor(routedContextWindow × ratio)处开始压缩 |
retainRatio | 0.16 | 以已路由上下文窗口的比例逐字保留近期对话;与retainTokens互斥 |
retainTokens | — | 逐字保留的近期对话绝对预算;与retainRatio互斥,且必须低于解析后的阈值 |
summarizationProvider | '' | 与summarizationModel成对设置;空对回落到最新已路由请求目标,再到AgentOptions对 |
summarizationModel | '' | 与summarizationProvider成对设置(同上) |
maxTokens | 8192 | 摘要请求的输出上限(可能包含推理 token) |
compactionRetries | 1 | 首次压缩后压力仍超阈值时的额外压缩尝试次数 |
maxOverflowRetries | 1 | 规范化上下文溢出确认后的最大重试次数;0仅禁用恢复 |
modelPolicies | [] | 针对单个模型路由的精确{ provider, model, ...partialPolicy }覆盖 |
auto | true | 启用自动压缩与溢出恢复;false仅手动模式 |
典型配置示例
一个后端服务多个不同容量模型时的定向覆盖(取自 packages/compaction/compaction-basic/README.md):
- name: '@deepseek-ai/dsh-compaction-basic' config: thresholdRatio: 0.8 retainRatio: 0.16 modelPolicies: - provider: local model: small-context thresholdRatio: 0.7 retainTokens: 2048加载期校验(fail-fast)
resolveConfig 在插件加载时完成全部静态校验,任一违反都会直接拒绝加载:
- 未知字段:顶层与覆盖项都做键集合校验(
BASIC_COMPACT_CONFIG_KEYS/MODEL_POLICY_KEYS,见 config.ts 与validateKeys),拼写错误或残留旧配置无法被默认值掩盖; - 重复目标:
modelPolicies中相同{ provider, model }组合重复出现即报错(resolveModelPolicies用provider\u0000model作去重键,config.ts); - 两种保留形式互斥:
retainRatio与retainTokens同时出现即报错(config.ts); - 比例保留必须低于阈值比例:继承完成后,若
retainRatio >= thresholdRatio,插件加载失败(validateRatioRetention,config.ts)——因为任何模型容量都无法让该策略成立; - 摘要对必须成对:
summarizationProvider与summarizationModel必须同时为空或同时非空(validateSummarizationPair,config.ts)。
数值约束由 schemastery schema(packages/compaction/compaction-basic/src/index.ts的thresholdRatioSchema等)与assert*辅助函数双重把关:比例必须在(0, 1]区间内,retainTokens/compactionRetries/maxOverflowRetries为非负整数,maxTokens为正整数。
运行期:比例缩放为 ResolvedCompactSpec
主动压力路径在每次检查时都执行完整解析(compactIfNeeded):
- 读取最新持久请求路由(
routedTarget从session.requestHeader().config取provider/model,index.ts); - 通过
ctx.llm.resolveModelInfo(target.provider, target.model)解析该路由的适配器容量; - 通过
resolveTargetPolicy合并精确目标策略(config.ts); - 通过
resolveCompactSpec把比例缩放为具体 token 预算(config.ts):
const thresholdTokens = Math.floor(contextWindow * policy.thresholdRatio) const retainTokens = policy.retainTokens === undefined ? Math.floor(contextWindow * policy.retainRatio) : policy.retainTokens if (retainTokens >= thresholdTokens) { /* TargetPressureConfigError */ }每次检查都重新解析意味着:同一会话内切换提供方或模型,容量与策略立即生效,无需重启或重新加载插件——这也正是"相同模型 id 在不同提供方下"能各自正确匹配覆盖项的原因(匹配键是精确的{ provider, model }对,见resolveTargetPolicy)。
与比例校验不同,绝对保留预算(retainTokens,顶层或逐模型)是否低于缩放后阈值,必须等目标容量首次可比较时才能判定,因此在运行期校验:resolveCompactSpec中retainTokens >= thresholdTokens会抛出目标专用的TargetPressureConfigError。
摘要与重试策略同样由覆盖项选择
同一精确目标覆盖还可以选择摘要提供方/模型(summarizationProvider/summarizationModel)、摘要输出上限(maxTokens)、收敛重试(compactionRetries)与溢出重试上限(maxOverflowRetries)。文档强调:这些都属于压缩问题,永远不会进入 LLM 提供方——它们是消费方事实,而非提供方事实。
压力触发与规范化溢出的两条不同路径
自动压力检查(agent/pre-step)
auto: true时,_registerAutomaticCompaction注册一个串行agent/pre-step监听器(packages/compaction/compaction-basic/src/index.ts):在请求派生前定价最新持久路由请求包络,压力越过该路由模型阈值后先做可选剪枝(dsh-compaction-tool-result-pruner),再压缩最老的平衡区间并保留定价的近期尾部。
目标专用压力错误的降级:警告抑制
缺少容量元数据的适配器仍是有效 LLM 路由,但压力检查无法进行:
- 手动主动压力:抛出目标专用的配置错误
TargetPressureConfigError(信息如 "no context capacity for {provider}/{model}; configure contextWindow on that adapter model",index.ts); - 自动监听器:按精确路由只警告一次(
warnedPressureConfigTargets集合按${provider}/${model}去重),然后next()继续完整历史(index.ts)。
同一按路由抑制机制也适用于"已解析容量暴露出无效绝对保留预算"的情况;而其他运行故障仍独立可见,不会被误吞。TargetPressureConfigError携带targetKey字段正是为了支撑这种路由级去重(config.ts)。
规范化溢出(CONTEXT_WINDOW_EXCEEDED):不依赖容量元数据
提供方已确认的规范化溢出(错误码CONTEXT_WINDOW_EXCEEDED_CODE)走agent/request-error监听器(index.ts),行为与压力路径截然不同:
- 绕过主动阈值与普通保留预算——溢出已经是提供方事实,无需容量元数据;
- 尝试一次最大且平衡的头部缩减(
selectCompactableRange(agent.session, measurement, 0)); - 只有 surface 替换代次(
replaceGeneration)推进后才授权{ kind: 'retry' }重试,否则保留原始提供方错误(防止无进展的无限循环); - 重试次数受
maxOverflowRetries限制;一次成功的 assistant 消息或 agent 回到 idle 都会重置溢出重试状态。
测试覆盖:关键行为的验证锚点
架构笔记记录的测试面在仓库中均有对应实现:
- 服务层(
packages/llm/llm/tests/service.spec.ts):脱离适配器内部状态的上下文元数据、无效适配器输出(INVALID_MODEL_CONTEXT)、目录独立性、默认缺失行为; - 适配器层(
packages/llm/llm-deepseek/tests/adapter.spec.ts):DeepSeek 的精确容量、默认容量、未列出模型解析与无效容量;packages/llm/llm-pi-ai/tests/adapter.spec.ts覆盖 pi-ai 精确描述符解析; - 压缩层(
packages/compaction/compaction-basic/tests/compaction-basic.spec.ts):配置与默认值、比例缩放、精确 provider/model 覆盖、加载期拒绝无效合并比例、运行期绝对预算校验、相同模型 id 的提供方切换、目标专用警告抑制、不依赖容量的溢出恢复; - Loader fixture:拒绝已移除的 token-meter 容量设置,示例则在适配器上配置容量。
为什么这样设计:被否决的替代方案
架构笔记记录了五个被明确否决的方案及其理由,理解它们能更好地把握最终设计的边界:
- 把容量与所有策略都放进 compaction-basic——否决:会复制适配器的模型知识,未列出的动态模型需要并行注册,且未安装压缩时容量会消失;
- 把压缩策略放进各 LLM 适配器——否决:适配器必须独立于可选消费方,且摘要与重试策略不是提供方事实;
- 让
listModels()成为权威来源——否决:发现能力只是建议信息,正确性元数据不能把选择器成员关系变成路由白名单(会把动态 id 挡在门外); - 给 token-meter 增加逐模型折叠——否决:回放算法可共享,变化的只有容量与消费方策略,多折叠只会重复状态而不改善估算;
- 建立独立模型上下文注册表——否决:适配器已拥有权威路由解析,第二套注册表会引入生命周期顺序、重复键与漂移问题,却没有独立后端。
设计后果与演进关系
架构笔记在 Consequences 中总结了可验证的设计结果:
- 容量在提供方约定(adapter contract)上拥有唯一权威归属方,压缩策略留在可选消费插件中;
- 同一个 compaction-basic 实例无需查询发现元数据,就能安全处理不同窗口、提供方切换,以及不同提供方下的相同模型 id;
- 仅 LLM 与仅 meter 的组合仍然有效;加载 compaction-basic 不会让适配器产生反向依赖(
static inject = ['llm', 'tokenMeter', 'sessions'],index.ts); - DeepSeek 部署可设置精确逐模型容量,或用
defaultContextWindow覆盖无容量条目与未列出透传 id; - 比例默认值随模型自然缩放,同时可按精确目标使用绝对保留值满足部署专用行为。
该笔记取代 回放式 token 计量服务 Agent Note 中的全局容量与无模型策略部分,单折叠计量决策保持不变。同一时期的配套决策还包括 2026-07-10-after-call-compaction-pressure-and-overflow-recovery.md(调用后压缩压力与溢出恢复)与 2026-07-14-provider-routed-llm-adapters.md(提供方路由的 LLM 适配器),可结合阅读以理解完整演进脉络。若需在自己的部署中复现,可直接查阅 compaction-basic README 与 llm-deepseek README 的完整配置说明,或运行对应包的单元测试验证上述行为。
【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考