SallaguntaRaahul/ragsentry

GitHub: SallaguntaRaahul/ragsentry

一个采用真正 MCP 客户端/服务端架构的 RAG 智能体项目,集成了 LLM tool-calling、prompt 注入防御、自动化测试和 LLM 评估工具,旨在提供生产级 AI agent 的完整工程切片。

Stars: 0 | Forks: 0

# RagSentry 一个检索增强 agent,可以回答您上传文档的相关问题, 它使用**真正的 MCP (Model Context Protocol) 客户端/服务端对**来进行工具 调用,而不是在进程内直接调用检索函数。它旨在构建 当前 agent 技术栈中一个完整、真实的切片:MCP、RAG、LLM tool-calling、 prompt 注入防御、自动化测试以及独立的 LLM eval 工具。 ## 为什么真正采用 MCP 大多数“AI agent”的演示会跳过 MCP,直接在同一个 进程内调用检索函数——那是 RAG,而不是 MCP。RagSentry 没有这样做: [`app/mcp_server.py`](app/mcp_server.py) 是一个独立的 MCP 服务端(使用 `FastMCP` 构建),将 `search_documents` 和 `list_documents` 作为工具公开。 [`app/mcp_agent.py`](app/mcp_agent.py) 中的 FastAPI 请求处理器是 MCP *客户端*——它将服务端作为通过 stdio 通信的子进程启动,调用 `list_tools()` 来发现可用功能,将这些 schema 交给 LLM, 并通过 `session.call_tool(...)` 执行 LLM 决定调用的任何内容。 将 `search_documents` 替换为 SQL 工具、网络搜索工具,或者完全替换为第二个 MCP 服务端,agent 的循环逻辑都不会改变。 ## 架构 ``` Browser (static HTML/JS) │ ▼ FastAPI (app/main.py) ── sqlite (chat history) ── hand-rolled vector index │ (fastembed + numpy, on disk) ▼ mcp_agent.run_agent_turn() │ spawns subprocess, stdio transport ▼ mcp_server.py (FastMCP) ──tools──▶ search_documents / list_documents │ ▼ Groq chat completions (OpenAI-compatible, tool-calling loop, ≤3 rounds) ``` 每个工具的返回结果都会被扫描以检测 prompt 注入模式,并在重新进入 LLM 上下文之前, 被包裹在明确的“这是数据,不是指令”的隔离边界中(`app/security.py`)——这与 生产级 agent 框架所使用的不可信内容边界模式相同。 ## 已实现的功能与已知权衡 **已实现并经过测试:** - 通过 stdio 通信的真正 MCP 客户端/服务端(不是进程内的快捷方式) - 具有有限轮次预算的 LLM tool-calling agent 循环 - RAG:PDF/文本提取 → 具有重叠的段落感知分块 → fastembed embeddings → 手写的余弦相似度索引,持久化到磁盘 - 安全性:对每个工具结果进行基于正则表达式的 prompt 注入扫描、 不可信内容隔离、写接口的 API-key 认证、基于 IP 的速率 限制、密钥脱敏辅助程序 - 50 个 pytest 测试(默认有 49 个在离线/模拟环境下运行;1 个标记为 `integration` 的测试 用于验证真实的 stdio 传输 + fastembed 模型) - 独立的 eval 工具(`evals/`),针对黄金数据集对 *系统 prompt + 检索 + 模型* 的组合进行评分——使用真实的 LLM 调用, 而不是模拟的,因为这才是 eval 的意义所在 **已知的权衡(有意为之):** - 向量索引是一个手写的 numpy 余弦相似度存储,而不是 Chroma/pgvector/Pinecone——以保持 Docker 镜像和 Render 免费层级的 内存占用较小。其接口(`add_document`、`search`、 `delete_document`、`list_documents`)足够精简,以后可以在不触动 agent 或 API 层的情况下替换为真正的向量数据库。 - prompt 注入扫描器是基于正则表达式/模式的,而不是 LLM 分类器 或 Anthropic 的 Prompt Guard——它可以捕获评估集中 常见的措辞,但并不是一个完整的防御。生产系统会在其之上 叠加一个经过训练的分类器。 - Render 的免费层级具有临时文件系统:上传的文档和 聊天历史在重新部署/重启时会重置,除非您挂载付费的持久化 磁盘。这对于作品集演示来说没问题,在此特别指出,以免让您感到意外。 - 速率限制器是每个实例在内存中进行的——适用于单个免费层级 dyno,如果在负载均衡器后面,则需要共享存储(Redis)。 - 聊天接口本身没有认证(它是公开的演示界面); 提取/删除操作需要 `X-API-Key`,这样访问者就无法清空知识 库或通过任意上传来耗尽 Groq 的免费层级配额。 ## eval 工具与测试套件——为什么两者都需要 `pytest`(49 个测试,离线,模拟 LLM/MCP)检查*代码*行为是否 正确:分块边界、认证拒绝、速率限制计算、 注入扫描器的正则表达式、agent 循环的轮次预算截止。它回答了 “我是不是弄坏了什么”。 `evals/run_evals.py` 检查*系统*——prompt + 检索 + 实际的 Groq 模型——在包含 5 个案例的黄金数据集(基础检索、多文档检索、“语料库中没有答案” → 应该 拒绝而不是产生幻觉,以及两次真实的 prompt 注入尝试)中表现是否正确。它 发起真实的 API 调用并回答“agent 是否真的做了正确的 事情”,而这是模拟的单元测试在结构上无法回答的。 构建这个工具捕获到了两个值得一提的真实 bug,而不是掩盖它们: 第一次评分有 2/5 的案例失败,因为简单的关键词匹配器 在处理模型合理生成的 Unicode 字符时卡住了(弯引号,以及 “Maria Chen”中的窄不换行空格),还有一个注入案例的 “违禁短语”检查标记了模型在回答中*描述*了攻击, 而不是因为模型真的遵从了攻击。这两个都是评估工具的 bug, 而不是 agent 的 bug——通过在匹配前规范化 Unicode 标点符号,并检查实际的系统 prompt 泄露,而不是攻击者的触发词来修复。目前运行结果:**5/5 (100%)**,可通过以下命令复现。 ``` python -m evals.run_evals ``` ## 设置 ``` python3 -m venv .venv && source .venv/bin/activate pip install -r requirements.txt cp .env.example .env # fill in GROQ_API_KEY (free tier: https://console.groq.com/keys) pytest # 49 passed, fully offline uvicorn app.main:app --reload # 打开 http://localhost:8000 ``` 分别运行较慢的 stdio 传输集成测试和实时 eval 工具 (两者都需要网络 / Groq 密钥): ``` pytest -m integration python -m evals.run_evals ``` ## LLM 提供商 默认在 Groq 的免费层级上运行(`openai/gpt-oss-20b` —— 一个 专门为可靠的 tool-calling 训练的开源权重模型;早期 使用 `llama-3.3-70b-versatile` 进行测试时,经常遇到 Groq 的 `tool_use_failed` 错误,该错误由 格式错误的函数调用生成引起,其频率已到了不可忽视的地步)。其通信格式 兼容 OpenAI,因此更换提供商只需在 `app/config.py` 中更改 base-url 和 key。 ## API - `POST /api/documents`(需要 `X-API-Key`)——上传 `.txt`/`.md`/`.pdf`, 进行分块并 embedding 到索引中 - `GET /api/documents`——列出已提取的文档 - `DELETE /api/documents/{doc_id}`(需要 `X-API-Key`) - `POST /api/chat` `{message, session_id?}`——提问;运行完整的 MCP agent 循环,按 IP 进行速率限制 - `GET /api/chat/{session_id}/history` - `GET /health` ## 部署 (Render) 本仓库包含一个 `Dockerfile` 和 `render.yaml`。创建 Render 账户 以及实际的“New Web Service”点击操作需要您自己完成(这不是我能够 代替您做的事): 1. 将此仓库推送到 GitHub(如果您正在 GitHub 上阅读本文,则已完成)。 2. 在 [render.com](https://render.com) 上,**New → Web Service**,连接此 仓库。Render 将自动检测 `render.yaml` 和 `Dockerfile`。 3. 在 Render 仪表板中设置两个必需的环境变量: - `GROQ_API_KEY`——您在 console.groq.com 获取的专属密钥 - `APP_API_KEY`——您选择的任何字符串;用于控制文档的上传/删除 4. 部署。健康检查路径为 `/health`。 ## 技术栈 Python · FastAPI · MCP (`mcp` SDK, `FastMCP`) · Groq (兼容 OpenAI 的 tool-calling) · fastembed (ONNX, `BAAI/bge-small-en-v1.5`) · numpy · sqlite · pytest · Docker · Render
标签:AV绕过, FastAPI, LLM Agent, LLM安全防护, MCP, RAG, 人工智能, 安全规则引擎, 用户模式Hook绕过, 请求拦截, 逆向工具