Skip to content

Commit 43abf0a

Browse files
committed
feat(knowledge): 新增知识库管理及用户旅程端到端测试支持
- 增加test:journey脚本,覆盖知识库跨命令全链路用户旅程测试 - 在文档中新增Journey E2E章节,详细说明用户旅程测试定位及断言机制 - 完善commands模块,新增知识库相关命令包括知识库列表、信息、创建、更新、删除 - 新增知识库文档相关命令,如文档列表、状态、上传、删除、打标签及OSS导入 - 添加知识服务管理命令,支持列表、创建、更新、部署、删除及复制 - 支持知识块增删查改命令,完善知识点的灵活操作能力 - 实现数据中心分类管理命令,支持分类增删查操作 - 优化knowledge chat命令,增加workspace-id统一解析及agent-version版本控制 - 重构与知识库相关命令的导出与注册,完善CLI整体能力覆盖 - 新增命令详尽的帮助文档,包含参数说明、使用示例及错误边界 - 实现批量删除知识块的自动分批处理逻辑,易于操作大规模数据 - 添加必要的输入校验与安全提示,确保操作安全且符合规范
1 parent b1908fa commit 43abf0a

83 files changed

Lines changed: 11207 additions & 139 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/agents/cli-e2e-tests.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
| --------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------------- |
77
| **共享基建** | `packages/e2e` | gating、子进程 runner、output、globalSetup(`private`,不发布) |
88
| **命令 E2E** | `packages/commands/tests/e2e` | help、缺参、dry-run、live(gated);每用例最小路由 |
9+
| **Journey E2E** | `packages/commands/tests/e2e/knowledge/journeys` | 用户旅程全链路(跨命令回路 + 标记词召回闭环),全部 live gated;见 `journeys/README.md` |
910
| **bl smoke** | `packages/cli/tests/e2e/registry.smoke.e2e.test.ts` | 产品 map 全部 path `--help`、分组 help、根 help |
1011
| **kscli smoke** | `packages/kscli/tests/e2e/registry.smoke.e2e.test.ts` |`kscli/src/commands.ts` 推导 path/分组;identity(`--version``search --help` path) |
1112
| **runtime** | `packages/runtime/tests` | `proxy.e2e`、console 跨域 flag 拒绝 |
@@ -27,7 +28,7 @@
2728

2829
### commands E2E
2930

