多代理论文摘要系统

一个多代理系统,用于接收论文(PDF、URL或文本),分类到科学领域,提取结构化JSON并生成葡萄牙语批判性评论。

  • by ThyagoSnt
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 ThyagoSnt/Multi-Agent-Vector-Store-MCP-System

使用说明

论文摘要任务的多代理系统(多代理+矢量存储+OCR+MCP)

该存储库实现了构建多代理系统的技术挑战,该系统:

  1. 接收论文(本地PDF、URL或文本)。
  2. 将论文分为三个科学领域之一。
  3. 提取包含字段的JSON 确切地 匹配提示(包括 错字 在 artcle).
  4. 用葡萄牙语撰写批判性评论,强调优势、局限性和对有效性的威胁。

该系统由以下部分组成:

  • A. 向量存储 ChromaDB中有9篇论文(3个区域×每个区域3个PDF)。
  • 一 MCP服务器 暴露对该矢量存储的访问(search_articles, get_article_content).
  • A. 多代理管道 在LangGraph(分类器→ 提取器→ 审稿人)。
  • 可选的 OCR支持 当PDF没有嵌入文本时,通过文档。
  • 自动化测试 用于矢量存储和集成管道。
  • Makefile, Dockerfile,以及 docker编写 以简化设置和执行。

1.高层架构

汇总流程:

  1. 矢量数据库摄取

    • 按以下方式组织的PDF pdf_database/<area>/ (例如。, economy, med, tech).
    • 每个PDF都被拆分为 块 (chunk_size=1000, overlap=200).
    • 使用生成的嵌入 sentence-transformers/all-MiniLM-L6-v2.
    • 所有内容都被编入Chroma系列,名为 articles 在...之下 chroma_db/.
  2. MCP服务器(src/mcp_server/server.py)

    • 从读取配置 configuration/base.yaml.
    • 打开现有的色度索引。
    • 通过MCP显示两个工具:
      • search_articles(query: str, top_k: int) → 列表 {id, title, area, score}.
      • get_article_content(article_id: str) → {id, title, area, content}.
  3. 多代理系统(src/multi_agent_system)

    • 已实施 LangGraph.

    • 主要节点:

      • 分类器_节点
        将纸张分类到一个区域。
        使用:

        • 纸质文本(截断为4000个字符)。
        • 通过MCP检索上下文(search_articles 带有初始片段)。
      • 提取器节点
        读取论文(带有安全截断),并用模式填充JSON:

        {
          "what problem does the artcle propose to solve?": "",
          "step by step on how to solve it": ["", "", ""],
          "conclusion": ""
        }
        

        钥匙在 相同的 提示,包括 artcle.

      • 审阅者_节点
        使用论文文本中提取的JSON+部分生成葡萄牙语评论(Markdown)。

    • 该图为:
      start → classifier → extractor → reviewer → END.

  4. 用户输入(scripts/run_agents.py + src/pipeline/pipeline_runner.py)

    • 接受:
      • 本地路径 .pdf, .txt,或 .md.
      • 指向PDF的URL。
    • 将输入标准化并保存到 samples/input_article_N.ext.
    • 运行多代理管道(run_pipeline).
    • 生成:
      • samples/review_N.md 随着审查。
      • samples/output_N.json 和 {area, extraction, review_markdown}.

2.目录结构

概述:

