From 60eb89c12ee0661785395bff90940204b16dcb3a Mon Sep 17 00:00:00 2001
From: ax_rd <ax_rd@aisim.cn>
Date: Thu, 03 Sep 2026 13:21:39 +0800
Subject: [PATCH] docs: e2e 验证脚本 + README 更新(增量同步/explore/构建要求)
---
scripts/e2e-verify.sh | 40 +++++++++++++
README.md | 89 +++++++++++++++++++++++++----
2 files changed, 116 insertions(+), 13 deletions(-)
diff --git a/README.md b/README.md
index fb6dd96..6243763 100644
--- a/README.md
+++ b/README.md
@@ -7,8 +7,10 @@
- ✅ **Vault 解析器**:解析 Obsidian frontmatter、标签、实体、wikilinks
- ✅ **知识图谱构建**:文件 → 节点,标签/实体/wikilinks → 边
- ✅ **SQLite 存储**:高效持久化,支持增量更新
-- ✅ **FTS5 全文搜索**:基于 SQLite FTS5 的快速搜索
-- ✅ **图谱评分算法**:考虑标签、实体、wikilinks 权重
+- ✅ **FTS5 全文搜索**:基于 SQLite FTS5 的快速搜索(ASCII 走 FTS5、CJK 走 LIKE 双通道)
+- ✅ **图谱评分算法**:文本位置分 + RWR 随机游走图质量双信号加权
+- ✅ **长中文词召回**:>3 字符 CJK 词自动 bigram 展开
+- ✅ **explore 命令**:按字节预算直出原文段落(agent 一次性上下文)
- ✅ **多种输出格式**:表格、JSON
- ✅ **内容返回**:`--with-content` 返回完整文件内容
- ✅ **关联链接**:`--with-links` 返回 wikilink 关联文档
@@ -28,6 +30,16 @@
**注意**:需要 CGO 和 FTS5 支持。
+## 构建要求
+
+go-sqlite3 需要系统 SQLite 开启 FTS5,构建时必须显式传入 CGO 标志(`make build` 已内置):
+
+```bash
+CGO_CFLAGS="-DSQLITE_ENABLE_FTS5" CGO_LDFLAGS="-lm" go build
+# 或
+make build
+```
+
## 使用方法
### 搜索
@@ -58,11 +70,34 @@
kb-cli search 充装 --top 5
```
+**双通道检索**:ASCII 词走 FTS5,CJK 词走 LIKE(title/aliases/content/tags 四列)。FTS5 unicode61 把连续中文当整串单 token,多字符中文词 MATCH 匹配不到,必须走 LIKE。长中文词(>3 字符)自动做 bigram 滑动展开(如「电子秤补气失败」→ 电子/子秤/秤补/补气/气失/失败),bigram 命中按扩展词档计权。
+
+**排序双信号**:`最终分 = 文本位置分 × TextWeight + RWR 随机游走图质量 × (1-TextWeight)`(TextWeight 缺省 0.5,可配 config.yaml);草稿态/待审阅板块降权 0.6。
+
+### 探索(explore)
+
+面向 agent 的一次性上下文获取:按字节预算直出相关文档的**原文段落**(整段不截半句),并附关联清单(wikilinks)与悬空链接提示,agent 无需再读文件。
+
+```bash
+# 默认预算 16000 字节、Top 5 篇(均可配 config.yaml explore 节)
+kb-cli explore "电子秤补气失败"
+
+# 自定义预算与文档数
+kb-cli explore "补气失败" --budget 8000 --top 3
+
+# JSON 输出
+kb-cli explore "补气失败" --json
+```
+
+**与 search 的分工**:`search` 返回文档列表(路径/标题/板块/得分,供浏览定位);`explore` 直接按预算返回命中文档的原文段落(供 agent 一次性获取上下文)。
+
### 索引管理
```bash
-# 构建/重建索引
+# 构建索引:默认增量对账同步(按 mtime/size 比对,只处理新增/修改/删除的文件),
+# --force 全量重建
kb-cli index build
+kb-cli index build --force
# 查看索引状态
kb-cli index status
@@ -78,6 +113,21 @@
kb-cli git sync
```
+### 知识图谱
+
+```bash
+# 图谱统计(节点数、边数、关系类型分布)
+kb-cli graph stats
+
+# 查询节点的关联关系
+kb-cli graph query 补气
+
+# 查找与关键词相关的节点
+kb-cli graph related 补气 --top 10
+```
+
+**provenance 标注**:每条边带 `provenance` 字段标注关系来源类型:`tag`(frontmatter 标签)、`entity`(正文实体)、`exact`/`fuzzy`(wikilink 精确/模糊匹配)。`graph query` 的边数据(含 `--json` 输出)携带该字段;悬空补全的 wikilink 边按匹配方式标注 `exact`/`fuzzy`。`graph related` 只输出节点级信息(路径/板块/标签/关联度),不含边 provenance。
+
### 全局选项
```bash
@@ -92,8 +142,10 @@
├── cmd/ # CLI 命令
│ ├── root.go # 根命令
│ ├── search.go # search 命令
+│ ├── explore.go # explore 命令
│ ├── index.go # index 命令
-│ └── rebuild.go # 索引重建逻辑
+│ ├── graph.go # graph 命令
+│ └── rebuild.go # 索引构建逻辑
├── internal/
│ ├── vault/ # Vault 解析器
│ │ ├── parser.go
@@ -101,27 +153,38 @@
│ │ └── sections.go
│ ├── graph/ # 知识图谱
│ │ ├── model.go
-│ │ └── builder.go
+│ │ ├── builder.go
+│ │ └── rwr.go # RWR 随机游走图质量
│ ├── index/ # SQLite 存储
│ │ ├── sqlite.go
-│ │ ├── fts.go
-│ │ └── cache.go
+│ │ ├── fts.go # 双通道检索(FTS5 + LIKE)
+│ │ ├── reconcile.go # 增量对账
+│ │ ├── migrations.go # schema 迁移
+│ │ └── graphload.go # RWR 邻接加载
│ ├── search/ # 搜索引擎
│ │ ├── engine.go
+│ │ ├── explore.go # explore 段落直出
+│ │ ├── expand.go # CJK bigram 展开(search/explore 共享)
│ │ └── scorer.go
+│ ├── llm/ # LLM 配置
+│ ├── classify/ # 实体/标签分类
+│ ├── draft/ # 草稿入库
+│ ├── review/ # 草稿预览
│ └── output/ # 输出格式化
│ └── formatter.go
+├── scripts/
+│ └── e2e-verify.sh # 端到端验证脚本
└── main.go
```
## 评分算法
-搜索结果评分考虑:
-- **FTS5 rank**:全文搜索相关性
-- **标签匹配**:标签权重 2.0
-- **实体匹配**:实体权重 1.5
-- **Wikilinks**:引用关系权重 1.2
-- **扩展词加成**:提升相关实体权重
+搜索结果按**双信号加权**排序:
+
+- **文本位置分**:路径/标题/板块/别名/内容命中计权(位置权重不同,别名按 title 档;实体词降权 1/5,通用词降权 1/3)
+- **RWR 图质量**:随机游走(Personalized PageRank),种子 = 检索候选前 20,体现节点在知识图谱中的中心性
+- **合并**:`最终分 = 归一化文本分 × TextWeight + RWR × (1-TextWeight)`,TextWeight 缺省 0.5(config.yaml 可配)
+- **降权**:草稿态(草稿/待确认/跟进中)与「待审阅」板块 ×0.6
## 开发
diff --git a/scripts/e2e-verify.sh b/scripts/e2e-verify.sh
new file mode 100644
index 0000000..17c4e96
--- /dev/null
+++ b/scripts/e2e-verify.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# 端到端验证(对标 spec 测试计划第 2 节)
+set -e
+export CGO_CFLAGS="-DSQLITE_ENABLE_FTS5"
+export CGO_LDFLAGS="-lm"
+VAULT="${1:-$HOME/rag-lpg-obsidian}"
+cd "$(dirname "$0")/.."
+go build -o /tmp/kb-cli-e2e .
+
+echo "=== 1. 全量重建基准 ==="
+/tmp/kb-cli-e2e index build --vault "$VAULT" --force 2>&1 | tail -1
+
+echo "=== 2. 增量同步耗时 ==="
+time /tmp/kb-cli-e2e index build --vault "$VAULT" 2>&1 | tail -1
+
+echo "=== 3. 未 commit 编辑可见性 ==="
+mkdir -p "$VAULT/笔记"
+TESTFILE="$VAULT/笔记/e2e-test-$(date +%s).md"
+printf -- "---\ntitle: e2e测试\ntags: [补气]\n---\ne2e 补气测试内容\n" > "$TESTFILE"
+/tmp/kb-cli-e2e search e2e --vault "$VAULT" --top 3 2>&1 | grep -q "e2e测试" && echo "PASS: 未commit编辑可见" || echo "FAIL: 未commit编辑不可见"
+rm -f "$TESTFILE"
+/tmp/kb-cli-e2e index build --vault "$VAULT" 2>/dev/null
+
+echo "=== 4. CJK 召回质量(补气应命中多条)==="
+# 适配说明:brief 原 grep 模式 ^文档/\|^FAQ/\|^知识/ 会漏掉「笔记/」等其它板块的结果行,
+# 实际输出结果行统一为「板块/…/xxx.md <标题>…」(行首即板块前缀、以 .md 结尾),
+# 故按「行首路径以 .md 结尾」计数(以实际输出为准的最小适配)。
+N=$(/tmp/kb-cli-e2e search 补气 --vault "$VAULT" --top 10 2>/dev/null | grep -cE '^[^[:space:]]+\.md[[:space:]]' || true)
+echo "补气 命中 $N 条 (期望 >= 5)"
+if [ "$N" -ge 5 ]; then echo "PASS: CJK 召回 >= 5"; else echo "FAIL: CJK 召回不足"; fi
+
+echo "=== 5. explore 预算内 ==="
+BYTES=$(/tmp/kb-cli-e2e explore "电子秤补气失败" --vault "$VAULT" --top 3 2>/dev/null | wc -c)
+echo "explore 输出 ${BYTES} 字节 (上限 32000+尾注)"
+if [ "$BYTES" -le 32200 ]; then echo "PASS: explore 预算内"; else echo "FAIL: explore 超预算"; fi
+
+echo "=== 6. 悬空补全 ==="
+/tmp/kb-cli-e2e graph stats --vault "$VAULT" 2>&1 | head -5
+
+echo "=== e2e 验证完成 ==="
--
Gitblit v1.10.0