mcpField
M
mcpRAG

mcpRAG

本地服务
github.com/rajagopal17AI 与智能体147 周前更新

关于 mcpRAG

mcpRAG 是一个文档问答流程,结合本地 Ollama 嵌入、FAISS 检索和 Gemini 生成。适用于希望索引文本文件、查询内容并逐步添加文档的用户。

主要功能

  1. 01使用 Ollama 生成嵌入
  2. 02使用 FAISS 建立向量索引
  3. 03通过 Gemini 回答问题
  4. 04增量添加文档而无需重建索引
  5. 05在本地保存分块元数据

适用场景

  1. 01查询一组 TXT 文档
  2. 02为 SAP 文档构建 RAG 系统
  3. 03向现有索引添加新文件

MCP 相关

项目说明其 MCP 服务用于 Agent 场景,但提供的 README 未说明 MCP 工具或接口。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

暂未收录安装方式

我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。

代码仓库

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

mcpRAG - 检索增强生成系统

一个可用于生产环境的 RAG(检索增强生成)实现,结合了开源嵌入、FAISS 向量数据库和 Gemini LLM,可准确回答基于文档的问题。

概览

本项目实现了完整的 RAG 流水线,可用于查询文本文件,使用:

  • 嵌入:通过 Ollama 使用 Nomic 嵌入(本地、开源)
  • 向量数据库:FAISS(Facebook AI Similarity Search)
  • LLM:Gemini 2.0 Flash(快速、经济高效)
  • 文档处理:通过带重叠的分块保留上下文
  • 增量更新:添加新文档,无需重建整个索引

架构

Documents (TXT) → Chunking (60 words, 10-word overlap)
                ↓
         Nomic Embeddings (Ollama, 768 dimensions)
                ↓
         FAISS Vector Index (L2 distance similarity)
                ↓
User Query → Query Embedding → FAISS Search → Top-K Chunks
                                              ↓
                                     Context + Query → Gemini LLM
                                              ↓
                                           Answer

主要功能

  • 本地嵌入:使用 Ollama 和 Nomic 模型生成嵌入,无需调用外部 API
  • 高效搜索:使用 FAISS IndexFlatL2 进行快速相似度搜索
  • 分块策略:每块 60 个单词,重叠 10 个单词,以保留上下文
  • 增量更新:appendEmbeds.py 可添加新文档,无需重建
  • 元数据跟踪:存储文档名称、分块 ID 和分块文本,便于追溯
  • 持久化存储:在本地保存索引和元数据,以便重复使用

安装

前提条件
  • Python 3.11+
  • 已在本地安装并运行 Ollama
  • Gemini API 密钥
  • 已在 Ollama 中下载 Nomic 嵌入模型
设置
  1. 安装 Ollama(如果尚未安装):
# macOS/Linux
curl -fsSL https://ollama.ai/install.sh | sh

# Windows
# Download from https://ollama.ai/download
  1. 拉取 Nomic 嵌入模型:
ollama pull nomic-embed-text

验证 Ollama 是否正在运行:

curl http://localhost:11434/api/embeddings -d '{"model":"nomic-embed-text","prompt":"test"}'
  1. 克隆项目并进入项目目录:
cd mcpRAG
  1. 创建虚拟环境并安装依赖项:
python -m venv .venv

# Windows
.venv\Scripts\activate

# macOS/Linux
source .venv/bin/activate

pip install -r requirements.txt
  1. 配置 API 凭据:

创建一个 .env 文件:

GEMINI_API_KEY=your_gemini_api_key_here

在 Google AI Studio 获取 API 密钥。

  1. 准备文档:

将 .txt 文件放入 docfiles/ 或 sapfiles/ 目录。

用法

1. 创建初始嵌入和索引

运行 ollamaEmbed.py,处理第一个文档并创建 FAISS 索引:

# Edit ollamaEmbed.py to set your document path
file_path = Path("C:\\path\\to\\your\\document.txt")

# Then run
python ollamaEmbed.py

功能:

  • 读取指定的文本文件
  • 将文本分成每块 60 个单词、重叠 10 个单词的片段
  • 使用 Ollama 的 Nomic 模型生成嵌入
  • 使用 L2 距离度量创建 FAISS 索引
  • 将索引保存到 my_faiss_index.faiss
  • 将元数据保存到 my_metadata.json

