基于MCP的LLM知识图检索
概述
LLM是强大的沟通者,但在需要连接、角色特定参与者或方向性的关系密集型事实上,它们仍然不可靠。传统的RAG提高了回忆能力,但保留了文本形式的知识;因此,约束和来源不是一流的。RDF知识图显式地编码实体和类型化边,而SPARQL为精确和可审计的查询提供了一种声明性语言。
我们研究了一种基于标准的集成,其中LLM在推理过程中通过模型上下文协议(MCP)发现并调用SPARQL工具。我们的系统公开了一个最小的SPARQL工具和模式/前缀资源;通过模式引导的提示将问题转换为SPARQL;结果(绑定)被反馈给模型,模型必须将其答案建立在这些绑定中。使用领域知识图作为案例研究,我们问:MCP介导的KG检索是否提高了以关系为中心的问题的准确性和归因?我们报告了它在哪里最有帮助,在哪里中断(端点错误、查询生成、歧义),以及使公共端点在实践中可用的操作护栏。
建筑
server.py — Entry point, MCP app, ASGI routing
tools/
__init__.py — Package docstring
shared.py — HTTP client, SPARQL execution, caching, linting, error codes
rhea.py — Rhea biochemical reaction tools
wikidata.py — Wikidata grounding + SPARQL execution tools运作原理
此MCP服务器将SPARQL查询工具暴露给LLM(如ChatGPT)。它支持两个知识图后端:
大黄(生物化学)
- 用于常见反应查找的预构建查询工具
- 描述中带有模式契约的自由形式SPARQL工具
维基数据(普通KG)
- 启动第一个工作流程:法学硕士必须致电
search_entity/search_property在编写SPARQL之前发现真实的QID和PID——防止产生幻觉的ID - 安全过梁:检查每个查询的LIMIT、阻塞构造(FROM/GRAPH/无界路径),并验证所有ID是否来自基础工具
- 试运行:首先使用LIMIT 1执行,以快速捕获语法错误
- 结构化错误:每次失败都会返回一个机器可读的错误代码(SYNTAX、TIMEOUT、RATE_LIMIT等)和一个修复提示
- TTL缓存:搜索结果和成功的查询将缓存在内存中,以避免重复调用
- 限速意识:在429秒时以指数回退自节流WDQS请求
工作流程
- 用户用自然语言提问
- LLM电话
search_entity/search_property地面ID - LLM仅使用接地ID写入SPARQL
run_sparql_wikidata棉绒→ 干运行→ 执行查询- 返回给LLM的结构化结果(或错误+提示)
- LLM的答案基于实际的查询结果
安装
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txt运行服务器
python server.py默认情况下,服务器在端口8080上运行(设置 PORT env变量要更改)。它在根路径上暴露了一个MCP端点 / 其可以通过模型上下文协议连接。
可用工具
维基数据——停飞
| 工具 | 说明 |
|---|---|
search_entity | 按文本查找QID(例如“阿尔伯特·爱因斯坦”→ Q937) |
search_property | 按文本查找PID(例如“的实例”→ 第31页) |
get_schema_context | 获取已知ID的标签、描述和数据类型 |
维基数据——执行
| 工具 | 说明 |
|---|---|
run_sparql_wikidata | Lint→ 干跑→ 对WDQS执行SPARQL |
normalize_sparql_error | 将错误消息分类为稳定代码+提示 |
debug_ping_wikidata | 测试WDQS连接 |
Rhea——查询
| 工具 | 说明 |
|---|---|
execute_sparql_rhea | 针对Rhea端点的自由形式SPARQL |
reactions_producing_product_from_substrate_names | 按底物查找反应→ 产品名称 |
reactions_by_ec | 按EC编号查找反应 |
find_reaction_by_equation_text | 按方程式文本搜索反应 |
children_of_reaction | 了解父母对孩子的反应 |
效用
| 工具 | 说明 |
|---|---|
fetch | 获取Rhea登录或URL的原始内容 |
debug_ping | 测试Rhea端点+HTTP/2状态 |
配置
环境变量:
| 变量 | 默认值 | 描述 |
|---|---|---|
RHEA_SPARQL | https://sparql.rhea-db.org/sparql | Rhea SPARQL端点 |
BIO_UA | GraphBio/3.0 (contact: ...) | HTTP请求的用户代理 |
BIO_HTTP2 | auto | HTTP/2切换: auto, on, off |
PORT | 8080 | 服务器侦听端口 |
可靠性特征
- 限制执行:如果缺失则注射,如果过高则加盖
- 被封锁的建筑:FROM、FROM NAMED、GRAPH、无界属性路径
- 服务允许列表:仅
SERVICE wikibase:label是允许的 - ID验证:SPARQL实体/属性必须来自接地工具输出
- 试运行:LIMIT 1执行在实际查询之前捕获语法错误
- 误差归一化:映射到SYNTAX/TIMEOUT/RATE_LIMIT/endpoint_ERROR/未知的原始端点错误
- 指数退避:WDQS 429响应自动节流
- 内存缓存:实体/属性搜索(10分钟)、模式(15分钟)、查询结果(5分钟)
- POST/GET回退:每个查询尝试4个HTTP方法来处理端点怪癖
备注
- 仅支持SELECT和ASK查询(CONSTRUCT/DESCRIBE被拒绝)
- WDQS速率限制激进;服务器自动节流以保持在限制范围内
- Wikidata的结果限制在500行以内,Rhea的结果限制为2000行
基准:QAWiki(黄金+文本→SPARQL)
金牌跑者(执行提供的SPARQL)
python3 -m benchmarks.qawiki_gold_runner \
--tsv qawiki-v1-simple-2025-09-09.tsv \
--out gold_full_100.csv \
--n 100 \
--timeout_ms 30000 \
--limit_cap 200Text→SPARQL运行器(LLM生成SPARQL,然后我们执行+评分)
所需的环境变量:
开放人工智能
LLM_PROVIDER:openaiOPENAI_API_KEY:您的API密钥(不提交)LLM_MODEL:型号名称(字符串)OPENAI_BASE_URL(可选):默认为https://api.openai.com/v1/chat/completions
Anthropic
LLM_PROVIDER:anthropicANTHROPIC_API_KEY:您的API密钥LLM_MODEL:例如。claude-3-5-sonnet-20241022ANTHROPIC_BASE_URL(可选):默认为https://api.anthropic.com/v1/messages
运行(OpenAI示例):
export LLM_PROVIDER=openai
export OPENAI_API_KEY="..."
export LLM_MODEL="..."
python3 -m benchmarks.qawiki_text2sparql_runner \
--gold_csv gold_full_100.csv \
--out_csv qawiki_pred_results.csv \
--n 100 \
--timeout_ms 30000 \
--limit_cap 200 \
--max_concurrency 1跑步者写道:
qawiki_pred_results.csv:每个问题的输出(预SPARQL、预答案、EM/F1、错误)benchmarks/logs/qawiki_text2sparql_.jsonl:提示+原始响应+每个项目解析的SPARQL
Web用户界面(Vercel上的Next.js)
这 web/ directory是一个Next.js应用程序,用于比较 MCP+LLM 对比 普通LLM 并排(同一模型,一个问题)。在Vercel上部署它 根目录 着手 web.复制 web/.env.example Vercel项目环境变量;集 MCP_SERVER_URL 将已部署的Python MCP源添加到MCP服务器 ALLOWED_HOSTS 因此421不会拒绝可流式传输的HTTP。
LLM API密钥 (OPENAI_API_KEY, ANTHROPIC_API_KEY)被阅读 仅限Next.js应用程序 当您在UI中选择提供者时。Python MCP服务器不调用OpenAI或Anthropic;它只公开SPARQL工具。