.
├── chroma_db/               # Where the persistent ChromaDB vector index is stored
├── configuration/
│   └── base.yaml            # Central configuration file (paths, vector DB, MCP, LLM, etc.)
├── pdf_database/            # Local PDF base used as reference for the vector store
│   ├── economy/             # 3 economy papers
│   ├── med/                 # 3 medical papers
│   └── tech/                # 3 technology papers
├── samples/                 # Outputs generated when running the pipeline
│   ├── input_article_N.pdf  # Normalized inputs (PDF/URL/MD/TXT)
│   ├── output_N.json        # Structured output (area + extracted JSON + review)
│   └── review_N.md          # Critical review written by the agent
├── src/
│   ├── mcp_server/
│   │   └── server.py        # MCP server exposing tools backed by the vector store
│   ├── multi_agent_system/
│   │   ├── classifier_agent.py   # Agent that classifies the paper's area
│   │   ├── extractor_agent.py    # Agent that generates the JSON required by the challenge
│   │   ├── reviewer_agent.py     # Agent that writes the critical review
│   │   ├── graph.py              # LangGraph graph connecting the three agents
│   │   └── mcp_vector_client.py  # HTTP client that talks to the MCP server
│   ├── pdf_parser/
│   │   └── pdf_parser.py         # PDF reader (PyPDF + Docling OCR fallback when needed)
│   ├── pipeline/
│   │   └── pipeline_runner.py    # Orchestrates the full execution flow
│   └── vector_database/
│       ├── vector_database.py    # Vector store implementation (Chroma + embeddings)
│       └── ingestion_runner.py   # Handles ingestion of the 9 PDFs and index creation
├── scripts/
│   ├── database_ingestion.py     # Script to rebuild the vector database
│   └── run_agents.py             # CLI script to run the pipeline on a paper
├── tests/                        # Automated test suite
│   ├── test_vector_database.py
│   └── test_graph_pipeline.py
├── mcp.json                      # MCP manifest (for external MCP clients)
├── Makefile                      # Main commands (setup, index, tests, agents, mcp)
├── Dockerfile                    # Project Docker image
├── docker-compose.yml            # Docker Compose orchestration
├── requirements.txt              # Python dependencies
└── pytest.ini                    # Pytest configuration

3.要求

3.1.主要依赖关系

执行旨在运行 Docker容器内部。在主机上,您只需要:

  • 码头工人

  • Docker Compose

  • 环境变量或 .env 文件包含:

    GROQ_API_KEY=<your_groq_key>
    

(可选)如果您在配置了GPU和CUDA的计算机上运行,PyTorch和 sentence-transformers 将在容器内自动使用它。

3.2.环境变量

在项目根目录下,创建一个 .env 与:

echo "GROQ_API_KEY=YOUR_TOKEN_HERE" > .env

docker-compose.yml 已配置为加载此 .env 放入容器中。


4.使用Docker和Docker编写运行

所有依赖项安装、向量索引创建和管道执行都会发生 在…内 集装箱。

4.1.塑造形象

在项目根节点:

docker compose build

4.2.输入容器

要打开容器内的外壳,请执行以下操作:

docker compose run --rm summary-app bash

你会在 /app 在容器内,代码通过卷安装。


5.建立病媒库(吸收9篇论文)

仍然 集装箱内,运行:

make index

这 index 目标:

  1. 清洁 chroma_db/ 文件夹(如果存在)。
  2. 通过调用来重建完整的向量索引 scripts.database_ingestion.

内部:

  1. 阅读 configuration/base.yaml.
  2. 解决 pdf_database/ 和 chroma_db/.
  3. 创建一个 VectorDatabase 实例包含:
    • embedding_model="sentence-transformers/all-MiniLM-L6-v2"
    • chunk_size=1000
    • chunk_overlap=200
  4. 迭代下的每个子文件夹 pdf_database/:
    • 每个PDF都会被读取、文本提取、分块和索引。
  5. 将嵌入和元数据持久化到Chroma中(存储在 /app/chroma_db,其被安装到主机)。

6.OCR和PDF文本提取

这 PdfTextExtractor 班级(src/pdf_parser/pdf_parser.py)实施:

  1. 使用PyPDF进行提取

    • 用途 pypdf.PdfReader 和 page.extract_text() 逐页。
    • 如果它可以提取文本,则返回该内容。
  2. 通过Docling进行OCR回退(可选)

    • 如果 无文本 与PyPDF一起找到 enable_ocr=True,它尝试OCR。
    • 用途 docling.document_converter.DocumentConverter().convert(...).
    • 呼叫 export_to_text().
    • 如果仍然没有文本,它会提高 ValueError.