输出:

Processing document.txt...
✅ Indexed 142 chunks
✅ Saved FAISS index to my_faiss_index.faiss
✅ Saved metadata to my_metadata.json
2. 查询 RAG 系统

运行 ragModel.py,搜索索引并生成答案:

# Edit ragModel.py to set your query
query = "how does SAP integrate with other systems?"
top_k = 5  # Number of relevant chunks to retrieve

# Then run
python ragModel.py

功能:

  1. 加载 FAISS 索引和元数据
  2. 使用 Nomic 将查询转换为嵌入
  3. 在 FAISS 中搜索最相似的前 K 个分块
  4. 将检索到的上下文和查询传递给 Gemini 2.0 Flash
  5. 返回结合上下文的答案

输出示例:

Query: how does SAP integrate with other systems?

Result 1:
  Document: SAP_Joule.txt
  Chunk: SAP integrates with various external systems through APIs...
  Chunk ID: SAP_Joule_42
--------------------

Gemini Response: SAP integrates with other systems primarily through REST APIs
and OData services. The integration layer supports real-time data synchronization...
3. 向现有索引添加新文档

运行 appendEmbeds.py,以增量方式添加文档,无需重建索引:

# Edit appendEmbeds.py to set your new document path
new_file_path = "C:\\path\\to\\new_document.txt"

# Then run
python appendEmbeds.py

功能:

  • 加载现有 FAISS 索引和元数据
  • 处理新文档(分块和生成嵌入)
  • 将新嵌入追加到现有 FAISS 索引
  • 使用新分块更新元数据
  • 保存更新后的索引和元数据

输出:

Processing SAP_GENAI.txt...
✅ Added 87 new chunks to the index
✅ Saved updated FAISS index to my_faiss_index.faiss
✅ Saved updated metadata to my_metadata.json

项目文件

文件用途
ollamaEmbed.py初始文档处理、嵌入生成和 FAISS 索引创建
ragModel.py查询接口——搜索索引并使用 Gemini 生成答案
appendEmbeds.py向现有索引增量添加新文档
requirements.txtPython 依赖项
.envAPI 凭据(需创建此文件)
my_faiss_index.faiss已保存的 FAISS 向量索引(自动生成)
my_metadata.json包含文档名称和文本的分块元数据(自动生成)
docfiles/源文档目录
sapfiles/SAP 相关文档目录

配置

分块参数

在任意 Python 文件中调整:

CHUNK_SIZE = 60        # Number of words per chunk
CHUNK_OVERLAP = 10     # Overlapping words between chunks

建议:

  • 较小的块(30-50 个词):精确度更高,块数更多,索引速度更慢
  • 较大的块(80-100 个词):上下文更多,块数更少,索引速度更快
  • 重叠部分(10-20 个词):避免在块边界处丢失上下文
检索设置

在 ragModel.py 中调整 top_k:

top_k = 5  # Number of chunks to retrieve

建议:

  • top_k=3:速度快,回答聚焦
  • top_k=5:平衡(默认值)
  • top_k=10:上下文更全面,速度更慢
LLM 模型

在 ragModel.py 中更改 Gemini 模型:

model="gemini-2.0-flash"      # Fast, cost-effective (default)
model="gemini-1.5-pro"         # More capable, higher cost
model="gemini-1.5-flash"       # Balanced
嵌入模型

更改 Ollama 嵌入模型(需要拉取模型):

"model": "nomic-embed-text"     # 768 dimensions (default)
"model": "mxbai-embed-large"    # 1024 dimensions

如果更改模型,请删除现有的 .faiss 和 .json 文件并重新构建。

工作原理

1. 文档分块

文本会被拆分为相互重叠的块:

Original: "The quick brown fox jumps over the lazy dog..."

Chunk 1: "The quick brown fox jumps..." (words 0-60)
Chunk 2: "...fox jumps over the lazy..." (words 50-110, 10-word overlap)
Chunk 3: "...lazy dog runs through..." (words 100-160, 10-word overlap)
2. 生成嵌入

