ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

DeepSeek Harness Agent Loop 2026:驱动每一轮对话的可替换插件内部解析

2026/8/14 19:49:29 拓冰建站 浏览量
DeepSeek Harness Agent Loop 2026:驱动每一轮对话的可替换插件内部解析

DeepSeek Harness Agent Loop 2026:驱动每一轮对话的可替换插件内部解析

DeepSeek Harness Agent Loop 2026:驱动每一轮对话的可替换插件内部解析

核心要点 (TL;DR)

  • DeepSeek Harness agent loop 本身就是一个可替换插件:packages/core/agent-loop 中的 ReactLoopAgent 是默认实现,它实现 core/agent 定义的 Agent 接口——其他插件只依赖接口、不依赖循环,因此整个循环可以整体换掉。
  • DeepSeek Harness agent loop 在两层上运作:turn(轮)(零或多个 step,收到第一条输入时打开,模型不再欠回应时关闭)与 step(步)(一次模型请求 + 它调用的工具)。模型可见的历史从不单独存储,而是通过 deriveMessages() 从追记式会话日志投影而来。
  • 驱动器由状态机(idle | maintenance | running)门控,turn/startstep/startuser/messageassistant/chunktool/calltool/resultstep/endturn/end 等所有边界都写入持久化会话日志——fork、resume、replay、telemetry 全部从同一条事件流派生。
  • DeepSeek Harness agent loop 暴露四个无需改源码即可拦截的扩展点:agent/pre-step(waterfall)、agent/request(waterfall)、agent/request-error(waterfall)、agent/turn-stopping(serial)。工具执行走三段流水线:tools/pre-execute → tools/execute → tools/post-execute
  • DeepSeek Harness agent loop 开发插件,DSH Plugins 目录是发现、收录、分享插件的最佳去处。

目录

  1. 什么是 DeepSeek Harness Agent Loop?
  2. 两个层次:turn 与 step
  3. 状态机
  4. 完整流程分步解析
  5. 工具执行:三段流水线
  6. 持久化事件 vs 扩展点
  7. 为什么可替换的 Agent Loop 很重要
  8. DSH Plugins 生态
  9. 常见问题解答
  10. 总结

什么是 DeepSeek Harness Agent Loop?

DeepSeek Harness agent loop 是驱动 Agent 持续工作的引擎:它读取输入、请求模型、执行工具,并判断 Agent 是否还欠模型一次请求。关于它最值得深挖的事实是:循环本身就是一个插件

packages/core/agent-loop 中,默认实现是 ReactLoopAgent,它实现 core/agent 定义的 Agent 接口。其他插件只依赖这个接口,从不依赖具体的循环类。这一架构决策意味着 DeepSeek Harness agent loop 可以被整体替换:挂载一个实现 Agent 接口的其他插件,所有消费者照常工作。接口是契约,循环是实现,Harness 是组合。

这与 DeepSeek Harness「一切皆插件」的整体哲学一脉相承。Agent loop 不是特权核心组件——它是众多插件中的一个,与其它插件共享同一套事件系统。

专业提示: 读代码时,先从 core/agentAgent 接口入手,再读 ReactLoopAgent。循环做的一切都是对该契约的响应,而接口正是你自己的循环插件必须满足的东西。

两个层次:turn 与 step

DeepSeek Harness agent loop 把工作组织成两个嵌套层次:turn 与 step。

  • turn(轮) 是零或多个 step。它在收到第一条输入时打开,在「不再欠模型任何东西」时关闭——即没有挂起输入、也没有需要另一次模型请求的工具结果。
  • step(步) 是一次模型请求加上它调用的工具。每个 step 是经过模型的一次往返,随后执行模型要求的工具调用。

模型可见的历史从不单独存储,而是通过 deriveMessages() 从追记式会话日志投影而来。模型能看到的一切都必须能从日志重建——这是 docs/architecture.md 明文记载的架构不变量。实际后果是:会话日志是唯一事实来源,模型的上下文窗口永远是它的派生视图。

层次 定义 边界事件
turn 零或多个 step;首条输入打开,模型不再欠回应时关闭 turn/startturn/end
step 一次模型请求 + 它调用的工具 step/startstep/end
message step 内的用户或助手消息 user/messageassistant/message

状态机

DeepSeek Harness agent loop 的驱动器由一个小型状态机门控:Phase = idle | maintenance | running

  • idle — 没有驱动器在跑,Agent 等待输入。
  • maintenance — 驱动器拆除或准备期间的过渡状态。
  • running — 驱动器在跨越多个连续 turn 的整个排空区间内活跃。

状态切换发出 agent/status 事件,任何插件都能在不触碰循环的情况下观察其生命周期。这是 DeepSeek Harness agent loop 反复出现的模式:状态变化是事件,事件就是扩展面。

完整流程分步解析

以下是 DeepSeek Harness agent loop 的完整流程,对应 packages/core/agent-loop/src/agent.ts 的实际代码。

第 0 步:唤醒与驱动循环

