Skip to content

Commit 491858b

Browse files
committed
docs(readme): 更新 Bailian KB dsh 插件的文档和添加运行时说明
- 增补详细的 runtime-behavior.md,说明插件的内部运行逻辑和设计取舍 - 完善 packages/bailian-kb-dsh 的 README,添加英文版及使用要求说明 - 细化配置项说明,示例及环境变量配置方式展示 - 增加 LICENSE 文件,明确 Apache 2.0 许可证 - 说明插件安装、配置、和卸载的详细步骤 - 规范 README 和文档多语言版本的同步更新及说明管理 - 说明服务发现、缓存刷新及代理行为的设计和技术细节 - 细化 Web UI 配置页功能介绍和操作指导
1 parent 3f21f55 commit 491858b

5 files changed

Lines changed: 597 additions & 114 deletions

File tree

docs/agents/dsh-plugin.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,19 @@
5757
- [ ] `skills/bailian-kb/` 留在**包内**,不要挪到仓库顶层 `skills/``.github/workflows/publish-skills.yml``skills/**` 全量对账到 OSS registry,`bl skill init` 会装给所有 `bl` 用户,而这个 skill 讲的 `kb_search` / `kb_chat` 原生工具只在 dsh 里存在
5858
- [ ] skill 只有一个手写 `SKILL.md`**不带 `reference/`**:它不是 CLI,没有义务维护一份 `bl` 参数手册。`bl` 命令的 flag 详情交给 `bl <命令> --help`(权威的 `bl` reference 由 `tools/generate-reference.ts` 写到 `skills/bailian-cli/reference/`,与本包无关)。SKILL.md 里写到的 `bl` 命令/flag 修改时手动核对 `packages/commands/src/commands/`,不要锚版本号
5959

60-
### E. 依赖与测试约定
60+
### E. 文档(README 是 npm 主页,双语)
61+
62+
- [ ] 用户可见行为变了(工具参数、配置字段、环境变量、设置页、安装/卸载命令)→ `README.md``README.zh.md` **一起改**;两份互为镜像,头部互链
63+
- [ ] README 只写用户要知道的事;"为什么这么设计"(上下文注入载体、缓存布局、刷新触发点、桥接路由)写进 [../kb-dsh/runtime-behavior.md](../kb-dsh/runtime-behavior.md),不要回流 README
64+
- [ ] 包根保留 `LICENSE`(npm 无条件打包),与 `package.json``license` 一致
65+
66+
### F. 依赖与测试约定
6167

6268
- [ ] `@deepseek-ai/dsh-*` 同时列在 `peerDependencies`(运行时由 dsh 安装闭包提供)和 `devDependencies`(本地类型检查)——升级时两处同步
6369
- [ ] 测试从 `vite-plus/test` 导入(仓库统一约定),不要用 `vitest`
6470
- [ ] 忽略的 catch 绑定与 mock 签名参数用 `_` 前缀(根 `vite.config.ts` 已为本包放开 `no-unused-vars` 的对应 pattern)
6571

66-
### F. 改完跑
72+
### G. 改完跑
6773