每个块都会通过 Ollama 转换为一个 768 维向量:

response = requests.post(
    "http://localhost:11434/api/embeddings",
    json={"model": "nomic-embed-text", "prompt": chunk}
)
embedding = np.array(response.json()["embedding"])  # Shape: (768,)
3. FAISS 索引

嵌入会存储在 FAISS IndexFlatL2(L2 距离)中:

dimension = 768
index = faiss.IndexFlatL2(dimension)
index.add(np.stack(all_chunks))  # Add all embeddings

FAISS IndexFlatL2 使用欧几里得距离:

  • 向量越接近(L2 距离越小)= 越相似
  • 穷举搜索可确保找到最佳匹配项
  • 对于多达约 100K 个向量,速度很快
4. 语义搜索

查询会转换为嵌入,并在索引中进行搜索:

query_embedding = get_embedding(query)  # Shape: (768,)
D, I = index.search(query_embedding.reshape(1, -1), top_k=5)
# D: distances, I: indices of most similar chunks
5. 生成答案

检索到的块会作为上下文传递给 Gemini:

context = "\n".join([metadata[i]["chunk"] for i in I[0]])
prompt = f"Query: {query}\n\nContext: {context}\n\nAnswer:"
response = client.models.generate_content(model="gemini-2.0-flash", contents=prompt)

示例工作流

场景:构建 SAP 文档 RAG 系统
  1. 初始设置,使用 SAP Joule 文档:
# Edit ollamaEmbed.py
file_path = Path("sapfiles/SAP_Joule.txt")

python ollamaEmbed.py
# Output: ✅ Indexed 142 chunks
  1. 查询系统:
# Edit ragModel.py
query = "What is SAP Joule?"

python ragModel.py
# Output: SAP Joule is an AI assistant that helps users...
  1. 添加更多文档:
# Edit appendEmbeds.py
new_file_path = "sapfiles/SAP_GENAI.txt"

python appendEmbeds.py
# Output: ✅ Added 87 new chunks to the index
  1. 使用扩展后的知识库进行查询:
# Query now searches across both documents
python ragModel.py

高级用法

批量处理多个文档

修改 ollamaEmbed.py 以处理一个目录:

from pathlib import Path

all_chunks = []
metadata = []

for file_path in Path("docfiles").glob("*.txt"):
    chunks, meta = process_document(file_path)
    all_chunks.extend(chunks)
    metadata.extend(meta)

# Then create index as usual
自定义相似度指标

将 IndexFlatL2 替换为其他 FAISS 索引:

# Inner product (for normalized embeddings)
index = faiss.IndexFlatIP(dimension)

# Approximate search (faster for large datasets)
index = faiss.IndexIVFFlat(quantizer, dimension, nlist=100)
多查询 RAG

使用经过优化的提示词多次查询:

queries = [
    "What is SAP Joule?",
    "How does SAP Joule integrate with SAP systems?",
    "What are the key features of SAP Joule?"
]

for query in queries:
    results = search_index(index, metadata, query, top_k=5)
    # Process results...

性能优化

适用于大型文档集合(>10K 个块)
  1. 使用 IVFPQ 索引(倒排文件与乘积量化):
nlist = 100  # Number of clusters
m = 8        # Number of subquantizers
quantizer = faiss.IndexFlatL2(dimension)
index = faiss.IndexIVFPQ(quantizer, dimension, nlist, m, 8)
index.train(embeddings)  # Training required
index.add(embeddings)
  1. 批量生成嵌入:
# Process chunks in batches
batch_size = 50
for i in range(0, len(chunks), batch_size):
    batch = chunks[i:i+batch_size]
    # Generate embeddings for batch...
加快查询速度
  1. 降低 top_k:检索更少的块(3 个而非 5 个)
  2. 使用 Gemini Flash:比 Pro 模型更快
  3. 缓存嵌入:存储查询嵌入,以便重复查询时使用

故障排除

Ollama 连接错误

错误:requests.exceptions.ConnectionError: Failed to establish a new connection

解决方案:

# Check if Ollama is running
curl http://localhost:11434/api/tags

# If not, start Ollama
ollama serve
找不到模型

