将你的 Obsidian 笔记变成可检索的知识库。从 GitHub 仓库拉取笔记,自动解析、分块、向量化,对外提供 HTTP API 供任何系统调用。
你的 Obsidian 笔记(GitHub 仓库)
↓ git pull
Markdown 文件扫描
↓ 解析 frontmatter / wiki链接 / 标签
文本清洗 + 分块(按标题结构 + 滑动窗口)
↓ sentence-transformers
向量化(bge-small-zh-v1.5,中文优化)
↓ 存入 Qdrant
可通过 HTTP API 检索
| 能力 | 说明 |
|---|---|
| 自动同步 | 从 GitHub 拉取最新笔记 |
| 智能解析 | 支持 frontmatter、wiki链接 [[xxx]]、标签 #AI |
| 结构化分块 | 按 Markdown 标题分块,保留上下文 |
| 中文优化 | 使用 bge-small-zh-v1.5 模型,专为中文场景优化 |
| 增量更新 | 只处理变更的文件,效率高 |
| metadata 过滤 | 支持按标签、类型、路径等条件过滤检索 |
| Docker 一键部署 | 一条命令启动,开箱即用 |
- Dify 工作流
- VCP 系统
- AstrBot / 聊天机器人
- 自定义 Agent / 脚本
- 任何支持 HTTP 的系统
| 依赖 | 版本要求 | 说明 |
|---|---|---|
| Docker | 20.10+ | 容器运行环境 |
| Docker Compose | v2.0+ | 多容器编排 |
| 磁盘空间 | 至少 3GB | 含 PyTorch + embedding 模型 |
| 内存 | 建议 4GB+ | embedding 模型加载需要内存 |
| 网络 | 能访问 GitHub | 首次拉取笔记需要 |
| 端口 | 8000, 6333 | API 服务和 Qdrant |
git clone https://github.com/yumoni6809/my-Rag.git
cd my-Rag复制示例配置文件并编辑:
cp .env.example .env编辑 .env 文件,必须配置以下三项:
# 你的 Obsidian 笔记仓库地址(必填)
GITHUB_REPO_URL=https://github.com/你的用户名/你的笔记仓库.git
# 分支名(默认 main)
GITHUB_BRANCH=main
# GitHub Token(私有仓库必填,公开仓库可留空)
# 获取方式:GitHub → Settings → Developer settings → Personal access tokens
# Fine-grained token: 需要对笔记仓库有 Contents 读取权限
# Classic token: 需要 repo 权限
GITHUB_TOKEN=github_pat_xxxxxxxxxxxxdocker compose up -d --build首次启动需要:
- 拉取 Qdrant 镜像(约 100MB)
- 构建 FastAPI 镜像(含 PyTorch,约 2GB,需几分钟)
- 下载 embedding 模型(首次入库时,约 100MB)
# Windows PowerShell
Invoke-RestMethod -Uri "http://localhost:8000/health"
# Linux / macOS
curl http://localhost:8000/health预期返回:{"status": "ok"}
# Windows PowerShell
Invoke-RestMethod -Uri "http://localhost:8000/ingest" -Method Post -Headers @{"X-API-Key"="change-me"}
# Linux / macOS
curl -X POST http://localhost:8000/ingest -H "X-API-Key: change-me"预期返回:
{
"status": "ok",
"git": {
"status": "cloned",
"commit": "a1b2c3d4e5f6"
},
"files_total": 21,
"chunks_total": 211
}首次入库会下载 embedding 模型,可能需要 1-3 分钟,请耐心等待。
# Windows PowerShell
$body = @{query="RAG"; top_k=5} | ConvertTo-Json
Invoke-RestMethod -Uri "http://localhost:8000/search" -Method Post `
-Headers @{"X-API-Key"="change-me"; "Content-Type"="application/json"} `
-Body $body
# Linux / macOS
curl -X POST http://localhost:8000/search \
-H "Content-Type: application/json" \
-H "X-API-Key: change-me" \
-d '{"query":"RAG","top_k":5}'所有配置通过 .env 文件管理,修改后需要重启容器生效:
docker compose up -d --force-recreate| 变量 | 说明 | 示例 |
|---|---|---|
GITHUB_REPO_URL |
Obsidian 笔记仓库地址 | https://github.com/user/notes.git |
GITHUB_BRANCH |
分支名 | main |
GITHUB_TOKEN |
GitHub Token | github_pat_xxxx |
Token 权限要求:
- Fine-grained token(推荐):Repository access → 选择笔记仓库 → Permissions → Contents 设为 Read-only
- Classic token:勾选
repo权限
| 变量 | 说明 | 默认值 |
|---|---|---|
QDRANT_URL |
Qdrant 服务地址 | http://qdrant:6333 |
QDRANT_COLLECTION |
collection 名称 | obsidian_notes |
| 变量 | 说明 | 默认值 |
|---|---|---|
EMBEDDING_MODEL |
HuggingFace 模型名 | BAAI/bge-small-zh-v1.5 |
可选模型:
| 模型 | 维度 | 特点 |
|---|---|---|
BAAI/bge-small-zh-v1.5 |
512 | 中文优化,体积小(推荐) |
BAAI/bge-base-zh-v1.5 |
768 | 中文优化,精度更高 |
shibing624/text2vec-base-chinese |
768 | 通用中文文本向量 |
更换模型后必须重建向量:重新执行
/ingest
| 变量 | 说明 | 默认值 |
|---|---|---|
CHUNK_SIZE |
每个 chunk 的字符数 | 800 |
CHUNK_OVERLAP |
相邻 chunk 重叠字符数 | 120 |
建议:
- 中文笔记:
CHUNK_SIZE=800,CHUNK_OVERLAP=120 - 长文章为主:可增大到
1200 - 短笔记为主:可减小到
500
| 变量 | 说明 | 默认值 |
|---|---|---|
SYNC_INCLUDE_DIRS |
只同步的目录(逗号分隔,留空=全部) | 博客,技术笔记,项目记录 |
SYNC_EXCLUDE_DIRS |
排除的目录(逗号分隔) | .git,.obsidian,.trash,仓库/截图 |
SYNC_EXCLUDE_EXTS |
排除的文件扩展名(逗号分隔) | .png,.jpg,.jpeg,.gif,.webp,.mp4,.zip,.pdf |
配置示例:
# 同步所有目录
SYNC_INCLUDE_DIRS=
# 只同步特定目录
SYNC_INCLUDE_DIRS=博客,技术笔记
# 排除草稿目录
SYNC_EXCLUDE_DIRS=.git,.obsidian,.trash,仓库/截图,草稿| 变量 | 说明 | 默认值 |
|---|---|---|
API_KEY |
API 鉴权密钥 | change-me |
重要:生产环境请务必修改默认 API Key!
所有写操作和检索接口需要在 Header 中携带 X-API-Key。
GET /health
无需鉴权。返回 {"status": "ok"}。
用途:监控服务是否正常运行。
POST /ingest
Header: X-API-Key: <your-api-key>
处理流程:
1. git clone / pull(从 GitHub 拉取最新笔记)
2. 扫描 .md 文件(按 include/exclude 过滤)
3. 解析每个文件(frontmatter + wiki链接 + 标签)
4. 分块(按标题结构 + 滑动窗口)
5. Embedding(bge-small-zh-v1.5 生成向量)
6. 删除旧 chunks(按 source_path)
7. 写入新 chunks 到 Qdrant
返回示例:
{
"status": "ok",
"git": {
"status": "pulled",
"commit": "864e43e55043"
},
"files_total": 21,
"chunks_total": 211
}返回字段说明:
| 字段 | 说明 |
|---|---|
git.status |
cloned 首次克隆 / pulled 有更新拉取 / unchanged 仓库无变化 |
git.commit |
当前 commit hash(前 12 位) |
files_total |
处理的 .md 文件数 |
chunks_total |
生成的向量 chunk 数 |
使用场景:
- 首次部署后执行一次
- 笔记更新后执行(建议定时或手动触发)
POST /search
Header: X-API-Key: <your-api-key>
Content-Type: application/json
请求体:
{
"query": "你的检索问题",
"top_k": 5,
"filters": {}
}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
query |
string | 是 | 检索问题,支持自然语言 |
top_k |
int | 否 | 返回结果数量,默认 5 |
filters |
object | 否 | metadata 过滤条件 |
filters 支持的字段:
| 字段 | 类型 | 说明 |
|---|---|---|
tags |
string[] | 按标签过滤,如 ["AI", "RAG"] |
type |
string | 按文档类型过滤(来自 frontmatter.type) |
source_path |
string | 按源文件路径过滤 |
title |
string | 按标题过滤 |
heading |
string | 按章节标题过滤 |
返回示例:
{
"query": "RAG怎么搭建?",
"results": [
{
"text": "RAG 搭建需要以下组件:向量数据库、Embedding 模型、文档解析器...",
"score": 0.83,
"metadata": {
"source_path": "技术笔记/RAG.md",
"title": "RAG搭建记录",
"tags": ["RAG", "AI"],
"heading": "搭建步骤",
"type": "tech"
}
}
]
}返回字段说明:
| 字段 | 说明 |
|---|---|
text |
匹配的文本片段 |
score |
相似度得分(0-1,越高越相关) |
metadata.source_path |
笔记文件路径 |
metadata.title |
笔记标题 |
metadata.tags |
标签列表 |
metadata.heading |
匹配的章节标题 |
metadata.type |
文档类型(来自 frontmatter) |
完整示例:
# 基础检索:用自然语言提问
Invoke-RestMethod -Uri "http://localhost:8000/search" -Method Post `
-Headers @{"X-API-Key"="change-me"; "Content-Type"="application/json"} `
-Body (@{query="机器学习入门"; top_k=3} | ConvertTo-Json)
# 带标签过滤:只检索 AI 相关笔记
Invoke-RestMethod -Uri "http://localhost:8000/search" -Method Post `
-Headers @{"X-API-Key"="change-me"; "Content-Type"="application/json"} `
-Body (@{query="深度学习"; top_k=5; filters=@{tags=@("AI")}} | ConvertTo-Json -Depth 3)
# 按文档类型过滤:只检索技术笔记
Invoke-RestMethod -Uri "http://localhost:8000/search" -Method Post `
-Headers @{"X-API-Key"="change-me"; "Content-Type"="application/json"} `
-Body (@{query="项目进度"; filters=@{type="tech"}} | ConvertTo-Json -Depth 3)GET /stats
Header: X-API-Key: <your-api-key>
返回示例:
{
"collection": "obsidian_notes",
"points_count": 211
}用途:了解当前知识库中有多少向量数据。
当你在 Obsidian 中编辑了笔记并推送到 GitHub 后,需要触发一次同步:
# Windows PowerShell
Invoke-RestMethod -Uri "http://localhost:8000/ingest" -Method Post -Headers @{"X-API-Key"="change-me"}
# Linux / macOS
curl -X POST http://localhost:8000/ingest -H "X-API-Key: change-me"# 创建定时任务,每小时执行一次同步
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument '-Command "Invoke-RestMethod -Uri http://localhost:8000/ingest -Method Post -Headers @{X-API-Key=''change-me''}"'
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Hours 1)
Register-ScheduledTask -TaskName "ObsidianRAGSync" -Action $action -Trigger $triggercrontab -e添加:
0 * * * * curl -X POST http://127.0.0.1:8000/ingest -H "X-API-Key: change-me"
# 查看向量数量
Invoke-RestMethod -Uri "http://localhost:8000/stats" -Headers @{"X-API-Key"="change-me"}
# Qdrant Web UI(浏览器打开)
# http://localhost:6333/dashboard本服务提供标准 HTTP JSON API,任何支持 HTTP 请求的系统都可以对接。
import requests
RAG_URL = "http://localhost:8000"
API_KEY = "change-me"
def search_notes(query: str, top_k: int = 5) -> list[dict]:
"""检索 Obsidian 笔记"""
resp = requests.post(
f"{RAG_URL}/search",
headers={
"X-API-Key": API_KEY,
"Content-Type": "application/json",
},
json={"query": query, "top_k": top_k},
)
resp.raise_for_status()
return resp.json()["results"]
# 使用示例
results = search_notes("RAG 怎么搭建?", top_k=3)
for r in results:
print(f"[{r['score']:.2f}] {r['metadata']['title']}")
print(f" 来源: {r['metadata']['source_path']}")
print(f" 内容: {r['text'][:100]}...")
print()在 Dify 工作流中:
- 添加 HTTP 请求 节点
- 配置:
- URL:
http://你的服务器IP:8000/search - Method:
POST - Headers:
X-API-Key: change-me,Content-Type: application/json - Body:
{"query": "{{用户输入}}", "top_k": 5}
- URL:
- 后续节点处理返回的 results
在机器人插件中,将用户消息作为 query 调用 /search,将返回的 results 作为上下文传给 LLM:
def get_context(question: str) -> str:
results = search_notes(question, top_k=3)
context_parts = []
for r in results:
source = r["metadata"]["source_path"]
context_parts.append(f"[来源: {source}]\n{r['text']}")
return "\n\n---\n\n".join(context_parts)将 /search 接口注册为 VCP tool:
{
"name": "search_obsidian_notes",
"description": "检索 Obsidian 笔记知识库,找到相关的笔记内容",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "检索问题"
},
"top_k": {
"type": "integer",
"description": "返回结果数量",
"default": 5
}
},
"required": ["query"]
}
}将检索结果作为上下文注入 LLM 提示词:
你是用户的私人知识助手。以下是用户 Obsidian 笔记中与问题相关的内容:
---
[来源: 技术笔记/RAG.md]
{检索结果1}
---
[来源: 博客/AI应用.md]
{检索结果2}
基于以上笔记内容回答用户的问题。如果笔记中没有相关内容,请如实告知。
# 查看容器运行状态
docker compose ps
# 查看 API 服务日志
docker logs obsidian-rag-api --tail 50
# 查看 Qdrant 日志
docker logs obsidian-rag-qdrant --tail 50# 重启所有服务
docker compose restart
# 仅重启 API 服务
docker compose restart rag-api
# 强制重建容器(修改 .env 后需要)
docker compose up -d --force-recreate# 拉取最新代码
git pull
# 重建镜像并重启
docker compose up -d --build# 编辑 .env 文件后
docker compose up -d --force-recreate
# 如果修改了 requirements.txt 或 Dockerfile
docker compose up -d --buildQdrant 数据存储在 Docker volume 中:
# 查看 volume
docker volume ls | findstr qdrant
# 备份 volume 数据
docker run --rm -v myrag_qdrant_data:/data -v ${PWD}:/backup alpine tar czf /backup/qdrant-backup.tar.gz -C /data .
# 恢复 volume 数据
docker run --rm -v myrag_qdrant_data:/data -v ${PWD}:/backup alpine tar xzf /backup/qdrant-backup.tar.gz -C /data# 停止服务(保留数据)
docker compose down
# 停止服务并删除数据(包括 Qdrant 数据)
docker compose down -v
# 清理未使用的 Docker 镜像
docker image prune# 1. 修改 .env
EMBEDDING_MODEL=BAAI/bge-base-zh-v1.5
# 2. 重建镜像
docker compose up -d --build
# 3. 清空旧数据并重建(不同模型维度不同,不能混用)
# 删除 Qdrant collection
docker exec obsidian-rag-qdrant curl -X DELETE http://localhost:6333/collections/obsidian_notes
# 4. 重新入库
Invoke-RestMethod -Uri "http://localhost:8000/ingest" -Method Post -Headers @{"X-API-Key"="change-me"}症状:/ingest 返回 500,日志显示 Could not connect to server
原因:容器内 DNS 解析异常(常见于 Windows Docker Desktop)
解决:在 docker-compose.yml 中添加 DNS 配置:
services:
rag-api:
dns:
- 8.8.8.8
- 8.8.4.4然后重启:docker compose up -d --force-recreate
症状:日志显示 Write access to repository not granted
排查步骤:
- 确认 Token 未过期
- Fine-grained token:检查是否选择了正确的仓库,Contents 权限是否为 Read-only
- Classic token:检查是否勾选了
repo权限
症状:日志显示 is not a valid point ID
原因:已修复。当前版本使用 UUID 格式的 ID。
排查步骤:
# 查看详细错误日志
docker logs obsidian-rag-api --tail 50常见原因:
- GitHub Token 权限不足
- 网络无法访问 GitHub
- 磁盘空间不足
可能原因及解决:
- chunk_size 太大:减小
CHUNK_SIZE(如 500) - embedding 模型不适合:尝试更换模型
- 笔记内容太少:增加更多笔记内容
- query 表述不清:尝试更具体的检索词
# 查看容器状态和错误
docker compose ps
docker logs obsidian-rag-api --tail 20
# 检查端口是否被占用
netstat -ano | findstr :8000
netstat -ano | findstr :6333my-Rag/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI 入口,4 个 API 路由
│ ├── config.py # 从 .env 读取所有配置
│ ├── git_sync.py # GitHub clone/pull
│ ├── loader.py # 扫描 .md 文件
│ ├── parser.py # 解析 frontmatter / wiki链接 / 标签
│ ├── chunker.py # 按标题分块 + 滑动窗口
│ ├── embedder.py # sentence-transformers embedding
│ ├── vector_store.py # Qdrant CRUD + 检索
│ ├── schemas.py # Pydantic 请求/响应模型
│ └── utils.py # chunk_id UUID 生成
├── data/repo/ # GitHub 仓库克隆目录
├── .env # 环境变量配置(不提交到 Git)
├── .gitignore # Git 忽略规则
├── requirements.txt # Python 依赖
├── Dockerfile # Python 3.11-slim + git
├── docker-compose.yml # FastAPI + Qdrant 编排
└── README.md # 本文档
GitHub 仓库
↓ git clone / pull
本地 /data/repo/
↓ loader.py 扫描
.md 文件列表
↓ parser.py 解析
结构化数据(title, text, tags, frontmatter)
↓ chunker.py 分块
chunks(id, text, metadata)
↓ embedder.py 向量化
向量 + chunks
↓ vector_store.py 存储
Qdrant 向量数据库
↓ 检索时
/embeddings(query) → 相似度搜索 → 返回 top_k 结果
| 组件 | 技术 | 用途 |
|---|---|---|
| Web 框架 | FastAPI | 提供 HTTP API |
| 向量数据库 | Qdrant | 存储和检索向量 |
| Embedding | sentence-transformers (bge-small-zh-v1.5) | 文本向量化 |
| Git 操作 | GitPython | 从 GitHub 拉取笔记 |
| Markdown 解析 | python-frontmatter + markdown-it-py | 解析 frontmatter 和 Markdown |
| 容器化 | Docker + Docker Compose | 一键部署 |
| 鉴权 | X-API-Key Header | API 安全 |
# 启动服务
docker compose up -d --build
# 停止服务
docker compose down
# 健康检查
Invoke-RestMethod -Uri "http://localhost:8000/health"
# 同步入库
Invoke-RestMethod -Uri "http://localhost:8000/ingest" -Method Post -Headers @{"X-API-Key"="change-me"}
# 检索笔记
$body = @{query="你的问题"; top_k=5} | ConvertTo-Json
Invoke-RestMethod -Uri "http://localhost:8000/search" -Method Post -Headers @{"X-API-Key"="change-me"; "Content-Type"="application/json"} -Body $body
# 查看统计
Invoke-RestMethod -Uri "http://localhost:8000/stats" -Headers @{"X-API-Key"="change-me"}
# 查看日志
docker logs obsidian-rag-api --tail 50
# Qdrant Web UI
# 浏览器打开 http://localhost:6333/dashboard