stm32-rag-mcp
# STM32 RAG Agent + MCP
一个以 **LangGraph RAG Agent** 为主、以 **Claude Code MCP** 为辅的 STM32 文档知识库。Agent 从本地 datasheet 和 reference manual 检索经过 provenance 校验的证据,再使用 `.env` 中配置的 DeepSeek 生成带证据标签的回答;`sources` 中的文档、页码、revision、section、寄存器和 source SHA-256 始终由服务端从已验证证据重建,模型不能控制这些元数据,答案正文则必须通过 evidence-id 和 citation-pattern 校验。
> 当前版本是 evidence-first、lexical-first RAG:检索使用确定性的 SQLite FTS5/BM25 和技术标识符重排,不依赖 Chroma 或远程向量库。LangGraph 编排“检索 → 相关性门 → 生成 → 引用校验”的有界流程;没有完整证据时明确 abstain,不猜寄存器、地址或页码。现有三个只读 MCP 证据工具保持兼容,Agent MCP 为独立的可选入口。
## 当前语料
| 系列 | 类型 | 文档 | 文件 | 页数 |
|---|---|---|---|---:|
| STM32F1 | datasheet | STM32F103C8 | `reference_manual/datasheet/STM32F1/STM32F103C8.pdf` | 117 |
| STM32F1 | reference manual | RM0008 Rev 21 | `reference_manual/STM32F1/RM0008.pdf` | 1,136 |
| STM32F4 | datasheet | STM32F405/407 | `reference_manual/datasheet/STM32F4/STM32F405_407.pdf` | 203 |
| STM32F4 | reference manual | RM0090 Rev 9 | `reference_manual/STM32F4/RM0090.pdf` | 1,718 |
本地验证语料合计 4 份 PDF、3,174 页、42,839,844 bytes。`download_manifest.csv` 保存 SHA-256、实际镜像来源和 ST 官方文档页面。当前 PDF 来自公开镜像,索引不会把它们描述成“自动同步的最新版”;更新文档后必须重新校验 revision、SHA 和 citation。
> **仓库语料说明:** 当前公开仓库已经包含上述 4 份 PDF,方便首次安装直接构建索引。PDF 仍应视为 ST 文档的再分发内容;更新或替换文件前请确认其来源和再分发许可。SQLite 索引是可再生构建产物,不提交到仓库。
## 架构
```text
STM32 PDF
-> SHA/provenance registry
-> PyMuPDF page/block parser
-> TOC + model-scope sections
-> section/register-aware chunks
-> SQLite metadata + FTS5 BM25
-> exact technical-token rerank + abstention
-> verified Evidence/Citation
-> LangChain Document adapter
-> LangGraph RAG Agent
-> deterministic relevance gate
-> DeepSeek answer generation
-> evidence-id validation
-> server-side citation reconstruction
-> CLI `stm32-rag ask`
-> optional Agent MCP `ask_stm32`
```
核心特点:
- page-first:保留 physical PDF page、PDF label、可见页脚和异常标记;
- scope-aware:区分 RM0090 的 F42/F43 RCC 章节与 F405/F407 RCC 章节;
- register-aware:支持 `GPIO_MODER` / `GPIOA_MODER` 到 `GPIOx_MODER` 的规范化,同时区分 F1 的 `GPIOx_CRL/CRH`;
- deterministic:SQLite FTS5 `unicode61 tokenchars '_'`、固定重排和 index fingerprint;
- fail loud:PDF、schema、parser、chunker 或 corpus fingerprint 变化时拒绝旧索引;
- read-only MCP:运行时不下载、不建库、不修改 PDF。
## 安装依赖
项目使用 `uv.lock` 固定依赖。当前验证环境为 Python 3.14.5(项目支持 Python >=3.11);锁文件同时保证依赖版本可复现。运行时包含 LangChain/LangGraph、DeepSeek 兼容模型适配、MCP 适配器、PyMuPDF 和 Pydantic;当前锁定的 LangChain Core 为 1.6.1、LangChain OpenAI 为 1.6.0、LangGraph 为 1.2.11、MCP 为 2.1.1、PyMuPDF 为 1.28.2。wheel 发行包只包含 Python 模块;STM32 PDF、manifest、SQLite index 和插件配置仍按源码/插件目录提供,独立安装时请通过项目根或显式路径配置它们。
```bash
uv sync --frozen --extra dev
```
创建本地 DeepSeek 配置(不要把真实 key 提交到 Git):
```bash
cp .env.example .env
```
PowerShell 用户可使用 `Copy-Item .env.example .env`。
然后在 `.env` 中设置 `DEEPSEEK_API_KEY`,可选设置 `DEEPSEEK_MODEL` 和 `DEEPSEEK_BASE_URL`。Agent 只读取 `DEEPSEEK_*`,不会回退到 OpenAI 或 DashScope;旧的证据检索和 MCP 工具不需要 key。
## 准备 PDF 与构建索引
克隆仓库后,4 份验证语料位于 `reference_manual/`,可先校验路径、大小和 SHA-256(索引尚未生成时使用 `--without-index`):
```bash
uv run stm32-rag doctor --corpus reference_manual --manifest download_manifest.csv --without-index --json
```
预期输出 `ok: true`,包含 4 documents、3,174 pages 和 42,839,844 bytes。manifest 中的 `source` 是原始镜像地址,`official_page` 是 ST 官方文档页;它们用于 provenance 记录,不会在正常启动时自动访问网络。
如果需要重新下载或替换 PDF,下载器只会在显式执行时联网,并将结果写入被 `.gitignore` 排除的 `download_results.csv`:
```bash
uv run python download_stm32_docs.py
```
下载完成后必须重新校验 manifest 中记录的文件路径、字节数和 SHA-256;下载器报告 `failed` 时会以非零状态退出。确认语料完整后,构建本地 SQLite FTS5 索引:
```bash
uv run stm32-rag index \\
--corpus reference_manual \\
--manifest download_manifest.csv \\
--db assets/stm32-index.sqlite3 \\
--index-manifest assets/index-manifest.json \\
--json
```
索引构建会在临时数据库中完成 integrity check 和 fingerprint 校验,成功后才原子替换 `assets/stm32-index.sqlite3`。索引不会提交到 GitHub;更新 PDF、parser、chunker 或 retrieval policy 后都应重新构建。
构建完成后再次检查索引:
```bash
uv run stm32-rag doctor \\
--corpus reference_manual \\
--manifest download_manifest.csv \\
--db assets/stm32-index.sqlite3 \\
--json
```
## CLI 查询
低层证据查询仍可直接使用:
```bash
uv run stm32-rag search --db assets/stm32-index.sqlite3 --corpus reference_manual --manifest download_manifest.csv --chip STM32F407 --query GPIO_MODER --json
```
```bash
uv run stm32-rag search --db assets/stm32-index.sqlite3 --corpus reference_manual --manifest download_manifest.csv --chip STM32F407 --query "USART_CR1 TE bit" --json
```
RAG Agent 是主要入口。它会先检索证据,再交给 LangGraph 的相关性门和 DeepSeek 生成答案:
```bash
uv run stm32-rag ask \
--db assets/stm32-index.sqlite3 \
--corpus reference_manual \
--manifest download_manifest.csv \
--chip STM32F407 \
--query "GPIO_MODER 的作用是什么?" \
--json
```
如需指定 dotenv 文件,可加 `--env-file path/to/.env`。交互模式从 stdin 逐行读取问题,以 `:quit` 或 `:exit` 结束;`--json` 模式每行输出一个 JSON 对象:
```bash
uv run stm32-rag ask --chip STM32F407 --interactive
```
证据不足或答案引用校验失败时返回 `abstained: true`,退出码为 2;DeepSeek 配置、网络/模型调用或索引基础设施错误是硬失败,退出码为 1,并且不会把基础设施故障伪装成“无证据”。不存在或跨系列不兼容的寄存器不会静默取消 chip filter。
## 重建索引
更新 PDF、parser 或 chunker 后运行:
```bash
uv run stm32-rag index --corpus reference_manual --manifest download_manifest.csv --db assets/stm32-index.sqlite3 --index-manifest assets/index-manifest.json --json
```
index builder 在临时 SQLite 中完成事务、integrity check 和 fingerprint 校验后再原子替换目标文件;失败不会破坏旧索引。
## Claude Code 插件
插件组件:
- `.claude-plugin/plugin.json`
- `.mcp.json`
- `agent.mcp.example.json`:可选的 Agent MCP 配置模板(仅在 Claude Code 插件上下文中解析 `${CLAUDE_PLUGIN_ROOT}`/`${CLAUDE_PLUGIN_DATA}`;独立项目使用时请替换为实际路径);复制/合并到本地 MCP 配置后,按需启用 `stm32-rag-agent`。
- `skills/stm32-docs/SKILL.md`
- MCP tools:`search_stm32_docs`、`get_register`、`search_peripheral`
- Agent MCP entry point:`stm32-rag-agent-mcp` / `ask_stm32`(显式可选)
验证插件:
```bash
claude plugin validate C:/Users/Administrator/rag_embedding --strict
```
本地开发加载:
```bash
claude --plugin-dir C:/Users/Administrator/rag_embedding
```
启动后在 Claude Code 中检查 `/mcp`,技能命令为:
```text
/stm32-rag:stm32-docs
```
`.mcp.json` 使用 `${CLAUDE_PLUGIN_ROOT}` 定位只读 corpus/index,并显式传入 `STM32_RAG_PROJECT_ROOT` 与 `STM32_RAG_ENV_FILE`;使用 `${CLAUDE_PLUGIN_DATA}` 保存 uv 环境/cache。该文件应在 Claude Code 插件上下文中加载(例如 `claude --plugin-dir ...`),不要直接把含有 `${CLAUDE_PLUGIN_*}` 占位符的文件当作普通项目 MCP 配置运行。首次在新安装位置启动时,uv 可能从 lockfile 安装 Python 依赖;它不会自动下载 STM32 PDF、生成 SQLite 索引或下载 embedding 模型。公开仓库中的 `.mcp.json` 需要在本地语料和索引准备完成后使用。
## MCP 工具
### `search_stm32_docs`
综合查询,可传:`query`、`chip`、`family`、`document_type`、`peripheral`、`register`、`top_k`。
### `get_register`
精确寄存器查询,必须传 `chip` 和 `register`。适合地址 offset、reset value、bit field 和清除语义。
### `search_peripheral`
外设范围查询,必须传 `chip` 和 `peripheral`,可附加具体问题。
三个基础工具只返回 evidence/citations,不返回一个伪装成权威的本地生成答案。Agent MCP 是独立工具,不改变上述三个工具的集合或响应 schema;它会返回 `answer`、服务端重建的 `sources` 和 Agent attempts/abstention 元数据。Agent MCP 本地读取索引,但默认会将用户问题和检索片段发送到配置的 DeepSeek endpoint,因此工具标注为可出站(`open_world_hint=true`);启用前请确认数据处理、网络和凭据策略。未配置 DeepSeek key 时,无证据查询不会初始化模型。
可在本地通过模块入口显式启动 Agent MCP(直接运行时请从项目根目录启动,或设置 `STM32_RAG_PROJECT_ROOT`、`STM32_RAG_ENV_FILE`、`STM32_RAG_CORPUS_DIR`、`STM32_RAG_MANIFEST` 和 `STM32_RAG_DB_PATH`):
```bash
uv run stm32-rag-agent-mcp
```
不要把 Agent MCP 的 API key 写入 `.mcp.json`;通过受保护的 `.env` 或进程环境提供 `DEEPSEEK_API_KEY`。远程 HTTP MCP 不在本版范围内,默认不开放网络端口。
## 参考 demo_src 的边界
`demo_src/` 保留为教学参考,不是生产入口,也不纳入 wheel/sdist 或 `init.sh` 的生产验证;其中脚本依赖外部教程资产,部分文件有导入时副作用或历史语法问题,不能当作可直接运行的应用。新 Agent 借鉴了其中的 LangChain `Document`、prompt、retriever 和有界候选处理思路,但没有复制其全局 `OPENAI_API_KEY`、旧版 `RetrievalQA`/`ConversationalRetrievalChain`、Chroma 私有 API、无 provenance 的 plain-string 流程、导入时网络/文件副作用或 Panel 上传界面。生产检索继续使用本项目的页码/作用域/引用校验层。
## Citation 语义
每条 evidence 包含:
- document / DocID / revision / type / family;
- source path、SHA-256、mirror URL、ST official page;
- physical PDF pages、PDF labels、source footers;
- section path、register、chip scope;
- warnings 和 page anomalies。
RM0008 p.67–80 是重要异常:PDF physical/page label 仍为 67–80,但可见页脚错误写成 `67/80`…`80/80`。系统保留 canonical page 与 source footer,并标记 `embedded_total_mismatch`。
## 评测与测试
```bash
uv run pytest -q
```
当前测试覆盖:
- corpus 路径、SHA、页数和 downloader 无副作用 import;
- RM0008 页码异常;
- RM0090 scope 与无效 TOC anchor;
- F4 datasheet 横向页;
- register chunk 跨页与确定性 ID;
- SQLite schema、FTS5、只读和 stale-index 防护;
- CLI、MCP in-memory client 和真实 stdio 子进程;
- `eval/golden_queries.json` 的 20 个正例 + 5 个负例 hard gate;另有 Agent 图的假模型、引用校验、重写上限和无关问题短路测试。
正例要求 Recall@5 / citation hit 至少 90%;当前 20/20 正例首条命中定义页,5/5 负例 abstain。
## 已知限制
- Agent 的语义生成需要可用的 DeepSeek API key;自动测试使用注入的 fake model,不会产生网络请求或费用。DeepSeek 兼容端点的模型能力可能不同,运行时会严格校验 JSON 和证据标签。
- Agent 首版不启用跨请求会话记忆/checkpointer;每次 ask 的芯片过滤和证据上下文彼此隔离。
- Agent 上下文使用检索器已生成的 bounded snippet,而不是重新读取 PDF;若 snippet 本身不足,系统会 abstain,而不会绕过 provenance 校验。
- 当前检索模式为 `lexical`,未打包 embedding 模型或 learned reranker;接口扩展点已保留,但响应不会谎称 hybrid。Agent 使用 LangChain/LangGraph 做编排和生成,并不因此把 FTS5 误报为向量检索。
- F4 datasheet p.14–15、62–70 为旋转横向表格。系统保留原文/rotation 并标记 `table_layout_degraded`;精确 pin/Alternate Function 查询会优先匹配非降级 pinout 表,无法建立可靠映射时显式 abstain。
- 尚未加入 SVD 结构化寄存器数据库、Errata、Application Note、HAL/LL、示例代码或其他 STM32 family。
- `download_stm32_docs.py` 只在显式执行时联网,并写 `download_results.csv`;它不会覆盖 verified corpus manifest。MVP 正常运行不调用 downloader。
## 项目计划
完整背景和后续路线见 `STM32_RAG_MCP_Project_Plan.md`。本版优先兑现计划中的核心目标:从 STM32 文档找到可靠证据、保留页码和来源,并通过 MCP 供 Claude 主动查询。
TDQS
Scored across 3 tools
General search_stm32_docs overlaps semantically with get_register and search_peripheral, since a broad docs search could return register or peripheral content. The specialized tools are clearly scoped, but agents may still hesitate between the general and resource-specific search paths.
All tool names follow a consistent verb_noun snake_case pattern: search_stm32_docs, get_register, and search_peripheral. The two search tools share a predictable prefix, and get_register fits the same structural style.
Three tools is compact but well-scoped for a documentation RAG server: general docs search, register lookup, and peripheral search. Each tool covers a distinct retrieval need without unnecessary padding.
Core retrieval workflows are covered: broad documentation search, register-level lookup, and peripheral-scoped search with citations. Minor gaps exist around discovering available chip models or document lists, but agents can likely work around them using the general search tool.