在管道中,默认情况下启用OCR .pdf 文件夹。


7.多代理管道(LangGraph)

图表存在于 src/multi_agent_system/graph.py.组件:

  • 分类器代理(classifier_agent.py)

    • 通过列出下的子文件夹来发现区域 pdf_database/ (例如。, economy, med, tech).
    • 将纸张文本截断为 max_article_chars (4000个字符)。
    • 使用MCP客户端(MCPVectorStoreClient)拨打电话 search_articles 带有初始片段(mcp_query_chars,800个字符)。
    • 从向量存储点击中构建文本上下文。
    • 致电Groq LLM:
      • 在中配置的系统提示 MultiAgentConfig.
      • 包含截断的纸张文本+类似纸张列表的人工消息。
    • 将输出规范化为已知区域(精确匹配、子字符串、同义词如“econ”)。
  • 提取剂(extractor_agent.py)

    • 接收 article_text (以及可选 area).

    • 将文本截断为 max_article_chars (6000).

    • 指示LLM返回 仅 JSON。

    • 用途 _extract_json_from_response 支持:

      • 原始JSON。
      • json ... 用栅栏围起来的街区。
    • 用途 _normalize_extraction 以确保:

      {
        "what problem does the artcle propose to solve?": "string",
        "step by step on how to solve it": ["string", "..."],
        "conclusion": "string"
      }
      
  • 审核代理(reviewer_agent.py)

    • 接收 area, extraction,以及 article_text.
    • 连载 extraction 转换为JSON字符串。
    • 将纸张截断为~4000个字符,以提供可选上下文。
    • 生成葡萄牙语评论,重点关注:
      • 新颖性/贡献。
      • 方法/实验设计。
      • 结果的有效性。
      • 对有效性和可重复性的威胁。
  • 图表(graph.py)

    • 国家: {"article_text", "area", "extraction", "review"}.
    • 订单:
      • start → classifier → extractor → reviewer → END.
    • 公共职能:
      • run_pipeline(article_text: str) -> Dict[str, Any].

8.MCP服务器

在 src/mcp_server/server.py:

  • 阅读 configuration/base.yaml:
    • 配置 pdf_root, chroma_path.
    • 配置 embedding_model, collection_name, chunk_size, chunk_overlap.
    • 配置 mcp.name, mcp.transport.
  • 实例化 VectorDatabase 使用这些设置。
  • 创建一个 FastMCP 服务器与 json_response=True.
  • 外露工具:
@mcp.tool()
def search_articles(query: str, top_k: int = 5) -> List[Dict[str, Any]]:
    ...
@mcp.tool()
def get_article_content(article_id: str) -> Dict[str, Any]:
    ...

8.1.MCP清单(mcp.json)

mcp.json 定义:

  • 服务器名称、标签、版本和描述。
  • 如何通过STDIO启动它:
{
  "servers": [
    {
      "name": "stdio",
      "transport": "stdio",
      "command": "python",
      "args": ["-m", "src.mcp_server.server"],
      "env": {
        "PYTHONPATH": "."
      }
    }
  ],
  "tools": [
    { "name": "search_articles", ... },
    { "name": "get_article_content", ... }
  ]
}

外部MCP客户端(如ChatGPT或IDE)使用它来发现如何与容器内的服务器通信。

8.2.内部MCP客户端(MCPVectorStoreClient)

src/multi_agent_system/mcp_vector_client.py:

  • 用途 mcp.ClientSession + stdio_client 将MCP服务器作为子进程启动:
    • 默认命令: python -m src.mcp_server.server 2>/dev/null.
  • 公共方法:
    • search_articles(query: str, top_k: int).
    • get_article_content(article_id: str).

换句话说,内部代理无法访问 VectorDatabase 直接;一切都通过MCP工具。


