mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
docs(i18n): proofread active Chinese documentation
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
# pnpm run verify-translation-pairing --write docs/user/develop/basic/config.md
|
||||
config.md: 26d2d48ebede74194fbf306aa97d214bdb99b722
|
||||
config.zh.md: 9ed389b16779f25c633d0c8772f8658197ba4322
|
||||
config.zh.md: 1ca727b56b661df315026902d48fbcaf507fe08b
|
||||
|
||||
@@ -75,7 +75,7 @@ Schema 在插件加载时执行校验。如果配置不合法,插件会加载
|
||||
|
||||
### 无硬编码可调参数
|
||||
|
||||
Harness 的约定:**任何两个部署可能想要不同值的东西,都应该是配置字段**。
|
||||
Harness 的约定:**凡是不同部署可能需要采用不同值的参数,都必须定义为配置字段**。
|
||||
|
||||
```ts
|
||||
// Wrong: hardcoded timeout.
|
||||
@@ -110,7 +110,7 @@ export function apply(ctx: Context, config: ModelConfig) {
|
||||
|
||||
## 配合 HMR
|
||||
|
||||
配置变更会触发插件热替换:修改 `cordis.yml` 中某个插件的 `config`,框架会卸载旧实例、加载新实例。由于注册都是效果(自动清理),这个过程是安全的。
|
||||
配置变更会触发插件热替换:修改 `cordis.yml` 中某个插件的 `config` 后,框架会卸载旧实例并加载新实例。由于注册都属于 effect 并会自动清理,替换后不会保留旧实例的注册。
|
||||
|
||||
## 下一步
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
# pnpm run verify-translation-pairing --write docs/user/develop/basic/index.md
|
||||
index.md: 5a9f8dfb8f2d87dfbd2ba30b4d09d002ae9b635c
|
||||
index.zh.md: 08aca87cbc02d1b0dfbe6fe2d92b3f6e87075097
|
||||
index.zh.md: 6f8926aeac5dcf667e4d311505ef7b2a321659c2
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](index.md) | 中文
|
||||
|
||||
本文带你编写一个最小的 Harness 插件并加载到 Agent 中。
|
||||
本文带你编写一个最小的 Harness 插件并加载到 agent(智能体)中。
|
||||
|
||||
## 插件是什么
|
||||
|
||||
@@ -18,7 +18,7 @@ export function apply(ctx: Context) {
|
||||
}
|
||||
```
|
||||
|
||||
就这么简单。
|
||||
这就是完整结构。
|
||||
|
||||
## 创建插件文件
|
||||
|
||||
@@ -48,7 +48,7 @@ export function apply(ctx: Context) {
|
||||
|
||||
## 自动清理
|
||||
|
||||
通过 `ctx` 注册的任何东西——事件监听、tool、定时器——在插件卸载时都会被自动清理。你不需要手动 removeListener 或 clearInterval。
|
||||
通过 `ctx` 注册的任何东西——事件监听、工具、定时器——在插件卸载时都会被自动清理。你不需要手动 removeListener 或 clearInterval。
|
||||
|
||||
如果你有需要手动清理的资源(比如一个网络连接),用 `ctx.effect()` 告诉框架怎么清理:
|
||||
|
||||
@@ -118,11 +118,11 @@ export default class MyService extends Service {
|
||||
}
|
||||
```
|
||||
|
||||
大多数情况下,函数形式足够了。类形式用于需要对外提供服务的插件(见 [服务与依赖](../framework/service.md))。
|
||||
大多数情况下,函数形式足够了。当插件需要向其他插件提供服务时,可使用类形式(见 [服务与依赖](../framework/service.md))。
|
||||
|
||||
## 完整示例
|
||||
|
||||
最小化的工具插件会在 `ctx.tools` 上注册其定义:
|
||||
最小的工具插件会在 `ctx.tools` 上注册其定义:
|
||||
|
||||
```ts
|
||||
import type { Context } from 'cordis'
|
||||
@@ -151,5 +151,5 @@ export function apply(ctx: Context) {
|
||||
|
||||
## 下一步
|
||||
|
||||
- [开发一个 Tool](./tool.md) — 详细了解 tool 定义 DSL
|
||||
- [开发一个工具](./tool.md) — 详细了解工具定义 DSL
|
||||
- [插件配置](./config.md) — 让插件接受用户配置
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
# pnpm run verify-translation-pairing --write docs/user/develop/basic/tool.md
|
||||
tool.md: 0d7cbc3f0b86f88fb67aeff6aa61181dff2912ee
|
||||
tool.zh.md: 30cc871d7b417bdf7f33025b22e3f0965e2b8805
|
||||
tool.zh.md: 37362c510a07fcc32e9eee2b578d82907788e471
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# 开发一个 Tool
|
||||
# 开发一个工具
|
||||
|
||||
[English](tool.md) | 中文
|
||||
|
||||
Tool 是模型可以调用的能力。本文介绍如何用 `defineTool` 编写一个 tool。
|
||||
工具是模型可以调用的能力。本文介绍如何用 `defineTool` 编写一个工具。
|
||||
|
||||
## 最小示例
|
||||
|
||||
@@ -156,9 +156,9 @@ async execute(args) {
|
||||
|
||||
你不需要在 `execute` 里手动校验参数类型。
|
||||
|
||||
## 展示层 (Presentation)
|
||||
## 展示层(Presentation)
|
||||
|
||||
Tool 可以定义与传输方式无关的展示方法,供终端和 Web 客户端使用:
|
||||
工具可以定义与传输方式无关的展示方法,供终端和 Web 客户端使用:
|
||||
|
||||
```ts ignore-check
|
||||
defineTool({
|
||||
@@ -187,7 +187,7 @@ defineTool({
|
||||
|
||||
## 注册与卸载
|
||||
|
||||
`ctx.tools.register()` 返回值就是 disposer。但由于你在 `ctx` 上调用,框架已经自动追踪了这个注册——插件卸载时会自动移除 tool。你不需要手动调用 disposer。
|
||||
`ctx.tools.register()` 返回值就是 disposer。但由于你在 `ctx` 上调用,框架已经自动追踪了这个注册——插件卸载时会自动移除工具。你不需要手动调用 disposer。
|
||||
|
||||
```ts ignore-check
|
||||
// This is sufficient:
|
||||
@@ -196,9 +196,9 @@ ctx.tools.register(defineTool({ /* ... */ }))
|
||||
// No saved disposer or extra cleanup registration is needed.
|
||||
```
|
||||
|
||||
## 完整实战示例
|
||||
## 完整示例
|
||||
|
||||
一个文件计数 tool:
|
||||
一个文件计数工具:
|
||||
|
||||
```ts
|
||||
import type { Context } from 'cordis'
|
||||
@@ -241,5 +241,5 @@ export function apply(ctx: Context) {
|
||||
|
||||
## 下一步
|
||||
|
||||
- [插件配置](./config.md) — 让你的 tool 可配置
|
||||
- [能力三件套](../practice/) — 了解 seam/impl/consumer 模式
|
||||
- [插件配置](./config.md) — 让你的工具可配置
|
||||
- [能力分层](../practice/) — 了解接口/实现/消费方模式
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
# pnpm run verify-translation-pairing --write docs/user/develop/framework/events.md
|
||||
events.md: 5cd5d22f854d0b4e271e892cbdb1ccebe687ae49
|
||||
events.zh.md: 5fd4d5de53897e32523ab478626965ad7c9602ba
|
||||
events.zh.md: 91082694c7546c0b2b77d9fddbd36b14a38a2a8c
|
||||
|
||||
@@ -22,11 +22,11 @@ ctx.emit('event-name', payload)
|
||||
|
||||
## 事件模式
|
||||
|
||||
Cordis 提供多种事件触发模式,适用于不同场景:
|
||||
Cordis 提供多种事件模式,适用于不同的交互契约:
|
||||
|
||||
### emit — 广播
|
||||
|
||||
所有监听器同步执行,不关心返回值:
|
||||
所有监听器同步执行,返回值会被忽略:
|
||||
|
||||
```ts ignore-check
|
||||
// Emit
|
||||
@@ -40,7 +40,7 @@ ctx.on('my-plugin/ready', ({ id }) => {
|
||||
|
||||
### bail — 短路
|
||||
|
||||
依次调用监听器,第一个返回非 `undefined` 值的结果作为最终值:
|
||||
依次调用监听器,第一个非 `undefined` 的返回值将作为最终结果:
|
||||
|
||||
```ts ignore-check
|
||||
// Dispatch
|
||||
@@ -61,7 +61,7 @@ ctx.on('some-check', (input) => {
|
||||
await ctx.serial('setup-phase', context)
|
||||
```
|
||||
|
||||
### waterfall — 管道
|
||||
### waterfall(瀑布式事件)— 流水线
|
||||
|
||||
每个监听器可以包装下游返回值,形成处理链。**必须调用 `next()` 传递给下游**,不调用即为否决:
|
||||
|
||||
@@ -77,10 +77,10 @@ ctx.on('my-plugin/transform', async (_input, next) => {
|
||||
```
|
||||
|
||||
::: warning
|
||||
Waterfall 监听器**必须调用 `next()`**。不调用 `next` 等于否决整个管道,这是故意为之的设计——用于实现拦截/网关逻辑。
|
||||
waterfall 监听器**必须调用 `next()`**。不调用 `next` 等于否决整个流水线,这是故意为之的设计——用于实现拦截/网关逻辑。
|
||||
:::
|
||||
|
||||
## Typed Events
|
||||
## 类型安全的事件
|
||||
|
||||
Harness 使用 TypeScript 声明合并来为事件提供类型安全:
|
||||
|
||||
@@ -101,11 +101,11 @@ declare module 'cordis' {
|
||||
|
||||
## Cordis 事件与会话记录
|
||||
|
||||
Harness 的 Cordis 事件遵循 `namespace/action` 命名,例如 `agent/step`、`agent/request`、`agent/request-error`、`tools/result` 和 `session/event`。完整签名与触发模式见[Events 目录](../../../cordis-catalog/events.md)。
|
||||
Harness 的 Cordis 事件遵循 `namespace/action` 命名,例如 `agent/step`、`agent/request`、`agent/request-error`、`tools/result` 和 `session/event`。生成的[事件目录](../../../cordis-catalog/events.md)记录了完整签名与触发模式。
|
||||
|
||||
`turn/*`、`step/*`、`tool/call`、`tool/result` 和 `compact/*` 是持久化的会话事件类型,不是同名 Cordis 事件。需要观察它们时,监听 `session/event` 并检查 `event.type`。
|
||||
|
||||
## 事件也是效果
|
||||
## 事件监听器也是效果
|
||||
|
||||
通过 `ctx.on()` 注册的监听器会在插件卸载时自动移除:
|
||||
|
||||
@@ -116,9 +116,9 @@ export function apply(ctx: Context) {
|
||||
}
|
||||
```
|
||||
|
||||
## 实战示例:日志插件
|
||||
## 示例:日志插件
|
||||
|
||||
一个记录所有 tool 调用的简单插件:
|
||||
这个插件记录工具调用和工具结果:
|
||||
|
||||
```ts
|
||||
import type { Context } from 'cordis'
|
||||
@@ -139,5 +139,5 @@ export function apply(ctx: Context) {
|
||||
|
||||
## 下一步
|
||||
|
||||
- [能力三件套](../practice/) — 事件在 capability seam 中的角色
|
||||
- [LLM 适配器](../practice/llm-adapter.md) — 实现一个完整的 LLM 后端
|
||||
- [能力分层](../practice/) — 了解能力接口中的事件
|
||||
- [LLM(大语言模型)适配器](../practice/llm-adapter.md) — 实现一个完整的 LLM 后端
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
# pnpm run verify-translation-pairing --write docs/user/develop/framework/index.md
|
||||
index.md: 79e925b54509da41535735527e283850384257ec
|
||||
index.zh.md: 62be8c706510704f7b07286f166f14fa81235a0a
|
||||
index.zh.md: 962677dc468c9cc233a51d50758247e028d9c3ed
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
[English](index.md) | 中文
|
||||
|
||||
深入了解 Cordis 插件模型和生命周期状态机。
|
||||
本页介绍 Cordis 插件模型和生命周期状态机。
|
||||
|
||||
## Fiber 状态机
|
||||
|
||||
每个被加载的插件对应一个 **Fiber**(作用域)。Fiber 有以下状态:
|
||||
每个被加载的插件都拥有一个 **Fiber** 作用域,其状态如下:
|
||||
|
||||
```
|
||||
PENDING → LOADING → ACTIVE
|
||||
@@ -16,16 +16,16 @@ ACTIVE → UNLOADING → DISPOSED
|
||||
|
||||
| 状态 | 含义 |
|
||||
|------|------|
|
||||
| PENDING | 已声明但依赖未就绪 |
|
||||
| PENDING | 已声明,但所需依赖未就绪 |
|
||||
| LOADING | 依赖就绪,正在执行 `apply` |
|
||||
| ACTIVE | 插件运行中 |
|
||||
| FAILED | `apply` 抛出异常 |
|
||||
| UNLOADING | 正在卸载,清理中 |
|
||||
| UNLOADING | 插件正在卸载并释放资源 |
|
||||
| DISPOSED | 已完全卸载 |
|
||||
|
||||
## 依赖驱动的加载
|
||||
|
||||
声明了 `inject` 的插件不会立即加载,而是等待依赖的服务就绪:
|
||||
声明了 `inject` 的插件会等待所有必需服务就绪:
|
||||
|
||||
```ts ignore-check
|
||||
export const inject = ['tools', 'llm']
|
||||
@@ -35,7 +35,7 @@ export function apply(ctx: Context) {
|
||||
}
|
||||
```
|
||||
|
||||
如果依赖的服务消失(比如提供者被热替换),插件会被自动卸载(ACTIVE → DISPOSED),待服务恢复后重新加载。
|
||||
如果依赖的服务消失(例如提供方被替换时),插件会被自动卸载(ACTIVE → DISPOSED),待服务恢复后重新加载。
|
||||
|
||||
## 自动清理机制
|
||||
|
||||
@@ -56,11 +56,11 @@ export function apply(ctx: Context) {
|
||||
|
||||
以下操作都会被自动追踪和清理:
|
||||
- `ctx.on(event, handler)` — 事件监听
|
||||
- `ctx.tools.register(tool)` — tool 注册
|
||||
- `ctx.llm.registerAdapter(names, adapter)` — LLM 适配器注册
|
||||
- `ctx.tools.register(tool)` — 工具注册
|
||||
- `ctx.llm.registerAdapter(names, adapter)` — LLM(大语言模型)适配器注册
|
||||
- `ctx.effect(() => cleanup)` — 自定义资源
|
||||
|
||||
插件卸载时,处置器按注册顺序的反向发起,但多个异步处置器会并发执行,不保证逐个完成。存在顺序依赖的清理步骤必须放进同一个 `ctx.effect()` 返回的处置器中,由该处置器负责串行等待。
|
||||
插件卸载时,处置器按注册顺序的逆序开始调用,但多个异步处置器会并发执行,不保证逐个完成。存在顺序依赖的清理步骤必须放进同一个 `ctx.effect()` 返回的处置器中,由该处置器负责串行等待。
|
||||
|
||||
## 嵌套上下文
|
||||
|
||||
@@ -75,7 +75,7 @@ export function apply(ctx: Context) {
|
||||
}
|
||||
```
|
||||
|
||||
## dispose 语义
|
||||
## dispose(资源释放)语义
|
||||
|
||||
当你需要提前终止一个插件实例:
|
||||
|
||||
@@ -92,21 +92,21 @@ await fiber.dispose()
|
||||
```
|
||||
|
||||
`dispose` 保证:
|
||||
1. 该插件注册的所有东西被撤销
|
||||
1. 该插件拥有的所有注册均被移除
|
||||
2. 它的子插件也被递归卸载
|
||||
3. 所有异步清理完成后 Promise resolve
|
||||
3. 返回的 Promise 会在所有异步清理完成后兑现
|
||||
|
||||
## 热替换 (HMR)
|
||||
## HMR(热模块替换)
|
||||
|
||||
在开发环境中(`cordis.yml` 加载了 `@cordisjs/plugin-hmr`),修改插件源文件会自动触发:
|
||||
通过 `cordis.yml` 加载 `@cordisjs/plugin-hmr` 后,修改插件源文件会触发:
|
||||
|
||||
1. 卸载旧插件(清理所有注册)
|
||||
2. 重新加载新代码
|
||||
3. 执行新的 `apply`
|
||||
|
||||
因为所有注册都会被自动清理,所以热替换天然安全——不会留下旧状态。
|
||||
因为插件注册会被自动清理,所以热替换不会保留旧实例的注册。
|
||||
|
||||
## 实战:理解生命周期
|
||||
## 生命周期示例
|
||||
|
||||
```ts ignore-check
|
||||
export function apply(ctx: Context) {
|
||||
@@ -132,5 +132,5 @@ effect cleaned up
|
||||
|
||||
## 下一步
|
||||
|
||||
- [服务与依赖](./service.md) — 让你的插件对外提供能力
|
||||
- [事件系统](./events.md) — 插件间通信的核心机制
|
||||
- [服务与依赖](./service.md) — 让插件向其他插件提供能力
|
||||
- [事件系统](./events.md) — 在插件之间通信
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
# pnpm run verify-translation-pairing --write docs/user/develop/framework/service.md
|
||||
service.md: 1bf28cb3c7dfdfbd6d0babfa3b1688ac65eea01e
|
||||
service.zh.md: 17785c056ab9a0a21974e6ed8bbe7f7de05fa00e
|
||||
service.zh.md: 78b9887a734b235bcff1d94a623e37cfeb2f41e3
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](service.md) | 中文
|
||||
|
||||
服务 (Service) 是插件对外暴露能力的方式。依赖 (inject) 是插件声明自己需要哪些服务。
|
||||
服务是一个插件向其他插件公开的能力。inject 声明插件需要哪些服务。
|
||||
|
||||
## 什么是服务
|
||||
|
||||
@@ -14,7 +14,7 @@ ctx.llm // LLM service
|
||||
ctx.agents // Agent service
|
||||
```
|
||||
|
||||
任何插件都可以提供一个新服务,供其他插件使用。
|
||||
任何插件都可以提供服务,供其他插件使用。
|
||||
|
||||
## 使用服务
|
||||
|
||||
@@ -52,7 +52,7 @@ export default class MetricsService extends Service {
|
||||
}
|
||||
```
|
||||
|
||||
加载这个插件后,其他插件就可以通过 `ctx.metrics` 访问它:
|
||||
加载这个插件后,消费方就可以通过 `ctx.metrics` 访问它:
|
||||
|
||||
```ts ignore-check
|
||||
export const inject = ['metrics']
|
||||
@@ -86,7 +86,7 @@ export default class MetricsService extends Service {
|
||||
|
||||
## 依赖的行为
|
||||
|
||||
### 必选依赖 vs 可选依赖
|
||||
### 必需依赖与可选依赖
|
||||
|
||||
```ts ignore-check
|
||||
// Required: the plugin does not load while the service is absent.
|
||||
@@ -101,12 +101,12 @@ export function apply(ctx: Context) {
|
||||
|
||||
### 服务消失时的行为
|
||||
|
||||
如果一个必选依赖的服务在运行时消失(比如提供者被卸载):
|
||||
如果应用运行期间某项必需服务消失(例如其提供方卸载):
|
||||
|
||||
1. 依赖它的插件自动 dispose
|
||||
1. 依赖它的插件会自动 dispose(资源释放)
|
||||
2. 当服务重新出现时,插件自动重新加载
|
||||
|
||||
这保证了不会出现"调用一个已不存在的服务"的情况。
|
||||
这可以防止插件调用已不存在的服务。
|
||||
|
||||
## 服务隔离
|
||||
|
||||
@@ -136,13 +136,13 @@ export function apply(ctx: Context) {
|
||||
- name: './src/plugin-b.ts'
|
||||
```
|
||||
|
||||
`plugin-a` 和 `plugin-b` 各自看到自己组内的 bash 实例,互不影响。
|
||||
`plugin-a` 和 `plugin-b` 各自看到自己组内的 Bash 实例,互不影响。
|
||||
|
||||
## Harness 内置服务
|
||||
|
||||
服务名、公开方法和源码位置由仓库自动生成,见[服务目录](../../../cordis-catalog/services.md)。开发插件时应以该目录和服务接口的 TypeScript 类型为准,不要复制一份静态清单。
|
||||
仓库会自动生成[服务目录](../../../cordis-catalog/services.md),其中包含服务名、公开方法和源码位置。开发插件时应以该目录和服务的 TypeScript 接口为准,不要维护另一份静态清单。
|
||||
|
||||
## 下一步
|
||||
|
||||
- [事件系统](./events.md) — 插件间松耦合通信
|
||||
- [能力三件套](../practice/) — 服务在 seam 模式中的应用
|
||||
- [能力分层](../practice/) — 将服务用作能力接口
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
# pnpm run verify-translation-pairing --write docs/user/develop/practice/index.md
|
||||
index.md: e197d499d7f5bd9911ea60bebf584251cd4ed915
|
||||
index.zh.md: 8b8d08f9d0c6d0ca8d95fbaa3281c98b7a600fe4
|
||||
index.zh.md: cacf13e8b23060ea5c309d30e51d732f09c76000
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
[English](index.md) | 中文
|
||||
|
||||
当一个能力(插件)足够通用(比如"执行 bash 命令"),Harness 会把它拆成三个包:**接口**、**实现**、**消费者**。这样可以独立替换其中任何一层。
|
||||
当一项能力足够通用,需要支持可替换的实现时(例如 Bash 执行),Harness 会将其拆成三个包:**接口**、**实现**和**消费方**。这样便可独立替换其中任何一层。
|
||||
|
||||
## 以 Bash 为例
|
||||
|
||||
考虑 "Bash 执行" 这个能力:
|
||||
以 Bash 执行能力为例:
|
||||
|
||||
- **接口** (`dsh-bash`) — 定义"bash 执行"长什么样:输入是什么、输出是什么
|
||||
- **实现** (`dsh-bash-local`) — 真正在本地跑命令的代码
|
||||
- **消费者** (`dsh-tool-bash`) — 把这个能力包装成模型能调用的 tool
|
||||
- **接口** (`dsh-bash`):定义 Bash 请求和结果的结构
|
||||
- **实现** (`dsh-bash-local`):在本地计算机上执行命令
|
||||
- **消费方** (`dsh-tool-bash`):将该能力公开为模型可调用的工具
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌──────────────────┐ ┌──────────────┐
|
||||
@@ -38,23 +38,23 @@
|
||||
# endpoint: 'https://sandbox.example.com'
|
||||
```
|
||||
|
||||
接口不变、tool 不变,只换实现。
|
||||
更换实现时,接口和工具均保持不变。
|
||||
|
||||
### 独立演进
|
||||
|
||||
- 接口定义稳定后很少改动
|
||||
- 实现可以独立优化(性能、安全)
|
||||
- 消费者(tool)可以调整对模型的呈现方式
|
||||
- 消费方可以调整能力向模型呈现的方式。
|
||||
|
||||
### 依赖解耦
|
||||
|
||||
- 实现 depend on 接口
|
||||
- 消费者 depend on 接口
|
||||
- 实现和消费者**互不依赖**
|
||||
- 实现依赖接口。
|
||||
- 消费方依赖接口。
|
||||
- 实现和消费方**互不依赖**。
|
||||
|
||||
## Harness 中内置的三件套
|
||||
|
||||
| 能力 | 接口 (seam) | 实现 | 消费者 (tool) |
|
||||
| 能力 | 接口(seam) | 实现 | 消费方(工具) |
|
||||
|------|-------------|------|---------------|
|
||||
| Bash | `dsh-bash` | `dsh-bash-local` | `dsh-tool-bash` |
|
||||
| 文件系统 | `dsh-fs` | `dsh-fs-local` + `dsh-fs-policy` | `dsh-tool-fs` |
|
||||
@@ -115,7 +115,7 @@ export function apply(ctx: Context) {
|
||||
}
|
||||
```
|
||||
|
||||
### 第三步:编写消费者 (tool)
|
||||
### 第三步:编写消费方
|
||||
|
||||
```ts ignore-check
|
||||
// packages/my-cap/tool-my-cap/src/index.ts
|
||||
@@ -153,10 +153,10 @@ export function apply(ctx: Context) {
|
||||
|
||||
## 设计要点
|
||||
|
||||
- **不要预防性拆分** — 只有当你确实需要可替换实现时才拆三件套。一个简单的 tool 插件不需要拆分。
|
||||
- **接口定义 Request/Result 类型** — 实现和消费者只依赖接口包。
|
||||
- **Explicit > Implicit** — 实现中的默认值处理应该是显式的 `resolve(request): Spec` 步骤,不是隐藏在 `run()` 中的 `?? default`。
|
||||
- **不要预防性拆分**:只有确实需要可替换实现时,才拆分为三个包。简单的工具插件无需拆分。
|
||||
- **接口拥有 Request/Result 类型**:实现和消费方只依赖接口包。
|
||||
- **显式优于隐式**:实现应通过显式的 `resolve(request): Spec` 步骤处理默认值,而不是在 `run()` 中隐藏 `?? default`。
|
||||
|
||||
## 下一步
|
||||
|
||||
- [LLM 适配器](./llm-adapter.md) — 实现一个 LLM 后端(最常见的 seam 扩展)
|
||||
- [LLM 适配器](./llm-adapter.md):实现一个 LLM 后端,这是一种常见的能力 seam 扩展
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/user/develop/practice/llm-adapter.md
|
||||
llm-adapter.md: 7445688530c1ba61e5c065f9f5e49db6498da5b1
|
||||
llm-adapter.zh.md: c30200314a01f7a61d48e3f47288013c31e5aef4
|
||||
llm-adapter.zh.md: e491bc0b6ef633b0b40cb094faf07fc84445c026
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
[English](llm-adapter.md) | 中文
|
||||
|
||||
本文介绍如何为 Harness 接入一个新的 LLM 提供方。
|
||||
本文介绍如何为 Harness 接入新的模型提供方。
|
||||
|
||||
## 概述
|
||||
|
||||
LLM 适配器是一个继承 `LlmAdapter` 的类,实现 `stream()` 方法,将 Harness 的统一请求格式转换为具体 API 的调用。
|
||||
LLM 适配器是一个继承 `LlmAdapter` 并实现 `stream()` 方法的类,它会将 Harness 的提供方无关请求转换为具体提供方的 API 调用,并将响应转换回 Harness 分片。
|
||||
|
||||
## 最小实现
|
||||
|
||||
@@ -51,7 +51,7 @@ export function apply(ctx: Context, config: Config) {
|
||||
|
||||
## StreamChunk 协议
|
||||
|
||||
`stream()` 必须按以下协议 yield chunk:
|
||||
`stream()` 必须按以下协议生成分片:
|
||||
|
||||
```ts
|
||||
import { CallId, type StreamChunk } from '@deepseek-ai/dsh-llm'
|
||||
@@ -102,17 +102,17 @@ async function* exampleChunks(): AsyncIterable<StreamChunk> {
|
||||
|
||||
### 关键规则
|
||||
|
||||
- 每个 `block-start` 必须有对应的 `block-end`
|
||||
- `index` 从 0 递增,标识内容块顺序
|
||||
- `tool-call-delta` 的 `argumentsDelta` 是 JSON 字符串的增量(可以一次 yield 全部,也可以分多次)
|
||||
- `finish` 必须是最后一个 chunk
|
||||
- `usage` 在 `finish` 之前 yield
|
||||
- 每个 `block-start` 都必须有与之对应的 `block-end`。
|
||||
- `index` 从 0 开始递增,用于标识内容块的顺序。
|
||||
- `tool-call-delta` 的 `argumentsDelta` 是原始 JSON 文本的增量,可以在一个分片中完整生成,也可以分多个分片生成。
|
||||
- `finish` 必须是最后一个分片。
|
||||
- `usage` 必须在 `finish` 之前生成。
|
||||
|
||||
## GenerateOptions
|
||||
|
||||
`stream()` 接收仓库导出的 `GenerateOptions`。它包含模型名、由适配器持有的推理强度 ID、对话历史、系统提示词、tool schema、生成参数、停止序列和中止信号;完整字段以 `@deepseek-ai/dsh-llm` 导出的 TypeScript 类型为准。适配器必须将支持的字段映射到具体 API;无法支持的字段应抛出带稳定 code 的 `LlmError`,不能静默丢弃。
|
||||
`stream()` 接收仓库导出的 `GenerateOptions`。它包含模型、适配器拥有的推理强度 ID、对话历史、系统提示词、工具 schema、生成参数、停止序列和中止信号;完整字段以 `@deepseek-ai/dsh-llm` 导出的 TypeScript 类型为准。适配器必须将支持的字段映射到具体 API;如果无法支持某个字段,应抛出带稳定 code 的 `LlmError`,不得静默丢弃。
|
||||
|
||||
请覆写 `resolveModel(provider, model, signal?)`,在一次查询中返回确切的提供方/模型身份以及可选的 `context` 和 `reasoning` 元数据。推理元数据包含有序的不透明 ID、展示名称,以及可选的配置默认值;请保留适配器给出的权威可选列表,包括其上游能力 API 返回的 `off`,而不要将这些值提升为核心枚举。异步查询必须响应这个可选信号,让取消和资源释放都能达到完全停稳。服务会校验聚合结果,并在调用 `stream()` 前拒绝显式指定但不受支持的推理强度;省略 `reasoning` 表示该模型没有可选的推理强度能力。
|
||||
请覆写 `resolveModel(provider, model, signal?)`,在一次查询中返回确切的提供方/模型身份以及可选的 `context` 和 `reasoning` 元数据。推理元数据包含有序的不透明 ID、展示名称,以及可选的配置默认值;请保留适配器给出的权威可选列表,包括其上游能力 API 返回的 `off`,不要将这些值提升为核心枚举。异步查询必须响应该可选信号,使取消和资源释放过程完全停稳。服务会校验聚合结果,并在调用 `stream()` 前拒绝显式指定但不受支持的推理强度;省略 `reasoning` 表示该模型没有可选的推理强度能力。
|
||||
|
||||
## 注册适配器
|
||||
|
||||
@@ -120,7 +120,7 @@ async function* exampleChunks(): AsyncIterable<StreamChunk> {
|
||||
ctx.llm.registerAdapter(['model-name-1', 'model-name-2'], adapter)
|
||||
```
|
||||
|
||||
第一个参数是该适配器支持的模型名列表。当用户在 `cordis.yml` 中配置 `model: model-name-1` 时,框架会路由到这个适配器。
|
||||
第一个参数是该适配器支持的模型名列表。当用户在 `cordis.yml` 中配置 `model: model-name-1` 时,框架会将请求路由到该适配器。
|
||||
|
||||
## 在 cordis.yml 中使用
|
||||
|
||||
@@ -145,7 +145,7 @@ ctx.llm.registerAdapter(['model-name-1', 'model-name-2'], adapter)
|
||||
|
||||
## 实战参考
|
||||
|
||||
仓库中有两个完整实现可供参考:
|
||||
仓库中包含以下两个完整实现:
|
||||
|
||||
- `packages/llm/llm-deepseek/` — DeepSeek API 适配器(OpenAI 兼容格式)
|
||||
- `packages/llm/llm-pi-ai/` — Pi AI 适配器(不同的 API 格式)
|
||||
@@ -154,7 +154,7 @@ ctx.llm.registerAdapter(['model-name-1', 'model-name-2'], adapter)
|
||||
|
||||
## 错误处理
|
||||
|
||||
适配器应将传输和协议故障作为带稳定 code 的 `LlmError` 抛出;agent loop 会保留该错误及其 code,供诊断和策略使用。不要依赖普通 `Error` 被自动转换。每个提供方 HTTP 请求还必须合并 `attributionHeaders()`,并传递 `options.signal`。
|
||||
适配器应通过带稳定 code 的 `LlmError` 抛出传输和协议故障;agent loop(智能体循环)会保留该错误及其 code,用于诊断和策略处理。不要依赖普通 `Error` 被自动转换。每个提供方 HTTP 请求还必须合并 `attributionHeaders()`,并传递 `options.signal`。
|
||||
|
||||
```ts
|
||||
import {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
# pnpm run verify-translation-pairing --write docs/user/index.md
|
||||
index.md: e9a1f03785c7472c47550ec59ea0165d28d3d9a6
|
||||
index.zh.md: 907f1452c9ff50d619989c18dcf2727addb2573d
|
||||
index.zh.md: aba42d79d36e7f5c2e6833f609e48f7b2a79f813
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
layout: home
|
||||
hero:
|
||||
name: DeepSeek Harness
|
||||
text: 插件化 Agent 开发框架
|
||||
text: 插件化 agent(智能体)开发框架
|
||||
tagline: 基于 Cordis 微内核,一切皆插件
|
||||
actions:
|
||||
- theme: brand
|
||||
@@ -15,9 +15,9 @@ features:
|
||||
- title: 插件化架构
|
||||
details: 基于 Cordis 插件系统,所有能力通过插件注册,加载即生效、卸载即还原。
|
||||
- title: 配置即组合
|
||||
details: 一个 cordis.yml 决定整个 Agent 的能力组合——换模型、加工具,只需改一行配置。
|
||||
details: 一个 cordis.yml 决定整个 agent 的能力组合——换模型、加工具,只需改一行配置。
|
||||
- title: 开箱即用
|
||||
details: 内置 LLM 调用、文件读写、Bash 执行、子代理委派等完整工具链,复制模板即可运行。
|
||||
details: 内置 LLM(大语言模型)调用、文件读写、Bash 执行、subagent 委派等完整工具链,复制模板即可运行。
|
||||
---
|
||||
|
||||
# DeepSeek Harness
|
||||
|
||||
Reference in New Issue
Block a user