输入通过 send / followup / steer / inject 进入,把消息塞进 Inbox 的两条有序队列(next-turn / next-step)。followupsteer 还会唤醒驱动器。

  • wakeDriver() — idle 时占一个 running phase(新 AbortController,turn=上一轮,step=0),在 ctx.agents.withInitiator(this, …) 里跑 kick()
  • kick()while (await this.turn()) {}:只要有挂起输入就一直开新 turn。

第 1 步:开 turn

turn()session.append('turn/start', { turn })——持久化开轮边界。然后循环处理每一步。

第 2 步:pre-step——认领输入 + 拦截决策

preStep() 做三件事:

  1. inbox.claim(target, turn) — 认领本步的输入批次(全部 next-step 消息,轮边界时再带一条 next-turn)。认领是纯删除式 splice,每条消息发 agent/inbox/claimed
  2. ctx.systemPrompt.assemble(...) — 组装 prompt 段与工具 schema。
  3. dispatch.waterfall('agent/pre-step', …)第一个扩展点。监听器可以 reject(不开步,turn 直接以 blocked 结束)或 enter 并改写消息批次;默认 enter 用认领的消息。返回 { reject }{ enter, messages, assembly }

特例: 第一步被改写为空 → turn 仍占边界但不花一次模型调用,以 completed 结束。

第 3 步:开 step + 落 user 消息

  • session.append('step/start', { turn, step }) — 持久化。
  • decision.messages 逐条 session.append('user/message', …) — 持久化。认领进来的输入此刻才落成 durable 用户消息。

第 4 步:构建请求 → 流式 → 组装消息 → 工具

step() 内部循环(支持重试):

4a. 构建请求 buildRequest()

  • dispatch.waterfall('agent/request', …)第二个扩展点。监听器可替换冻结的调用配置(provider/model/reasoningEffort/maxTokens);默认用 agent 选项或已记录的 header。
  • ctx.llm.prepareCall(config, signal) — 绑定到具体 adapter,物化 exact-model 默认值。
  • session.append('request/header', …)request/context(变化时才记)— 持久化,保证日志可重建请求。
  • 组装冻结的 request(config + deriveMessages() 历史 + system + tools + sessionId + signal)。

4b. 流式

  • preparedCall.stream(request) ?? ctx.llm.stream(request) — 发请求、读流。
  • for await chunk — 每片 session.append('assistant/chunk', …)(持久化,保原始流保真,供 replay/UI)+ 推进 BlockAssembler

4c. finish 分流 assembler.finish

  • error / aborteddispatch.waterfall('agent/request-error', …)第三个扩展点。监听器返回 { kind: 'retry' }(不调 next)则重试本步;默认 undefined 让失败终止(抛 LlmError)。
  • max-tokens → 追加 assistant/message,返回 { kind: 'max-tokens' }
  • 正常 → 追加 assistant/message{ turn, step, message, usage }sourceEventSeqs 引用对应 chunk)— 持久化。

4d. 工具调用

  • 从 assistant 消息滤出 tool-call 块。没有 → 返回 { kind: 'completed' }(本步结束,模型不欠回应)。
  • 有 → executeToolCalls(...)tool-calls.ts)。

第 5 步:关 step / 判定是否再开步

  • finally: session.append('step/end', { turn, step }) — 持久化。
  • 若本步产生终止结果(turnEnds 非 null)且 inbox 没有 next-step 输入:
  • dispatch.serial('agent/turn-stopping', { turn, signal })第四个扩展点(serial,无 next)。监听器若反对,调 agent.steer(...) 塞 steering,机器重读 inbox → 再开一步;没人反对 → 关 turn。
  • next-step 输入 → target='next-step',回第 2 步再开一个 step(工具延续)。

第 6 步:关 turn / 判定是否再开轮

  • finally: session.append('turn/end', { turn, reason: turnEnds }) — 持久化。reasoncompleted / max-tokens / blocked / aborted / error
  • 若 inbox 还有挂起输入 → 重置 AbortController、step=0,返回 true(开新 turn);否则回 idle

工具执行:三段流水线

DeepSeek Harness agent loop 的工具调度按 execution mode 分组:互斥调用是 barrier,并行调用用有界滚动池(maxParallelToolCalls)。每个调用走三段流水线,事件挂在 ctx.tools 的 scheduler 上——这是策略/超时/观测的挂载点:

tools/pre-execute → tools/execute → tools/post-execute
  • prepare(pre-execute)可能短路成直接结果。
  • dispatch(execute)跑工具。
  • finalize / finish(post-execute)收尾。

两个细节值得强调。第一,结果按模型顺序提交commitReady 跨连续槽推进),而不是按完成顺序——模型的世界观保持一致。第二,tool/call 在派发前追加(持久化),tool/result 在 post-execute 后追加(持久化,引用对应 call seq)。结果的 additionalContextsnext-step inbox,成为下个 step 边界的上下文;concludesTurn 的结果提前结束本 turn。

返回值是 { concluded }concluded{ kind: 'completed' };否则返回 null,表示工具还欠一次模型请求——回到 4a 再跑一轮。

