| name | ReferenceRAG |
| description | 本地知识库语义检索服务。从 Obsidian 笔记库检索技术教程、配置说明、最佳实践等内容。触发规则:(1)强制触发:rag:关键词、/rag 关键词 (2)组合触发:领域词(知识库/笔记/vault/obsidian/文档) + 动作词(搜/查/找/检索/查询) (3)意图触发:笔记里有没有、帮我搜一下笔记、在知识库中查找。NOT for: 天气、新闻、股票等实时信息。 |
| allowed-tools | ["Read","Bash"] |
ReferenceRAG 知识库检索
本地知识库检索服务,支持 Obsidian 笔记和 Markdown 文档的语义搜索、关键词搜索、知识图谱查询。
服务地址
BASE_URL=http://localhost:7897 # 默认端口,以实际配置为准
如需自定义,在 ~/.agents/.env 中设置 OBSIDIAN_RAG_API_URL。
认证
服务可配置 API Key。若已配置,所有请求需附加:
Authorization: Bearer <ApiKey>
未配置 ApiKey 时无需此头。
触发规则
强制触发
| 格式 | 示例 |
|---|
rag:关键词 | rag:Git 分支管理 |
/rag 关键词 | /rag TypeScript 类型 |
组合触发(领域词 + 动作词)
领域词:知识库、笔记、vault、obsidian、文档、文库
动作词:搜、查、找、检索、查询、翻一下、看看
意图触发
笔记里有没有 xxx / 帮我搜一下笔记 / 在知识库中查找
不触发
- 纯动作词无领域词:
查询 Git、搜索配置 ❌
- 实时信息:天气、新闻、股票 ❌
Agent 决策树
拿到用户意图后,按以下顺序选择 API:
用户意图
├── 通用语义查询(绝大多数情况)
│ └── POST /api/ai/query [mode: HybridRerank]
│ ├── 结果相关但内容不够 → POST /api/ai/drill-down
│ ├── 需要了解该笔记的关联 → GET /api/graph/neighbors/{nodeId}
│ ├── 先看文件结构再决定读哪段(可批量)→ POST /api/sources/files/info
│ └── 按行范围取内容 / 读全文(可批量)→ POST /api/sources/file/lines
│
├── 精确关键词 / 代码 / 错误码 / API 名称
│ └── GET /api/bm25index/search
│
├── 按笔记标题查找某篇具体文档
│ └── GET /api/graph/search?q=标题关键词
│ ├── 单节点探索关联 → GET /api/graph/neighbors?nodeId=<id>
│ ├── 多节点批量探索关联 → POST /api/graph/subgraph
│ └── 按行范围取内容 / 读全文(可批量)→ POST /api/sources/file/lines
│
└── 列出知识库有哪些文件
└── GET /api/sources → GET /api/sources/{name}/files
查询前处理(调用任何搜索 API 前必须执行)
在调用 /api/ai/query 或 /api/bm25index/search 之前,必须先将用户输入扩展为丰富的查询字符串。
扩展规则
- 提取核心名词和技术术语
- 补充中英文同义词、缩写、别名
- 补充上位/下位概念、相关操作动词
- 拼接为单个字符串(空格分隔,无需引号)
扩展示例
| 用户输入 | 扩展后查询 |
|---|
docker 怎么配置网络 | docker 网络配置 network docker-compose 容器网络 bridge overlay port mapping 端口映射 |
项目笔记整理方法 | 笔记整理 知识管理 PKM 项目管理 Obsidian 工作流 笔记结构 分类 归档 |
git 撤销提交 | git 撤销 revert reset undo 回滚 commit 提交 撤回 版本控制 |
Python 读取配置文件 | Python config 配置文件 读取 解析 yaml json ini configparser settings |
如何做好需求分析 | 需求分析 需求文档 PRD 用户故事 功能规格 业务需求 需求评审 需求收集 |
简单 2-3 词的查询不扩展,召回率可能下降 40% 以上。扩展后再搜索。
精读策略(按需使用)
触发条件
满足以下任一条件时,使用「先看结构再精读」代替直接用 context 回答:
- 用户明确要求"完整内容"/"读全文"/"这篇文档说了什么"
- 搜索结果来自同一文件的多个碎片 chunk(score 差异 < 0.1)
- 需要某文件特定章节,但 chunk 内容被截断且 drill-down 仍不完整
- 已知文件路径,需要精确取某行范围的内容
执行步骤
步骤 1:从搜索结果取 filePath(绝对路径)
步骤 2:POST /api/sources/files/info
→ 获取文件章节目录(headingPath + startLine + endLine)
→ 【不返回正文,几乎不消耗 token】
步骤 3:根据 headingPath 和行号判断哪些章节与问题相关
步骤 4:POST /api/sources/file/lines
→ items: [{ path, startLine, endLine }]
→ 只取目标章节内容,精准省 token
步骤 5:用取到的内容回答用户
全文读取
startLine: 0, endLine: 0 等价于读取整个文件的所有 chunk:
{ "items": [{ "path": "/abs/path/to/note.md", "startLine": 0, "endLine": 0 }] }
先用 files/info 确认文件结构,仅在确实需要全文时再用 0,0,避免超大文件撑爆上下文。
API 参考
1. 通用语义查询(主力接口)
POST /api/ai/query
| 参数 | 类型 | 说明 |
|---|
| query | string | 查询词(必填,建议先扩展) |
| mode | string | HybridRerank(默认推荐)/ Quick / Deep |
| topK | int | 返回数量,默认 10 |
| sources | string[] | 限定源,省略 = 全部 |
| filters.folders | string[] | 限定文件夹路径 |
| slim | bool | true = 省略 prompt 和 chunks[*].content,响应体积减少约 60%,Agent 调用时强烈推荐 |
模式说明:
HybridRerank:BM25 + 向量混合召回 + rerank 精排,准确率最高,日常首选
Hybrid:BM25 + 向量混合召回,不带 rerank,速度快于 HybridRerank
Standard:纯向量,返回 10 条(默认)
Quick:纯向量,返回 5 条,快速试探
Deep:纯向量,返回 20 条,适合探索性查询
响应关键字段:
{
"chunks": [
{
"refId": "用于 drill-down 的引用 ID",
"title": "文件标题",
"headingPath": "所在章节路径,如 ## 安装 > ### 配置",
"content": "片段内容",
"score": 0.95,
"bm25Score": 12.3,
"source": "源名称",
"obsidianLink": "可直接在 Obsidian 中打开的链接"
}
],
"context": "所有结果拼装的上下文文本(可直接用于回答)",
"stats": { "totalMatches": 5, "durationMs": 120 }
}
⚡ 优先使用 context 字段作为最终上下文,系统已自动拼装去重格式化,无需手动处理 chunks。
调用示例(Windows Git Bash):
curl -s -X POST "http://localhost:7897/api/ai/query" \
-H "Content-Type: application/json; charset=utf-8" \
--data-binary @- << 'EOF'
{"query": "Git 分支管理 branch 版本控制", "mode": "HybridRerank", "topK": 10}
EOF
curl -X POST "http://localhost:7897/api/ai/query" \
-H "Content-Type: application/json" \
-d '{"query": "Git 分支管理", "mode": "HybridRerank"}'
2. 深入展开上下文
当某个 chunk 看起来相关但内容被截断时,用 refId 取完整上下文。
POST /api/ai/drill-down
| 参数 | 类型 | 说明 |
|---|
| query | string | 原始查询词 |
| refIds | string[] | 来自 /query 结果的 chunk.refId |
| expandContext | int | 扩展窗口大小,默认 2 |
响应关键字段:
{
"fullContext": "展开后的完整上下文文本",
"expandedChunks": [{ "content": "...", "score": 0.9 }]
}
示例:
curl -s -X POST "http://localhost:7897/api/ai/drill-down" \
-H "Content-Type: application/json" \
--data-binary @- << 'EOF'
{"query": "Git 分支", "refIds": ["chunk_abc123"], "expandContext": 2}
EOF
3. BM25 关键词搜索
适合精确词匹配:变量名、错误码、API 名、专有名词。
GET /api/bm25index/search?query=关键词&topK=10
响应关键字段:
{
"results": [
{ "chunkId": "...", "content": "...", "score": 15.2, "rank": 1 }
],
"totalResults": 5
}
示例:
curl -s "http://localhost:7897/api/bm25index/search?query=IndexOutOfRangeException&topK=5"
4. 图谱节点搜索
按笔记标题关键词查找节点,适合"有没有一篇关于 XXX 的笔记"。
GET /api/graph/search?q=关键词&limit=10
响应关键字段:
[
{
"id": "节点ID(用于 neighbors 查询)",
"title": "笔记标题",
"type": "document | tag | heading | external",
"chunkIds": ["关联的 chunk ID 列表"]
}
]
示例:
curl -s "http://localhost:7897/api/graph/search?q=Docker%20部署&limit=5"
5. 图谱关联关系(邻居节点)
从一个节点出发,探索它链接到哪些笔记、被哪些笔记引用。
GET /api/graph/neighbors?nodeId=<id>&depth=1&edgeTypes=wikilink
| 参数 | 说明 |
|---|
| nodeId | 来自 graph/search 结果的 id(query 参数,自动处理编码) |
| depth | 遍历深度 1-3,默认 1 |
| edgeTypes | 逗号分隔,省略 = 全部;可选:wikilink, tag, heading |
响应关键字段:
{
"nodes": [{ "id": "...", "title": "关联笔记标题", "type": "document" }],
"edges": [{ "fromId": "...", "toId": "...", "type": "wikilink" }]
}
示例:
curl -s --get "http://localhost:7897/api/graph/neighbors" \
--data-urlencode "nodeId=Projects/Docker/安装教程" \
--data-urlencode "depth=1"
6. 图谱子图(批量邻居遍历)
已知多个节点 ID,一次获取所有节点的邻居关系,结果自动去重合并。适合"探索多篇相关笔记的关联网络"。
POST /api/graph/subgraph
请求体:
{
"rootIds": ["Projects/Docker/安装教程.md", "Projects/Docker/配置.md"],
"depth": 1
}
rootIds:节点 ID 列表(来自 graph/search 结果的 id 字段)
depth:遍历深度 1-3,默认 1
响应关键字段:
{
"nodes": [
{ "id": "...", "title": "关联笔记标题", "type": "document", "chunkIds": ["..."] }
],
"edges": [
{ "fromId": "...", "toId": "...", "type": "wikilink" }
]
}
示例:
curl -s -X POST "http://localhost:7897/api/graph/subgraph" \
-H "Content-Type: application/json" \
--data-binary @- << 'EOF'
{"rootIds": ["Projects/Docker/安装教程.md", "Projects/Git/分支管理.md"], "depth": 1}
EOF
7. 批量获取文件结构(目录级,不含正文)
已知一批文件路径,先拿到每个文件的章节目录(标题 + 行号范围),不返回正文内容,用于规划后续精准读取。
POST /api/sources/files/info
请求体:
{
"paths": [
"C:/Vault/Docker/安装教程.md",
"C:/Vault/Git/分支管理.md"
]
}
响应关键字段:
{
"results": [
{
"path": "C:/Vault/Docker/安装教程.md",
"title": "Docker 安装教程",
"source": "Obsidian",
"totalChunks": 8,
"totalLines": 120,
"sections": [
{ "index": 0, "headingPath": "## 安装", "startLine": 1, "endLine": 40 },
{ "index": 1, "headingPath": "## 安装 > ### Windows", "startLine": 41, "endLine": 80 },
{ "index": 2, "headingPath": "## 配置", "startLine": 81, "endLine": 120 }
],
"error": null
}
]
}
示例:
curl -s -X POST "http://localhost:7897/api/sources/files/info" \
-H "Content-Type: application/json" \
--data-binary @- << 'EOF'
{"paths": ["C:/Vault/Docker/安装教程.md", "C:/Vault/Git/分支管理.md"]}
EOF
8. 按行范围批量获取内容(含全文)
已知文件路径和行号范围(如来自搜索结果的 startLine/endLine),精准取出对应的分段。支持一次请求多个文件、多个范围。
POST /api/sources/file/lines
请求体:
{
"items": [
{ "path": "C:/Vault/Docker/安装教程.md", "startLine": 10, "endLine": 50 },
{ "path": "C:/Vault/Git/分支管理.md", "startLine": 0, "endLine": 0 }
]
}
startLine / endLine 均为 0 时等价于返回整个文件(同 /file/chunks)
- 行范围按 chunk 的
StartLine/EndLine 做重叠匹配(chunkStart <= endLine && chunkEnd >= startLine)
响应关键字段:
{
"results": [
{
"path": "C:/Vault/Docker/安装教程.md",
"title": "Docker 安装教程",
"source": "Obsidian",
"requestedRange": { "startLine": 10, "endLine": 50 },
"chunks": [
{ "index": 1, "headingPath": "## 安装 > ### Windows", "startLine": 8, "endLine": 52, "content": "..." }
],
"error": null
},
{
"path": "C:/Vault/Git/分支管理.md",
"chunks": [...],
"error": null
}
]
}
error 非空时表示该条目失败(文件未索引、路径越权等),其余条目不受影响
示例(Git Bash):
curl -s -X POST "http://localhost:7897/api/sources/file/lines" \
-H "Content-Type: application/json" \
--data-binary @- << 'EOF'
{
"items": [
{ "path": "C:/Vault/Docker/安装教程.md", "startLine": 10, "endLine": 80 }
]
}
EOF
9. 文件列表
列出某个源下的所有文件,回答"知识库里有哪些笔记"。
# 先获取源列表
GET /api/sources
# 再获取指定源的文件
GET /api/sources/{name}/files?page=1&pageSize=50
示例:
curl -s "http://localhost:7897/api/sources"
curl -s "http://localhost:7897/api/sources/Obsidian/files?pageSize=50"
多步查询策略
场景 A:通用查询(最常用)
- 扩展查询词
POST /api/ai/query (HybridRerank, slim: true)
- 直接使用响应中的
context 字段回答用户
场景 B:结果不够详细
POST /api/ai/query → 找到相关 chunk
- 取
chunk.refId → POST /api/ai/drill-down
- 用
fullContext 回答
场景 C:探索某篇笔记的关联网络
GET /api/graph/search?q=笔记标题 → 获取一批 nodeId
- 单节点:
GET /api/graph/neighbors?nodeId=<id>&depth=2
多节点:POST /api/graph/subgraph 传入 rootIds 批量获取
- 对感兴趣的节点取
chunkIds → POST /api/ai/query 补充内容
场景 D:精确术语 + 语义组合
GET /api/bm25index/search?query=精确术语 → 锁定相关 chunk
POST /api/ai/query (Deep) → 补充语义相关内容
- 合并两路结果回答
场景 E:读取指定文件完整内容
- 通过搜索结果或文件列表拿到
filePath(绝对路径)
POST /api/sources/file/lines 传 {"items":[{"path":"<filePath>","startLine":0,"endLine":0}]}
- 拼接
chunks[].content 呈现完整文档
场景 F:多文件"先看目录再精读"(最省 token)
- 搜索 → 得到多个相关
filePath
POST /api/sources/files/info 批量拿所有文件的章节目录(无内容)
- 根据
headingPath + 行号判断哪些章节与问题相关
POST /api/sources/file/lines 只取目标行范围的内容
- 用取到的内容回答用户
支持的模型
本地 ONNX(Embedding):bge-small-zh-v1.5、bge-base-zh-v1.5、bge-large-zh-v1.5、bge-m3
本地 ONNX(Rerank):bge-reranker-base、bge-reranker-large
OpenAI 兼容 API:支持任意 Ollama / vLLM / Xinference / LM Studio / TEI 等兼容模型,在设置页切换推理模式后配置。
Web UI / Swagger
- Web UI:
http://localhost:7897
- Swagger:
http://localhost:7897/swagger
GitHub
https://github.com/csvkse/ReferenceRAG