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