持久化事件 vs 扩展点

DeepSeek Harness agent loop 的整个设计可以浓缩成一张图:持久化事件(记录)与扩展点(接缝)。

turn/start (durable)认领 inbox + 组装 prompt─ agent/pre-step (waterfall) reject | enter(messages) ─step/start (durable)user/message* (durable)─ agent/request (waterfall) 换配置 ─llm/stream → assistant/chunk* (durable) → assistant/message (durable)tool/call* (durable) → tools/pre-execute → tools/execute → tools/post-execute → tool/result* (durable)─ agent/request-error (waterfall) 失败时 retry ─step/end (durable)工具还欠请求 or 有 next-step 输入 → 再开一步─ agent/turn-stopping (serial) 没延续就关轮 ─
turn/end (durable)
扩展点 类型 插件能做什么
agent/pre-step waterfall 拒绝本步,或 enter 并改写消息批次
agent/request waterfall 替换冻结的调用配置(provider/model/effort/tokens)
agent/request-error waterfall 返回 { kind: 'retry' } 重试失败的 step
agent/turn-stopping serial 通过 steering 反对关轮;循环重读 inbox 再开一步

─ ─ 的是插件可挂的扩展点(waterfall 必须 next() 才向下传);其余带 (durable) 的是写进会话日志的持久化事件——fork/resume/转写/telemetry 全从这条流派生。这套设计的意义就是:换掉某个 adapter、加策略、拦截请求/工具/turn,都是挂事件或换 provider,不需要改 loop 本身。

为什么可替换的 Agent Loop 很重要

DeepSeek Harness agent loop 是插件这件事不是实现细节,而是产品本身。三个推论:

  1. 无需 fork。 需要不同循环行为(不同重试策略、不同工具调度策略、不同关轮启发式)的团队,写一个实现 Agent 的插件即可,而不是维护一个 Harness 的 fork。
  2. 策略住在接缝上。 超时、审批门、限流、观测都挂在 ctx.tools scheduler 和四个扩展点上,而不是循环代码内部。
  3. 日志即契约。 因为每个模型可见的产物都能从追记式会话日志重建,任何循环实现——默认或自定义——都能用同一套工具审计、回放、恢复。

最佳实践: 写自定义循环之前,先确认你的需求是不是一个可以挂在现有扩展点上的策略。DeepSeek Harness agent loop 的设计目标就是让大多数定制根本不碰循环。

DSH Plugins 生态

DeepSeek Harness agent loop 与其它所有能力都是插件,因此围绕它的生态与核心同样重要。DSH Plugins 目录是发现和收录 DeepSeek Harness 插件的社区枢纽——包括循环替换、工具适配器、模型提供商、策略插件。为 DeepSeek Harness agent loop 开发时,把插件收录进去能让社区发现它;动手前先浏览,也能避免重复造轮子。

常见问题解答

Q: DeepSeek Harness agent loop 真的是插件吗?

A: 是的。packages/core/agent-loop 提供 ReactLoopAgent 作为 core/agentAgent 接口的默认实现。其他插件只依赖接口,因此挂载另一个插件即可整体替换循环。

Q: turn 和 step 有什么区别?

A: turn 是零或多个 step,首条输入到达时打开,模型不再欠回应时关闭。step 是一次模型请求加上它调用的工具。两者在会话日志中都有持久化的开始/结束事件。

Q: 模型的历史从哪里来?

A: 不单独存储。DeepSeek Harness agent loop 通过 deriveMessages() 从追记式会话日志投影模型可见的历史。模型能看到的一切都必须能从日志重建。

Q: DeepSeek Harness agent loop 有哪些扩展点?

A: 四个:agent/pre-step(waterfall——拒绝或改写输入批次)、agent/request(waterfall——替换调用配置)、agent/request-error(waterfall——失败重试)、agent/turn-stopping(serial——通过 steering 反对关轮)。

Q: 工具结果按什么顺序提交?

A: 按模型顺序提交(commitReady 跨连续槽推进),而不是按完成顺序,保证模型的世界观一致。

Q: 在哪里可以找到 DeepSeek Harness agent loop 的插件?

A: DSH Plugins 目录收录了 DeepSeek Harness 的社区插件,包括循环替换、工具适配器、策略插件等。

总结

DeepSeek Harness agent loop 是可替换架构的教科书。通过定义 Agent 接口、把 ReactLoopAgent 作为众多实现之一、把每个边界持久化到追记式日志、并暴露四个 waterfall/serial 扩展点,循环把 agent harness 中最容易僵化的部分变成了最灵活的部分。

对开发者的实际启示:不理解循环也能用它,但理解了才能打开接缝。在 agent/request 拦截请求、在 agent/request-error 重试失败、在 agent/turn-stopping 门控关轮,或者用你自己的 Agent 实现整体替换循环。当你做出值得分享的东西,DSH Plugins 目录就是生态发现它的地方。循环是 DeepSeek Harness 的心脏——而且是一颗可以移植的心脏。