news 2026/9/20 1:55:49

DeepSeek Harness 路由式模型上下文与压缩策略:适配器权威容量与定向压缩策略的实现解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DeepSeek Harness 路由式模型上下文与压缩策略:适配器权威容量与定向压缩策略的实现解析

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.tspackages/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)完成三步工作:

  1. 通过registration(provider)选择该路由的注册适配器;
  2. 调用适配器的resolveModel
  3. normalizeModelInfo验证并"脱离"(detach)元数据。

验证逻辑的关键在 normalizeModelInfo:contextWindow必须是正整数Number.isInteger(contextWindow) && contextWindow > 0),否则抛出INVALID_MODEL_CONTEXT;同时校验providerid、非空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-flashdeepseek-v4-prodeepseek-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 与架构笔记一致):

  1. 可复用性:未加载 compaction-basic 时计量依然可用——计量不依赖任何消费方;
  2. 避免第二个模型注册表:回放核算(replay accounting)不会因为逐模型折叠而复制状态、变成又一套容量登记处。

从源码结构看,计量以"单例折叠"贯穿所有定价决策:压力(pressure)、近期尾部保留(retention)、范围选择(range selection)与收缩校验(shrink validation)全部使用同一个ctx.tokenMetermeasure(session)结果(packages/compaction/compaction-basic/src/index.ts)。文档同时注明:移除全局容量后,本设计取代了 回放式 token 计量服务 Agent Note 中的"全局容量"与"无模型策略"部分,单折叠计量决策保持不变

Compact-basic 解析目标规格:配置面全解

完整配置表

compaction-basic 的完整策略面(packages/compaction/compaction-basic/README.md 与 types.ts 一致):

字段默认值含义
thresholdRatio0.8floor(routedContextWindow × ratio)处开始压缩
retainRatio0.16以已路由上下文窗口的比例逐字保留近期对话;与retainTokens互斥
retainTokens逐字保留的近期对话绝对预算;与retainRatio互斥,且必须低于解析后的阈值
summarizationProvider''summarizationModel成对设置;空对回落到最新已路由请求目标,再到AgentOptions
summarizationModel''summarizationProvider成对设置(同上)
maxTokens8192摘要请求的输出上限(可能包含推理 token)
compactionRetries1首次压缩后压力仍超阈值时的额外压缩尝试次数
maxOverflowRetries1规范化上下文溢出确认后的最大重试次数;0仅禁用恢复
modelPolicies[]针对单个模型路由的精确{ provider, model, ...partialPolicy }覆盖
autotrue启用自动压缩与溢出恢复;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 }组合重复出现即报错(resolveModelPoliciesprovider\u0000model作去重键,config.ts);
  • 两种保留形式互斥retainRatioretainTokens同时出现即报错(config.ts);
  • 比例保留必须低于阈值比例:继承完成后,若retainRatio >= thresholdRatio,插件加载失败(validateRatioRetention,config.ts)——因为任何模型容量都无法让该策略成立;
  • 摘要对必须成对summarizationProvidersummarizationModel必须同时为空或同时非空(validateSummarizationPair,config.ts)。

数值约束由 schemastery schema(packages/compaction/compaction-basic/src/index.tsthresholdRatioSchema等)与assert*辅助函数双重把关:比例必须在(0, 1]区间内,retainTokens/compactionRetries/maxOverflowRetries为非负整数,maxTokens为正整数。

运行期:比例缩放为 ResolvedCompactSpec

主动压力路径在每次检查时都执行完整解析(compactIfNeeded):

  1. 读取最新持久请求路由(routedTargetsession.requestHeader().configprovider/model,index.ts);
  2. 通过ctx.llm.resolveModelInfo(target.provider, target.model)解析该路由的适配器容量;
  3. 通过resolveTargetPolicy合并精确目标策略(config.ts);
  4. 通过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,顶层或逐模型)是否低于缩放后阈值,必须等目标容量首次可比较时才能判定,因此在运行期校验:resolveCompactSpecretainTokens >= 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 容量设置,示例则在适配器上配置容量。

为什么这样设计:被否决的替代方案

架构笔记记录了五个被明确否决的方案及其理由,理解它们能更好地把握最终设计的边界:

  1. 把容量与所有策略都放进 compaction-basic——否决:会复制适配器的模型知识,未列出的动态模型需要并行注册,且未安装压缩时容量会消失;
  2. 把压缩策略放进各 LLM 适配器——否决:适配器必须独立于可选消费方,且摘要与重试策略不是提供方事实;
  3. listModels()成为权威来源——否决:发现能力只是建议信息,正确性元数据不能把选择器成员关系变成路由白名单(会把动态 id 挡在门外);
  4. 给 token-meter 增加逐模型折叠——否决:回放算法可共享,变化的只有容量与消费方策略,多折叠只会重复状态而不改善估算;
  5. 建立独立模型上下文注册表——否决:适配器已拥有权威路由解析,第二套注册表会引入生命周期顺序、重复键与漂移问题,却没有独立后端。

设计后果与演进关系

架构笔记在 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),仅供参考

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

Ghidra逆向工程实战指南:从反编译到脚本化扩展

手头有一个没有源码的二进制文件&#xff0c;想弄清楚它的核心逻辑&#xff0c;用文本编辑器打开全是乱码&#xff0c;用objdump看汇编又像在翻天文——这是很多逆向入门者最真实的一刻。我第一次用Ghidra时就是这种状态&#xff0c;后来熟悉了才发现&#xff0c;这个工具确实能…

作者头像 李华
网站建设 2026/9/20 1:52:22

Windows 11 语言切换不彻底?彻底英文化完整指南

1. 问题现象与核心症结定位Windows 11 的语言切换有个很典型的现象&#xff1a;你在设置里把显示语言改成 English&#xff0c;重启之后发现登录界面、开始菜单、任务栏右键菜单确实变成英文了&#xff0c;但打开文件资源管理器、设置应用、部分系统对话框&#xff0c;里面还是…

作者头像 李华
网站建设 2026/9/20 1:52:20

如何彻底删除360安全卫士:从常规卸载到残留清理全指南

最近好几个朋友找我&#xff0c;说电脑里的360安全卫士卸载不干净&#xff0c;卸载完过一阵子又自动装回来了&#xff0c;或者桌面残留快捷方式、后台还有进程在跑。我自己早年折腾系统也跟这款软件缠斗过&#xff0c;后来换过几个思路才算真正搞定。这篇就把我实测下来有效的一…

作者头像 李华
网站建设 2026/9/20 1:49:03

读透组合树,TaoToken 换 DSH 的 Key

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

作者头像 李华
网站建设 2026/9/20 1:48:59

ISO/IEC 29500-4-2016实用指南:OOXML Part 4与docx解析

简介&#xff1a;ISO/IEC 29500-4:2016 是 ISO 与 IEC 联合发布的 Office Open XML 文件格式系列标准第四部分&#xff0c;主题为“过渡迁移特性”&#xff08;Transitional Migration Features&#xff09;。这份国际标准面向办公软件开发者、文档格式兼容性测试人员及标准研究…

作者头像 李华