30-
- 路径:`packages/commands/tests/e2e/<kebab-topic>.e2e.test.ts`
31+
- 路径:`packages/commands/tests/e2e/<kebab-topic>.e2e.test.ts`;knowledge 领域集中在 `packages/commands/tests/e2e/knowledge/` 子目录(新增 knowledge 命令测试放这里)
3132
- 子进程:`runCommandE2e(routes, args)` from `./helpers.ts`(spawn `harness/main.ts``routes` 为本 topic 最小 path → export 映射)
3233
- fixtures:`packages/commands/tests/e2e/fixtures/`
3334
- 路由常量:`topic-routes.ts`(按 topic 维护,****全量产品 map)
@@ -78,6 +79,14 @@ describe.skipIf(<ready>)("e2e: <topic>(DashScope …)", () => {
7879
3. **--dry-run**:实现在联网/上传/写盘**之前**返回;断言 stdout JSON/文本
7980
4. **真实集成**:放在 skip 块**末尾**
8081

82+
## Journey 层(用户旅程全链路)
83+
84+
- **定位**:命令 E2E 验单命令契约;journey 验“用户带着目标跨命令走通回路”,结构性断言不在 journey 重复
85+
- **闭环断言**:fixture 埋独特标记词,以“标记词能否被召回”判定回路闭合;硬断言 fail,软断言 `recordSoft` 落报告人工复核
86+
- **日志产物**`createJourneyReporter``test/output/<session>/` 落盘 `journey-report.md`、分步 stdout/stderr、`resources.json`(未清理资源警示)
87+
- **入口**`pnpm run test:journey`;旅程清单与约定见 [journeys/README.md](../../packages/commands/tests/e2e/knowledge/journeys/README.md)
88+
- **新增命令时**:评估是否属于某条旅程的环节,是则纳入对应 journey 并更新 README 映射表
89+
8190
## 增删命令同步
8291

8392
- **commands export** + **topic 路由**`topic-routes.ts` 或测试文件内 `ROUTES`)+ **产品 map**`cli/commands.ts` / `kscli/commands.ts`

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"bl": "pnpm -F bailian-cli dev",
2222
"kscli": "pnpm -F knowledge-studio-cli dev",
2323
"test": "vp test",
24+
"test:journey": "vp test packages/commands/tests/e2e/knowledge/journeys",
2425
"release:check": "node tools/release/check.mjs",
2526
"wiki:crawl": "node tools/wiki-crawler/index.mjs",
2627
"test:stress": "node packages/cli/tests/stress/run.mjs"

packages/cli/doc-commands.md

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# 迭代一设计 · doc 组命令
2+
3+
> 命令:`doc upload` / `doc list` / `doc status` / `doc delete` / `doc tag` / `doc import-oss`
4+
> 公共约定见 [README.md](README.md)
5+
6+
## doc upload — 上传本地文件入库(编排命令)
7+
8+
**说明**:本迭代最复杂命令。把"本地文件 → 数据中心 →(可选)导入知识库"封装为一条命令,替代构建期最高频的控制台操作(S2.2 痛点:高)。对标竞品 add-file。
9+
10+
**编排四步**
11+
12+
|| API | 输入 | 输出 |
13+
| ---------------------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------- | -------------------------------------- |
14+
| 1 申请租约 | `POST /api/v1/connector/dash/applyFileUploadLease` | `category`(类目ID) + `fileName` + `sizeBytes`(字符串!) + `contentMd5`(Base64) | `leaseId` + `param.url/method/headers` |
15+
| 2 OSS 上传 | `PUT {param.url}` | 文件二进制 + `param.headers`(含 `x-bailian-extra``Content-Type`| HTTP 200 |
16+
| 3 注册文件 | `POST /api/v1/connector/dash/addFile` | `leaseId` + `category` + `parser: "AUTO_SELECT"` + `tags?` | `fileId` |
17+
| 4 导入(可选,传 `--index-id` 时) | `POST /api/v1/indices/rag/index/job/create` | `indexId` + `dataSource: { sourceType: "DATA_CENTER_FILE", fileIds }` | `ingestionId` |
18+
19+
坑位(实现注释必须标注):
20+
21+
- `sizeBytes` 必须字符串;`contentMd5` = `crypto.createHash("md5").update(buf).digest("base64")`
22+
- 租约/注册的类目参数名是 `category`,不是 `categoryId`
23+
- 第 4 步 body 是嵌套 `dataSource: { sourceType, fileIds }`(实测;公开文档的平铺 `documentIds` 会报 `Index.InvalidParameter`
24+
- **第 4 步必须显式传 `sourceType`,不传会导入整个数据中心(API 文档明示的默认行为)**
25+
- 步骤 2 走 OSS 域名不走 DashScope 网关,用原生 fetch 而非 ctx.client(无 Bearer 头);失败归类 NETWORK
26+
27+
**Flags**
28+
29+
| flag | 类型 | 必填 | 说明 |
30+
| -------------------------------------------------- | ------ | ---- | --------------------------------------------------------------------------------------------------------------------- |
31+
| `--file <path>` | array || 本地文件路径,可重复;扩展名与大小按产品支持范围预校验(见下方格式白名单) |
32+
| `--index-id <id>` | string || 注册后立即导入该知识库(触发第 4 步,多文件合并为一个 job) |
33+
| `--category-id <id>` | string || 目标类目;缺省自动解析默认类目(listCategory 取 `isDefault: true`),解析失败报 GENERAL + hint 显式传 `--category-id` |
34+
| `--tag <text>` | array || addFile tags,可重复 |
35+
| `--wait` / `--poll-interval <s>` / `--timeout <s>` |||`--index-id` 联用,轮询 job status 至终态 |
36+
37+
**validate**`--wait``--index-id` → USAGE;文件不存在/不可读 → GENERAL + errno hint(沿用错误边界规范)。
38+
39+
**格式白名单与大小预校验**(依据 data/documents.md「支持的格式」,读文件前拦截,避免白传 OSS):
40+
41+
| 类型 | 扩展名 | 硬限(超限 USAGE) |
42+
| ------ | -------------------------- | ----------------------------------------------------- |
43+
| 文档 | .doc .docx .ppt .pptx .pdf | 150 MB |
44+
| 表格 | .xls .xlsx | 10 MB(产品为“建议值”,超限降级为 stderr 警告不拦截) |
45+
| 图片 | .png .jpg .jpeg .bmp .gif | 20 MB(尺寸约束不做客户端校验,留服务端) |
46+
| 纯文本 | .md .txt .html | 10 MB(同表格,警告不拦截) |
47+
48+
- 扩展名不在白名单 → USAGE,错误信息列出支持格式;白名单常量独立导出便于后续随产品更新
49+
- 开放问题:create-kb.md 提及 .csv 但 documents.md 格式表未列——文档口径不一致,实现前向产品确认;确认前 .csv 暂入白名单(服务端拒绝会透传)
50+
51+
**输出**
52+
53+
- text:每文件一行 `<fileName> <fileId> registered`;有导入时追加 `job: <ingestionId>`;--wait 结束追加终态
54+
- json:`{ files: [{path, fileId}], index_id?, ingestion_id?, final_status? }`(编排命令无单一响应可透传,输出自定义稳定结构)
55+
- quiet:仅 fileId 每行一个
56+
57+
**实现方案**
58+
59+
- 文件 `doc-upload.ts`;多文件串行执行 1-3 步(首版不并发,避免 OSS 限流复杂化),全部注册成功后合并执行第 4 步
60+
- 部分失败语义:任一文件步骤 1-3 失败即中止并报错,已成功的 fileId 列入错误 hint(幂等重传代价低)
61+
- 默认类目解析结果进程内缓存(多文件只查一次)
62+
- dry-run:不读文件内容(size/md5 以占位符表示),输出四步编排计划 `{ steps: [{step, endpoint, request}] }`
63+
64+
**测试方案**
65+
66+
- help / 缺 `--file` exitCode 2 / `--wait``--index-id` exitCode 2
67+
- 文件不存在 → 非零退出 + ENOENT hint;`.zip` 扩展名 → USAGE 列出支持格式
68+
- dry-run:断言 steps 长度(带/不带 --index-id 为 4/3)、lease 请求 `sizeBytes` 为字符串类型、job 请求含 `sourceType: "DATA_CENTER_FILE"`
69+
- live:上传 1KB 临时 md 文件 → 断言 fileId 前缀 `file_` → afterAll doc delete + 数据中心 deleteFile 清理
70+
71+
## doc list — 查询知识库文档列表
72+
73+
**说明**:列出库内文档及解析/索引状态,含 FAILED 发现(S2.3 / S5.2)。
74+
75+
**API**`GET /api/v1/indices/rag/index/files`,query string:`index_id` + `page_num`(注意本接口是 page_num)+ `page_size`(默认 10,最大 100)。
76+
77+
**Flags**`--index-id` 必填;`--page-number` / `--page-size`
78+
79+
**输出**
80+
81+
- text:每行 `doc_id status doc_name doc_type size`;status=FAILED 行红色高亮(TTY);尾行 `total: N`
82+
- json 透传;quiet 仅 doc_id
83+
84+
**实现/测试**:单 API 直映射(`doc-list.ts`);dry-run 断言 query 参数名为 `page_num`;live 断言 rows 结构与 doc_id 前缀。
85+
86+
## doc status — 查询导入任务状态
87+
88+
**说明**:查导入任务进度,`--wait` 阻塞至终态供脚本串行(S2.3 痛点:高,L3 验收:FAILED 时非零 exit code)。
89+
90+
**API**`GET /api/v1/indices/rag/index_job/status`,query string:`index_id` + `job_id`**双必填,仅传其一服务端返回 SystemError,客户端前置双校验拦截**)+ 分页参数。
91+
92+
**Flags**
93+
94+
| flag | 必填 | 说明 |
95+
| -------------------------------------------------------------------- | ---- | --------------------------------------------------------------------------------------- |
96+
| `--index-id <id>` || 知识库 ID |
97+
| `--job-id <id>` || 导入任务 ID(kb create / doc upload 返回的 ingestionId;也见 doc list 的 ingestion_id) |
98+
| `--page-number` / `--page-size` || 任务含大量文档时分页 |
99+
| `--wait` / `--poll-interval <s>`(默认 5) / `--timeout <s>`(默认 600) || 轮询至终态 |
100+
101+
**行为**
102+
103+
- 终态 FINISH → exit 0;FAILED → `BailianError(GENERAL)` 透传服务端 message(含文档级失败明细摘要),exit 1
104+
- `--wait` 超时 → TIMEOUT(5)
105+
- 已知行为:库无进行中任务时接口可能返回 SystemError——hint 引导 "check ingestion_id via doc list"
106+
107+
**输出**:text 顶部任务总状态 + 文档级状态列表(FAILED 高亮);json 透传。
108+
109+
**测试方案**:help / 缺任一必填(两条用例)/ dry-run 断言 query 含两个 id / live:配合 upload 用例拿真实 job 轮询到 FINISH;`--wait --timeout 1` 对慢任务断言 exitCode 5(若不稳定则仅静态覆盖超时路径,live 标记 skip 原因)。
110+
111+
## doc delete — 删除文档【危险操作】
112+
113+
**说明**:从知识库删除文档及其全部切片(S5.1 内容更新循环)。
114+
115+
**API**`POST /api/v1/indices/rag/index/delete_file`,body `{ index_id, doc_ids }`(snake_case)。响应 `data.deleted[]` 为实际删除列表。
116+
117+
**Flags**`--index-id` 必填;`--doc-id` array 必填(可重复);`--yes`
118+
119+
**实现方案**`doc-delete.ts`;确认摘要含 index_id + doc_id 列表(≤5 个全列,超出显示前 5 + 总数);输出以 `data.deleted` 为准(与入参数量不一致时 text 模式警告差异)。
120+
121+
**测试方案**:help / 缺参×2 / dry-run 断言 `doc_ids` 数组 / 非 TTY 无 `--yes` exitCode 2 / live 配合 upload 清理链。
122+
123+
## doc tag — 批量更新文档标签
124+
125+
**说明**:批量打标,支撑标签过滤检索(S2.4)。
126+
127+
**API**`POST /api/v1/connector/dash/batchUpdateFileTag``fileInfos`(1-20 项,每项 `fileId` + `tags`,单标签 ≤32 字符、单文件 ≤100 个、总长 ≤700)+ `updateMode`(OVERWRITE/APPEND)。
128+
129+
**Flags**
130+
131+
| flag | 必填 | 说明 |
132+
| --------------- | ---- | ------------------------------------------------------------------------- |
133+
| `--doc-id <id>` || 可重复,1-20 个(客户端预校验),映射 fileInfos[].fileId |
134+
| `--tag <text>` || 可重复,应用到所有 `--doc-id`(首版同一组标签批量打;异构标签用多次调用) |
135+
| `--mode <m>` || choices: `overwrite`/`append`,默认 `append`(追加比覆盖安全,作为缺省) |
136+
137+
**实现/测试**`doc-tag.ts` 单 API 直映射;客户端预校验标签长度约束(USAGE 前置拦截);dry-run 断言 `updateMode: "APPEND"` 大写映射与 fileInfos 结构;live 打标后 listFile/describeFile 验证回读。
138+
139+
## doc import-oss — 从授权 OSS 批量导入
140+
141+
**说明**:从已 SLR 授权的 OSS Bucket 批量导入数据中心(大客户批量场景)。
142+
143+
**API**`POST /api/v1/connector/dash/addFilesFromAuthorizedOss`。必填 `categoryId/categoryType/ossBucket/ossRegionId/fileDetails`(1-10 项,每项 `fileName+ossKey`)。返回 `data.fileIds`
144+
145+
**Flags**
146+
147+
| flag | 必填 | 说明 |
148+
| -------------------- | ---- | -------------------------------------------- |
149+
| `--bucket <name>` || 映射 ossBucket |
150+
| `--region <id>` || 映射 ossRegionId(如 cn-beijing) |
151+
| `--oss-key <key>` || 可重复,1-10 个;fileName 取 key 的 basename |
152+
| `--category-id <id>` || 缺省走默认类目解析(复用 upload 的解析函数) |
153+
| `--tag <text>` || 可重复,≤10 |
154+
| `--overwrite` || switch,映射 overWriteFileByOssKey |
155+
156+
固定值:`categoryType: "UNSTRUCTURED"``parser` 不暴露(默认 AUTO_SELECT,审慎原则——DASH_QWEN_VL_PARSER 等需配 parserConfig,使用方式未验证)。
157+
158+
**错误边界**:SLR 未授权的服务端权限错误原样透传,hint 附 RAM 控制台确认 `AliyunServiceRoleForBailian` 的指引(该指引来自 API 文档 Note,属可权威解释范围)。
159+
160+
**实现/测试**`doc-import-oss.ts` 单 API 直映射;dry-run 断言 fileDetails 结构与 fileName 派生逻辑;live 依赖 OSS 授权环境,gating 追加 `BAILIAN_E2E_OSS_BUCKET` 环境变量,无则 skip。

packages/cli/src/commands.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,37 @@ import {
3333
knowledgeRetrieve,
3434
knowledgeSearch,
3535
knowledgeChat,
36+
knowledgeKbList,
37+
knowledgeKbInfo,
38+
knowledgeDocList,
39+
knowledgeDocStatus,
40+
knowledgeDocUpload,
41+
knowledgeKbCreate,
42+
knowledgeKbUpdate,
43+
knowledgeKbDelete,
44+
knowledgeDocDelete,
45+
knowledgeDocTag,
46+
knowledgeServiceList,
47+
knowledgeServiceGet,
48+
knowledgeServiceCreate,
49+
knowledgeServiceUpdate,
50+
knowledgeServiceDeploy,
51+
knowledgeServiceDelete,
52+
knowledgeServiceCopy,
53+
knowledgeChunkAdd,
54+
knowledgeChunkList,
55+
knowledgeChunkUpdate,
56+
knowledgeChunkDelete,
57+
knowledgeKbStats,
58+
knowledgeCategoryList,
59+
knowledgeCategoryAdd,
60+
knowledgeCategoryDelete,
61+
knowledgeFileList,
62+
knowledgeFileGet,
63+
knowledgeFileDelete,
64+
knowledgeCollectionCreate,
65+
knowledgeCollectionGet,
66+
knowledgeDocImportOss,
3667
mcpCall,
3768
mcpList,
3869
mcpTools,
@@ -151,6 +182,39 @@ export const commands: Record<string, AnyCommand> = {
151182
"knowledge retrieve": knowledgeRetrieve,
152183
"knowledge search": knowledgeSearch,
153184
"knowledge chat": knowledgeChat,
185+
"knowledge list": knowledgeKbList,
186+
"knowledge info": knowledgeKbInfo,
187+
"knowledge create": knowledgeKbCreate,
188+
"knowledge update": knowledgeKbUpdate,
189+
"knowledge delete": knowledgeKbDelete,
190+
"knowledge doc list": knowledgeDocList,
191+
"knowledge doc status": knowledgeDocStatus,
192+
"knowledge doc upload": knowledgeDocUpload,
193+
"knowledge doc delete": knowledgeDocDelete,
194+
"knowledge doc tag": knowledgeDocTag,
195+
"knowledge service list": knowledgeServiceList,
196+
"knowledge service get": knowledgeServiceGet,
197+
"knowledge service create": knowledgeServiceCreate,
198+
"knowledge service update": knowledgeServiceUpdate,
199+
"knowledge service deploy": knowledgeServiceDeploy,
200+
"knowledge service delete": knowledgeServiceDelete,
201+
"knowledge service copy": knowledgeServiceCopy,
202+
"knowledge chunk add": knowledgeChunkAdd,
203+
"knowledge chunk list": knowledgeChunkList,
204+
"knowledge chunk update": knowledgeChunkUpdate,
205+
"knowledge chunk delete": knowledgeChunkDelete,
206+
"knowledge stats": knowledgeKbStats,
207+
"knowledge doc import-oss": knowledgeDocImportOss,
208+
// Data-center commands live under knowledge (no separate connector namespace);
209+
// the user-facing term for connector is "collection".
210+
"knowledge collection create": knowledgeCollectionCreate,
211+
"knowledge collection get": knowledgeCollectionGet,
212+
"knowledge category list": knowledgeCategoryList,
213+
"knowledge category add": knowledgeCategoryAdd,
214+
"knowledge category delete": knowledgeCategoryDelete,
215+
"knowledge file list": knowledgeFileList,
216+
"knowledge file get": knowledgeFileGet,
217+
"knowledge file delete": knowledgeFileDelete,
154218
"mcp call": mcpCall,
155219
"mcp list": mcpList,
156220
"mcp tools": mcpTools,

0 commit comments

Comments
 (0)