dootask/resources/ai-kb/README.md
kuaifan 4de6c69972 feat(ai-assistant): RAG 反馈闭环 + driver.js 页面操作引导
方向7 反馈闭环:
- 新增 ai_assistant_search_logs / ai_assistant_feedbacks 两表 + 模型
- AssistantController 加 log__search / feedback__save 端点,auth 透传 session_id→context_key
- 前端 AI 回复下方 👍/👎(可改票、随会话持久化回显),extractSourceIds 解析引用
- ai-kb:feedback chunk + README 运营 SQL 口径(低分 top query / 👎 source)

方向4 页面操作引导:
- 渲染层用 driver.js(高亮可点击挖洞 + 稳定定位),编排层自研
  (脚本 schema / 四级元素定位 / 跨页 pre_action 导航 / 找不到降级文字)
- leave-semantics:跳转动作在点「下一步」后才执行
- markdown.js 渲染 ```ai-guide 围栏为「带我去」按钮;DialogMarkdown 点击启动
- 近义词归一化(创建/新建/新增/添加互通)提升 target 命中
- ai-kb:guide/start-guide chunk + tool-binding 加 show_guide

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 16:07:08 +00:00

119 lines
6.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ai-kb — DooTask AI 助手知识库
这是**专为大语言模型LLM检索使用**的 DooTask 功能知识库,不是给人类阅读的产品文档(那个在 [dootask-website](https://github.com/dootask/dootask-website) 仓库的 `help/docs`)。
它的唯一消费者是 AI 助手:用户问"看板列怎么改名 / 审批可以分支吗 / 5.4 有什么新功能"时,助手通过 RAG 检索这里的内容来作答。
## 目录结构
```
ai-kb/
├── _schema/ 写作规范(必读)
│ ├── frontmatter.md frontmatter 字段规范 + 受控词表
│ └── chunk-style.md chunk 写作风格 + 正反例
├── _meta/ 元数据lint / eval 脚本读取)
│ ├── feature-map.yaml feature 全集 + 每个 feature 的 chunk 清单
│ └── tool-binding.yaml chunk ↔ MCP 工具映射
├── _eval/ 回归测试
│ └── golden-50q.yaml 50 题评估集
├── zh/ 中文知识库P0 主战场)
│ ├── concept/ 「是什么」
│ ├── howto/ 「怎么做」(含 apps/ 子目录覆盖应用中心)
│ ├── faq/ 「为什么 / 出错怎么办」
│ ├── menu-map/ 「X 入口在哪」
│ ├── glossary/ 术语 + 别名
│ └── shortcut/ 快捷键、移动端手势
└── en/ 英文知识库P1 起草P0 保留空目录)
```
## 为什么不复用 dootask-website 的人类文档
| 维度 | 人类文档 | ai-kb |
|---|---|---|
| 阅读单位 | 一篇文章 | 一个 chunk128-512 token |
| 自包含性 | 假设从头读 | 每个 chunk 独立可懂 |
| 跨章节指代 | 「如上图所示」可以 | 禁止 |
| 截图 | 必要 | 禁止依赖(用文字描述) |
| 同义词 | 一处定义 | 显式列别名 |
| 否定信息 | 少 | 必备 |
| 元数据 | 标题即可 | 严格 frontmatter |
直接对人类文档做 RAG 召回率低、易编造,所以这里独立维护。
## 怎么开始写一个 chunk
1. 通读 [`_schema/frontmatter.md`](./_schema/frontmatter.md) — 字段规范与受控词表
2. 通读 [`_schema/chunk-style.md`](./_schema/chunk-style.md) — 写作风格与正反例
3. 在 [`_meta/feature-map.yaml`](./_meta/feature-map.yaml) 找到对应 feature 的 chunk 清单和归属批次
4. 在对应 `zh/<type>/<feature>/<id>.md` 路径下新建文件
5. 提交 PR、review 后合入。内容进索引不需要额外操作AI 插件容器每次启动会按文件 hash 对账reconcile自动增量收敛新增/变更/删除;想免重启即时生效可手动调 `POST /kb/reindex`
## 改 DooTask 主程序后必须同步更新这里
**这是硬性约束** —— 详见主仓库根目录 `CLAUDE.md` 中「DooTask AI 知识库 (ai-kb) 同步规则」章节。新增/修改/删除任何用户可见的功能、菜单、按钮、流程、字段、API 行为、权限角色,都必须在**同一 PR**里更新对应 chunk 并把 frontmatter 的 `last_verified` 改成当前版本号。
不更新的代价是 AI 助手给用户讲错路径,比 PR 多写两行成本高得多。
## 工程接口(代码在 AI 插件那一侧)
ingest、检索、lint、eval 的实现在 `dootask-plugins/system-plugins/ai/src/helper/kb/`。本目录纯内容,不放 Python 代码。
AI 插件容器通过只读 volume mount 看到本目录:
```yaml
volumes:
- ../../../dootask/resources/ai-kb:/app/kb-content:ro
```
内容同步机制:容器每次启动按文件 hash 对账reconcile自动增量收敛新增/变更/删除的 markdown——客户实例更新 DooTask 后重启插件容器即生效。需要免重启即时生效时手动触发:
```bash
curl -X POST 'http://ai-service/kb/reindex' \
-H "X-Ingest-Token: $KB_INGEST_TOKEN" \
-d '{"mode":"reconcile"}'
```
## 用检索打点与用户反馈数据迭代内容
主程序记录了两类质量数据mariadb表前缀以实际 `DB_PREFIX` 为准,下例用 `pre_`
- `pre_ai_assistant_search_logs` — 每次 `search_help_docs` 检索一行query、命中 source、分数、是否空结果
- `pre_ai_assistant_feedbacks` — 用户对 AI 回复的 👍/👎(含回复引用的 source id 列表)
**口径 1 —— 近 14 天低质量检索 top 问题(直接产出待补 chunk 清单):**
注意:向量 KNN 检索几乎总能返回 top-5胡乱提问也会命中分数偏低的近邻所以 `empty=1`
基本只在所查语种库为空时出现(如英文库未起草)。"知识库覆盖不到"的主信号是 **top_score 低**
```sql
SELECT query, locale, ROUND(AVG(top_score),3) AS avg_score, COUNT(*) AS cnt
FROM pre_ai_assistant_search_logs
WHERE (empty = 1 OR top_score < 0.8) AND created_at >= NOW() - INTERVAL 14 DAY
GROUP BY query, locale ORDER BY cnt DESC LIMIT 30;
```
**口径 2 —— 分数阈值校准(先看全局分布再定口径 1 的阈值):**
```sql
SELECT ROUND(top_score,1) AS bucket, COUNT(*) AS cnt
FROM pre_ai_assistant_search_logs
WHERE created_at >= NOW() - INTERVAL 14 DAY
GROUP BY bucket ORDER BY bucket;
```
**口径 3 —— 👎 最多的 source待修订清单**
```sql
SELECT jt.sid, COUNT(*) AS dislikes
FROM pre_ai_assistant_feedbacks f
JOIN JSON_TABLE(f.source_ids, '$[*]' COLUMNS (sid VARCHAR(191) PATH '$')) jt
WHERE f.feedback = 'dislike' AND f.created_at >= NOW() - INTERVAL 30 DAY
GROUP BY jt.sid ORDER BY dislikes DESC LIMIT 20;
```
钻取某条 👎 当时检索到了什么:`SELECT * FROM pre_ai_assistant_search_logs WHERE context_key = '<feedback.session_id>'`
**迭代流程**:每周跑口径 1/3 → 空结果高频 query 补新 chunk 或给现有 chunk 加 aliases → 👎 集中的 source 重写正文/negative → 提 PR → 容器重启 reconcile或手动 `/kb/reindex`)→ 下周对比同 query 的 empty 率与 👎 数验证收效。
## 维护责任
- **内容**:产品功能负责人 / PM / 技术写作者按 `_meta/feature-map.yaml` 中的 `owner` 列认领
- **schema 与受控词表**:架构组维护,修改需走 PR
- **lint / ingest / retriever 代码**AI 插件维护组