9.管道执行CLI(使用下面解释的Makefile)

src/pipeline/pipeline_runner.py:

  • ArticleSampleManager:

    • 阅读 samples/output_N.json 以发现下一个索引。
    • 将本地文件或下载URL复制到 samples/input_article_N.ext.
    • 计算路径 review_N.md 和 output_N.json.
  • ArticlePipelineRunner:

    • 解析来源→ 规范输入→ 阅读文本。
    • 呼叫 run_pipeline(article_text).
    • 保存 review_N.md 和 output_N.json.
    • 返回执行元数据。

10.自动化测试

10.1.运行测试(容器内)

随着 GROQ_API_KEY 在环境中可用(通过 .env):

make test

这 test 目标:

  1. 重建矢量数据库(scripts.database_ingestion).
  2. 跑 pytest.

10.2.测试

  • tests/test_vector_database.py:
    • 测试组块, search_articles,以及 get_article_content.
  • tests/test_graph_pipeline.py:
    • 图的端到端集成(run_pipeline)在PDF上。
    • 跳过如果 GROQ_API_KEY 未设置。

11.生成文件

可用的主要目标 集装箱内:

make help
  • make index
    清洁 chroma_db/ 文件夹并从中重建完整的矢量索引 pdf_database/.

  • make test
    重建索引并运行 pytest.

  • make agent SOURCE=...
    在纸张(本地文件或URL)上运行多代理管道。
    示例:

    make agent SOURCE="samples/input_article_1.pdf"
    make agent SOURCE="https://example.com/paper.pdf"
    
  • make mcp
    在容器内的后台启动MCP服务器,将PID写入 .mcp_server.pid。这仅在您想将外部MCP客户端(如ChatGPT)连接到容器内运行的服务器时有用。

  • make stop-mcp
    停止通过启动的MCP服务器 make mcp.


12.Docker和Docker组合

Docker流程概述:

  1. 塑造形象 (在主机上):

    docker compose build
    
  2. 输入容器 (在主机上):

    docker compose run --rm summary-app bash
    
  3. 集装箱内部 (in /app):

    
    # 1) Build the vector index in chroma_db/
    make index
    
    # 2) Run the pipeline on an example paper
    make agent SOURCE="samples/input_article_1.pdf"
    
    # 3) Run tests
    make test
    
    # 4) Start MCP server in the background for external clients
    make mcp
    
    # ... use it from an external MCP client ...
    make stop-mcp
    

这 /app/chroma_db, /app/samples,以及 /app/pdf_database 文件夹作为主机卷装载,因此容器内生成的工件显示在本地项目树中。


13.快速总结

  1. 创建 .env 使用密钥(在主机上):

    echo "GROQ_API_KEY=YOUR_TOKEN_HERE" > .env
    
  2. 构建Docker镜像(在主机上):

    docker compose build
    
  3. 输入容器:

    docker compose run --rm summary-app bash
    
  4. 在容器内部,构建索引:

    make index
    
  5. 在示例上运行服务器和管道:

    make mcp
    make agent SOURCE="samples/input_article_1.pdf"
    
  6. 检查输出(来自主机或容器):

    • samples/output_N.json
    • samples/review_N.md

14.详细配置(base.yaml)--参数说明

以下是对 每个配置字段的作用 和 为什么选择它 在这个系统内。

mcp block:MCP服务器参数

mcp:
  name: "ArticleVectorStore"
  transport: "http"
  host: "0.0.0.0"
  port: 8000
  base_url: "http://127.0.0.1:8000"

✦ name: "ArticleVectorStore"

MCP服务器的逻辑名称。
仅用于外部MCP客户端的识别。
我们选择这个名字是因为服务器只公开一个矢量存储的论文。

✦ transport: "http"

定义MCP作为 HTTP服务器,不是STDIO。
这允许多代理系统使用正常的HTTP请求与MCP通信——更简单、更可预测、更容易调试。

