ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

DeepSeek Harness 沙箱策略上下文注入:面向 Prompt 缓存安全(Cache-safe)的当前策略快照设计

DeepSeek Harness 沙箱策略上下文注入:面向 Prompt 缓存安全(Cache-safe)的当前策略快照设计 DeepSeek Harness 沙箱策略上下文注入面向 Prompt 缓存安全Cache-safe的当前策略快照设计【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness导读DeepSeek Harness 的沙箱策略sandbox policy决定每个会话中文件写入类操作的实际权限但在早期设计中这一状态只被强制执行与记录模型发起的新请求里并不包含它导致 Web 会话在read-only模式下仍能看到 write/edit 工具 schema模型可能宣称自己能写文件、直到第一次调用被拒绝才得知真相。本篇技术指南基于仓库内的实现决策文档 2026-07-30-current-sandbox-policy-context.md 及其后续简化决策 2026-07-31-capability-neutral-sandbox-policy-context.md系统讲解 DeepSeek Harness 如何通过dsh-sandbox-policy包向模型注入能力中立capability-neutral的sandbox:policy运行时上下文以及 agent-loop 如何把它物化为追加式append-only的完整快照从而在策略切换后仍保持稳定系统提示词前缀、最大化 KV-Cache 复用。读完本文你将掌握沙箱三种模式的语义与精确措辞、会话级模式切换的持久化机制、缓存安全快照的投射与清理逻辑以及该设计在真实模型提供方上的缓存命实验证。问题背景策略被强制执行却不被模型感知在引入本次机制之前DeepSeek Harness 的沙箱策略已经能够强制执行并记录每个会话的文件效果模式file-effect mode但存在一个关键缺口一次全新的模型请求并不携带该状态。具体表现为三类典型场景见 决策文档 的 Problem 一节Web 会话处于read-only时write 与 edit 工具的 schema 仍然可见。模型会据此宣称自己具备写入能力直到某次写调用被沙箱拒绝才通过 denial拒绝结果间接学习到真实策略——这是一种先产生虚假能力声明、后靠报错纠偏的被动机制。执行/permission danger-full-access切换后下一次请求确实携带了审批策略approval policy的变更但沙箱模式仍然缺失模型无法感知这次权限提升。用户在任何操作之前询问能力时denial 结果成为模型可见的第一个策略来源即使模型从未发起过任何操作。核心矛盾在于工具 schema 描述的是可以调用什么而沙箱策略描述的是在什么文件效果约束下执行两者是正交的两个信息面。方案的目标是让模型在探测任何工具之前就收到当前生效的文件策略同时不让这条信息破坏系统提示词的缓存复用。核心设计dsh-sandbox-policy包与sandbox:policy上下文包职责与注册方式沙箱策略的单一所有者是dsh-sandbox-policy包仓库路径 packages/sandbox/sandbox-policy其插件入口位于 src/index.ts。根据源码注释它是部署级沙箱回退策略加上每次会话解析的唯一所有者负责部署默认模式mode与回退工作区根workspaceRoot每次会话的解析文件效果模式、workspace-write根以及覆盖套件sandbox/mode事件及其 fold 与写入路径来自 src/session-mode.ts在每次 agent 请求前将已解析的策略贡献给缓存安全的运行时上下文快照。在构造函数中服务通过ctx.inject([systemPrompt], ...)注册一个名为sandbox:policy、order: 110的动态上下文贡献src/index.ts#L112-L123ctx.inject([systemPrompt], (scope: Context) { scope.systemPrompt.context({ name: sandbox:policy, order: 110, text: (context) { const session context.agent?.session return session undefined ? : renderPolicyContext(this.resolve({ session })) }, }) })关键点在于文本只从resolve({ session })派生每次请求组装时直接以活动会话解析当前策略不存在denial 历史扫描或进程内 last-told 状态见决策文档 Decision 一节。同时order: 110与审批策略贡献的order: 115见 packages/interaction/user-approval/src/index.ts#L170-L181一起参与系统提示词组装器中有序动态上下文的排序。三种模式的精确措辞renderPolicyContextsrc/index.ts#L38-L52按模式返回固定的能力中立语句只陈述所有执行方言enforcement dialect共享的事实不枚举已挂载的能力模式模型可见文本源码原文语义要点read-onlyCurrent DSH file policy: read-only. Any available operation enforced by the DSH file sandbox cannot modify files in the standing mode. Do not refuse a required modification from this policy alone: try an available tool normally and follow any denial and escalation guidance it returns.反预拒绝anti-refusal原则仅凭该标签不得推断操作不可能应正常尝试可用工具再遵循工具返回的拒绝与升级指导workspace-writeCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: workspaceRoot. Some platform temporary areas may also be writable.以非排他措辞non-exclusive wording声明规范会话工作区临时区域只概括、不枚举danger-full-accessCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.文件沙箱不限制可用操作的修改能力值得注意的边界决策文档 Decision 一节明确列出后端选择的临时路径、/dev/null、runner 就绪状态、精确工具可用性及其他策略域均不出现因为resolve()在请求组装阶段无法确定这些信息。例如workspace-write只是概括某些平台临时区域可能可写而不会列出具体路径——不同后端bwrap、Landlock、Seatbelt、进程内文件系统 fence授予的临时路径集合在confine()时才选定见决策文档 Alternatives 中Enumerate writable temporary roots被拒绝的原因。能力中立原则为什么不做能力清单最初的实现曾通过独立的 enforced-family 与 escalatable-family 两套注册表由六个后端/工具/示例调用点贡献filesystem、bash、terminal家族策略服务需要维护 token 集合、交叉取交并、排序并在每次生命周期变更时失效 prompt 组装还要测试每一种家族组合。后续简化决策 2026-07-31-capability-neutral-sandbox-policy-context.md 判定该清单既不必要、也不权威后端贡献的家族可能与模型可见工具不一致工具可能被请求作用域隐藏而工具 schema 已经精确告知模型哪些操作可用。因此工具 schema 是哪些操作可用的权威工具结果是特定操作的拒绝与批准后的重试的权威策略上下文只负责陈述当前策略且措辞对可用操作作条件化表述任何被 DSH 文件沙箱强制执行的可用操作……即使没有适用操作语句依然真实。能力的新增与移除不再扰动运行时上下文快照只有模式与工作区变化才会见简化决策 Consequences 一节。会话级模式切换sandbox/mode事件与 fold事件即状态会话的模式切换由 src/session-mode.ts 提供完整的读写套件其核心思想是**切换本身就是事件**export function setSandboxMode(session: Session, mode: SandboxMode): void { session.append(sandbox/mode, { mode }) }sandbox/mode是仅日志log-only事件与approval/*先例一致不携带surfaceOp、不出现在模型转写中但可持久化、可重放。source: delegation标记表示委派给子会话时注入的覆盖缺省 source 表示运行时切换。会话的覆盖模式由纯函数 fold 得出src/session-mode.ts#L52-L58export function effectiveSandboxMode(events: readonly SessionEvent[]): SandboxMode | undefined { for (let index events.length - 1; index 0; index - 1) { const event events[index] as SessionEvent if (event.type sandbox/mode) return event.data.mode } return undefined }即取事件日志中最后一个sandbox/mode事件。这个设计带来三个可验证的性质源码注释与测试共同印证重启后覆盖仍生效重放日志即是状态无需任何追赶机制会话间隔离两个会话永不互见对方状态无外部配置存储模式是策略状态被 bash 与 filesystem 等所有执行家族共享因此放在策略包中而非某个能力 seam 内。解析优先级resolve()src/index.ts#L135-L142返回单次能力调用所需的完整策略resolve(request: SandboxPolicyRequest {}): SandboxExecutionPolicy { const { session } request return { mode: request.mode ?? (session undefined ? undefined : this.overrideOf(session)) ?? this.defaultMode, workspaceRoot: resolveWorkspaceRoot(session?.header.cwd ?? this.workspaceRoot), ...session undefined ? {} : { sessionId: session.id }, } }优先级自高到低为批准的显式模式request.mode如升级授予——只对该次调用生效会话最后记录的sandbox/mode事件通过overrideOf→effectiveSandboxMode部署默认模式defaultMode默认为read-only。工作区根则是会话的不可变SessionHeader.cwd优先否则回退到配置的workspaceRoot默认process.cwd()。注意resolveWorkspaceRootsrc/index.ts#L33-L35先用canonicalPath解析文件系统身份再resolve词法路径以避免 symlink 敏感组件在词法规范化前被抹掉——测试 policy.spec.ts#L87-L108 验证了symlink/..这种场景会解析为物理真实路径。配置参数来自 packages/sandbox/sandbox-policy/README.md 的最小配置示例- name: deepseek-ai/dsh-sandbox-policy config: mode: workspace-write workspaceRoot: /absolute/path/to/workspace字段默认值含义moderead-only会话起步的部署默认模式加载时经 schemastery 校验z.union([read-only, workspace-write, danger-full-access])非法值如yolo在插件加载时即被拒绝测试 policy.spec.ts#L126-L130workspaceRootprocess.cwd()无 agent 调用或会话无 cwd 时workspace-write的回退根正常 agent 调用使用会话不可变 cwd配置项无 schema 默认值在构造函数中解析为绝对路径src/index.ts#L104-L110注意runner 选择不属于这里那是ctx.sandbox提供者的配置本包是唯一共享的策略之家。缓存安全从动态系统段到追加式完整快照为什么动态系统段是错的决策文档记录了一个被真实提供方实验否定的方案把当前策略放进动态系统提示词段。真实 Web fixture 量化了缺陷决策文档 Wording evidence 一节首次danger-full-access与workspace-write请求cache-read 只有 256 tokens而 uncached 输入高达 14,691 与 14,782 tokens策略不变时后续步骤约 14.7k–15.5k cache-read tokens。原因在于DeepSeek 按完整前缀匹配缓存切换权限时系统段被重写改变了第一条线上消息导致系统提示词 历史的更长前缀无法复用。而且只搬动沙箱语句也无法修复——同一个 preset 切换同时改写了审批策略系统段。agent-loop 的快照物化流程现行设计让dsh-system-prompt组装器拥有有序动态上下文与稳定系统段、工具 schema 并列。核心流程在 packages/core/agent-loop/src/agent.ts 的preStep#L232-L250const assembly await this.loopCtx.systemPrompt.assemble(assembleContextFor(this, signal)) const sections renderContextSections(assembly) const context this.runtimeContext.project(joinContextSections(sections), sections) // ...进入 agent/pre-step waterfallcontext 追加在 claimed 消息之后其中renderContextSectionssystem-prompt/src/index.ts#L302-L306把组装结果渲染为带名字的贡献节{ name, text }空文本被过滤joinContextSections#L287-L291生成显式取代语句的完整快照Current runtime context. This snapshot supersedes earlier runtime-context snapshots. 各贡献节按 order 升序、以空行连接RuntimeContextProjection.projectpackages/core/agent-loop/src/runtime-context.ts#L64-L75仅在保留快照与当前文本不同时才产生一条候选 user 消息且仅在以下情况追加带来源的user/message无保留快照、字节发生变化、压缩compaction移除了保留消息、或最后一个贡献消失需要一条清理快照。清理快照的固定文本为Current runtime context: none. Earlier runtime-context snapshots no longer apply.runtime-context.ts#L13。快照被追加在既有历史之后、step/start之前agent.ts#L286-L291因此策略变化时先前的系统 对话缓存前缀得到保留。会话事件本身即可重构精确的模型输入仅策略上下文变化时request/header保持逐字节一致。归属与保留RuntimeContextProjection构造时runtime-context.ts#L34-L56从会话事件中恢复最近一条仍保留在 surface 上的、由deepseek-ai/dsh-system-prompt来源source.kind plugin拥有的user/message并忽略其他会话之后通过session/event订阅跟随权威事件——新的归属消息被保留、替代性 surface 事件isReplacementSurfaceEvent且sourceEventSeqs命中将其置空。这正是会话事件重构精确模型输入的实现基础。多所有者协调为什么审批策略也进同一快照决策明确所有权保持狭窄审批策略approval:policyorder 115把其完整当前的ask或never事实贡献给同一个完整快照。这是因为/permission切换同时改变两个所有者沙箱模式与审批策略若只迁移沙箱而不迁移审批缓存缺陷依旧存在决策文档 Decision 与 Alternatives 均有论证。其余边界计划模式仍是plan:policy系统段PLAN_POLICY: 500见 system-prompt/src/index.ts#L135工具插件继续拥有 schema 及尝试、拒绝、升级指导执行边界仍是 filesystem、一次性 bash 与 terminal 后端消费同一份已解析策略resolve()上下文只是陈述策略不是强制护栏——运行时安全始终来自执行后端决策文档 Consequences 一节。为什么不改为让每个策略所有者各自调用agent.inject()Callagent.inject()independently备选被拒兄弟监听器顺序会决定模型顺序、分离的消息可能暴露不一致的中间快照、每个所有者还需自己的压缩保留扫描由既有组装所有者排序并物化一条原子完整快照更优。措辞的实验证据与反预拒绝原则预先注册的正向对照措辞实验把**预拒绝preemptive refusal**预先注册为主要终点要求旧有固定语句在十二个全新会话中至少产生一次拒绝才允许评估任何替代措辞决策文档 Wording evidence 一节2026-07-30commit2bf4199以deepseek-v4-flash运行 shipped Web 组合使用精确正向对照句Bash commands run under the read-only file sandbox.加当前工具自有的尝试指导。结果零预拒绝、零投机性升级全部十二个会话都发起普通 bash 调用、观察到拒绝、同一回合内升级、获得批准、落地请求文件。无样本被排除。缓存安全投递改造后commit10d4e0f同一十二会话正向对照经由新的尾部上下文通道重复。同样零预拒绝、零投机性升级八个会话落地了精确请求的文件无样本被排除。两个正向对照均未通过预先注册的敏感性门槛因此正式的 Candidate A/B 十二会话实验并未运行——这些实验不选择也不验证当前措辞它们确立的是早前十二分之五的拒绝率在本任务与当前工具指导下不可复现在做出模型行为率声明之前需要更强的正向对照或不同的任务分布。确定性测试只确立真实请求构造与重放见下节。缓存安全改造后的非统计验收在缓存安全投递重构后另行执行了一次独立的、非统计的验收对比任务是中性 Web 任务Create the relative path policy-neutral.txt ...决策文档 Wording evidence 一节Candidate A分类式read-only直白陈述产生纯文本拒绝、零工具调用Candidate B仅对工具暴露升级的执行家族追加一句组合条件化语句的措辞下真实提供方运行发起普通write、观察到 read-only 拒绝、同一回合内以sandbox_permissions: workspace-write重试同一操作、获得批准、读回文件并验证内容无投机性升级。在权限切换与四次变更步骤期间cache reads 为14,848–15,872 tokens而每次请求的 uncached 输入仅59–306 tokens直接展示了稳定前缀收益。这也解释了反预拒绝原则的存活形态它本身不陈述任何升级机制只是告诉模型不要从固定标签推断不可能性然后把拒绝与升级行为委托回可用工具。模型侧词元与缓存效应packages/sandbox/sandbox-policy/README.md 的 Model Experience 一节总结Token effect首次请求与每次策略实际变化时各有一条简明的持久上下文消息不变请求不新增。workspace-write只携带规范会话工作区路径平台临时路径被概括、不引入主机相关字节测试 policy.spec.ts#L164-L182 验证整个渲染 prompt 与上下文快照在TMPDIR变化时保持逐字节稳定。KV Cache effect稳定系统提示词在模式切换间保持逐字节一致变化后的完整快照追加在保留历史之后保留先前缓存前缀后续不变请求复用该保留快照。备选方案与拒绝理由决策文档 Alternatives 一节记录了完整论证此处按主题归纳备选方案拒绝理由只叙述模式变化narrate only mode changes全新会话仍不知情第一次被拒操作成为策略发现机制且需要不必要的基线定义扫描 denial 历史或记住最后叙述的模式denial 事件描述的是尝试过的操作而非权威当前状态进程内簿记无法跨重启存活所有者可直接在每次请求上折叠持久策略把当前策略放进动态系统段真实证据显示首次权限切换使 cache reads 降至 256 tokens 而约 14.7k 输入未命中DeepSeek 匹配完整前缀改变第一条线上消息即阻断长前缀复用每个策略所有者独立调用agent.inject()兄弟监听顺序决定模型顺序、可能暴露不一致中间快照、每个所有者需自己的压缩保留扫描通用 runtime-facts 包既有组装所有者已拥有分段、schema、变量、作用域与权威逐步瀑布扩展它无需新包或第二注册服务在上下文中重复工具 schema 或计划指导那些表面已有所有者和独立生命周期审批当前状态加入快照只因同一/permission切换会改变它缓存安全改造后保留 Candidate A中性真实任务中模型返回纯文本拒绝且零工具调用尽管已有 bash 尝试指导因旧标签曾致预拒绝而完全省略沙箱模式全新 Web 请求会暴露变更工具却隐藏其现行策略在首次操作前产生虚假能力声明旧测量是必备对照测试十二分之五无工具调用但工具自有尝试指导晚于该测量替代措辞须在新实验下选择单独 model-context 包策略所有者可直接解析当前会话状态既有组装服务可排序新包只添加浅层组合层与文档/门面开销枚举可写临时根后端在confine()时才选定bwrap、Landlock、Seatbelt、进程内 fence 不授予共同临时路径集合主机特定路径既不稳定又过度声明后果与测试保障行为后果模型在探测工具前即收到当前文件策略/permission后的下一个请求反映已提交的模式稳定系统提示词不再因沙箱或审批状态而改变变化的完整上下文快照在保留历史后追加不变状态不新增消息历史中的旧快照仍在但被最新完整快照显式取代该语句是指导而非强制护栏运行时安全仍来自消费同一已解析策略的 filesystem、一次性 bash 与 terminal 后端。确定性测试覆盖聚焦测试固定了以下行为见 policy.spec.ts 与 runtime-context.spec.ts三种模式的精确文本渲染且无能力清单it.each逐字断言policy.spec.ts#L152-L162部署默认read-only与进程 cwd 根#L43-L47每会话模式与 cwd 一起解析、回退根不变#L63-L85symlink 敏感 cwd 的 POSIX 组件语义#L87-L108批准显式模式压过会话模式但保留其根#L110-L119无 cwd 会话使用配置根#L121-L124非法模式在加载时被拒#L126-L130子 fiber 中服务与上下文贡献的处置HMR 安全#L132-L141TMPDIR变化下完整渲染 prompt 与快照逐字节稳定#L164-L182最新持久切换在下一次组装中生效、其余情况逐字节稳定#L184-L197从会话日志重建已恢复策略、无 agent 时省略诊断#L199-L207setSandboxMode每次切换恰好追加一个sandbox/mode事件、effectiveSandboxModefold 到最后一次切换#L210-L229RuntimeContextProjection恢复最新可见归属快照、忽略其他会话、替换 surface 事件后不再投射runtime-context.spec.ts#L16-L44。此外无密钥keyless组装快照通过真实 Loader 组合固定持久上下文消息无密钥重放拥有中性的拒绝到升级轨迹——它是结构性回归证明而非措辞选择证据决策文档 Consequences 一节。相关资源决策文档.agents/notes/implemented/feature/2026-07-30-current-sandbox-policy-context.md本文主依据简化决策.agents/notes/implemented/simplification/2026-07-31-capability-neutral-sandbox-policy-context.md策略服务实现packages/sandbox/sandbox-policy/src/index.ts 与 packages/sandbox/sandbox-policy/src/session-mode.ts包文档packages/sandbox/sandbox-policy/README.md快照物化packages/core/agent-loop/src/runtime-context.ts 与 packages/core/agent-loop/src/agent.ts组装与渲染packages/core/system-prompt/src/index.ts测试packages/sandbox/sandbox-policy/tests/policy.spec.ts、packages/core/agent-loop/tests/runtime-context.spec.ts【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表