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绕过, 请求拦截, 逆向工具