✦ host: "0.0.0.0"

使服务器监听容器内的所有网络接口。
这是必需的,这样即使在单独的进程中运行,多代理系统也可以到达MCP。

✦ port: 8000

项目FastAPI/uvicorn服务器的默认端口。

✦ base_url: "http://127.0.0.1:8000"

MCP客户端使用的URL(MCPVectorStoreClient)发送请求。
即使服务器绑定到 0.0.0.0,客户端连接到 127.0.0.1 从容器内。

paths 块:主要路径

paths:
  pdf_root: pdf_database
  chroma_path: chroma_db

✦ pdf_root

包含用于构建矢量存储的9个PDF的目录。
我们选择了 <area>/<pdf> 结构,因为分类器通过列出子文件夹自动发现区域。

✦ chroma_path

ChromaDB保存其持久矢量数据库的目录。
保持简单,从项目根开始,通过以下方式简化版本控制和清理 make index.

vector_db 块:向量存储参数

vector_db:
  embedding_model: sentence-transformers/all-MiniLM-L6-v2
  collection_name: articles
  chunk_size: 1000
  chunk_overlap: 200

✦ embedding_model: all-MiniLM-L6-v2

一种快速、轻便的模型,被广泛推荐用于 语义相似度.
动机:

  • 比大型型号轻得多
  • 强大的嵌入功能,可缩短技术文本
  • 低延迟,是多代理管道的理想选择

✦ collection_name: articles

ChromaDB集合名称。
我们保持 articles 因为存储的内容完全是科学论文。

✦ chunk_size: 1000

每个PDF被分割成最多1000个字符的块。
此尺寸平衡:

  • 每个块有足够的上下文
  • 矢量搜索的良好粒度
  • 更快的嵌入生成

✦ chunk_overlap: 200

块之间有20%的重叠。
选择它是为了防止跨块边界的上下文丢失,这对较长的PDF尤为重要。

multi_agent block:LLM代理配置

multi_agent:
  llm:
    provider: groq
    model: openai/gpt-oss-120b
    temperature: 0.0

✦ provider: groq

我们使用 格罗克 以实现极低的延迟,减少整体管道响应时间。

✦ model: openai/gpt-oss-120b

Groq加速的OSS模型,具有以下强大的平衡:

  • 成本
  • 速度
  • 推理能力

根据经验,它为分类器、提取器和审阅者产生了最一致的结果。

✦ temperature: 0.0

完全确定的行为。
关键在于:

  • 自动化测试稳定
  • 无结构变化的JSON提取
  • 分类不会在运行中波动

代理提示

分类器提示

专注于选择 正好一个 这三个领域。
它可以访问以下输出 search_articles(),鼓励使用真实的矢量存储上下文。

提取器提示

强制LLM返回 仅 JSON包含:

  • 与提示相同的按键
  • 严格格式
  • 自信的循序渐进的解决方案

这 artcle 拼写错误被保留以遵循官方提示。

审阅者提示

在中生成完整的批判性评论 巴西葡萄牙语,有八个强制性部分。
它还引导模型识别纸张何时“超出区域”,与分类器行为相匹配。

主要依赖关系和基本原理

groq

低延迟LLM提供程序→ 减少了管道响应时间。

chromadb

简单高效的矢量存储,直接使用Python API。

句子变换器

语义搜索的高质量嵌入。

pypdf

第一阶段文本提取——快速且无本地依赖。

文档

现代OCR被用作没有嵌入文本的PDF的后备方案。

easyocr

Docling在某些场景中内部使用的互补依赖关系。

兰格拉夫

构建一个确定性和可重复的代理管道。

朗肯码头

Groq司机简化LLM呼叫。

fastapi+uvicorn

MCP服务器通过HTTP的轻量级基础设施。

皮丹提克

对所有MCP请求/响应进行严格验证。

测试

矢量存储和多代理管道的自动化测试。