6874
```sh
6975
pnpm --filter bailian-kb-dsh run build # tsc 出 dist/ + web 半隔离检查 + tsdown 出 client.js
@@ -114,5 +120,6 @@ node tools/release/publish-kb-dsh.mjs --dry-run --channel dsh-beta
114120
## 相关文档
115121

116122
- 设计与实现计划归档:[docs/kb-dsh/](../kb-dsh/)
117-
- 包内实现说明:[packages/bailian-kb-dsh/README.md](../../packages/bailian-kb-dsh/README.md)
123+
- 运行时行为与设计取舍(内部):[docs/kb-dsh/runtime-behavior.md](../kb-dsh/runtime-behavior.md)
124+
- 用户面说明:[packages/bailian-kb-dsh/README.md](../../packages/bailian-kb-dsh/README.md) / [README.zh.md](../../packages/bailian-kb-dsh/README.zh.md)
118125
- skill 文案与路由约定:[skill-change.md](skill-change.md)

docs/kb-dsh/runtime-behavior.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# bailian-kb-dsh 运行时行为(内部说明)
2+
3+
面向维护者:记录 `packages/bailian-kb-dsh` 里那些**为什么这么做**的选择。用户面文档在 [packages/bailian-kb-dsh/README.md](../../packages/bailian-kb-dsh/README.md)(中文版 `README.zh.md`),改动清单在 [docs/agents/dsh-plugin.md](../agents/dsh-plugin.md)
4+
5+
## Bundle 声明与配置分层
6+
7+
`package.json``dsh.bundle.patch` 指向 `cordis.patch.yml`,向 profile 插入插件行:
8+
9+
```yaml
10+
- insert:
11+
- id: tool-bailian-kb
12+
name: "bailian-kb-dsh"
13+
config:
14+
workspaceId: !!js process.env.BAILIAN_WORKSPACE_ID
15+
```
16+
17+
`workspaceId` 只是解析链的一层,不是唯一来源:Config 同时注册为 `bailian-kb` settings namespace,patch entry 作 base 层,设置页 / 设置文档的用户层叠在其上;都未设置时 per-call 回退到 `BAILIAN_WORKSPACE_ID` credential。同样的回退覆盖 `defaultRetrieveAgentId`(`BAILIAN_DEFAULT_RETRIEVE_AGENT_ID`)、`defaultChatAgentId`(`BAILIAN_DEFAULT_CHAT_AGENT_ID`)与 API key(`DASHSCOPE_API_KEY`,无 settings 面)。
18+
19+
settings 注册是**手写**的,没有用 `installSettingsSection`:需要两个它不带的东西 —— `expose` opt-in(设置页从浏览器改这个 section)和凭据迁移要写入的 scope handle。所有值每次调用经 source thunk 读取,因此设置改动无需重启或重注册工具。
20+
21+
### 四个值的解析链
22+
23+
| 值 | 1️⃣ settings 用户层(设置页可编辑、回显) | 2️⃣ entry config(patch 或用户覆盖,作 base 层) | 3️⃣ credential(`~/.dsh/.credentials.yaml` / env) | 4️⃣ 都缺失时 |
24+
| ----------------------------------- | ---------------------------------------- | ----------------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------- |
25+
| `DASHSCOPE_API_KEY` | —(无 settings 面) | —(无 config 面) | ✅ | 工具调用报错并引导配置 |
26+
| `BAILIAN_WORKSPACE_ID` | ✅ `workspaceId` | ✅ `workspaceId` | ✅ | 工具调用报错并引导配置 |
27+
| `BAILIAN_DEFAULT_RETRIEVE_AGENT_ID` | ✅ `defaultRetrieveAgentId` | ✅ `defaultRetrieveAgentId` | ✅ | 该 scene 只有一个已部署服务时取它;否则省略 `agent_id` 的调用报错 |
28+
| `BAILIAN_DEFAULT_CHAT_AGENT_ID` | ✅ `defaultChatAgentId` | ✅ `defaultChatAgentId` | ✅ | 同上 |
29+
30+
"唯一服务即默认"这一层是 2C 部署的零配置路径:只有一个服务时没有可选项,逼用户在设置里点一次名字买不到任何东西。注意 `agent_id` 在两个工具的 schema 中**恒必填**,模型路径不会触发默认服务回退;回退保留是为程序化调用与 credential 热切换。
31+
32+
行为参数(`endpointHost` / `agentVersion` / `chatTimeoutMs`)只在 config/settings 层(设置文档可改,实时生效)。
33+
34+
解析后的 workspaceId 还经 `shellEnv` 注册导出为 `BAILIAN_WORKSPACE_ID`,否则 settings 文档里的值对 bash 子进程(`bl knowledge …`)不可见。
35+
36+
### 用户覆盖
37+
38+
用户 patch 层在本 bundle 之上,按 id 覆盖时**替换整个 config(无 deep-merge)**:
39+
40+
```yaml
41+
# ~/.dsh/cordis.patch.yml 或 profile 的 cordis.patch.yml
42+
- id: tool-bailian-kb
43+
config:
44+
defaultRetrieveAgentId: aid-search-service
45+
defaultChatAgentId: aid-chat-service
46+
chatTimeoutMs: 600000
47+
```
48+
49+
禁用:`- id: tool-bailian-kb` + `disabled: true`。
50+
51+
## Web UI 配置页
52+
53+
装进 profile 后,Settings 左侧导航出现"百炼知识库"页(`settings.section` 槽位):
54+
55+
- **DashScope API Key** — write-only,`type=password` 遮罩输入草稿,仅显示 configured / 来自环境变量 徽标;写 `~/.dsh/.credentials.yaml`
56+
- **Bailian Workspace ID / 默认检索服务 ID / 默认对话服务 ID** — 回显:读写 `bailian-kb` settings 用户层,预填当前解析值;清空保存 = 移除用户层,回退 entry config → credential。两个服务 ID 可从服务缓存里选
57+
- **自动获取** — 按钮调 Host 桥接路由 `/bailian-kb/autofill`:Host 在宿主机拉起浏览器登录百炼控制台(不经 `bl` 命令),回调落到本机 loopback 端口后直接把 API 密钥写入凭据存储、工作空间 ID 写入 settings,明文 key 不过浏览器;面板轮询到完成后自动刷新(无需再次点击)。登录 URL 始终请求签发新 key,因此每次都与当前账号配对,切换账号直接点一次即可
58+
- **检索服务缓存** — 经 `/bailian-kb/services` 读缓存诊断(上次拉取时间、各 scene 条数、是否截断)并提供强制刷新按钮:面板存在的意义就是"开发者认为缓存不对"的那一刻
59+
60+
桥接路由(`/bailian-kb/settings`、`/bailian-kb/services`、`/bailian-kb/autofill`)而不是 settings wire:wire 需要 apiproxy 白名单,而 composition 不给树外 namespace 授权。GET 和 POST 共用一次 exact-route 注册 —— webServer map 按 (kind, path) 建键,同路径注册两次会抛 "duplicate route"。
61+
62+
首次接入 seed:启动时若 API key / workspaceId 从未被设置过(settings、credential、env 均无值),自动从 `~/.bailian/config.json` 采纳一次;`seededFields` 字段(settings 文档内,面板不可编辑)记账已消费 / 已由用户管理的字段,用户主动清空的值永不会被重新填回。
63+
64+
降级:远程浏览器(非 loopback,settings RPC 不可达)或未组合 settings 服务时,ID 字段退回旧的 write-only credential 控件,页面顶部显示提示。
65+
66+
## 检索服务缓存与上下文注入
67+
68+
模型要判断"该不该检索",靠的是看到本 workspace 部署了哪些检索服务。插件内部经 `/api/v1/indices/rag/app/list` 拉取该清单并缓存,**不对模型暴露服务发现工具**(`kb_service_list` 不会回归:它会把"先 list 再 search"的额外一轮重新引入);管理面仍用 bl。
69+
70+
### 载体:上下文消息,不是工具描述
71+
72+
两个工具的 **description 保持静态**(不含任何服务 id)。清单经 `agent/pre-step` 注入为一条带 source 的 `UserMessage`(`{ kind: 'plugin', plugin: 'tool-bailian-kb/services', form: 'catalog' }`),而不是烘进 tool description。两个原因:
73+
74+
1. **插件加载是每进程一次,不是每会话一次。** 描述在 `apply()` 时定型,长驻宿主里 TTL 只会被评估一次,用户在控制台新建的服务要等重启才能被感知;
75+
2. **重注册工具会废掉 prompt 前缀缓存**(从第一个变化的 schema token 起)。走上下文消息则让 schema 永久稳定。
76+
77+
**变化抑制是正确性要求,不是优化**:`pre-step` 每个"步"(= 一次模型请求)触发一次,一轮里调 5 次工具就触发 6 次。只有清单内容变化时才重发,且判定叠加**可见性**(`session.surface.nodes`)—— 压缩把清单消息裁掉后会自动重新注入,否则模型会静默失去清单。
78+
79+
### 清单内容策略
80+
81+
| 情形 | 注入内容 |
82+
| ------------------------ | ----------------------------------------------------- |
83+
| 配了默认服务 | 只列该服务 + "另有 N 个" 提示 |
84+
| 未配默认,deployed ≤ 10 | 全量 `agent_id` + 名称 |
85+
| 未配默认,deployed > 10 | 按 `modify_time` 倒序取 10 条,**显式标明截断**与总数 |
86+
| 0 个 / 拉取失败 / 无缓存 | 不注入(工具仍可用) |
87+
88+
英文框架 + 服务名原样保留;空 scene 整节省略;截断必须告知(静默截断会让模型把清单当全集,进而断言"没有对应知识库")。
89+
90+
### 缓存与刷新
91+
92+
落点:`${DSH_HOME:-~/.dsh}/cache/bailian-kb/services-<workspaceId>.json`(临时文件 + `rename()` 原子发布,目录 `0o700`)。按 workspace 分文件是必需的:api key 只能访问自己的 workspace,而"自动获取"按钮就是为了切账号。
93+
94+
存:`agent_id` / `agent_name` / `scene` / `status` / `modify_time`,预留 `description`(待列表接口返回)。**不存 `pipeline_list`** —— 它不稳定携带 `pipeline_name`,做不了知识库标签。
95+
96+
| 刷新触发点 | 模型何时看见 |
97+
| ---------------------------------------------------------------------------------- | ------------------------------------ |
98+
| pre-step 间隔调度(超 TTL 30 分钟,后台异步,**不阻塞**) | 下一步 |
99+
| 控制台登录成功(`/bailian-kb/autofill` 回调) | 下一步 |
100+
| agent 跑了 `bl knowledge service create/deploy/delete/copy`(`tools/result` 观察) | 下一步 |
101+
| 面板强制刷新(`POST /bailian-kb/services`) | 下一步 |
102+
| 调用撞 4xx(agent_id 已失效) | **本步**,刷新后的列表追加进错误消息 |
103+
| workspaceId / apiKey 变更 | 下一步 |
104+
105+
`tools/result` 的匹配是在序列化参数里找命令串,而不是认某个具体工具名:agent 可能用 bash、终端工具或 run_code 跑 `bl`。宽匹配是故意的 —— 误判只多花一次 list 请求,漏判则退回 TTL。
106+
107+
刷新失败只 warn,保留旧文档;并发刷新共享一个请求(pre-step 每步都会检查)。pre-step 监听器**永不抛异常** —— 抛出会使用户当前这一步失败。未组合 `agents` 的 headless 装配只是没有清单,工具照常可用。
108+
109+
## 错误语义
110+
111+
- HTTP 错误:4xx 时刷新服务缓存并把当前可用服务追加进错误消息(这两个接口上 `agent_id` 是唯一的调用方标识符,所以 4xx 大多是 id 已失效);5xx 与刷新本身失败则原错误透传;
112+
- 凭证缺失:指向 `~/.dsh/.env` / `.credentials.yaml` 配置方式与控制台取 key 页面;
113+
- chat 超时:说明服务端多轮检索特性,建议重试或改用 `kb_search`;
114+
- 服务端错误体截断至 500 字符进入错误信息(优先 `code: message`)。
115+
116+
## 管理面 skill
117+
118+
`skills/bailian-kb/SKILL.md` 随包分发,插件通过 `ctx.inject(['skills'])` 在 skills 服务可用时以 `source: 'bundled'` 运行时注册;无 skills 服务的组合(headless 最小装配)不受影响。文件的 YAML frontmatter 是 name / description 的**单一事实源**,注册时会被剥离(`SkillDefinition.content` 契约上是已去元数据的正文,而 runtime 注册路径不做任何解析)。
119+
120+
内容:bl CLI 安装 / 鉴权 / workspace 解析、建库 → 上传 → 部署工作流、服务清单的行为语义。**skill 不承担"该不该检索"的引导**(那是工具描述与上下文清单的事:skill 正文要模型先决定加载才能读到,是二阶决策);它反过来承担一件工具做不到的事:**引导 agent 在 `service create` 时把服务名写清楚**。无 desc 时服务名是唯一语义来源,管理面的动作直接决定检索面的效果。
121+
122+
## 已知限制的成因
123+
124+
- kb_chat 执行期无进展显示(缓冲式消费 SSE)。
125+
- `top_k` 是客户端截断:请求体不含该参数,服务端返回条数由检索服务配置决定,截断只影响进入模型上下文的量。
126+
- **服务画像的质量上限取决于服务名**:`service list` 接口当前不返回描述字段,所以模型只能靠 `agent_name` 判断一个服务能查什么。名字模糊的部署引导能力接近于零。列表接口补齐描述字段后只需改三处(`api-types` 补字段名 → `services.ts` 解析 → `buildServiceCatalog` 追加并截断到 200 字符),缓存已预留 `description` 键,无需迁移。
127+
- 拉取每个 scene 最多 2 页,超出时标 `truncated` 并在清单里告知。

0 commit comments

Comments
 (0)