diff --git a/commands/lyxy-kb/ask.md b/commands/lyxy-kb/ask.md new file mode 100644 index 0000000..61ce4b1 --- /dev/null +++ b/commands/lyxy-kb/ask.md @@ -0,0 +1,55 @@ +基于知识库项目进行问答。 + +**输入**: `/lyxy-kb-ask` 后的参数为项目名称,可选附带问题。例如: +- `/lyxy-kb-ask my-project` — 进入问答模式 +- `/lyxy-kb-ask my-project 这个系统用了什么技术栈?` — 直接提问 + +**前置条件**: 查找并阅读名为 **lyxy-kb** 的 skill,了解渐进式查询策略和来源引用格式。 + +**步骤** + +1. **获取项目名称并验证结构** + + 从参数中获取项目名称。如果未提供参数,提示用户输入。 + + 按照 lyxy-kb skill「结构完整性验证」规则检查项目目录,不完整则提示用户先 init。 + +2. **加载项目摘要** + + 读取 `/project.md`,获取项目概述和文件索引。 + + 按照 lyxy-kb skill「空知识库」规则,如果文件索引为空(尚无已入库文件),告知用户知识库为空,建议先使用 `/lyxy-kb-ingest ` 入库文档,终止操作。 + +3. **进入问答模式** + + 如果用户在参数中附带了问题,直接回答该问题。否则提示用户可以开始提问。 + + **对每个问题,按照 lyxy-kb skill「渐进式查询策略」执行**: + + **a) 分析问题与文件索引的关联** + + 根据用户的问题内容,对照 project.md 文件索引表中各文件的摘要,判断需要查阅哪些 parsed 文件。 + + **b) 按需加载 parsed 文件** + + 读取相关的 `/parsed/<文件名>.md` 文件。如果文件较大,可以先提取标题结构,再读取相关章节。 + + **c) 回答并标注来源** + + 基于获取的信息回答问题。按照 lyxy-kb skill「来源引用格式」标注来源: + + ``` + 根据《文件名》(parsed/文件名.md),... + ``` + + 如果回答综合了多个文件的信息,分别标注各信息点的来源。 + + **d) 无相关信息处理** + + 按照 lyxy-kb skill「无相关信息」规则,明确告知用户当前知识库中未找到相关信息,不编造答案。 + +4. **保持会话上下文** + + 回答完成后,保持当前的知识库上下文。用户可以继续提问,无需每次重新加载 project.md。已加载的 parsed 文件内容可在后续问答中复用。 + + 会话的退出由用户自然决定(开启新话题或新会话),不主动终止问答模式。 diff --git a/commands/lyxy-kb/ingest.md b/commands/lyxy-kb/ingest.md new file mode 100644 index 0000000..46e38f5 --- /dev/null +++ b/commands/lyxy-kb/ingest.md @@ -0,0 +1,65 @@ +解析 sources/ 中的新文件并增量更新知识库。 + +**输入**: `/lyxy-kb-ingest` 后的参数为项目名称。 + +**前置条件**: 查找并阅读名为 **lyxy-kb** 的 skill,了解知识库的完整规范。 + +**步骤** + +1. **获取项目名称并验证结构** + + 从参数中获取项目名称。如果未提供参数,提示用户输入。 + + 按照 lyxy-kb skill「结构完整性验证」规则检查项目目录,不完整则提示用户先 init。 + +2. **检查 office 文档解析能力** + + 按照 lyxy-kb skill「Office 文档解析」规则,查找当前环境中名为 **lyxy-reader-office** 的 skill。如果不存在且无其他可替代的文档解析 skill,则提示用户无法处理 office 文档并中止流程。 + +3. **读取 manifest.json** + + 读取 `/manifest.json`,获取已入库文件的信息。 + +4. **递归扫描 sources/ 目录** + + 按照 lyxy-kb skill「sources/ 扫描规则」,递归检查 sources/ 及其所有子目录中的文件。如果无任何文件,提示用户无待处理文件并终止。 + +5. **预检查** + + **空文件检测**:按照 lyxy-kb skill「空文件处理」规则,识别 0 字节文件,标记为跳过。 + + **同名不同扩展名冲突检测**:按照 lyxy-kb skill「同名不同扩展名冲突检测」中的两条检测规则执行。冲突文件标记为跳过。 + + 如果有跳过的文件,列出详情(空文件 / 冲突文件分别列出)。如果所有文件都被跳过,终止流程。 + +6. **逐个处理文件** + + 对每个通过预检查的文件: + + **a) 解析**:按照 lyxy-kb skill「文件类型解析策略」判断解析方式。office 文档使用 lyxy-reader-office skill(查找并阅读该 skill 获取具体命令),其他文件直接读取。 + + **b) 写入 parsed**:按照 lyxy-kb skill「parsed 文件元信息标记」格式,在内容头部添加元信息注释,写入 `/parsed/<文件名>.md`(同名覆盖)。 + + **c) 归档**:按照 lyxy-kb skill「归档命名规则」,移动原始文件到 archive/(带时间戳后缀 `YYYYMMDDHHmm`)。 + + **d) 更新 manifest.json**:新文件追加条目,已有文件在 versions 数组追加新版本。使用 `sha256sum` 计算文件哈希。更新 `last_ingest`。 + + **e) 解析失败处理**:按照 lyxy-kb skill「解析失败处理」规则,失败文件保留在 sources/ 中不移动,报告错误,继续处理下一个文件。 + +7. **增量更新 project.md** + + 按照 lyxy-kb skill「增量追加」策略: + - 对每个新处理的文件,读取其 parsed 内容生成简要摘要(1-2 句话) + - 新文件:在文件索引表追加新行 + - 已有文件更新:更新文件索引表中对应行 + - 在更新记录追加本次 ingest 条目 + - 不修改概述和关键信息部分 + +8. **输出结果** + + 汇总显示: + - 成功处理的文件列表 + - 跳过的文件(空文件 / 冲突文件 / 解析失败文件,分别列出) + - 当前项目已入库文件总数 + - 提示可使用 `/lyxy-kb-rebuild ` 更新概述和关键信息 + - 提示可使用 `/lyxy-kb-ask ` 进行知识问答 diff --git a/commands/lyxy-kb/init.md b/commands/lyxy-kb/init.md new file mode 100644 index 0000000..8d5d474 --- /dev/null +++ b/commands/lyxy-kb/init.md @@ -0,0 +1,67 @@ +初始化一个知识库项目。 + +**输入**: `/lyxy-kb-init` 后的参数为项目名称。 + +**前置条件**: 查找并阅读名为 **lyxy-kb** 的 skill,了解知识库的目录结构规范、项目名称规则和 project.md 格式规范。 + +**步骤** + +1. **获取项目名称** + + 从参数中获取项目名称。如果未提供参数,提示用户输入项目名称。 + +2. **验证项目名称** + + 按照 lyxy-kb skill 中的「项目名称规则」验证名称是否合法(只允许中文、英文、数字、短横线、下划线,不允许空格和其他特殊字符)。不合法时提示用户修改。 + +3. **检查目标目录是否已存在** + + 检查 CWD 下是否已存在同名目录。如果目录已存在,提示用户该目录已存在,不覆盖任何现有内容,终止操作。 + +4. **创建目录结构** + + ```bash + mkdir -p /parsed /sources /archive + ``` + +5. **创建 project.md** + + 按照 lyxy-kb skill 中定义的「project.md 格式规范」,生成初始内容: + + ```markdown + # <项目名称> + + ## 概述 + + (待补充) + + ## 关键信息 + + (待补充) + + ## 文件索引 + + | 文件名 | 解析文件 | 最新归档 | 摘要 | + |--------|----------|----------|------| + + ## 更新记录 + - : 初始化项目 + ``` + +6. **创建 manifest.json** + + ```json + { + "project": "<项目名称>", + "created_at": "<当前时间 ISO 格式>", + "last_ingest": null, + "files": [] + } + ``` + +7. **输出结果** + + 提示用户: + - 项目已创建,显示完整的目录结构 + - 引导用户将文档放入 `/sources/` 目录 + - 提示使用 `/lyxy-kb-ingest ` 解析入库 diff --git a/commands/lyxy-kb/rebuild.md b/commands/lyxy-kb/rebuild.md new file mode 100644 index 0000000..b8aba8b --- /dev/null +++ b/commands/lyxy-kb/rebuild.md @@ -0,0 +1,55 @@ +全量重新生成 project.md。 + +**输入**: `/lyxy-kb-rebuild` 后的参数为项目名称。 + +**前置条件**: 查找并阅读名为 **lyxy-kb** 的 skill,了解 project.md 格式规范和全量重写策略。 + +**步骤** + +1. **获取项目名称并验证结构** + + 从参数中获取项目名称。如果未提供参数,提示用户输入。 + + 按照 lyxy-kb skill「结构完整性验证」规则检查项目目录,不完整则提示用户先 init。 + +2. **检查 parsed 目录** + + 列出 `/parsed/` 下的所有 `.md` 文件。如果为空,提示用户尚无已解析文件,建议先执行 `/lyxy-kb-ingest `。 + +3. **检查 sources/ 待处理文件** + + 检查 `/sources/` 中是否还有未 ingest 的文件。如果有,提醒用户 sources/ 中存在未入库文件,rebuild 将仅基于已有的 parsed 文件生成,建议先执行 ingest。 + +4. **确认操作** + + 向用户说明 rebuild 将覆盖当前 project.md 的概述、关键信息和文件索引(更新记录会保留),请求用户确认是否继续。用户确认后再执行。 + +5. **读取所有 parsed 文件** + + 逐个读取 `/parsed/` 下的所有 `.md` 文件内容。 + +6. **读取 manifest.json** + + 读取 `/manifest.json`,获取文件元信息(用于生成文件索引表中的归档路径等信息)。 + +7. **读取现有更新记录** + + 读取当前 `/project.md`,提取 `## 更新记录` 部分的内容以保留历史记录。 + +8. **全量重新生成 project.md** + + 按照 lyxy-kb skill「全量重写」策略和 project.md 格式规范,基于所有 parsed 文件内容重新生成: + + - **概述**:基于所有文件内容,生成高度总结的项目信息(几百字以内) + - **关键信息**:从所有文档中提炼核心要点 + - **文件索引**:基于 manifest.json 和 parsed 文件,重新生成完整索引表(文件名、解析文件路径、最新归档路径、简要摘要) + - **更新记录**:保留历史记录,追加本次 rebuild 条目,格式:`- : 全量重建 project.md` + + 将生成的内容写入 `/project.md`,覆盖原有内容。 + +9. **输出结果** + + 提示用户: + - project.md 已全量重建 + - 显示处理的文件数量 + - 提示可使用 `/lyxy-kb-ask ` 进行知识问答 diff --git a/openspec/changes/archive/2026-02-19-add-lyxy-kb/.openspec.yaml b/openspec/changes/archive/2026-02-19-add-lyxy-kb/.openspec.yaml new file mode 100644 index 0000000..e3dce8f --- /dev/null +++ b/openspec/changes/archive/2026-02-19-add-lyxy-kb/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-02-18 diff --git a/openspec/changes/archive/2026-02-19-add-lyxy-kb/design.md b/openspec/changes/archive/2026-02-19-add-lyxy-kb/design.md new file mode 100644 index 0000000..3af55a9 --- /dev/null +++ b/openspec/changes/archive/2026-02-19-add-lyxy-kb/design.md @@ -0,0 +1,176 @@ +## Context + +当前项目已有 `lyxy-reader-office` skill(解析 docx/pdf/pptx/xlsx 为 markdown)和 `lyxy-runner-python` skill(uv 执行 Python 脚本)。需要在此基础上新增知识库管理能力,让用户能将项目文档组织为可被大模型高效检索和问答的知识库。 + +核心约束: +- Skill 和 Command 分离:skill 定义底层规范和能力,command 定义用户交互流程 +- 纯文件驱动:不依赖数据库或向量存储,所有数据以文件形式存在 +- 渐进式查询:优先读摘要索引,按需加载详细内容,节省 token + +## Goals / Non-Goals + +**Goals:** + +- 提供完整的文档入库流程:放入文件 → 解析 → 归档 → 生成摘要 +- 支持增量更新和全量重建两种 project.md 维护模式 +- 基于知识库进行多轮问答,回答时标注文件来源 +- 复用已有 lyxy-reader-office 解析 office 文档 +- 支持任意纯文本文件直接入库 + +**Non-Goals:** + +- 不做向量化或语义搜索 +- 不做跨项目知识关联 +- 不做文档版本对比或 diff +- 不做权限控制或多用户协作 +- 不做 Web UI 或可视化界面 + +## Decisions + +### 1. 目录结构:CWD 即知识库根目录 + +每个知识项目是 CWD 下的一个子目录,内含固定结构: + +``` +CWD/ +└── / + ├── project.md # 高度摘要 + 文件索引 + ├── manifest.json # 增量追踪 + ├── parsed/ # 解析后的 markdown + ├── sources/ # 待处理区 + └── archive/ # 原始文件备份 +``` + +**为什么不加 `knowledge/` 外层目录**:CWD 本身就是用户选定的知识库工作目录,额外嵌套层没有意义。用户可以在任意位置 `mkdir my-kb && cd my-kb` 然后使用 commands。 + +### 2. 文档生命周期:sources → parsed + archive + +文件流转: +1. 用户将文档放入 `sources/` +2. ingest 解析文件,生成 `parsed/<文件名>.md` +3. 原始文件移入 `archive/<文件名_YYYYMMDDHHmm>.`(每个版本都带时间戳) +4. 同名文件覆盖 parsed 中的旧版本,archive 中保留所有历史版本 + +**为什么 archive 全部带时间戳**:统一规则,无需判断"是否已有同名文件"。每次入库都是一个带时间戳的快照。 + +**同名不同扩展名冲突处理**:如 `技术方案.pdf` 和 `技术方案.docx` 同时存在于 sources/,因为 parsed 产物都会命名为 `技术方案.md`,产生冲突。此时拒绝处理并提示用户重命名。 + +### 3. 增量追踪:manifest.json + +```json +{ + "project": "my-project", + "created_at": "2026-02-18T16:00", + "last_ingest": "2026-02-18T17:25", + "files": [ + { + "name": "需求文档", + "ext": ".docx", + "parsed": "parsed/需求文档.md", + "versions": [ + { + "archived": "archive/需求文档_202602181600.docx", + "hash": "sha256:abc123...", + "ingested_at": "2026-02-18T16:00" + } + ] + } + ] +} +``` + +manifest 用于: +- 检测 sources/ 中哪些文件是新文件 +- 检测同名不同扩展名冲突(对比 files 中已有的 name 和 ext) +- 记录版本历史,关联 parsed 和 archive 文件 + +### 4. project.md 格式与更新策略 + +project.md 结构: + +```markdown +# <项目名称> + +## 概述 +(高度总结的项目信息) + +## 关键信息 +(从所有文档中提炼的核心要点) + +## 文件索引 + +| 文件名 | 解析文件 | 最新归档 | 摘要 | +|--------|----------|----------|------| +| 需求文档 | parsed/需求文档.md | archive/需求文档_202602181600.docx | 简要摘要... | + +## 更新记录 +- 2026-02-18 16:00: 解析 需求文档.docx +``` + +**默认增量追加**(`lyxy-kb-ingest`): +- 新文件:在文件索引表追加新行,在更新记录追加条目 +- 概述和关键信息部分**不**自动更新 + +**全量重写**(`lyxy-kb-rebuild`): +- 读取所有 parsed/*.md,重新生成整个 project.md +- 概述、关键信息、文件索引全部重新生成 + +### 5. 解析后 markdown 的元信息标记 + +每个 parsed 文件头部包含元信息注释: + +```markdown + + + + +# 技术方案 +(文档正文内容...) +``` + +用于问答时标注来源。 + +### 6. 文件类型解析策略 + +| 文件类型 | 解析方式 | +|----------|----------| +| .docx, .pdf, .pptx, .xlsx | lyxy-reader-office(通过 lyxy-runner-python 执行) | +| .md, .txt, .csv, .json, .xml, .yaml/.yml, .log, .html 等 | 直接读取文件内容 | + +判断逻辑:先检查是否为 office 文档扩展名,是则调用 lyxy-reader-office;否则视为纯文本直接读取。 + +### 7. 渐进式查询策略(ask 模式) + +``` +① 读取 project.md → 获取整体概述和文件索引 +② 根据用户问题判断需要哪些 parsed 文件 +③ 读取相关 parsed 文件(可能只需部分章节) +④ 回答问题,标注来源格式:「根据《文件名》(parsed/文件名.md),...」 +⑤ 保持会话上下文,用户可继续追问 +``` + +### 8. Skill 与 Command 的职责划分 + +**Skill(`skills/lyxy-kb/SKILL.md`)**: +- 定义知识库目录结构规范 +- 定义 project.md 格式规范 +- 定义 manifest.json 结构 +- 定义解析规则和文件类型映射 +- 定义渐进式查询策略 +- 定义来源引用格式 + +**Commands(`commands/lyxy-kb/`)**: +- `init.md`:创建项目目录和初始文件的交互流程 +- `ingest.md`:触发解析、展示进度、增量更新 project.md 的交互流程 +- `rebuild.md`:全量重写 project.md 的交互流程 +- `ask.md`:进入会话问答模式的交互流程 + +## Risks / Trade-offs + +**[project.md 增量追加导致概述过时]** → 用户可通过 `lyxy-kb-rebuild` 全量重写来更新概述。增量模式优先保证 token 效率,trade-off 是概述不会自动融入新文件的信息。 + +**[大量文件时 rebuild 的 token 消耗]** → 如果 parsed 文件总量很大,全量重写时需要读取所有文件。目前无特殊缓解措施,依赖大模型上下文窗口限制自然约束项目规模。 + +**[parsed 文件名冲突]** → 同名不同扩展名直接拒绝,要求用户重命名。简单但可能偶尔不便。 + +**[纯文本文件的摘要质量]** → CSV、JSON 等结构化数据直接读取后,摘要可能不如 office 文档自然。大模型需要自行判断如何提取关键信息。 diff --git a/openspec/changes/archive/2026-02-19-add-lyxy-kb/proposal.md b/openspec/changes/archive/2026-02-19-add-lyxy-kb/proposal.md new file mode 100644 index 0000000..89493bf --- /dev/null +++ b/openspec/changes/archive/2026-02-19-add-lyxy-kb/proposal.md @@ -0,0 +1,31 @@ +## Why + +在使用大模型辅助工作时,经常需要基于一组项目相关文档(需求文档、技术方案、数据表等)进行问答和分析。目前缺乏一种轻量的、基于文件的方式来组织这些文档,让大模型能够高效地读取、总结和检索。需要一套 skill + command 来实现个人知识库的初始化、文档解析入库、渐进式问答。 + +## What Changes + +- 新增 `lyxy-kb` skill,定义知识库的目录结构规范、文档生命周期、解析规则、渐进式查询策略等底层能力 +- 新增 `lyxy-kb-init` command,引导用户创建知识项目目录结构 +- 新增 `lyxy-kb-ingest` command,解析 sources/ 中的新文件,增量更新 project.md +- 新增 `lyxy-kb-rebuild` command,全量重新生成 project.md +- 新增 `lyxy-kb-ask` command,进入会话式问答模式,基于项目知识渐进式查询回答问题并标注来源 +- 复用已有的 `lyxy-reader-office` skill 解析 office 文档,纯文本类文件直接读取 + +## Capabilities + +### New Capabilities + +- `kb-project-management`:知识项目的初始化与目录结构管理,包括 project.md、parsed/、sources/、archive/ 的创建和维护 +- `kb-document-ingestion`:文档解析入库流程,包括文件类型识别、调用解析器、生成 parsed markdown、归档原始文件(带时间戳)、增量追踪(manifest.json)、同名冲突检测 +- `kb-knowledge-query`:基于知识库的渐进式问答能力,包括读取 project.md 摘要索引、按需加载 parsed 文件、回答时标注文件来源 +- `kb-project-summary`:project.md 的生成与维护策略,包括增量追加(默认)和全量重写两种模式 + +### Modified Capabilities + +无。 + +## Impact + +- **新增文件**:`skills/lyxy-kb/SKILL.md`、`commands/lyxy-kb/` 下 4 个 command 文件(init.md、ingest.md、rebuild.md、ask.md) +- **依赖**:运行时依赖 `lyxy-reader-office` skill 解析 office 文档,依赖 `lyxy-runner-python` skill 执行 Python 脚本 +- **用户侧影响**:用户在任意项目目录下即可使用 command 创建和管理知识库项目,CWD 即为知识库根目录 diff --git a/openspec/changes/archive/2026-02-19-add-lyxy-kb/specs/kb-document-ingestion/spec.md b/openspec/changes/archive/2026-02-19-add-lyxy-kb/specs/kb-document-ingestion/spec.md new file mode 100644 index 0000000..a55c6d3 --- /dev/null +++ b/openspec/changes/archive/2026-02-19-add-lyxy-kb/specs/kb-document-ingestion/spec.md @@ -0,0 +1,71 @@ +## ADDED Requirements + +### Requirement: 扫描并识别待处理文件 +系统 SHALL 扫描项目 `sources/` 目录下的所有文件,并根据扩展名判断解析方式: +- Office 文档(.docx、.pdf、.pptx、.xlsx):调用 lyxy-reader-office skill 解析 +- 其他文件(.md、.txt、.csv、.json、.xml、.yaml、.yml、.log、.html 等):直接读取内容 + +#### Scenario: sources 中有 office 文档 +- **WHEN** sources/ 中存在 `报告.docx` +- **THEN** 系统 SHALL 使用 lyxy-reader-office skill(通过 lyxy-runner-python 执行)将其解析为 markdown + +#### Scenario: sources 中有纯文本文件 +- **WHEN** sources/ 中存在 `config.json` +- **THEN** 系统 SHALL 直接读取文件内容作为 parsed 产物 + +#### Scenario: sources 目录为空 +- **WHEN** sources/ 中没有任何文件 +- **THEN** 系统 SHALL 提示用户 sources/ 中无待处理文件 + +### Requirement: 同名不同扩展名冲突检测 +系统 SHALL 在解析前检测 sources/ 中是否存在同名但不同扩展名的文件(如 `技术方案.pdf` 和 `技术方案.docx`),因为 parsed 产物都会命名为相同的 `.md` 文件。同时也需检测 sources/ 中的文件名是否与 manifest.json 中已有记录的不同扩展名文件冲突。 + +#### Scenario: sources 中存在同名不同扩展名文件 +- **WHEN** sources/ 中同时存在 `技术方案.pdf` 和 `技术方案.docx` +- **THEN** 系统 SHALL 拒绝处理这两个文件,并提示用户重命名其中一个以消除冲突 + +#### Scenario: sources 中文件与已入库文件同名但不同扩展名 +- **WHEN** manifest.json 中已有 `技术方案`(ext: `.pdf`)的记录,且 sources/ 中出现 `技术方案.docx` +- **THEN** 系统 SHALL 拒绝处理该文件,并提示用户重命名 + +### Requirement: 生成 parsed markdown 文件 +系统 SHALL 将解析后的内容写入 `parsed/<文件名>.md`,文件头部 MUST 包含元信息注释: +``` + + + +``` +若 parsed/ 中已存在同名文件(同一文档的更新版本),SHALL 覆盖旧文件。 + +#### Scenario: 首次解析文件 +- **WHEN** 解析 `需求文档.docx`,parsed/ 中不存在 `需求文档.md` +- **THEN** 系统创建 `parsed/需求文档.md`,头部包含 source、archived、parsed_at 元信息,正文为解析后的 markdown 内容 + +#### Scenario: 更新已有文件 +- **WHEN** 解析 `技术方案.pdf`,parsed/ 中已存在 `技术方案.md`(上一版本) +- **THEN** 系统覆盖 `parsed/技术方案.md`,元信息更新为最新版本的 archive 路径和时间 + +### Requirement: 归档原始文件 +系统 SHALL 将已解析的原始文件从 `sources/` 移动到 `archive/`,文件名格式为 `<文件名_YYYYMMDDHHmm>.<扩展名>`。每个进入 archive 的文件都 MUST 带有时间戳后缀,即使该文件只有一个版本。 + +#### Scenario: 归档文件 +- **WHEN** `需求文档.docx` 解析完成,当前时间为 2026-02-18 16:00 +- **THEN** 原始文件移动为 `archive/需求文档_202602181600.docx` + +#### Scenario: 同名文件多次入库 +- **WHEN** `技术方案.pdf` 第二次入库,archive 中已有 `技术方案_202602181600.pdf` +- **THEN** 新版本归档为 `技术方案_202602181725.pdf`(以当前时间为时间戳),两个版本并存于 archive + +### Requirement: 更新 manifest.json +系统 SHALL 在每个文件处理完成后更新 manifest.json: +- 新文件:在 files 数组中追加新条目,包含 name、ext、parsed 路径,versions 数组包含首个版本的 archived 路径、hash 和 ingested_at +- 已有文件更新:在对应条目的 versions 数组中追加新版本记录 +- last_ingest 时间戳 SHALL 更新为当前 ingest 的时间 + +#### Scenario: 新文件入库更新 manifest +- **WHEN** `需求文档.docx` 首次解析完成 +- **THEN** manifest.json 的 files 数组中追加 `{"name": "需求文档", "ext": ".docx", "parsed": "parsed/需求文档.md", "versions": [{"archived": "archive/需求文档_202602181600.docx", "hash": "sha256:...", "ingested_at": "2026-02-18T16:00"}]}` + +#### Scenario: 已有文件更新 manifest +- **WHEN** `技术方案.pdf` 第二次入库 +- **THEN** manifest.json 中该文件条目的 versions 数组追加新版本记录,不删除旧版本记录 diff --git a/openspec/changes/archive/2026-02-19-add-lyxy-kb/specs/kb-knowledge-query/spec.md b/openspec/changes/archive/2026-02-19-add-lyxy-kb/specs/kb-knowledge-query/spec.md new file mode 100644 index 0000000..d637444 --- /dev/null +++ b/openspec/changes/archive/2026-02-19-add-lyxy-kb/specs/kb-knowledge-query/spec.md @@ -0,0 +1,38 @@ +## ADDED Requirements + +### Requirement: 渐进式查询策略 +系统 SHALL 采用渐进式查询策略回答用户问题,以节省 token 消耗: +1. 首先读取 project.md 获取整体概述和文件索引 +2. 根据用户问题和文件索引判断需要查阅哪些 parsed 文件 +3. 按需读取相关 parsed 文件的全部或部分内容 +4. 基于获取的信息回答问题 + +#### Scenario: 问题可通过摘要回答 +- **WHEN** 用户提问"这个项目主要做什么?",且 project.md 的概述中已包含足够信息 +- **THEN** 系统仅基于 project.md 内容回答,不加载 parsed 文件 + +#### Scenario: 问题需要查阅具体文件 +- **WHEN** 用户提问"系统的权限控制是怎么设计的?",且 project.md 文件索引中 `需求文档` 的摘要提到了权限相关内容 +- **THEN** 系统读取 `parsed/需求文档.md` 获取详细信息后回答 + +### Requirement: 来源标注 +系统在回答中引用具体信息时 SHALL 标注文件来源,格式为:「根据《文件名》(parsed/文件名.md),...」。来源标注 MUST 指向 parsed 目录下的具体文件。 + +#### Scenario: 回答中包含来源标注 +- **WHEN** 系统从 `parsed/技术方案.md` 中获取信息来回答问题 +- **THEN** 回答中 SHALL 包含类似「根据《技术方案》(parsed/技术方案.md),系统采用微服务架构...」的来源标注 + +#### Scenario: 回答综合多个文件 +- **WHEN** 回答需要综合 `parsed/需求文档.md` 和 `parsed/技术方案.md` 的信息 +- **THEN** 回答中 SHALL 分别标注各信息点的来源文件 + +### Requirement: 会话问答模式 +系统 SHALL 在 ask 模式下保持会话上下文,用户可以连续提问而无需每次重新加载知识库。会话的退出由用户自然决定(开启新话题或新会话),系统不主动终止会话。 + +#### Scenario: 多轮追问 +- **WHEN** 用户先问"系统用了什么技术栈?",接着追问"数据库选型的理由是什么?" +- **THEN** 系统在第二次回答时保持之前的上下文,可复用已加载的 parsed 文件内容 + +#### Scenario: 知识库中无相关信息 +- **WHEN** 用户提出的问题在 project.md 和所有 parsed 文件中均无相关信息 +- **THEN** 系统 SHALL 明确告知用户当前知识库中未找到相关信息,而非编造答案 diff --git a/openspec/changes/archive/2026-02-19-add-lyxy-kb/specs/kb-project-management/spec.md b/openspec/changes/archive/2026-02-19-add-lyxy-kb/specs/kb-project-management/spec.md new file mode 100644 index 0000000..af52cb7 --- /dev/null +++ b/openspec/changes/archive/2026-02-19-add-lyxy-kb/specs/kb-project-management/spec.md @@ -0,0 +1,24 @@ +## ADDED Requirements + +### Requirement: 初始化知识项目目录结构 +系统 SHALL 在 CWD 下创建以指定名称命名的子目录,并在其中生成以下固定结构: +- `project.md`:初始内容包含项目名称标题、空的概述/关键信息段落、空的文件索引表和空的更新记录 +- `manifest.json`:初始内容包含项目名称、创建时间、空的 files 数组 +- `parsed/` 目录 +- `sources/` 目录 +- `archive/` 目录 + +#### Scenario: 成功初始化新项目 +- **WHEN** 用户执行 `/lyxy-kb-init my-project`,且 CWD 下不存在 `my-project` 目录 +- **THEN** 系统创建 `my-project/` 目录及完整子结构(project.md、manifest.json、parsed/、sources/、archive/),并提示用户将文档放入 sources/ 目录 + +#### Scenario: 目标目录已存在 +- **WHEN** 用户执行 `/lyxy-kb-init my-project`,且 CWD 下已存在 `my-project` 目录 +- **THEN** 系统 SHALL 提示用户该目录已存在,不覆盖任何现有内容 + +### Requirement: 项目目录结构规范 +知识项目 SHALL 遵循固定的目录结构:`project.md`、`manifest.json`、`parsed/`、`sources/`、`archive/`。所有 command 和 skill 操作 SHALL 基于此结构进行,不在结构外创建额外文件或目录。 + +#### Scenario: 验证项目结构完整性 +- **WHEN** 任何 command(ingest/rebuild/ask)在指定项目目录上执行 +- **THEN** 系统 SHALL 先检查目录结构是否完整(包含 project.md、manifest.json、parsed/、sources/、archive/),若不完整则提示用户先执行 init diff --git a/openspec/changes/archive/2026-02-19-add-lyxy-kb/specs/kb-project-summary/spec.md b/openspec/changes/archive/2026-02-19-add-lyxy-kb/specs/kb-project-summary/spec.md new file mode 100644 index 0000000..a1e5abf --- /dev/null +++ b/openspec/changes/archive/2026-02-19-add-lyxy-kb/specs/kb-project-summary/spec.md @@ -0,0 +1,53 @@ +## ADDED Requirements + +### Requirement: project.md 格式规范 +project.md SHALL 遵循以下固定结构: + +```markdown +# <项目名称> + +## 概述 +(高度总结的项目信息) + +## 关键信息 +(从所有文档中提炼的核心要点) + +## 文件索引 + +| 文件名 | 解析文件 | 最新归档 | 摘要 | +|--------|----------|----------|------| + +## 更新记录 +``` + +初始化时概述和关键信息为空,文件索引表为空表头,更新记录为空。 + +#### Scenario: 初始化后的 project.md +- **WHEN** 执行 `/lyxy-kb-init my-project` +- **THEN** 生成的 project.md 包含 `# my-project` 标题、空的概述/关键信息段落、空的文件索引表(仅表头)和空的更新记录 + +### Requirement: 增量追加模式 +执行 ingest 时,系统 SHALL 以增量方式更新 project.md: +- 在文件索引表中追加新解析文件的行(文件名、parsed 路径、最新 archive 路径、该文件的简要摘要) +- 在更新记录中追加本次 ingest 的条目(时间和处理的文件列表) +- 已有文件更新时:覆盖文件索引表中对应行的最新归档路径和摘要 +- 概述和关键信息部分 SHALL NOT 在增量模式下自动更新 + +#### Scenario: 首次 ingest 追加索引 +- **WHEN** 首次 ingest 解析了 `需求文档.docx` +- **THEN** project.md 文件索引表中追加一行,更新记录中追加 `- 2026-02-18 16:00: 解析 需求文档.docx` + +#### Scenario: 已有文件更新时追加索引 +- **WHEN** `技术方案.pdf` 第二次入库 +- **THEN** project.md 文件索引表中该文件的最新归档路径和摘要被更新,更新记录追加新条目 + +### Requirement: 全量重写模式 +执行 rebuild 时,系统 SHALL 读取所有 `parsed/*.md` 文件,重新生成整个 project.md: +- 概述:基于所有 parsed 文件内容重新生成高度总结 +- 关键信息:重新提炼核心要点 +- 文件索引:基于 manifest.json 和 parsed 文件重新生成完整索引表 +- 更新记录:保留历史记录,追加本次 rebuild 条目 + +#### Scenario: 全量重写 +- **WHEN** 用户执行 `/lyxy-kb-rebuild my-project`,项目中有 3 个 parsed 文件 +- **THEN** 系统读取所有 3 个 parsed 文件,重新生成 project.md 的概述、关键信息和文件索引,更新记录追加 rebuild 条目 diff --git a/openspec/changes/archive/2026-02-19-add-lyxy-kb/tasks.md b/openspec/changes/archive/2026-02-19-add-lyxy-kb/tasks.md new file mode 100644 index 0000000..83ae9e4 --- /dev/null +++ b/openspec/changes/archive/2026-02-19-add-lyxy-kb/tasks.md @@ -0,0 +1,26 @@ +## 1. Skill 基础 + +- [x] 1.1 创建 `skills/lyxy-kb/` 目录 +- [x] 1.2 编写 `skills/lyxy-kb/SKILL.md`,定义知识库底层规范,包括:目录结构规范(project.md、manifest.json、parsed/、sources/、archive/)、project.md 格式规范(标题/概述/关键信息/文件索引表/更新记录)、manifest.json 结构定义、文件类型解析策略(office 文档用 lyxy-reader-office,其他纯文本直接读取)、parsed 文件元信息标记格式、渐进式查询策略、来源引用格式、同名不同扩展名冲突检测规则 + +## 2. Command: lyxy-kb-init + +- [x] 2.1 创建 `commands/lyxy-kb/` 目录 +- [x] 2.2 编写 `commands/lyxy-kb/init.md`,实现初始化交互流程:接收项目名称参数,检查目标目录是否已存在(已存在则提示不覆盖),在 CWD 下创建项目子目录及完整结构(project.md、manifest.json、parsed/、sources/、archive/),project.md 按规范格式生成初始内容(空概述/关键信息/文件索引/更新记录),manifest.json 初始化为含项目名和创建时间的空结构 + +## 3. Command: lyxy-kb-ingest + +- [x] 3.1 编写 `commands/lyxy-kb/ingest.md`,实现增量解析入库交互流程,包括以下步骤: + - 接收项目名称参数,验证项目目录结构完整性 + - 读取 manifest.json,扫描 sources/ 下所有文件 + - 执行同名不同扩展名冲突检测(sources/ 内部互相检测 + 与 manifest 已有记录检测) + - 对每个无冲突的文件:根据扩展名判断解析方式(office → lyxy-reader-office,其他 → 直接读取),生成 parsed markdown(含头部元信息注释),移动原始文件到 archive(带时间戳后缀),更新 manifest.json + - 增量更新 project.md:在文件索引表追加/更新行,在更新记录追加条目,不修改概述和关键信息 + +## 4. Command: lyxy-kb-rebuild + +- [x] 4.1 编写 `commands/lyxy-kb/rebuild.md`,实现全量重写交互流程:接收项目名称参数,验证项目目录结构完整性,读取所有 parsed/*.md 文件,基于全部内容重新生成 project.md(概述、关键信息、文件索引表全部重写),保留历史更新记录并追加本次 rebuild 条目 + +## 5. Command: lyxy-kb-ask + +- [x] 5.1 编写 `commands/lyxy-kb/ask.md`,实现会话问答交互流程:接收项目名称参数,验证项目目录结构完整性,指导大模型执行渐进式查询策略(先读 project.md 摘要索引 → 按需加载 parsed 文件 → 回答并标注来源),进入持续会话模式(用户可连续追问),知识库无相关信息时明确告知 diff --git a/openspec/config.yaml b/openspec/config.yaml index 2cfb3ef..39f6c46 100644 --- a/openspec/config.yaml +++ b/openspec/config.yaml @@ -1,7 +1,7 @@ schema: spec-driven context: | - 忽略项目目录下的「.opencode」和「opencode」两个目录,与开发的skill无关; + 忽略项目目录下的「.opencode」、「opencode」、「.claude」、「.codex」这几个目录,与开发的skill无关; 这个项目是专门用于开发用于大模型工具的 skill; 所有开发的 skill 都放在「skills」目录下,每个子目录都代表一个 skill,目录名为 skill 的名称; 开发过程中的文档使用中文,面向中文开发者进行交流; diff --git a/openspec/specs/kb-document-ingestion/spec.md b/openspec/specs/kb-document-ingestion/spec.md new file mode 100644 index 0000000..a55c6d3 --- /dev/null +++ b/openspec/specs/kb-document-ingestion/spec.md @@ -0,0 +1,71 @@ +## ADDED Requirements + +### Requirement: 扫描并识别待处理文件 +系统 SHALL 扫描项目 `sources/` 目录下的所有文件,并根据扩展名判断解析方式: +- Office 文档(.docx、.pdf、.pptx、.xlsx):调用 lyxy-reader-office skill 解析 +- 其他文件(.md、.txt、.csv、.json、.xml、.yaml、.yml、.log、.html 等):直接读取内容 + +#### Scenario: sources 中有 office 文档 +- **WHEN** sources/ 中存在 `报告.docx` +- **THEN** 系统 SHALL 使用 lyxy-reader-office skill(通过 lyxy-runner-python 执行)将其解析为 markdown + +#### Scenario: sources 中有纯文本文件 +- **WHEN** sources/ 中存在 `config.json` +- **THEN** 系统 SHALL 直接读取文件内容作为 parsed 产物 + +#### Scenario: sources 目录为空 +- **WHEN** sources/ 中没有任何文件 +- **THEN** 系统 SHALL 提示用户 sources/ 中无待处理文件 + +### Requirement: 同名不同扩展名冲突检测 +系统 SHALL 在解析前检测 sources/ 中是否存在同名但不同扩展名的文件(如 `技术方案.pdf` 和 `技术方案.docx`),因为 parsed 产物都会命名为相同的 `.md` 文件。同时也需检测 sources/ 中的文件名是否与 manifest.json 中已有记录的不同扩展名文件冲突。 + +#### Scenario: sources 中存在同名不同扩展名文件 +- **WHEN** sources/ 中同时存在 `技术方案.pdf` 和 `技术方案.docx` +- **THEN** 系统 SHALL 拒绝处理这两个文件,并提示用户重命名其中一个以消除冲突 + +#### Scenario: sources 中文件与已入库文件同名但不同扩展名 +- **WHEN** manifest.json 中已有 `技术方案`(ext: `.pdf`)的记录,且 sources/ 中出现 `技术方案.docx` +- **THEN** 系统 SHALL 拒绝处理该文件,并提示用户重命名 + +### Requirement: 生成 parsed markdown 文件 +系统 SHALL 将解析后的内容写入 `parsed/<文件名>.md`,文件头部 MUST 包含元信息注释: +``` + + + +``` +若 parsed/ 中已存在同名文件(同一文档的更新版本),SHALL 覆盖旧文件。 + +#### Scenario: 首次解析文件 +- **WHEN** 解析 `需求文档.docx`,parsed/ 中不存在 `需求文档.md` +- **THEN** 系统创建 `parsed/需求文档.md`,头部包含 source、archived、parsed_at 元信息,正文为解析后的 markdown 内容 + +#### Scenario: 更新已有文件 +- **WHEN** 解析 `技术方案.pdf`,parsed/ 中已存在 `技术方案.md`(上一版本) +- **THEN** 系统覆盖 `parsed/技术方案.md`,元信息更新为最新版本的 archive 路径和时间 + +### Requirement: 归档原始文件 +系统 SHALL 将已解析的原始文件从 `sources/` 移动到 `archive/`,文件名格式为 `<文件名_YYYYMMDDHHmm>.<扩展名>`。每个进入 archive 的文件都 MUST 带有时间戳后缀,即使该文件只有一个版本。 + +#### Scenario: 归档文件 +- **WHEN** `需求文档.docx` 解析完成,当前时间为 2026-02-18 16:00 +- **THEN** 原始文件移动为 `archive/需求文档_202602181600.docx` + +#### Scenario: 同名文件多次入库 +- **WHEN** `技术方案.pdf` 第二次入库,archive 中已有 `技术方案_202602181600.pdf` +- **THEN** 新版本归档为 `技术方案_202602181725.pdf`(以当前时间为时间戳),两个版本并存于 archive + +### Requirement: 更新 manifest.json +系统 SHALL 在每个文件处理完成后更新 manifest.json: +- 新文件:在 files 数组中追加新条目,包含 name、ext、parsed 路径,versions 数组包含首个版本的 archived 路径、hash 和 ingested_at +- 已有文件更新:在对应条目的 versions 数组中追加新版本记录 +- last_ingest 时间戳 SHALL 更新为当前 ingest 的时间 + +#### Scenario: 新文件入库更新 manifest +- **WHEN** `需求文档.docx` 首次解析完成 +- **THEN** manifest.json 的 files 数组中追加 `{"name": "需求文档", "ext": ".docx", "parsed": "parsed/需求文档.md", "versions": [{"archived": "archive/需求文档_202602181600.docx", "hash": "sha256:...", "ingested_at": "2026-02-18T16:00"}]}` + +#### Scenario: 已有文件更新 manifest +- **WHEN** `技术方案.pdf` 第二次入库 +- **THEN** manifest.json 中该文件条目的 versions 数组追加新版本记录,不删除旧版本记录 diff --git a/openspec/specs/kb-knowledge-query/spec.md b/openspec/specs/kb-knowledge-query/spec.md new file mode 100644 index 0000000..d637444 --- /dev/null +++ b/openspec/specs/kb-knowledge-query/spec.md @@ -0,0 +1,38 @@ +## ADDED Requirements + +### Requirement: 渐进式查询策略 +系统 SHALL 采用渐进式查询策略回答用户问题,以节省 token 消耗: +1. 首先读取 project.md 获取整体概述和文件索引 +2. 根据用户问题和文件索引判断需要查阅哪些 parsed 文件 +3. 按需读取相关 parsed 文件的全部或部分内容 +4. 基于获取的信息回答问题 + +#### Scenario: 问题可通过摘要回答 +- **WHEN** 用户提问"这个项目主要做什么?",且 project.md 的概述中已包含足够信息 +- **THEN** 系统仅基于 project.md 内容回答,不加载 parsed 文件 + +#### Scenario: 问题需要查阅具体文件 +- **WHEN** 用户提问"系统的权限控制是怎么设计的?",且 project.md 文件索引中 `需求文档` 的摘要提到了权限相关内容 +- **THEN** 系统读取 `parsed/需求文档.md` 获取详细信息后回答 + +### Requirement: 来源标注 +系统在回答中引用具体信息时 SHALL 标注文件来源,格式为:「根据《文件名》(parsed/文件名.md),...」。来源标注 MUST 指向 parsed 目录下的具体文件。 + +#### Scenario: 回答中包含来源标注 +- **WHEN** 系统从 `parsed/技术方案.md` 中获取信息来回答问题 +- **THEN** 回答中 SHALL 包含类似「根据《技术方案》(parsed/技术方案.md),系统采用微服务架构...」的来源标注 + +#### Scenario: 回答综合多个文件 +- **WHEN** 回答需要综合 `parsed/需求文档.md` 和 `parsed/技术方案.md` 的信息 +- **THEN** 回答中 SHALL 分别标注各信息点的来源文件 + +### Requirement: 会话问答模式 +系统 SHALL 在 ask 模式下保持会话上下文,用户可以连续提问而无需每次重新加载知识库。会话的退出由用户自然决定(开启新话题或新会话),系统不主动终止会话。 + +#### Scenario: 多轮追问 +- **WHEN** 用户先问"系统用了什么技术栈?",接着追问"数据库选型的理由是什么?" +- **THEN** 系统在第二次回答时保持之前的上下文,可复用已加载的 parsed 文件内容 + +#### Scenario: 知识库中无相关信息 +- **WHEN** 用户提出的问题在 project.md 和所有 parsed 文件中均无相关信息 +- **THEN** 系统 SHALL 明确告知用户当前知识库中未找到相关信息,而非编造答案 diff --git a/openspec/specs/kb-project-management/spec.md b/openspec/specs/kb-project-management/spec.md new file mode 100644 index 0000000..af52cb7 --- /dev/null +++ b/openspec/specs/kb-project-management/spec.md @@ -0,0 +1,24 @@ +## ADDED Requirements + +### Requirement: 初始化知识项目目录结构 +系统 SHALL 在 CWD 下创建以指定名称命名的子目录,并在其中生成以下固定结构: +- `project.md`:初始内容包含项目名称标题、空的概述/关键信息段落、空的文件索引表和空的更新记录 +- `manifest.json`:初始内容包含项目名称、创建时间、空的 files 数组 +- `parsed/` 目录 +- `sources/` 目录 +- `archive/` 目录 + +#### Scenario: 成功初始化新项目 +- **WHEN** 用户执行 `/lyxy-kb-init my-project`,且 CWD 下不存在 `my-project` 目录 +- **THEN** 系统创建 `my-project/` 目录及完整子结构(project.md、manifest.json、parsed/、sources/、archive/),并提示用户将文档放入 sources/ 目录 + +#### Scenario: 目标目录已存在 +- **WHEN** 用户执行 `/lyxy-kb-init my-project`,且 CWD 下已存在 `my-project` 目录 +- **THEN** 系统 SHALL 提示用户该目录已存在,不覆盖任何现有内容 + +### Requirement: 项目目录结构规范 +知识项目 SHALL 遵循固定的目录结构:`project.md`、`manifest.json`、`parsed/`、`sources/`、`archive/`。所有 command 和 skill 操作 SHALL 基于此结构进行,不在结构外创建额外文件或目录。 + +#### Scenario: 验证项目结构完整性 +- **WHEN** 任何 command(ingest/rebuild/ask)在指定项目目录上执行 +- **THEN** 系统 SHALL 先检查目录结构是否完整(包含 project.md、manifest.json、parsed/、sources/、archive/),若不完整则提示用户先执行 init diff --git a/openspec/specs/kb-project-summary/spec.md b/openspec/specs/kb-project-summary/spec.md new file mode 100644 index 0000000..a1e5abf --- /dev/null +++ b/openspec/specs/kb-project-summary/spec.md @@ -0,0 +1,53 @@ +## ADDED Requirements + +### Requirement: project.md 格式规范 +project.md SHALL 遵循以下固定结构: + +```markdown +# <项目名称> + +## 概述 +(高度总结的项目信息) + +## 关键信息 +(从所有文档中提炼的核心要点) + +## 文件索引 + +| 文件名 | 解析文件 | 最新归档 | 摘要 | +|--------|----------|----------|------| + +## 更新记录 +``` + +初始化时概述和关键信息为空,文件索引表为空表头,更新记录为空。 + +#### Scenario: 初始化后的 project.md +- **WHEN** 执行 `/lyxy-kb-init my-project` +- **THEN** 生成的 project.md 包含 `# my-project` 标题、空的概述/关键信息段落、空的文件索引表(仅表头)和空的更新记录 + +### Requirement: 增量追加模式 +执行 ingest 时,系统 SHALL 以增量方式更新 project.md: +- 在文件索引表中追加新解析文件的行(文件名、parsed 路径、最新 archive 路径、该文件的简要摘要) +- 在更新记录中追加本次 ingest 的条目(时间和处理的文件列表) +- 已有文件更新时:覆盖文件索引表中对应行的最新归档路径和摘要 +- 概述和关键信息部分 SHALL NOT 在增量模式下自动更新 + +#### Scenario: 首次 ingest 追加索引 +- **WHEN** 首次 ingest 解析了 `需求文档.docx` +- **THEN** project.md 文件索引表中追加一行,更新记录中追加 `- 2026-02-18 16:00: 解析 需求文档.docx` + +#### Scenario: 已有文件更新时追加索引 +- **WHEN** `技术方案.pdf` 第二次入库 +- **THEN** project.md 文件索引表中该文件的最新归档路径和摘要被更新,更新记录追加新条目 + +### Requirement: 全量重写模式 +执行 rebuild 时,系统 SHALL 读取所有 `parsed/*.md` 文件,重新生成整个 project.md: +- 概述:基于所有 parsed 文件内容重新生成高度总结 +- 关键信息:重新提炼核心要点 +- 文件索引:基于 manifest.json 和 parsed 文件重新生成完整索引表 +- 更新记录:保留历史记录,追加本次 rebuild 条目 + +#### Scenario: 全量重写 +- **WHEN** 用户执行 `/lyxy-kb-rebuild my-project`,项目中有 3 个 parsed 文件 +- **THEN** 系统读取所有 3 个 parsed 文件,重新生成 project.md 的概述、关键信息和文件索引,更新记录追加 rebuild 条目 diff --git a/skills/lyxy-kb/SKILL.md b/skills/lyxy-kb/SKILL.md new file mode 100644 index 0000000..f97bfc8 --- /dev/null +++ b/skills/lyxy-kb/SKILL.md @@ -0,0 +1,293 @@ +--- +name: lyxy-kb +description: 基于文件的个人知识库管理 skill,提供知识项目的目录结构规范、文档解析入库、渐进式问答等底层能力定义。配合 commands/lyxy-kb/ 下的 command 使用。 +compatibility: 依赖 lyxy-reader-office skill 解析 office 文档(.docx/.pdf/.pptx/.xlsx),依赖 lyxy-runner-python skill 执行 Python 脚本。 +--- + +# 个人知识库 Skill + +基于文件的个人知识库管理系统。将项目相关文档组织为可被大模型高效检索和问答的知识库,支持文档解析入库、增量摘要、渐进式问答。 + +## Purpose + +**纯文件驱动**:不依赖数据库或向量存储,所有数据以文件形式存在于项目目录中。 + +**渐进式查询**:通过 project.md 摘要索引 + parsed 详细文件的分层结构,优先读取摘要,按需加载详细内容,节省 token 消耗。 + +**增量管理**:支持增量解析入库和增量更新摘要,避免重复处理已入库的文档。 + +## When to Use + +任何需要基于一组项目文档进行知识管理和问答的场景。 + +### 典型场景 +- **项目文档管理**:将需求文档、技术方案、数据表等组织为结构化知识库 +- **文档解析入库**:将 office 文档和纯文本文件解析为 markdown 并生成摘要 +- **知识问答**:基于已入库的文档回答问题,并标注信息来源 + +### 不适用场景 +- 需要语义搜索或向量化检索 +- 需要跨多个知识项目关联查询 +- 需要多人协作或权限控制 + +## 配套 Commands + +| Command | 触发方式 | 说明 | +|---------|----------|------| +| init | `/lyxy-kb-init ` | 初始化知识项目目录结构 | +| ingest | `/lyxy-kb-ingest ` | 解析 sources/ 中新文件,增量更新 project.md | +| rebuild | `/lyxy-kb-rebuild ` | 全量重新生成 project.md | +| ask | `/lyxy-kb-ask ` | 基于知识库进行会话问答 | + +## 项目名称规则 + +项目名称只允许使用以下字符: +- 中文字符 +- 英文字母(a-z、A-Z) +- 数字(0-9) +- 短横线(-) +- 下划线(_) + +**不允许包含空格或其他特殊字符。** 不符合规则时应提示用户修改。 + +## 知识项目目录结构 + +每个知识项目是当前工作目录(CWD)下的一个子目录,包含以下固定结构: + +``` +/ +├── project.md # 高度摘要 + 文件索引 +├── manifest.json # 增量追踪 +├── parsed/ # 解析后的 markdown(中间产物) +├── sources/ # 待处理区(用户放入原始文档) +└── archive/ # 原始文件备份(带时间戳) +``` + +### 各目录/文件职责 + +| 路径 | 职责 | +|------|------| +| `project.md` | 项目的高度摘要和文件索引,作为问答时的入口文件 | +| `manifest.json` | 记录已处理文件的元信息,用于增量检测和版本追踪 | +| `parsed/` | 存放解析后的 markdown 文件,便于大模型读取分析 | +| `sources/` | 用户放入待处理文档的目录,解析后文件会被移走 | +| `archive/` | 原始文件的备份,每个文件都带时间戳后缀 | + +### 结构完整性验证 + +执行任何 command(ingest / rebuild / ask)时,必须先验证项目目录结构是否完整,即以下 5 项是否全部存在: +- `/project.md` +- `/manifest.json` +- `/parsed/` +- `/sources/` +- `/archive/` + +若不完整,提示用户先执行 `/lyxy-kb-init `,终止当前操作。 + +## project.md 格式规范 + +```markdown +# <项目名称> + +## 概述 +(高度总结的项目信息,几百字以内) + +## 关键信息 +(从所有文档中提炼的核心要点) + +## 文件索引 + +| 文件名 | 解析文件 | 最新归档 | 摘要 | +|--------|----------|----------|------| +| 需求文档 | parsed/需求文档.md | archive/需求文档_202602181600.docx | 简要摘要... | + +## 更新记录 +- 2026-02-18 16:00: 解析 需求文档.docx +``` + +### 更新策略 + +**增量追加**(默认,由 ingest 触发): +- 新文件:在文件索引表追加新行,在更新记录追加条目 +- 已有文件更新:覆盖文件索引表中对应行的最新归档路径和摘要 +- 概述和关键信息部分**不**自动更新 + +**全量重写**(由 rebuild 触发): +- 读取所有 parsed/*.md 文件 +- 重新生成概述、关键信息、文件索引 +- 保留历史更新记录,追加本次 rebuild 条目 + +## manifest.json 结构 + +```json +{ + "project": "<项目名称>", + "created_at": "2026-02-18T16:00", + "last_ingest": "2026-02-18T17:25", + "files": [ + { + "name": "需求文档", + "ext": ".docx", + "parsed": "parsed/需求文档.md", + "versions": [ + { + "archived": "archive/需求文档_202602181600.docx", + "hash": "sha256:abc123...", + "ingested_at": "2026-02-18T16:00" + } + ] + } + ] +} +``` + +### 字段说明 + +| 字段 | 说明 | +|------|------| +| `project` | 项目名称 | +| `created_at` | 项目创建时间 | +| `last_ingest` | 最近一次 ingest 的时间 | +| `files[].name` | 文件名(不含扩展名) | +| `files[].ext` | 原始文件扩展名 | +| `files[].parsed` | 解析产物的相对路径 | +| `files[].versions` | 版本历史数组 | +| `files[].versions[].archived` | 归档文件的相对路径 | +| `files[].versions[].hash` | 文件内容的 SHA-256 哈希(使用 `sha256sum` 命令计算) | +| `files[].versions[].ingested_at` | 该版本的入库时间 | + +## 文件类型解析策略 + +| 文件类型 | 解析方式 | +|----------|----------| +| `.docx`, `.pdf`, `.pptx`, `.xlsx` | 使用名为 **lyxy-reader-office** 的 skill 解析 | +| 其他所有文件(`.md`, `.txt`, `.csv`, `.json`, `.xml`, `.yaml`, `.yml`, `.log`, `.html` 等) | 直接读取文件内容 | + +### Office 文档解析 + +解析 office 文档时,必须查找当前环境中名为 **lyxy-reader-office** 的 skill,阅读其 SKILL.md 获取具体的执行方式和命令。 + +**如果环境中不存在 lyxy-reader-office skill,且没有其他可替代的文档解析 skill,则提示用户无法处理 office 文档,中止整个 ingest 流程。** + +### sources/ 扫描规则 + +扫描 sources/ 时**递归检查所有子目录**中的文件。parsed 产物的路径仍为 `parsed/<文件名>.md`(扁平化存放),不保留 sources 中的子目录结构。 + +### 空文件处理 + +sources/ 中 0 字节的空文件应**跳过处理**,不解析、不归档、不更新 manifest。处理完成后向用户列出被跳过的空文件列表,提示用户检查。 + +### 解析失败处理 + +如果某个文件解析失败(如文档损坏、解析器报错),该文件**保留在 sources/ 中不移动**,报告错误信息,继续处理其他文件。 + +## parsed 文件元信息标记 + +每个 parsed markdown 文件头部必须包含元信息注释: + +```markdown + + + + +# 技术方案 +(文档正文内容...) +``` + +| 元信息 | 说明 | +|--------|------| +| `source` | 原始文件名(含扩展名) | +| `archived` | 对应的归档文件相对路径 | +| `parsed_at` | 解析时间(YYYY-MM-DD HH:mm 格式) | + +## 文档生命周期 + +``` +用户放入 sources/(支持子目录) + │ + ▼ + 检查文件(跳过空文件、检测冲突) + │ + ▼ + 解析文件内容(失败则保留在 sources/) + │ + ├──▶ 写入 parsed/<文件名>.md(含头部元信息) + │ + ├──▶ 移动原始文件到 archive/<文件名_YYYYMMDDHHmm>. + │ + ├──▶ 更新 manifest.json + │ + └──▶ 增量更新 project.md(追加文件索引和更新记录) +``` + +### 归档命名规则 + +所有进入 archive 的文件都必须带时间戳后缀,格式为 `<文件名_YYYYMMDDHHmm>.<扩展名>`,即使只有一个版本。 + +示例: +- `需求文档.docx` → `archive/需求文档_202602181600.docx` +- `技术方案.pdf`(第二次入库)→ `archive/技术方案_202602181725.pdf` + +### 同名文件更新 + +同名同扩展名的文件再次入库时: +- `parsed/` 中的 markdown 文件被覆盖为最新版本 +- `archive/` 中保留所有历史版本(每个版本独立的时间戳文件) +- `manifest.json` 中该文件条目的 `versions` 数组追加新版本记录 + +## 同名不同扩展名冲突检测 + +因为 parsed 产物以文件名(不含扩展名)+ `.md` 命名,同名不同扩展名的文件会产生冲突。 + +### 检测规则 + +1. **sources/ 内部检测**:扫描 sources/ 中所有文件(含子目录),如果存在同名但不同扩展名的文件(如 `技术方案.pdf` 和 `技术方案.docx`),拒绝处理并提示用户重命名 +2. **与已入库文件检测**:将 sources/ 中文件的名称(不含扩展名)与 manifest.json 中已有记录对比,如果名称相同但扩展名不同,拒绝处理并提示用户重命名 + +### 处理方式 + +冲突文件不予处理,保留在 sources/ 中,提示用户重命名后重新执行 ingest。非冲突文件正常处理。 + +## 渐进式查询策略 + +问答时采用分层加载策略,节省 token: + +1. **读取 project.md**:获取项目概述和文件索引(低 token 开销) +2. **判断相关文件**:根据用户问题和文件索引中的摘要,判断需要查阅哪些 parsed 文件 +3. **按需加载**:读取相关 parsed 文件的全部或部分内容 +4. **回答并标注来源**:基于获取的信息回答问题 + +### 来源引用格式 + +回答中引用具体信息时,使用以下格式标注来源: + +``` +根据《文件名》(parsed/文件名.md),... +``` + +多个来源时分别标注各信息点的来源文件。 + +### 无相关信息 + +当知识库中未找到与用户问题相关的信息时,明确告知用户,不编造答案。 + +### 空知识库 + +如果 project.md 文件索引为空(尚无已入库文件),应告知用户知识库为空,建议先使用 `/lyxy-kb-ingest` 入库文档。 + +## Notes + +### 依赖关系 + +| 依赖 | 用途 | +|------|------| +| lyxy-reader-office | 解析 .docx、.pdf、.pptx、.xlsx 文件为 markdown | +| lyxy-runner-python | 通过 uv 执行 lyxy-reader-office 的 Python 解析脚本 | + +### 限制 + +- 不支持向量化语义搜索 +- 不支持跨知识项目关联查询 +- 不支持文档版本对比或 diff +- 不支持多用户协作或权限控制 +- 大量文件全量重写时 token 消耗较高