内容
# PaperGraph AI
[](https://github.com/vsokoltsov/papergraph-ai/actions/workflows/ci.yml)
[](https://codecov.io/gh/vsokoltsov/papergraph-ai)
















## 问题描述

PaperGraph AI 帮助研究人员探索 OpenAlex 中的科学论文,并通过智能 AI 工作流。应用程序摄取论文元数据和摘要,将语义内容存储在 Qdrant 中,将论文关系存储在 Neo4j 中,并允许 LLM 代理结合向量检索和图上下文。
主要目标是回答研究问题,例如:
- 哪些论文讨论了特定话题?
- 论文如何按话题、来源、作者、机构或引用关系?
- 在检索到的论文集中,主要的研究方向是什么?
该系统围绕自动化摄取管道、智能检索层、评估脚本、反馈收集和 Grafana 监控仪表盘构建。
## 检索功能
PaperGraph AI 实现了以下检索功能:
- **混合搜索**:评估的 `vector_plus_graph` 方法首先从 Qdrant 检索语义匹配,然后用 Neo4j 图上下文丰富选定的 OpenAlex 论文。
- **用户查询重写**:代理具有 `rewrite_search_query` 工具,可以将自然语言问题转换为紧凑的检索查询,然后进行数据库搜索。
- **文档重新排序**:代理具有 `rerank_documents` 工具,可以使用问题项重叠和后端检索分数重新排序检索到的候选。
LLM 评估比较了 `vector_only`、`graph_only` 和 `vector_plus_graph` 方法,而检索评估比较了 Qdrant 向量搜索、Neo4j 图搜索和组合的向量加图策略。
研究代理本身作为显式的 LangGraph 工作流实现:
```text
重写查询 -> 检索文档 -> 重新排序文档 -> 获取图上下文 -> 生成答案
```
这使得工具使用可预测,防止不必要的重复检索调用,并使每个代理步骤在流式研究事件中可见。
## UI 接口
用户界面是一个 Streamlit 聊天应用程序。
它提供:
- 用于研究问题的聊天输入。
- 研究部分的实时代理进度。
- 从检索的论文上下文中生成的最终答案。
- 用于标记答案是否有用的反馈按钮。
- 从 FastAPI API 到 UI 的后端流式传输。
本地 URL:
- 🖥️ Streamlit UI:`http://localhost:8501`
- 🚀 FastAPI 后端:`http://localhost:8000`
- 📊 Grafana 仪表盘:`http://localhost:3000`
- 📈 Prometheus:`http://localhost:9090`
- 🧠 Neo4j 浏览器:`http://localhost:7474`
- 🔎 Qdrant API:`http://localhost:6333`
## 如何运行项目
安装依赖:
```bash
uv sync
```
启动基础设施:
```bash
docker compose up -d
```
运行迁移:
```bash
uv run alembic upgrade heads
```
使用 dlt 摄取 OpenAlex 论文:
```bash
uv run python -m app.ingestion.run "mathematics" --limit 10
```
在本地启动后端:
```bash
make backend
```
在本地启动 UI:
```bash
make ui
```
或者,API 和 UI 也包含在 `docker-compose.yml` 中,因此完整的 Docker 运行是:
```bash
docker compose up -d --build
```
运行检查:
```bash
make check
```
## API 契约
本地开发的基本 URL:`http://localhost:8000`。
### `GET /health`
检查 API 进程是否正在运行。
响应:
```json
{
"status": "ok"
}
```
### `POST /agent/runs`
运行研究代理并在运行完成后返回完整答案。
请求:
```json
{
"question": "哪些论文讨论了图检索增强生成?"
}
```
响应:
```json
{
"run_id": "29611bb8-d0cd-4546-90e4-5cc39b405b58",
"answer": "摘要...\n\n关键论文...",
"events": [
{
"type": "run_start",
"input": {
"question": "哪些论文讨论了图检索增强生成?"
}
},
{
"type": "tool_start",
"tool": "search_vector_database",
"input": {
"query": "图检索增强生成",
"limit": 5
}
},
{
"type": "tool_end",
"tool": "search_vector_database",
"output": {
"count": 5
}
},
{
"type": "run_end",
"output": {
"answer": "摘要...\n\n关键论文..."
}
}
]
}
```
### `POST /agent/runs/stream`
运行研究代理并以服务端事件流式传输进度。请求正文与 `POST /agent/runs` 相同。
请求:
```json
{
"question": "哪些论文讨论了图检索增强生成?"
}
```
每个流式传输的项目都作为 SSE `data:` 事件发出,包含 JSON:
```text
data: {"type":"status","message":"Running agent"}
data: {"type":"agent_event","event":{"type":"tool_start","tool":"search_vector_database","input":{"query":"图检索增强生成","limit":5}}}
data: {"type":"done","run_id":"29611bb8-d0cd-4546-90e4-5cc39b405b58","answer":"摘要...\n\n关键论文...","events":[...]}
```
在失败时,流式传输发出:
```text
data: {"type":"error","message":"错误信息"}
```
### `POST /feedback`
存储用户对已完成代理运行的反馈。
请求:
```json
{
"run_id": "29611bb8-d0cd-4546-90e4-5cc39b405b58",
"rating": "thumbs_up",
"comment": "有用的答案,包含相关论文。"
}
```
`rating` 必须是 `thumbs_up` 或 `thumbs_down`。`comment` 是可选的。
响应:
```json
{
"status": "ok"
}
```
## MCP 服务器
PaperGraph AI 公开了一个本地 MCP 服务器,以便 MCP 兼容的客户端可以使用与 API 和 UI 相同的论文搜索、图上下文、摄取和代理工作流。
使用标准输入输出传输运行:
```bash
make mcp
```
可用的 MCP 工具:
- `search_papers`:对存储的 Qdrant 论文标题和摘要进行语义搜索。
- `search_paper_graph`:对存储的 Neo4j 论文元数据和关系进行关键字搜索。
- `get_paper_graph_context`:OpenAlex 论文 ID 的图上下文查找。
- `ingest_openalex_papers`:搜索 OpenAlex 并将结果存储在 Qdrant 和 Neo4j 中。
- `ask_papergraph`:运行完整的 PaperGraph 研究代理并返回答案和事件。
当启用 Logfire 时,MCP 工具调用会发出结构化的 `mcp.*` 跨度,并带有有界查询/问题属性和结果计数。
建议的提交拆分:
- `Add MCP SDK dependency`:`pyproject.toml`、`uv.lock`
- `Add PaperGraph MCP server`:`app/mcp.py`、`tests/test_mcp.py`
- `Document MCP server command`:`Makefile`、`README.md`
## 可观察性
本地可观察性使用 Prometheus、Grafana 和 Tempo 来自 `docker-compose.yml`。
外部可观察性也可以发送到 Pydantic Logfire。 在 `.env` 中设置 Logfire 编写令牌:
```bash
LOGFIRE_ENABLED=true
LOGFIRE_TOKEN=your-logfire-write-token
```
`LOGFIRE_TOKEN` 是官方的 Logfire 环境变量。应用程序还接受 `LOGFIRE_API_KEY` 以兼容旧的本地 `.env` 文件。
启用时,应用程序配置 Logfire 一次,在 `app/tracing.py` 中,仪器 FastAPI 请求、HTTPX 调用、OpenAI SDK 调用和失败的 Pydantic 验证,并将现有的 OpenTelemetry 跨度转发到 Logfire。 如果 `OTEL_TRACING_ENABLED=true`,相同的跨度也会导出到用于 Tempo 的本地 OTLP 端点。
## LLM 评估
项目使用课程风格的 LLM 评估流程:
1. 将论文摄取到 Qdrant 和 Neo4j 中。
2. 使用 `app/eval/llm/llm_dataset.json` 中提交的冻结地面实况示例。
3. 为每个评估问题运行真正的 PaperGraph 代理。
4. 使用 LLM 评估者比较生成的代理答案与地面实况答案。
5. 使用相同的评估者评估代理轨迹,即在生成最终答案之前调用的工具。
生成的地面实况数据集具有以下形状:
```json
{
"question": "这篇论文对图检索有什么看法?",
"answer_orig": "从源论文数据生成的地面实况答案。",
"document": "https://openalex.org/W..."
}
```
`answer_orig` 是预期的答案。 `answer_agent` 通过运行实际的应用程序代理后生成。 评估器发送两个答案、原始问题、源文档 ID 和记录的工具调用到评估器。
### 比较方法
LLM 评估比较了三种检索/工具使用变体:
- `vector_only`:代理只能使用 Qdrant 向量搜索。
- `graph_only`:代理只能使用 Neo4j 图搜索和图上下文。
- `vector_plus_graph`:代理首先使用 Qdrant 向量搜索,然后为返回的 OpenAlex ID 使用 Neo4j 图上下文。
评估摘要报告了每种方法按 `answer_good_rate` 和 `trajectory_good_rate`。 应从当前评估输出中选择最佳方法。 目前,`vector_only` 是默认基准,而 `vector_plus_graph` 在不增加不必要的工具调用的情况下,有助于图上下文提高答案质量。
冻结数据集故意混合直接论文问题、语义释义和跨论文图上下文问题。 这避免了仅评估确切的标题或摘要关键字查找。 图上下文问题要求代理按主题、应用领域和关系样式上下文比较论文,这是 `vector_plus_graph` 相对于纯向量搜索应该具有优势的地方。
### 本地运行
启动数据库并运行迁移:
```bash
docker compose up -d qdrant neo4j postgres
uv run alembic upgrade heads
```
摄取论文:
```bash
uv run python -m app.cli "知识图谱检索增强生成" --limit 10
```
从提交的冻结数据集中运行廉价的 LLM 烟雾评估:
```bash
uv run python -m app.eval.llm.evaluate \
--dataset app/eval/llm/llm_dataset.json \
--output-format markdown \
--limit 2 \
--approaches vector_only vector_plus_graph
```
在需要基准数字时,在本地运行完整的 LLM 评估:
```bash
uv run python -m app.eval.llm.evaluate \
--dataset app/eval/llm/llm_dataset.json \
--output-format markdown
```
使用相同的评估器运行写入 Markdown 和 JSON 工件:
```bash
uv run python -m app.eval.llm.evaluate \
--dataset app/eval/llm/llm_dataset.json \
--output-format markdown \
--output-dir eval-results
```
要重新生成候选地面实况数据,请先摄取聚焦查询,然后运行:
```bash
uv run python -m app.eval.llm.ground_truth.evaluate \
--source qdrant \
--limit 10 \
--questions-per-document 1 \
--output app/eval/llm/generated_dataset.json
```
生成的 dataset 和评估输出被 Git 忽略。 提交的 LLM 数据集故意冻结,以便 CI 运行可以在构建之间进行比较。 如果重新生成的数据集更好,请在手动审查后替换 `app/eval/llm/llm_dataset.json`。
### CI
GitHub Actions 在测试后运行 `llm-eval` 作业。 作业启动 Qdrant 和 Neo4j,运行迁移,摄取一批聚焦的 Graph RAG 论文,对冻结的数据集运行 LLM 评估器,将 Markdown 摘要写入 Actions 摘要,并上传评估器运行生成的 JSON/Markdown 工件。
推送和拉取请求构建仅运行烟雾 LLM 评估:两个问题和 `vector_only` / `vector_plus_graph` 方法。 使用手动 `workflow_dispatch` 运行并设置 `llm_eval_mode=full` 以进行完整的 LLM 基准测试。
作业标记为 `continue-on-error`,因为它依赖于外部服务和 API 密钥。 这使得在环境可用的情况下,正常的 CI 运行仍然有用,同时在环境可用时生成评估工件。