内容
# 🏦 RAG 银行监管代理 — V.2.0 (POC 工业化)






> **多个免费 LLM(Ollama,Gemini)编排代理,应用于法国/欧洲银行法规,支持 MCP(服务器 + 客户端)和云端部署(Docker,Kubernetes,CI/CD,监控)。**
> ⚠️ **状态:POC / 技术演示。** 该项目展示了 AI 工程模式(混合 RAG、LLM 路由、MCP、可观测性)。未经额外安全审查,不得用于银行生产环境。参见 [SECURITY.md](./SECURITY.md)。
该项目从简单的 RAG 管道(`ingest.py` / `query.py` / `evaluate.py` 脚本)演化为 **工业化代理**:
- 🧠 **LLM 编排**:智能路由 + 自动降级,在 Ollama(免费,本地)、Gemini(免费层)和 OpenAI(可选,付费)之间
- 🔌 **MCP(模型上下文协议)**:RAG 作为 **MCP 服务器**(可从 Claude Desktop 或任何 MCP 客户端使用),代理可以消费 **外部 MCP 服务器**作为工具
- 🌐 **REST API**(FastAPI),带有密钥身份验证、健康检查和 Prometheus 指标
- 🐳 **容器化**(Docker 多阶段构建,docker-compose)
- ☸️ **云端就绪**:Kubernetes 清单(Deployment、HPA、PDB、Ingress、ConfigMap/Secret)
- 🔁 **CI/CD**:GitHub Actions(lint → 测试 → 构建 → 推送到注册表 → Kubernetes 部署)
- 📊 **可观测性**:结构化 JSON 日志(structlog)、Prometheus 指标、Grafana 仪表盘
---
## 🏗️ 架构
```
┌─────────────────────────────────────────┐
│ 客户端 │
│ REST API · Claude Desktop (MCP) · │
│ 其他 MCP 代理 │
└───────────────┬───────────────────────────┘
│
┌──────────────────────────┼──────────────────────────┐
▼ ▼ │
┌───────────────────┐ ┌────────────────────────┐ │
│ FastAPI 接口 │ │ MCP 服务器 │ │
│ /query /ingest │ │ rag_search / rag_answer│ │
│ /health /metrics │ └────────────┬────────────┘ │
└──────────┬──────────┘ │ │
└──────────────┬──────────────┘ │
▼ │
┌─────────────────────────┐ ┌──────────────────────────┐
│ 编排器(代理) │◀──────▶│ MCP 客户端(工具 │
│ - RAG 检索 │ │ 外部:网络、文件、 │
│ - 工具选择 │ │ Slack、Drive...) │
│ - 提示构造 │ └──────────────────────────┘
└────────────┬──────────────┘
▼
┌─────────────────────────┐
│ RAG 检索器 │
│ FAISS(稠密)+ BM25 │
│ (稀疏)→ RRF 融合 │
└────────────┬──────────────┘
▼
┌─────────────────────────────────────┐
│ LLM 路由器 │
│ 策略:cost_first / quality_first│
│ Ollama(免费)→ Gemini → OpenAI │
│ 自动降级 │
└───────────────┬───────────────────────┘
▼
引用来源的回答
[文档.pdf, 页 X]
```
### LLM 路由决策
`LLMRouter`(`src/rag_agent/llm/router.py`)根据 `LLM_ROUTING_STRATEGY` 选择后端:
| 策略 | 尝试顺序 | 用例 |
|---|---|---|
| `cost_first`(默认) | Ollama → Gemini → OpenAI | 最小化成本,同时保持质量安全网 |
| `quality_first` | Gemini → Ollama → OpenAI | 优先考虑响应质量 |
| `ollama_only` | 仅 Ollama | 最大化保密性(无数据离开本地网络) |
| `gemini_only` | 仅 Gemini | 无 Ollama 基础设施可用 |
| `round_robin` | 每次调用轮流 | 负载均衡 / A/B 测试 |
如果首选后端失败(不可用、超时、配额超限),路由器会 **自动尝试** 下一个后端 - 每次尝试都会记录(`llm_provider_failed`、`llm_call_succeeded`)以便可观测性。
---
## 📂 项目结构
```
rag-banking-agent/
├── src/rag_agent/
│ ├── config.py # 集中式配置(pydantic-settings)
│ ├── logging_config.py # 结构化 JSON 日志(structlog)
│ ├── cli.py # 统一 CLI(ingest/query/evaluate/serve/mcp-serve)
│ ├── llm/ # ── LLM 编排 ──
│ │ ├── base.py # 共同接口(策略模式)
│ │ ├── ollama_provider.py # 免费本地后端
│ │ ├── gemini_provider.py # 免费 API 后端
│ │ ├── openai_provider.py # 可选付费后端
│ │ └── router.py # 自动选择 + 降级
│ ├── rag/ # ── RAG 管道 ──
│ │ ├── ingest.py # 解析 → 分块 → 嵌入 → FAISS
│ │ ├── retrieval.py # 稠密 + BM25 + RRF
│ │ └── prompts.py # 系统提示(引用 + 放弃)
│ ├── agent/ # ── 编排器 ──
│ │ ├── orchestrator.py # RAG + 工具 + LLM 路由器,统一接口
│ │ └── tools.py # 工具注册(RAG、外部 MCP)
│ ├── mcp/ # ── 模型上下文协议 ──
│ │ ├── server.py # 将 RAG 暴露为 MCP 服务器
│ │ └── client.py # 消费外部 MCP 服务器
│ ├── api/ # ── REST API ──
│ │ ├── main.py, routes/, schemas.py, metrics.py, dependencies.py
│ └── evaluation/ # ── 评估 ──
│ ├── test_set.py # 15 个测试问题
│ └── evaluate.py # Precision@k + 保真度 + 使用的提供商
├── tests/ # 单元测试 + API 集成测试(pytest)
├── deploy/
│ ├── docker/ # Dockerfiles(API + MCP),多阶段构建
│ ├── docker-compose.yml # 完整的本地环境
│ ├── k8s/ # Kubernetes 清单(云端就绪)
│ └── monitoring/ # Prometheus 配置
├── .github/workflows/ci-cd.yml # 完整的 CI/CD 管道
├── scripts/download_corpus.py # 下载 + 生成合成语料库
├── Makefile # 命令快捷方式
└── requirements.txt / requirements-dev.txt
```
---
## 🚀 快速启动(本地,无 Docker)
```bash
# 1. 安装(Linux/Mac)
python -m venv .venv && source .venv/bin/activate
make install-dev
# Windows:
# python -m venv .venv && .venv\Scripts\Activate.ps1
# pip install -r requirements.txt
# 2. 配置
cp .env.example .env
# 编辑 .env:填写 GEMINI_API_KEY(https://aistudio.google.com/apikey 的免费层)
# 和/或安装 Ollama(https://ollama.com)+ `ollama pull mistral`
# 3. 准备语料库
make download-corpus
# 4. 索引
make ingest
# 5. 在 CLI 中查询代理
make query Q="什么是巴塞尔 III 规定的最低 CET1 比例?"
# 6. 启动 API
make serve
# → http://localhost:8000/docs(Swagger UI)
# 7. 启动 MCP 服务器(例如:用于 Claude Desktop)
make mcp-serve
```
### 评估
```bash
make evaluate
# → Precision@k、忠实度(关键词覆盖率)、LLM 提供商使用率
# (有助于权衡成本/质量)
```
---
## 🐳 使用 Docker Compose 启动(API + MCP + Ollama + 监控)
```bash
export GEMINI_API_KEY=your_key_here # 可选但推荐作为备用
docker compose -f deploy/docker-compose.yml up --build -d
# 在容器中下载 Ollama 模型
docker compose -f deploy/docker-compose.yml exec ollama ollama pull mistral
# 索引语料库(映射到 API 容器中)
curl -X POST localhost:8000/ingest
# 查询
curl -X POST localhost:8000/query -H "Content-Type: application/json" \
-d '{"question": "法国银行有哪些 LCB-FT 义务?"}'
```
访问:
- API + Swagger:http://localhost:8000/docs
- Prometheus:http://localhost:9090
- Grafana:http://localhost:3000(admin/admin)
- MCP 服务器(SSE):http://localhost:8765
---
## ☸️ Kubernetes 部署
```bash
# 1. 构建并推送镜像(或让 CI/CD 处理)
docker build -f deploy/docker/Dockerfile -t ghcr.io/your-org/rag-banking-agent-api:latest .
docker build -f deploy/docker/Dockerfile.mcp -t ghcr.io/your-org/rag-banking-agent-mcp:latest .
# 2. 配置密钥(不要提交真实值)
cp deploy/k8s/secret.example.yaml deploy/k8s/secret.yaml
# 编辑 secret.yaml 并输入真实密钥,然后:
kubectl apply -f deploy/k8s/secret.yaml
# 3. 部署其余部分
make k8s-apply
```
部署包括:
- **至少 2 个 API 副本**,带有 `HorizontalPodAutoscaler`(2→8,根据 CPU/内存)
- **PodDisruptionBudget**,以确保节点更新期间的可用性
- **Liveness/Readiness 探针**,位于 `/health/live` 和 `/health/ready`
- **PersistentVolumeClaims**,用于 FAISS 索引和语料库
- **Ingress** TLS(通过 cert-manager)用于外部暴露
- CI/CD 管道(`.github/workflows/ci-cd.yml`)自动构建、推送和部署到 `main`
---
## 🔌 通过 MCP 使用
### 作为 MCP 服务器(RAG 暴露给 Claude Desktop 或任何 MCP 客户端)
在 MCP 客户端配置中添加(例如 `claude_desktop_config.json`):
```json
{
"mcpServers": {
"rag-banking-regulatory": {
"command": "python",
"args": ["-m", "rag_agent.mcp.server"],
"env": { "PYTHONPATH": "/path/to/rag-banking-agent/src" }
}
}
}
```
然后可以使用两个工具:`rag_search`(原始摘录 + 来源)和 `rag_answer`(完整回答 + 引用)。
### 作为 MCP 客户端(代理使用外部工具)
在 `.env` 中配置 `MCP_CLIENT_SERVERS_JSON`:
```json
[{"name": "filesystem", "url": "http://localhost:8001/sse"}]
```
代理可以注册一个 `Tool`(参见 `agent/tools.py`),它通过 `MCPClientManager.call_tool(...)` 调用此服务器,并在关键字触发时自动触发(可扩展到由 LLM/function-calling 控制的路由)。
---
## ⚠️ 已知限制和演进路径
| 限制 | 详情 | 演进路径 |
|---|---|---|
| 关键词路由 | MCP 工具选择是启发式的,不是 LLM 驱动的 | 切换到结构化 function-calling(JSON 模式),由 LLM 驱动 |
| 演示语料库 | ~5 个合成文档 + 2 个公共 PDF | 扩展到真实的 ACPR 循环 |
| 同步摄入 | `/ingest` 阻止 HTTP 请求 | 转换为异步作业(Celery/Argo Workflows)并跟踪状态 |
| Kubernetes 中的 Ollama | 需要具有足够 CPU/RAM(甚至 GPU)的节点 | 为更重的模型准备 `nodeSelector`/GPU 池 |
| 无响应缓存 | 每个问题都会重新运行检索 + LLM | 添加语义缓存(Redis + 嵌入)用于频繁问题 |
| FAISS IndexFlatIP | 详尽搜索 O(n) | 切换到 IndexIVFFlat 或 HNSW 以支持超过 100K 向量 |
## 📂 重要文件
| 文件 | 角色 |
|---|---|
| [SECURITY.md](./SECURITY.md) | 安全策略和已知风险(POC) |
| [CONTRIBUTING.md](./CONTRIBUTING.md) | 贡献指南和代码标准 |
| [.env.example](./.env.example) | 环境变量(带有警告) |
| [guide\_local\_use.md](./guide_local_use.md) | 本地使用指南 + 6 个 I/O 流详解 |
## 📜 许可证和源码
- **代码**:MIT
- **语料库**:公共文档(ACPR、Banque de France、EBA)+ 明确标记为 `Synthetic_*` 的合成文档。无客户或机密数据。