news 2026/9/20 20:42:44

DeepSeek Harness 拦截扩展点深度解析:基于类型化 Decision 的 Agent Hook 事件面设计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DeepSeek Harness 拦截扩展点深度解析:基于类型化 Decision 的 Agent Hook 事件面设计

DeepSeek Harness 拦截扩展点深度解析:基于类型化 Decision 的 Agent Hook 事件面设计

【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness

本文是 DeepSeek Harness 的 Agent Note 解读系列之一,源自 .agents/notes/implemented/feature/2026-06-30-interception-extension-points.md。DeepSeek Harness 以「Everything is a Plugin」为核心理念,通过 Cordis 事件体系把 Agent 生命周期全面插件化。本文聚焦其 hooks 子系统的地基——一组类型化、分权、可组合的拦截扩展点agent/*生命周期事件与tools/*五阶段工具执行管道。读完本文,你将理解「原生 hook 即普通插件」这一设计重构的本质,掌握PreStepDecision/PreToolDecision/PostToolDecision等类型化 Decision 的语义边界,以及循环(agent-loop)与工具注册表(dsh-tools)之间如何各司其职,并能在真实插件中直接复现这套拦截逻辑。

一、背景与核心重构:原生 Hook 不是「包」,而是事件 API

在 DeepSeek Harness 中,hooks 子系统的设计起点是一个关键的思想重构:「原生 hooks」并不是一个独立的软件包。一个原生 hook 本质上就是一个订阅了权威生命周期事件的普通 Cordis 插件;而 Claude Code / Codex 的桥接层(dsh-hooks-claude-code/dsh-hooks-codex)只是把外部 shell hook 协议翻译到同一套事件 API 上的翻译器(translator)

这意味着一个重要的能力结论:任何桥接层能做的事,普通插件都能直接做,而且做得更强——没有序列化边界、拥有完整的ctx、返回类型化(typed)结果。这一结论决定了本文后面所有事件签名的设计取向:事件 API 必须「强大且类型完备」,而不是围绕外部协议的兼容性打转。

该设计还依托另一个前置约定:.agents/notes/implemented/architecture/2026-06-30-event-domain-semantics.md 中提出的三域语义(session 是事实日志、agent 是实时事件通道、tools 是工具注册表与执行管道)以及类型化 Decision 惯用法。本文中的扩展点正是把这两条规则落实到 Agent 生命周期上的产物。

二、事件面总览:三类权威,泾渭分明

决策的核心是把拦截面拆成三种互相隔离的权威类型,避免「给所有扩展同样的能力」带来的越权问题:

类别代表事件拥有的能力不能做的事
可变换的策略瀑布(waterfall)agent/pre-steptools/pre-executetools/post-execute返回扩展点专属的类型化 Decision 联合,允许 / 拒绝 / 改写不得拥有与自身阶段无关的变更通道
环绕派发控制(around-dispatch)tools/execute包装器用next()委托核心派发,返回规范化结果不能移除exec.signal
只读通知(observe-only)agent/session-starttools/resultagent/turn-stopping接收不可变快照,观察生命周期不能改变最终结果

把各阶段混为一谈的坏处是双重的:插件会获得它们根本不需要的变更通道;同时「终局性」会依赖监听器的注册顺序。而上述划分让每个阶段只有一种权威,策略瀑布的终局性由 Decision 的类型联合天然决定,与监听器顺序解耦。

三、Agent 生命周期事件(dsh-agent)

3.1agent/session-start:纯通知,不能阻塞启动

  • 签名agent/session-start({ agent, source })
  • 触发时机:turn 1 之前,恰好发射一次。
  • SessionStartSource取值startup(全新创建或 fork 创建)、resume(重载持久化会话);clear/compact为预留值。
  • 关键约束:这是纯通知不能阻塞启动。这是一个刻意的设计缺口——桥接层在这里只负责「记日志 / 注入上下文」,不负责「把关启动」。需要种入上下文的监听器应调用agent.inject()

3.2agent/pre-step:每个提议步骤前的策略瀑布

  • 签名agent/pre-step({ agent, messages, turn, step, signal }, next) → PreStepDecision
  • 触发时机:在循环原子地取走其独占收件箱批次(inbox batch)之后、每个被提议的步骤执行之前。
  • 载荷说明:载荷携带请求的turnstep以及取消信号signal。被退役的PreStepContext字段直接并入载荷(见 .agents/notes/implemented/architecture/2026-08-06-agent-event-payload-objects.md);当工具延续(tool continuation)没有新的介入输入时,messages为空数组。
  • 两种返回
    • enter:返回完整消息批次(含监听器贡献的当前请求上下文),步骤正式开启;
    • reject:不开启任何步骤,已认领的消息保持被移除状态(不会回滚到收件箱)。

源码佐证:在 packages/core/agent-loop/tests/interception.spec.ts 中,agent/pre-step用例验证了坐标上报——初始提示与工具延续分别得到{ turn: 1, step: 1, messages: 1 }{ turn: 1, step: 2, messages: 0 },正好对应「无介入输入的工具延续提交空批次」的约定;同一测试还断言传入监听器的message及其content均被Object.isFrozen冻结,证明输入身份不可变。

3.3agent/turn-stopping:自然停止边界的等待式通知

  • 在自然停止边界处,该事件是**被等待(awaited)**的通知。
  • 需要再走一步的监听器调用agent.steer(),并携带显式标明来源的、面向模型的内容;循环随后重新读取 outbox,决定继续推进还是关闭本回合。

四、工具管道:每个阶段只拥有一种权威

每一次工具调用都严格遵循如下七段管线:

tools/pre-execute → guards → tools/execute → dispatch → tools/post-execute → ToolDefinition.finalizeContent → tools/result

在策略开始之前,注册表会完成三件事:快照调用者输入、物化并冻结参数、分配不透明 token,同时快照可见定义的 final-content 回调。嵌套调用只携带父 token;执行身份(identity)不可变,只有signal允许在派发期间发生变化。因此日志、UI 与工具本体三者看到的「执行的是什么」完全一致。

4.1tools/pre-execute:可扩展的瀑布闸门

  • PreToolDecision三选一:allow(放行)、deny(拒绝)、ask(询问)。
  • deny会跳过tools/execute与核心派发;ask通过可选的审批接缝(ctx.approval)解决,只有allowed-once继续穿过 guards 与派发;拒绝、取消、通道不可用、缺少审批服务、或无 agent 的调用,全部归一化为规范化拒绝
  • 无论决议结果如何,都会进入后置策略(post-policy);抛异常的监听器最终归一化为失败结果。

4.2ctx.tools.guard():同步、作用域感知的终局守门员

  • 安装在整个 pre-execute 瀑布之后
  • 守卫只能denyabstain(弃权),永远不能强制放行——这样监听器顺序无法复活一个被最终不变式(final invariant)禁止的操作。

4.3tools/execute:环绕派发瀑布

  • 面向超时(timeout)、重试(retry)、指标(metrics)插件。
  • 包装器用next()委托核心派发;可以在委托前替换并恢复必需的exec.signal,但不能移除它;接收的是已归一化的权威成功 / 失败结果(对抛异常或未知工具同样适用)。
  • 包装器自行构造的「成功」会短路派发,并经解析后的输出声明(output declaration)重新归一化。

4.4tools/post-execute:检查 / 变换瀑布

  • PostToolDecision的能力集:
    • accept:接受;
    • block:携带反馈阻塞;
    • replace:替换展示内容(presentation content)权威值(canonical value);
    • 附加additionalContexts
  • 值替换会重新校验并重算展示内容;内容替换保留程序化值,且不是机密性边界。返回的 Decision 是官方支持的变换通道。

4.5ToolDefinition.finalizeContent:工具自有的末段内容不变式

  • 可选的、同步的、纯内容边界的回调,在调用创建时与可见定义一同快照。
  • 在注册表完成规范化、并对候选结果(含绕过后续瀑布的 pre-/around-/post- 监听器失败、以及快照其他结果字段时发现的错误)做无损快照之后,恰好运行一次。
  • 可替换content,或返回undefined保留原样;但不能改写isError、结构化错误身份、上下文或展示元数据。
  • 价值在于:工具在这里强制自己的末段内容不变式,而不必把策略失败降级为更弱的 block 决策

4.6tools/result:同步、受控的结果通知

  • 在每一次变换、无损 JSON 物化以及外层错误边界之后触发。
  • 收到同一个冻结的执行身份,以及权威结果的不可变快照;观察者失败按监听器隔离,不能改变或拒绝ToolRuntime.execute()返回的结果

4.7 归一化边界:错误永不逃逸出回合

核心派发与工具本体都位于归一化边界之内:工具抛错、监听器抛错、非法权威值、渲染器 / 投影器失败、非 JSON 展示、身份形状失败——全部归一化为 JSON 安全的isError结果,而不是逃逸出回合。因此:

  • post-execute 监听器可以检查「抛了异常的工具」;
  • 定义自有的 final content 不变式同时覆盖外层管道失败与候选物化失败;
  • 最终观察者看到的,是执行局部的权威值 + 会话日志恰好能持久化的展示字段。

权威值与投影、持久化规则由 .agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md 承载。

五、三个承重(load-bearing)的循环决策

  1. 在每个被提议的步骤运行 pre-step 策略。循环在首次认领与决策之前就打开回合,因此reject关闭的是一个「有记录但无步骤、无模型可见消息」的受阻回合;工具延续无新认领输入时仍提交空批次,允许按请求的上下文生产者把日志消息追加到该精确请求上。enter时循环打开步骤,并在请求推导前把返回批次作为user/message事件追加。依据 one-send-one-turn 简化,每个被认领的后续消息仍是其回合内唯一的直接提示。

  2. post-tool 的additionalContexts与异步注入进入活动批次 FIFO,在该批次落定时追加content/feedback塑造execute()返回的结果,但每个 context 都是独立的、带来源的user/message,单个步骤或复合工具可能产生多个。若立即追加,会得到result(c1) → context → result(c2)的穿插序列,或让嵌套 context 出现在其外层 result 之前,破坏「工具调用/结果相邻」的不变式。为此:

    • ToolRunContext.deferContext()在失败路径上收集嵌套派发的 context;
    • execute()ToolExecutionResult上暴露有序数组;
    • 循环把它与执行期间产生的agent.inject()调用放入同一个 FIFO;FIFO 在批次落定时、每一条已记录 result 之后追加——包括在被打断的回合关闭之前。
    • 被接受的外层调用在 decision context 之前保留延迟 context;被阻塞的外层调用丢弃延迟 context,只暴露阻塞决策显式提供的 context。
  3. 停止中的监听器通过 steering 通道请求续跑,因此下一步循环顶部排空(drain)时会把这次续跑记录为同回合内下一步的 steering——是 next-step 而非 next-turn 的提示。

六、边界:什么不属于这套扩展点

  • hook/*会话事件(持久化的 hook 调用日志)不属于Service Definition 包,而归属于dsh-hook-protocol——因为原生插件使用类型化 Decision,根本不需要外部 hook 日志。原生插件集成测试 packages/core/agent-loop/tests/interception.spec.ts 通过真实循环组合这些扩展点,全程没有任何hook/*协议。
  • CompactionPreCompact/PostCompact)、Notification、以及 Codex 的PermissionRequest都排除在本决策之外。
  • ask决议通过 审批接缝 以ctx.approval解决;终态单调停止由工具结果数据表达,而agent/turn-stopping是引导下一步的最后机会

七、被否决的备选方案

  • 把 pre-tool 输入改写并入本扩展点集合:否决。理由是一个一致性问题——审计、历史与 UI 展示读的都是执行前记录的tool/call.arguments;在身份创建前,一次合法的改写必须同时更新历史、审计、展示与执行四者。该契约由 pre-tool input-rewrite 提案 单独拥有,不应由扩展点隐式承担。
  • 在扩展点旁同时声明持久化hook/*会话事件:否决。原生插件直接使用类型化 Decision、完全不产生 hook 日志(集成测试已证明),因此持久化日志属于 hook-protocol 库,而非扩展面。

八、后果与落地验证

最终形态是一套统一类型化但权力分级的拦截面:hooks 返回 Decision、执行包装器做 wrap、终局守卫只能 deny、最终观察者只能 observe。职责划分清晰:

  • 循环(agent-loop)拥有:session-start、pre-step 认领结算、post-tool 上下文缓冲、停止(stopping)。
  • dsh-tools拥有:身份密封(identity sealing)与五阶段执行管道。

契约文档化位置:docs/architecture.md、各包 README、docs/subsystems/core.md(interception-decisions 一节)以及 docs/subsystems/tools.md(tool structures 一节)。ACP 桥接层会把初始 pre-step 拒绝导致的「无步骤回合」结算为end_turn,而 hook 驱动的快照则端到端验证桥接层的可观察行为。

对插件作者而言,这套设计的实操含义可以浓缩为一张自检清单:要放行或拒绝,写agent/pre-step/tools/pre-execute返回 Decision;要包裹派发做超时与重试,写tools/execute包装器;要校验或变换结果,写tools/post-execute;要强制工具自身的内容不变式,用ToolDefinition.finalizeContent;要观察而不得干预,订阅agent/session-start/tools/result记住每条原则对应的权威类型,就能在保持循环与管道不变式的前提下,安全地把任何外部 hook 协议「翻译」为原生插件能力。

【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness

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

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

美赛优秀论文合集高效拆解与实战提分指南

简介:历年美赛数学建模优秀论文大全1.pdf,内容聚焦2008年国际大学生数学建模竞赛优秀参赛作品,由重庆大学团队完成,题目为《Less Resources, More Outcomes》,针对WHO成员国卫生系统绩效评估展开完整建模。论文结构清晰…

作者头像 李华
网站建设 2026/9/20 20:40:27

基于深度学习与摄像头的坐姿检测系统设计与实现

简介:一份基于深度学习的智能坐姿检测系统完整项目,适合课程设计、期末大作业或毕业设计场景。项目通过摄像头或图像输入,利用姿态估计与分类模型实时判断人体坐姿是否规范,可扩展至学习提醒、健康监测等应用。压缩包内共15个文件…

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

uniapp+Java多端淘宝客源码拆解:架构、部署与避坑指南

简介:面向电商导购与CPS推广场景的“省钱兄淘宝客”多端项目是一套完整的源码包,适合需要快速搭建返利/优惠券平台的开发者,也适合 Java 后端与 uniapp 前端学习者参考。资源内整合 APP 端、小程序、公众号及 H5 页面,对应 uniapp…

作者头像 李华
网站建设 2026/9/20 20:37:07

AI辅助红队评估:用Claude构建结构化安全技能库的实践指南

这两年安全圈里聊得最多的话题,大概就是“AI 到底能不能替代渗透测试工程师”。我的观点一直很明确:短期内不能完全替代,但 AI 绝对能在红队评估里把那些最磨人、最耗时的脏活累活接过去。前段时间我花了大量时间折腾 claude-red 这个思路——…

作者头像 李华
网站建设 2026/9/20 20:36:47

Python函数与模块化开发核心技术与实践

1. 为什么函数与模块是Python开发的基石刚接触Python时,我们往往习惯把所有代码写在一个文件里。但随着项目规模扩大,这种写法很快会变成难以维护的"面条代码"。三年前我接手过一个遗留项目,8000多行代码挤在单个.py文件里&#xf…

作者头像 李华