错误:model 'nomic-embed-text' not found

解决方案:

ollama pull nomic-embed-text
ollama list  # Verify model is downloaded
FAISS 维度不匹配

错误:RuntimeError: Error in void faiss::IndexFlat::add_with_ids()

解决方案:删除现有的 .faiss 和 .json 文件并重新构建:

rm my_faiss_index.faiss my_metadata.json
python ollamaEmbed.py
Gemini API 错误

错误:google.api_core.exceptions.PermissionDenied: 403 API key not valid

解决方案:检查 .env 文件:

cat .env  # Should show: GEMINI_API_KEY=AIza...

从 Google AI Studio 获取新密钥

内存问题(大型文档)

错误:MemoryError: Unable to allocate array

解决方案:分批处理较小批次的文档,或使用降维:

# Use PCA to reduce dimensions
import faiss
pca_matrix = faiss.PCAMatrix(768, 256)  # Reduce to 256 dimensions
index = faiss.IndexFlatL2(256)

技术细节

FAISS IndexFlatL2
  • 算法:穷举搜索(蛮力搜索)
  • 指标:L2(欧几里得)距离
  • 准确率:100%(找到精确的最近邻)
  • 速度:O(N*D),其中 N=向量数量,D=维度
  • 适用范围:最多 1M 个 768 维向量
Nomic 嵌入
  • 模型:nomic-embed-text
  • 维度:768
  • 上下文长度:8192 个 token
  • 训练数据:数十亿个用于语义相似度的文本对
  • 许可证:开源(Apache 2.0)
分块策略

为什么采用 60 个词并重叠 10 个词?

  • 60 个词:约 300-400 个字符,符合典型语义单元(段落)的长度
  • 重叠 10 个词:避免在边界处丢失上下文
  • 结果:每个分块都包含一些来自相邻分块的上下文

权衡:

  • 重叠越多 → 上下文越好,存储需求越大
  • 重叠越少 → 处理越快,但可能出现上下文断层

与替代方案的比较

组件本项目替代方案
嵌入Ollama(本地、免费)OpenAI($0.0001/1K 个词元)
向量数据库FAISS(本地、快速)Pinecone/Weaviate(云端、$$)
LLMGemini Flash(廉价)GPT-4(昂贵)
存储本地文件云数据库
隐私嵌入保留在本地数据发送至 API

优点:

  • 成本更低(仅需支付 LLM API 调用费用)
  • 注重隐私(嵌入保留在本地)
  • 速度快(本地 FAISS 搜索)
  • 不受供应商锁定

缺点:

  • 需要配置 Ollama
  • 需要本地存储空间
  • 不支持内置扩展

扩展项目

添加 PDF 文档支持
pip install PyPDF2
import PyPDF2

def extract_text_from_pdf(pdf_path):
    with open(pdf_path, 'rb') as file:
        reader = PyPDF2.PdfReader(file)
        text = ""
        for page in reader.pages:
            text += page.extract_text()
    return text
添加对话记忆

存储对话历史并将其纳入上下文:

conversation_history = []
conversation_history.append({"role": "user", "content": query})
conversation_history.append({"role": "assistant", "content": response.text})
使用 Streamlit 添加 Web 界面
pip install streamlit
import streamlit as st

st.title("RAG Document Q&A")
query = st.text_input("Ask a question:")
if st.button("Search"):
    results = search_index(index, metadata, query, top_k=5)
    answer = generate_answer(results, query)
    st.write(answer)
部署为 MCP 服务

采用 MCP(模型上下文协议)模式进行集成:

  • 将 RAG 搜索作为 MCP 工具公开
  • 添加用于文档管理的资源
  • 参考 ../agenticMCP_rag/ 中的实现

参考资料

许可证

本项目是实验性 AI/ML 单体仓库的一部分。许可证详情请参阅根仓库。

相关项目

如需了解更高级的 RAG 实现,请参阅:

  • ../agenticMCP_rag/ - 集成 MCP 和 Agent 架构的 RAG
  • ../R_RAG/ - 另一种 RAG 实现
  • ../perceptionAgent/ - 采用感知-决策-行动模式的 Agent 架构

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。