Clarify DeepSeek Harness architecture
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
---
|
||||
{
|
||||
"title": "DeepSeek Harness:全插件化 Agent 运行时与评测现状",
|
||||
"summary": "从配置组合、Agent loop、工具审批、事件日志与恢复机制出发,解释 DeepSeek Harness 的架构取舍,并核对公开评测证据是否足以支持采用。",
|
||||
"summary": "从一个 greet 工具的完整生命周期出发,分开解释启动装配、请求调用、事件记录和协议边界,再核对 DeepSeek Harness 的架构取舍与公开评测证据。",
|
||||
"date": "2026-08-14",
|
||||
"updated": "2026-08-14",
|
||||
"topic": "agent-systems",
|
||||
@@ -20,54 +20,30 @@
|
||||
|
||||
## 调研范围
|
||||
|
||||
本文面向需要选择或建设 Agent Harness 的研发与技术管理者,回答三个问题:DeepSeek Harness 实际如何组织和运行 Agent;它与常见 coding agent 系统的关键差异是什么;当前公开证据是否足以支持观察、试点或正式采用。
|
||||
本文面向理解大模型、API 和基本工具调用,但尚不了解 Cordis 或 Agent Runtime 内部结构的读者。它回答三个问题:DeepSeek Harness 实际如何组装和运行 Agent;它与常见 coding agent 系统的关键差异是什么;当前公开证据是否足以支持观察、试点或正式采用。
|
||||
|
||||
调研冻结在 2026 年 8 月 14 日,目标代码固定为提交 [`47f943859bef60e4160492346772ded9b24f765a`](https://github.com/deepseek-ai/deepseek-harness/tree/47f943859bef60e4160492346772ded9b24f765a)。横向对照也固定到同日抓取的 Codex、Gemini CLI 与 OpenHands 提交。本文不评价 DeepSeek 模型能力,不使用 GitHub star 数作为成熟度证据,也不把不同项目、不同模型、不同任务下的数字拼成排行榜。
|
||||
|
||||
## 当前判断
|
||||
## 项目位置与必要概念
|
||||
|
||||
1. **最值得关注的是扩展边界。** dsh 允许替换的不只包括工具和模型适配器,还包括会话、Agent loop、工具注册表、策略、持久化和 UI。Profile、Bundle 与 patch 可以逐层改写这些配置,比“在固定 Agent 核心外围加插件”更激进。
|
||||
2. **插件由完整主链路连接。** 一次 turn 通过 durable session event、live agent event 和 capability waterfall 串成完整流程;工具审批、执行和结果回写有明确顺序;会话日志同时服务模型上下文、恢复、分叉和 UI 投影。
|
||||
3. **工程质量证据多于效果证据。** 仓库有高覆盖率单元测试、keyless snapshot、真实 API e2e 入口、Web 性能/压力 runner 和 CI runner benchmark;但在冻结范围内没有发现公开的 Agent 任务成功率成绩。
|
||||
4. **现在的合理动作是观察或隔离试点。** Developer Preview、兼容性主动破坏、会话格式 v0、无正式 GitHub Release,以及缺少可复现的目标任务评测,都会阻断生产级采用。
|
||||
DeepSeek Harness(命令名 `dsh`)不是一个模型,也不是某个单独工具的封装。它是一个 **Agent Harness**:负责把模型、工具、会话状态、执行循环、权限策略和用户入口组装成一个可以持续运行的 Agent 应用。
|
||||
|
||||
## 一次 Agent 请求如何流过系统
|
||||
先建立四个最小概念:
|
||||
|
||||

|
||||
| 名称 | 白话解释 | 在 dsh 中负责什么 |
|
||||
|---|---|---|
|
||||
| Agent | 能接收目标、调用模型和工具、保留状态并继续工作的程序 | 一个 Agent 由模型、工具、会话和执行循环共同组成 |
|
||||
| Agent Harness | 承载 Agent 的运行外壳 | 启动组件、接收请求、管理状态、执行工具并暴露 Web/协议入口 |
|
||||
| Cordis | dsh 进程内部的插件装配器和生命周期管理器 | 决定有哪些插件、依赖是否满足,以及变化时如何卸载和重建 |
|
||||
| Agent loop | 一次任务中的“模型—工具—模型”循环 | 组装上下文,调用模型,执行工具,再把结果交回模型直到结束 |
|
||||
|
||||
启动时,dsh 先从 Profile 读取有序 Bundle,再叠加 Profile、Harness home 和命令行 patch,得到实际 Cordis 插件树。官方架构文档明确写到,模型适配器、工具注册表、会话日志和 Agent loop 本身都是插件;配置行可以被更高层 patch 整体替换。[架构文档](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/docs/architecture.md)
|
||||
dsh 主体是 TypeScript monorepo,运行在 Node.js ESM 环境;冻结提交的根配置要求 Node.js 22.19 以上或 24 以上。Cordis 插件在运行时是由 Node 加载的 JavaScript/TypeScript 模块,通常导出 `apply(ctx, config)`。[根 package.json](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/package.json) [第一个 Cordis 插件](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/docs/cordis-tutorial/01-first-plugin.zh.md)
|
||||
|
||||
运行时,输入先进入 Agent inbox。loop 在每个 step 前组装系统提示、工具 schema 与从会话日志派生的历史,然后发出 `agent/pre-step`;通过后写入 `step/start` 与用户消息,再经 `agent/request` 调用 LLM。模型产生工具调用时,执行路径依次经过 `tools/pre-execute`、审批、guard、`tools/execute`、工具本体、`tools/post-execute` 和结果固化。需要审批却没有可用 answerer 时,`ask` 会退化为拒绝,而不是静默放行。[Tools README](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/packages/core/tools/README.md)
|
||||
理解这套架构最重要的前提是把两个问题分开:**启动装配**回答“哪些组件存在、谁依赖谁、谁随谁卸载”;**请求执行**回答“用户的一条消息在已经启动的组件之间怎样移动”。Cordis 插件树主要回答前一个问题,不是用户请求的调用顺序。
|
||||
|
||||
这些事实被追加到 `SessionEvent` 日志。模型历史从日志派生;resume、fork、轨迹视图和持久化也复用同一事实源。若进程在工具调用中断,恢复逻辑会区分“工具尚未开始”和“工具结果未知”,后者会提示模型先验证副作用,避免盲目重试。[持久化说明](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/packages/session/session-persistence/README.md)
|
||||
## 一次完整的 `greet("Ada")` 走查
|
||||
|
||||
这条链路的价值在于,扩展不必侵入一个巨大核心:插件可以提供服务、监听或包裹 waterfall,并在卸载时撤销注册。Cordis 预印本将其归纳为时间可组合性与空间可组合性:一方面追踪可逆 effect,另一方面根据依赖变化重新协调组件。但论文仍处于 active revision,适合作为设计解释,不应当作稳定标准。[Cordis 预印本](https://github.com/cordiverse/paper)
|
||||
|
||||
## Cordis 插件树到底怎样实现
|
||||
|
||||
“插件树”容易让人误以为是一棵类继承树。dsh 里实际叠加了三层机制:
|
||||
|
||||
1. **配置层决定“挂载什么”。** Profile 先列出有序 Bundle;启动时再依次应用 Bundle patch、Profile 自身 patch、Harness home patch 和命令行 `--patch`。每个配置行用 `id` 作稳定身份,`name` 指向插件模块,还可带 `config`、`inject` 和 `disabled`。后层 patch 按 `id` 命中前层行时,替换整个 `config`,不做字段级深合并。[CLI 组合参考](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/apps/cli/reference/README.md)
|
||||
2. **Cordis 运行时决定“何时激活”。** 根 `Context` 下的 Loader 把每行配置挂成一个插件实例,每个实例都有 Fiber 状态。插件通过 `apply(ctx, config)` 贡献能力,通过 `inject` 声明必需服务。因此 YAML 行的先后不决定加载顺序:依赖未就绪的插件保持 `PENDING`,服务出现后才激活。[Cordis 服务教程](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/docs/cordis-tutorial/03-services.zh.md)
|
||||
3. **effect 层决定“怎样安全拆除”。** `ctx.tools.register(...)`、`ctx.on(...)`、服务注册和子插件都与当前插件生命周期绑定。配置删除、HMR 或服务提供方消失时,Cordis 会卸载相关 Fiber,反向撤销注册;服务恢复后,依赖它的插件再重新加载。[Cordis 生命周期教程](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/docs/cordis-tutorial/02-lifecycle-and-effects.zh.md)
|
||||
|
||||
可以把一个简化后的运行时理解为:
|
||||
|
||||
```text
|
||||
Root Context
|
||||
└─ Loader
|
||||
├─ tools provider Fiber → 提供 ctx.tools
|
||||
├─ greet-tool Fiber → inject: tools
|
||||
├─ llm provider Fiber → 提供 ctx.llm
|
||||
├─ agent-loop Fiber → 消费 agents / tools / llm
|
||||
└─ surface Fiber → Web、ACP 或 SDK JSON-RPC
|
||||
```
|
||||
|
||||
这棵“树”同时包含两种关系:Loader 建立的父子生命周期,以及 `inject` 建立的服务依赖图。Bundle 是生成配置行的发布层,并不会成为一个不可拆的运行时黑盒。
|
||||
|
||||
### 一个最小例子:向模型增加 `greet` 工具
|
||||
|
||||
下面是官方 Cordis 教程示例的精简版。插件不自己启动 Agent,只声明“我需要 `tools` 服务,并向它注册一个工具”:
|
||||
假设现有 Profile 已经包含 LLM、工具注册表、会话、Agent loop 和 Web/ACP/SDK 入口。我们只增加一个虚构示例包 `@acme/dsh-greet-tool`,让模型能够调用 `greet`。下面代码根据官方教程的工具插件写法精简;它只演示插件机制,不是仓库已经发布的包。
|
||||
|
||||
```ts
|
||||
import type { Context } from '@deepseek-ai/cordis'
|
||||
@@ -91,7 +67,7 @@ export function apply(ctx: Context) {
|
||||
}
|
||||
```
|
||||
|
||||
假设将它发布并安装为虚构示例包 `@acme/dsh-greet-tool`,可在 Profile 的 `cordis.patch.yml` 插入一行:
|
||||
把它加入 Profile 的 `cordis.patch.yml`:
|
||||
|
||||
```yaml
|
||||
- insert:
|
||||
@@ -99,20 +75,123 @@ export function apply(ctx: Context) {
|
||||
name: '@acme/dsh-greet-tool'
|
||||
```
|
||||
|
||||
这个例子假定所选 Profile 已有 `tools`、LLM 和 agent loop 等基础行;它只演示新能力如何插入既有 Agent。完整过程是:Loader 看到 `greet-tool` 行 → 发现它需要 `tools`,Fiber 在缺失时保持 `PENDING` → `ctx.tools` 就绪后调用 `apply` 并进入 `ACTIVE` → `greet` 的 schema 进入模型工具列表 → 模型发出 `greet({"name":"Ada"})` 时经标准工具管线执行 → 返回 `Hello, Ada!`。删掉这行或 HMR 热替换包时,Loader 根据稳定 `id` 重挂变化节点;旧 Fiber 进入卸载并最终 `DISPOSED`,工具注册随 effect 自动撤销。官方完整例子还演示了如何监听 `tools/result` 事件。[进入 Harness 教程](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/docs/cordis-tutorial/07-into-the-harness.zh.md)
|
||||
这个工具从配置到卸载会经历六个连续阶段。
|
||||
|
||||
### “接入协议”要先区分方向
|
||||
### 第一阶段:配置先决定“准备挂载什么”
|
||||
|
||||
| 接入面 | 连接方式 | 解决的问题 |
|
||||
dsh 不会直接把某一个 YAML 文件原样交给 Cordis。它先读取 Profile 指定的有序 Bundle,依次应用各 Bundle 的 patch,再叠加 Profile 自身 patch、Harness home patch 和本次命令行 `--patch`,最终得到一组有效配置行。`greet-tool` 是其中一行;它的 `id` 是稳定身份,`name` 指向要加载的模块。[CLI 组合参考](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/apps/cli/reference/README.md)
|
||||
|
||||
如果后层 patch 命中同一个 `id`,该行的 `config` 会整体替换,不是字段级深合并。这里的配置合成只回答“本次启动要挂载什么”,尚未执行任何用户请求。
|
||||
|
||||
### 第二阶段:Loader 创建 Fiber,`inject` 决定何时启动
|
||||
|
||||
启动器创建根 `Context` 并挂载 Loader。Loader 解析 `@acme/dsh-greet-tool`,为这次插件挂载创建一个 Fiber。Fiber 不是线程或操作系统进程,而是 **一个插件实例的运行时句柄**:它记录父上下文、配置、依赖、状态、注册的 effect 和清理过程。
|
||||
|
||||
插件导出了 `inject = ['tools']`,所以 Cordis 会检查名为 `tools` 的 Service 是否已经存在。若不存在,Fiber 保持 `PENDING`,不会调用 `apply`;当 `ctx.tools` 出现后,Fiber 进入 `LOADING`,执行 `apply(ctx)`,完成后进入 `ACTIVE`。因此 YAML 中哪一行写在前面并不决定启动顺序,服务依赖才决定。[Cordis 服务教程](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/docs/cordis-tutorial/03-services.zh.md)
|
||||
|
||||
`apply` 中的 `ctx.tools.register(...)` 把 `greet` 的名称、参数 schema、返回值渲染和执行函数注册到工具运行时。该注册本身属于一个 effect;Cordis 会记住对应的 disposer,以便插件卸载时自动注销工具。[进入 Harness 教程](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/docs/cordis-tutorial/07-into-the-harness.zh.md)
|
||||
|
||||
### 第三阶段:用户请求进入已经启动的 Agent
|
||||
|
||||
用户通过 Web、ACP 或 SDK 输入“向 Ada 问好”。入口适配器把消息交给对应 Agent 的 inbox。Agent loop 取得待处理输入,从会话日志派生历史,加入系统提示和当前可用工具 schema,然后进入一个 model step。此时 `greet` 已经是工具列表中的一项;Cordis 不再决定模型是否调用它,Cordis 只保证工具已经正确注册。
|
||||
|
||||
模型可以直接回答,也可以产生工具调用。这个例子中,模型返回 `greet({"name":"Ada"})`,于是 Agent loop 把调用交给统一 Tools Runtime。
|
||||
|
||||
### 第四阶段:工具经过统一执行管线
|
||||
|
||||
工具调用不会从模型直接跳进示例函数。标准路径依次经过 `tools/pre-execute`、审批、guard、`tools/execute`、工具本体、`tools/post-execute` 和结果固化。若某项策略返回 `ask`,但当前入口没有可用审批 answerer,系统会拒绝而不是静默放行。[Tools README](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/packages/core/tools/README.md)
|
||||
|
||||
`greet` 执行后返回 `Hello, Ada!`。Tools Runtime 将结果交回 Agent loop,Agent loop 再把它放入下一次模型请求。模型据此生成最终回答,例如“已向 Ada 问好”。这就是 Agent loop 所负责的“模型 → 工具 → 模型”循环。
|
||||
|
||||
### 第五阶段:SessionEvent 在旁路记录事实
|
||||
|
||||
用户消息、step 开始、模型消息、工具调用、工具结果和最终回答会分别追加为 `SessionEvent`。它不是调用链中的“下一台服务器”,也不负责把工具结果转发给模型;它是执行过程中形成的 durable fact。模型历史、resume、fork、轨迹视图、持久化和 UI 投影都从同一事实源派生。[持久化说明](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/packages/session/session-persistence/README.md)
|
||||
|
||||
如果进程在工具调用期间中断,恢复逻辑会检查日志:工具尚未真正开始,可以安全标记失败;工具可能已经产生副作用但没有留下结果,则标记“结果未知”,提示模型先验证外部状态,避免盲目重试。这解释了事件日志为什么与执行链同样重要,但二者仍是不同关系。
|
||||
|
||||
### 第六阶段:配置或依赖变化时自动撤销
|
||||
|
||||
Fiber 的主要状态为 `PENDING → LOADING → ACTIVE → UNLOADING`,加载失败时进入 `FAILED`。如果 `tools` Service 暂时消失,已经激活的 `greet-tool` 会卸载自己的 effect,回到等待依赖的状态;服务恢复后重新加载。如果配置行被删除,旧 Fiber 完成清理后进入 `DISPOSED`,不能再次启动。HMR 则卸载旧实例,再根据新模块挂载替代实例。[Cordis 生命周期教程](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/docs/cordis-tutorial/02-lifecycle-and-effects.zh.md) [组合与 HMR](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/docs/cordis-tutorial/06-composition-and-hmr.zh.md)
|
||||
|
||||
卸载时,`greet` 的工具注册、事件监听、子插件和通过 `ctx.effect()` 管理的定时器或连接都会执行 disposer。插件不需要在每个退出分支手工寻找自己曾经注册的对象。这个“注册与撤销属于同一生命周期”是 Cordis 最核心的工程价值。
|
||||
|
||||
到这里可以用一句话复述完整过程:**配置决定挂载 `greet-tool`;`inject` 让它等待 `tools`;Fiber 激活后注册工具;Agent loop 在一次请求中让模型调用它;SessionEvent 记录事实;依赖或配置变化时 effect 自动撤销。**
|
||||
|
||||
## 启动装配:Profile 如何变成运行中的插件
|
||||
|
||||

|
||||
|
||||
这张图只回答启动问题。可以把它拆成配置层和运行时层。
|
||||
|
||||
### 配置层:Profile、Bundle 与 patch
|
||||
|
||||
- **Bundle** 是可复用的默认插件组合,例如一组基础服务和工具。它贡献配置行或 patch,但运行时不会把整个 Bundle 当成不可拆的黑盒。
|
||||
- **Profile** 是一种产品或运行形态的入口。它选择有序 Bundle,并附加自己的 patch,例如组合 Web 或 headless 版本。
|
||||
- **Harness home patch** 是用户或部署环境的持久覆盖。
|
||||
- **CLI `--patch`** 是本次启动最后应用的临时覆盖。
|
||||
|
||||
合成结果是一组带 `id` 的配置行。每行通常包含 `name`、`config`、`inject` 和 `disabled` 等字段。稳定 `id` 让 Loader 判断一项变化是在更新已有节点,还是删除旧节点后增加新节点。
|
||||
|
||||
### 运行时层:Context、Loader 与 Fiber
|
||||
|
||||
根 `Context` 是进程内能力和事件的访问入口;Loader 根据有效配置加载模块,并把每次挂载变成 Fiber。官方教程支持函数、带 `apply` 的对象和 `Service` 子类三种插件形态。`apply(ctx, config)` 只描述插件向当前上下文贡献什么,启动器和 Loader 负责实际挂载。[第一个 Cordis 插件](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/docs/cordis-tutorial/01-first-plugin.zh.md)
|
||||
|
||||
Fiber 负责把一次插件应用变成可观察、可等待、可失败、可卸载的运行实例。它记录所需 Service 的具体实现;提供方变化时,Cordis 可以比较依赖并只重载受影响的插件,而不是重启整个进程。
|
||||
|
||||
### 依赖层:Service 与 `inject`
|
||||
|
||||
Service 是插件提供给其他插件的具名能力,例如 `ctx.llm`、`ctx.tools` 和 `ctx.sessions`。消费者声明 `inject: ['tools']`,只表示“我需要工具服务”,不绑定某一个具体提供包。部署可以替换 provider,而消费插件代码无需改变。
|
||||
|
||||
`inject` 是硬依赖:缺失时 Fiber 保持 `PENDING`。可选能力则不应写入 `inject`,而是在使用处通过 `ctx.get(...)` 探测。服务名称共享一个命名空间,这也意味着大型部署必须治理名称、提供方和配置来源。
|
||||
|
||||
## 请求执行:一次消息如何经过 Agent loop
|
||||
|
||||

|
||||
|
||||
这张图只回答运行问题。系统已经完成装配,因此请求链中不再出现 Profile、Bundle 和 Loader:
|
||||
|
||||
1. Web、ACP 或 SDK 入口把用户输入交给 Agent inbox。
|
||||
2. Agent loop 取得输入,组装系统提示、历史和工具 schema。
|
||||
3. Agent loop 调用 LLM;模型可以直接回答或请求工具。
|
||||
4. 工具调用进入统一 Tools Runtime,经过策略、审批、guard 和执行阶段。
|
||||
5. 工具结果回到 Agent loop,再进入下一次模型 step。
|
||||
6. 模型生成最终消息,Agent loop 提交结果并在没有待处理工作时回到 idle。
|
||||
|
||||
dsh 同时存在两类容易混淆的“事件”。`SessionEvent` 是写入会话日志的 durable fact,承担重建、恢复和投影;`agent/pre-step`、`agent/request`、`tools/pre-execute` 等 live event 或 waterfall 是运行时扩展点,插件可以监听、修改、放行或短路当前过程。前者回答“发生过什么”,后者参与“现在怎样继续执行”。
|
||||
|
||||
## 插件树、依赖图和调用链不是同一张图
|
||||
|
||||
| 关系 | 它回答的问题 | `greet` 例子 |
|
||||
|---|---|---|
|
||||
| Cordis 插件 | 进程内:TypeScript `apply(ctx, config)`、`inject`、Service、Event、effect | 增加或替换模型、工具、会话、策略、loop 和 UI 组件 |
|
||||
| Profile / Bundle / patch | 部署时:YAML 配置行与稳定 `id` | 选哪些插件、如何覆盖默认值;它不是远程协议 |
|
||||
| Web | 浏览器 → dsh:HTTP POST 一元调用;dsh → 浏览器:WebSocket 事件下行 | 产品 UI、会话展示和交互式操作;业务 Remote 由 Typert 生成严格描述 |
|
||||
| ACP | 外部 Agent 客户端 ↔ dsh:Agent Client Protocol over newline-delimited JSON-RPC stdio | 标准化的 `session/new`、`session/prompt`、取消和一次性权限回答 |
|
||||
| Python / TypeScript SDK | 评测器或程序 ↔ dsh:项目自有的逐行 JSON-RPC 2.0 stdio | 批量任务、自动化和 benchmark runner;方法为 `initialize`、`session/prompt`、`shutdown` 及事件/状态通知 |
|
||||
| MCP client | dsh ↔ 外部工具服务器:MCP stdio 或 Streamable HTTP | 发现工具并注册为 `mcp__<server>__<tool>`;当前不桥接 Resources 和 Prompts |
|
||||
| 插件父子与生命周期 | 谁由谁挂载,父节点卸载时谁一起清理 | Loader 挂载 `greet-tool` Fiber;删除配置时旧实例被清理 |
|
||||
| Service 依赖 | 谁必须等待谁,提供方变化时谁需要重载 | `greet-tool` 通过 `inject` 等待 `tools` |
|
||||
| 请求调用 | 一条消息在运行时经过哪些已经激活的组件 | Agent loop → LLM → Tools → `greet` → LLM |
|
||||
|
||||
关键区别是:**Web 是浏览器产品面;ACP 和 SDK 是“从外部驱动整个 Agent”;MCP 是“把外部工具接给 Agent”;Cordis 则是“在进程内改变 Agent 由哪些部件构成”。** 它们解决的问题不同,不应放在同一层比较。ACP 只暴露基线自动化能力,而 SDK 线协议当前没有版本协商和单 prompt 取消,都不能等同于 Web 产品面的完整功能。[ACP 协议契约](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/packages/acp/acp/README.md) [SDK 线协议](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/packages/sdk/protocol/README.md) [Web Connection](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/packages/client/connection/README.md) [MCP client](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/packages/mcp/mcp-client/README.md)
|
||||
所谓“Cordis 插件树”首先是一套运行实例的所有权结构;再叠加 `inject` 后,形成服务依赖图。一次请求的调用链则发生在这些实例都准备好之后。三者可能涉及相同插件,但箭头含义不同,不能用一棵树同时表示。
|
||||
|
||||
## Web、ACP、SDK、MCP 与 Cordis 的边界
|
||||
|
||||

|
||||
|
||||
先看进程边界,再看协议名称:Web、ACP 和 SDK 把请求从外部送入 Agent;MCP 把外部工具送入 Tools;Cordis 位于 dsh 的 Node.js 进程内部,负责组件装配,不是远程协议。
|
||||
|
||||
| 接入面 | 连接方向与载体 | 解决的问题 |
|
||||
|---|---|---|
|
||||
| Cordis 插件 | dsh 进程内的 ESM 模块:`apply`、Service、Event、effect | 增加或替换模型、工具、会话、策略、loop 和 UI 组件 |
|
||||
| Web | 浏览器 → dsh 为 HTTP POST;dsh → 浏览器为 WebSocket 事件 | 产品 UI、会话展示和交互操作 |
|
||||
| ACP | 外部 Agent Client ↔ dsh,newline-delimited JSON-RPC over stdio | 创建会话、发送 prompt、取消和一次性权限回答的基线自动化 |
|
||||
| Python / TypeScript SDK | 评测器或程序 ↔ dsh,项目自有 line JSON-RPC 2.0 over stdio | 批量任务、自动化和 benchmark runner |
|
||||
| MCP client | dsh ↔ 外部 MCP Server,stdio 或 Streamable HTTP | 发现外部工具并注册为 `mcp__<server>__<tool>`;当前只桥接 Tools |
|
||||
|
||||
Profile、Bundle 和 patch 不在表中,因为它们是部署配置方式,不是通信协议。ACP 也不等于完整 Web 产品面:它只暴露自动化基线;SDK 线协议当前没有版本协商和单 prompt 取消;MCP 当前不桥接 Resources 和 Prompts。[ACP 协议契约](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/packages/acp/acp/README.md) [SDK 线协议](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/packages/sdk/protocol/README.md) [Web Connection](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/packages/client/connection/README.md) [MCP client](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/packages/mcp/mcp-client/README.md)
|
||||
|
||||
## 架构判断
|
||||
|
||||
1. **最值得关注的是扩展边界。** dsh 允许替换的不只包括工具和模型适配器,还包括会话、Agent loop、工具注册表、策略、持久化和 UI。Profile、Bundle 与 patch 可以逐层改写配置,比“在固定 Agent 核心外围加插件”更激进。
|
||||
2. **Cordis 解决的是组合变化。** Fiber、Service、`inject` 和 effect 让插件能随配置与依赖变化安全地加载、等待、卸载和重建;它并不替代 Agent loop。
|
||||
3. **Agent loop、工具管线和事件日志形成执行主链。** loop 决定下一步,Tools 执行动作,SessionEvent 保留可恢复事实;三者职责分开。
|
||||
4. **工程质量证据多于效果证据。** 仓库有高覆盖率单元测试、keyless snapshot、真实 API e2e 入口、Web 性能/压力 runner 和 CI runner benchmark;但在冻结范围内没有发现公开的 Agent 任务成功率成绩。
|
||||
5. **现在的合理动作是观察或隔离试点。** Developer Preview、兼容性主动破坏、会话格式 v0、无正式 GitHub Release,以及缺少可复现的目标任务评测,都会阻断生产级采用。
|
||||
|
||||
## 这套设计解决了什么
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1440" height="860" viewBox="0 0 1440 860" role="img" aria-labelledby="title desc">
|
||||
<title id="title">DeepSeek Harness greet 请求调用图</title>
|
||||
<desc id="desc">用户请求进入已经启动的 Agent,模型调用 greet 工具并返回结果;SessionEvent 在下方记录事实,但不是调用链的下一跳。</desc>
|
||||
<defs>
|
||||
<style>
|
||||
.bg { fill: #f7f4ec; }
|
||||
.title { font: 700 30px -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif; fill: #183a34; }
|
||||
.subtitle { font: 400 18px -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif; fill: #60706a; }
|
||||
.box { fill: #fffdf8; stroke: #286458; stroke-width: 2; rx: 18; }
|
||||
.focus { fill: #fff2df; stroke: #ca6715; stroke-width: 2.4; rx: 18; }
|
||||
.event { fill: #edf5f1; stroke: #557b72; stroke-width: 2; rx: 18; }
|
||||
.label { font: 650 19px -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif; fill: #1f413a; }
|
||||
.body { font: 400 16px -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif; fill: #354c47; }
|
||||
.small { font: 400 15px -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif; fill: #66766f; }
|
||||
.solid { stroke: #286458; stroke-width: 3; fill: none; marker-end: url(#arrow); }
|
||||
.return { stroke: #ca6715; stroke-width: 3; fill: none; marker-end: url(#arrow-orange); }
|
||||
.dash { stroke: #7a8c86; stroke-width: 2.2; stroke-dasharray: 8 8; fill: none; marker-end: url(#arrow-gray); }
|
||||
</style>
|
||||
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L0,6 L9,3 z" fill="#286458"/></marker>
|
||||
<marker id="arrow-orange" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L0,6 L9,3 z" fill="#ca6715"/></marker>
|
||||
<marker id="arrow-gray" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L0,6 L9,3 z" fill="#7a8c86"/></marker>
|
||||
</defs>
|
||||
<rect class="bg" width="1440" height="860" rx="32"/>
|
||||
<text class="title" x="64" y="64">一次 greet 请求:消息在已启动的组件之间怎样移动</text>
|
||||
<text class="subtitle" x="64" y="98">这是一张运行时调用图;Profile、Bundle 和 Fiber 装配已经完成。</text>
|
||||
|
||||
<rect class="box" x="58" y="168" width="180" height="106"/>
|
||||
<text class="label" x="82" y="207">用户入口</text>
|
||||
<text class="body" x="82" y="238">Web / ACP / SDK</text>
|
||||
|
||||
<rect class="box" x="288" y="168" width="180" height="106"/>
|
||||
<text class="label" x="312" y="207">Agent inbox</text>
|
||||
<text class="body" x="312" y="238">“向 Ada 问好”</text>
|
||||
|
||||
<rect class="box" x="518" y="150" width="220" height="142"/>
|
||||
<text class="label" x="542" y="190">Agent loop</text>
|
||||
<text class="body" x="542" y="222">组装历史、系统提示</text>
|
||||
<text class="body" x="542" y="248">和可用工具 schema</text>
|
||||
|
||||
<rect class="focus" x="788" y="150" width="220" height="142"/>
|
||||
<text class="label" x="812" y="190">LLM</text>
|
||||
<text class="body" x="812" y="222">决定调用工具:</text>
|
||||
<text class="body" x="812" y="250">greet({ name: "Ada" })</text>
|
||||
|
||||
<rect class="box" x="1058" y="132" width="320" height="178"/>
|
||||
<text class="label" x="1082" y="170">Guarded tool pipeline</text>
|
||||
<text class="body" x="1082" y="204">pre-execute → approval → guard</text>
|
||||
<text class="body" x="1082" y="232">→ execute → post-execute → result</text>
|
||||
<text class="small" x="1082" y="268">最终调用 greet handler</text>
|
||||
|
||||
<path class="solid" d="M238 221 H280"/>
|
||||
<path class="solid" d="M468 221 H510"/>
|
||||
<path class="solid" d="M738 221 H780"/>
|
||||
<path class="solid" d="M1008 221 H1050"/>
|
||||
|
||||
<rect class="focus" x="1058" y="374" width="320" height="112"/>
|
||||
<text class="label" x="1082" y="414">greet 工具返回</text>
|
||||
<text class="body" x="1082" y="450">“Hello, Ada!”</text>
|
||||
<path class="return" d="M1218 310 V366"/>
|
||||
|
||||
<rect class="box" x="788" y="374" width="220" height="112"/>
|
||||
<text class="label" x="812" y="414">LLM 继续生成</text>
|
||||
<text class="body" x="812" y="450">把工具结果写成回答</text>
|
||||
<path class="return" d="M1058 430 H1016"/>
|
||||
|
||||
<rect class="box" x="518" y="374" width="220" height="112"/>
|
||||
<text class="label" x="542" y="414">Agent loop 收束</text>
|
||||
<text class="body" x="542" y="450">提交 assistant/message</text>
|
||||
<path class="return" d="M788 430 H746"/>
|
||||
|
||||
<rect class="box" x="288" y="374" width="180" height="112"/>
|
||||
<text class="label" x="312" y="414">用户收到回答</text>
|
||||
<text class="body" x="312" y="450">“已向 Ada 问好”</text>
|
||||
<path class="return" d="M518 430 H476"/>
|
||||
|
||||
<rect class="event" x="140" y="610" width="1160" height="156"/>
|
||||
<text class="label" x="170" y="650">SessionEvent 日志:记录旁路,不是请求的“下一跳”</text>
|
||||
<text class="body" x="170" y="687">用户消息、step/start、模型消息、工具调用、工具结果和最终回答分别追加为 durable facts。</text>
|
||||
<text class="body" x="170" y="719">历史重建、resume、fork、故障修复和 UI 投影都从这些事实派生。</text>
|
||||
<path class="dash" d="M378 274 C378 430 380 520 444 600"/>
|
||||
<path class="dash" d="M1218 486 C1218 540 1130 560 1080 602"/>
|
||||
<path class="dash" d="M628 486 C628 545 650 565 676 602"/>
|
||||
<text class="small" x="66" y="824">记忆锚点:Agent loop 决定“下一步做什么”;Tools 执行“具体动作”;SessionEvent 记录“发生过什么”。</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
@@ -0,0 +1,80 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1440" height="860" viewBox="0 0 1440 860" role="img" aria-labelledby="title desc">
|
||||
<title id="title">DeepSeek Harness 协议边界图</title>
|
||||
<desc id="desc">Web、ACP 和 SDK 从外部驱动 Agent;MCP 把外部工具接入 Tools;Cordis 位于 dsh 的 Node 进程内部,负责组件装配而不是远程通信。</desc>
|
||||
<defs>
|
||||
<style>
|
||||
.bg { fill: #f7f4ec; }
|
||||
.title { font: 700 30px -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif; fill: #183a34; }
|
||||
.subtitle { font: 400 18px -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif; fill: #60706a; }
|
||||
.outside { fill: #fffdf8; stroke: #70817b; stroke-width: 2; rx: 18; }
|
||||
.inside { fill: #edf5f1; stroke: #286458; stroke-width: 2; rx: 18; }
|
||||
.boundary { fill: none; stroke: #286458; stroke-width: 3; stroke-dasharray: 12 8; rx: 26; }
|
||||
.focus { fill: #fff2df; stroke: #ca6715; stroke-width: 2.4; rx: 18; }
|
||||
.label { font: 650 20px -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif; fill: #1f413a; }
|
||||
.body { font: 400 16px -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif; fill: #354c47; }
|
||||
.small { font: 400 15px -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif; fill: #66766f; }
|
||||
.arrow { stroke: #286458; stroke-width: 3; fill: none; marker-end: url(#arrow); }
|
||||
.bi { stroke: #ca6715; stroke-width: 3; fill: none; marker-start: url(#arrow-orange-start); marker-end: url(#arrow-orange); }
|
||||
</style>
|
||||
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L0,6 L9,3 z" fill="#286458"/></marker>
|
||||
<marker id="arrow-orange" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L0,6 L9,3 z" fill="#ca6715"/></marker>
|
||||
<marker id="arrow-orange-start" markerWidth="10" markerHeight="10" refX="1" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M9,0 L9,6 L0,3 z" fill="#ca6715"/></marker>
|
||||
</defs>
|
||||
<rect class="bg" width="1440" height="860" rx="32"/>
|
||||
<text class="title" x="64" y="64">协议边界:谁从哪里接进 Harness</text>
|
||||
<text class="subtitle" x="64" y="98">先看进程边界,再看协议名称;Cordis 位于 dsh 进程内部,不是远程协议。</text>
|
||||
|
||||
<text class="small" x="62" y="150">dsh 进程外:驱动端</text>
|
||||
<rect class="outside" x="60" y="176" width="260" height="116"/>
|
||||
<text class="label" x="86" y="216">浏览器</text>
|
||||
<text class="body" x="86" y="250">产品 UI 和交互</text>
|
||||
<rect class="outside" x="60" y="342" width="260" height="116"/>
|
||||
<text class="label" x="86" y="382">ACP Client</text>
|
||||
<text class="body" x="86" y="416">编辑器或另一个 Agent</text>
|
||||
<rect class="outside" x="60" y="508" width="260" height="116"/>
|
||||
<text class="label" x="86" y="548">Python / TS 程序</text>
|
||||
<text class="body" x="86" y="582">自动化、批量任务、评测器</text>
|
||||
|
||||
<rect class="boundary" x="420" y="132" width="680" height="604"/>
|
||||
<text class="label" x="450" y="170">dsh:TypeScript / Node.js 进程</text>
|
||||
|
||||
<rect class="inside" x="466" y="202" width="250" height="92"/>
|
||||
<text class="label" x="490" y="240">Web adapter</text>
|
||||
<text class="body" x="490" y="268">HTTP POST / WebSocket</text>
|
||||
<rect class="inside" x="466" y="342" width="250" height="92"/>
|
||||
<text class="label" x="490" y="380">ACP adapter</text>
|
||||
<text class="body" x="490" y="408">ACP JSON-RPC over stdio</text>
|
||||
<rect class="inside" x="466" y="482" width="250" height="92"/>
|
||||
<text class="label" x="490" y="520">SDK server</text>
|
||||
<text class="body" x="490" y="548">line JSON-RPC 2.0 over stdio</text>
|
||||
|
||||
<rect class="focus" x="792" y="274" width="250" height="118"/>
|
||||
<text class="label" x="816" y="314">Agent loop</text>
|
||||
<text class="body" x="816" y="346">Web / ACP / SDK</text>
|
||||
<text class="body" x="816" y="370">都从外部驱动整个 Agent</text>
|
||||
<rect class="focus" x="792" y="454" width="250" height="118"/>
|
||||
<text class="label" x="816" y="494">Tools registry</text>
|
||||
<text class="body" x="816" y="526">本地工具与 MCP 工具</text>
|
||||
<text class="body" x="816" y="550">以统一名称注册</text>
|
||||
|
||||
<rect class="inside" x="548" y="634" width="414" height="68"/>
|
||||
<text class="label" x="572" y="676">Cordis:装配并管理以上进程内插件</text>
|
||||
|
||||
<path class="arrow" d="M320 234 H458"/>
|
||||
<path class="arrow" d="M320 400 H458"/>
|
||||
<path class="arrow" d="M320 566 H458"/>
|
||||
<path class="arrow" d="M716 248 C760 248 760 316 784 326"/>
|
||||
<path class="arrow" d="M716 388 H784"/>
|
||||
<path class="arrow" d="M716 528 C760 528 760 364 784 350"/>
|
||||
<path class="arrow" d="M917 392 V446"/>
|
||||
|
||||
<text class="small" x="1146" y="150">dsh 进程外:能力提供端</text>
|
||||
<rect class="outside" x="1140" y="342" width="250" height="146"/>
|
||||
<text class="label" x="1166" y="382">MCP Server</text>
|
||||
<text class="body" x="1166" y="416">stdio 或 Streamable HTTP</text>
|
||||
<text class="small" x="1166" y="450">当前只桥接 Tools</text>
|
||||
<path class="bi" d="M1042 512 C1094 512 1094 420 1132 420"/>
|
||||
|
||||
<rect class="outside" x="120" y="778" width="1200" height="54"/>
|
||||
<text class="body" x="148" y="812">记忆锚点:Web / ACP / SDK 把“请求”送进 Agent;MCP 把“工具”送进 Tools;Cordis 只负责 dsh 进程内的组装与生命周期。</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.3 KiB |
@@ -0,0 +1,93 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1440" height="860" viewBox="0 0 1440 860" role="img" aria-labelledby="title desc">
|
||||
<title id="title">DeepSeek Harness 启动装配图</title>
|
||||
<desc id="desc">Profile、Bundle 和 patch 先形成有效配置,Cordis Loader 再创建插件 Fiber;虚线表示服务依赖,不表示请求调用顺序。</desc>
|
||||
<defs>
|
||||
<style>
|
||||
.bg { fill: #f7f4ec; }
|
||||
.title { font: 700 30px -apple-system, BlinkMacSystemFont, "PingFang SC", "Noto Sans CJK SC", sans-serif; fill: #183a34; }
|
||||
.subtitle { font: 400 18px -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif; fill: #60706a; }
|
||||
.box { fill: #fffdf8; stroke: #286458; stroke-width: 2; rx: 18; }
|
||||
.config { fill: #edf5f1; stroke: #286458; stroke-width: 2; rx: 16; }
|
||||
.focus { fill: #fff2df; stroke: #ca6715; stroke-width: 2.4; rx: 18; }
|
||||
.pending { fill: #fff9e8; stroke: #aa7a12; stroke-width: 2; rx: 18; }
|
||||
.label { font: 650 20px -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif; fill: #1f413a; }
|
||||
.body { font: 400 17px -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif; fill: #354c47; }
|
||||
.small { font: 400 15px -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif; fill: #66766f; }
|
||||
.solid { stroke: #286458; stroke-width: 3; fill: none; marker-end: url(#arrow); }
|
||||
.dash { stroke: #b17220; stroke-width: 2.5; stroke-dasharray: 9 8; fill: none; marker-end: url(#arrow-orange); }
|
||||
.divider { stroke: #cdd8d2; stroke-width: 1.5; }
|
||||
</style>
|
||||
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L0,6 L9,3 z" fill="#286458"/></marker>
|
||||
<marker id="arrow-orange" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L0,6 L9,3 z" fill="#b17220"/></marker>
|
||||
</defs>
|
||||
<rect class="bg" width="1440" height="860" rx="32"/>
|
||||
<text class="title" x="64" y="64">启动装配:谁被创建、谁等待谁</text>
|
||||
<text class="subtitle" x="64" y="98">这是一张依赖和生命周期图,不是一次用户请求的调用顺序。</text>
|
||||
|
||||
<text class="small" x="66" y="143">第一步:多层配置合成最终插件清单</text>
|
||||
<rect class="config" x="64" y="165" width="240" height="102"/>
|
||||
<text class="label" x="88" y="201">Bundle</text>
|
||||
<text class="body" x="88" y="232">可复用的默认插件组合</text>
|
||||
<rect class="config" x="344" y="165" width="240" height="102"/>
|
||||
<text class="label" x="368" y="201">Profile patch</text>
|
||||
<text class="body" x="368" y="232">为某种产品形态做选择</text>
|
||||
<rect class="config" x="624" y="165" width="240" height="102"/>
|
||||
<text class="label" x="648" y="201">Harness home patch</text>
|
||||
<text class="body" x="648" y="232">用户或部署环境覆盖</text>
|
||||
<rect class="config" x="904" y="165" width="210" height="102"/>
|
||||
<text class="label" x="928" y="201">CLI --patch</text>
|
||||
<text class="body" x="928" y="232">本次启动覆盖</text>
|
||||
<rect class="focus" x="1154" y="165" width="222" height="102"/>
|
||||
<text class="label" x="1178" y="201">有效配置行</text>
|
||||
<text class="body" x="1178" y="232">按稳定 id 得到结果</text>
|
||||
<path class="solid" d="M304 216 H336"/>
|
||||
<path class="solid" d="M584 216 H616"/>
|
||||
<path class="solid" d="M864 216 H896"/>
|
||||
<path class="solid" d="M1114 216 H1146"/>
|
||||
<text class="small" x="1065" y="292">后层命中同一 id 时,整段 config 替换,不做深合并</text>
|
||||
|
||||
<line class="divider" x1="64" y1="326" x2="1376" y2="326"/>
|
||||
<text class="small" x="66" y="371">第二步:Loader 为配置行创建 Fiber;Fiber 是否启动由服务依赖决定</text>
|
||||
<path class="solid" d="M1000 364 H1050"/>
|
||||
<text class="small" x="1060" y="370">Loader 创建 Fiber</text>
|
||||
<path class="dash" d="M1212 364 H1262"/>
|
||||
<text class="small" x="1272" y="370">消费者 → 提供方</text>
|
||||
<rect class="focus" x="524" y="394" width="392" height="92"/>
|
||||
<text class="label" x="550" y="430">Root Context + Loader</text>
|
||||
<text class="body" x="550" y="460">读取有效配置,为每一行挂载运行实例 Fiber</text>
|
||||
|
||||
<rect class="box" x="70" y="560" width="245" height="128"/>
|
||||
<text class="label" x="94" y="598">LLM provider Fiber</text>
|
||||
<text class="body" x="94" y="630">提供 ctx.llm</text>
|
||||
<text class="small" x="94" y="660">ACTIVE</text>
|
||||
|
||||
<rect class="box" x="370" y="560" width="245" height="128"/>
|
||||
<text class="label" x="394" y="598">Tools provider Fiber</text>
|
||||
<text class="body" x="394" y="630">提供 ctx.tools</text>
|
||||
<text class="small" x="394" y="660">ACTIVE</text>
|
||||
|
||||
<rect class="pending" x="670" y="560" width="245" height="128"/>
|
||||
<text class="label" x="694" y="598">greet-tool Fiber</text>
|
||||
<text class="body" x="694" y="630">inject: tools</text>
|
||||
<text class="small" x="694" y="660">PENDING → ACTIVE</text>
|
||||
|
||||
<rect class="pending" x="970" y="540" width="330" height="168"/>
|
||||
<text class="label" x="994" y="578">Agent loop Fiber</text>
|
||||
<text class="body" x="994" y="610">inject: agents, sessions,</text>
|
||||
<text class="body" x="994" y="638">llm, tools, systemPrompt</text>
|
||||
<text class="small" x="994" y="674">依赖齐全后才能处理请求</text>
|
||||
|
||||
<path class="solid" d="M650 486 L206 550"/>
|
||||
<path class="solid" d="M690 486 L500 550"/>
|
||||
<path class="solid" d="M750 486 L792 550"/>
|
||||
<path class="solid" d="M810 486 L1110 530"/>
|
||||
<path class="dash" d="M670 624 H625"/>
|
||||
<text class="small" x="628" y="610">等待 tools</text>
|
||||
<path class="dash" d="M970 592 C850 505 350 500 248 551"/>
|
||||
<text class="small" x="625" y="516">等待 llm</text>
|
||||
<path class="dash" d="M970 650 C860 710 694 720 600 676"/>
|
||||
<text class="small" x="735" y="744">等待 tools 等服务</text>
|
||||
|
||||
<rect class="config" x="64" y="770" width="1312" height="58"/>
|
||||
<text class="body" x="88" y="806">记忆锚点:配置行决定“挂载什么”;inject 决定“何时能启动”;Fiber/effect 决定“变化时怎样卸载和重建”。</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.9 KiB |
Reference in New Issue
Block a user