Vivianmxmf/crucible-ai
GitHub: Vivianmxmf/crucible-ai
Crucible 是一个将原始网页经爬取、LLM 标注、混合 RAG 索引转化为受治理可查询数据集的端到端 AI 训练数据平台。
Stars: 0 | Forks: 0
# Crucible
[](https://crucible-ai-k00p.onrender.com/forge/login.html)
[](https://github.com/Vivianmxmf/crucible-ai/actions/workflows/ci.yml)


[](LICENSE)
Crucible 将原始网页直接转化为可查询、受治理的数据集:
隐身爬虫为 LLM 标注器提供数据,再由其驱动混合(稠密 + 稀疏)
检索引擎,所有这些均通过受 JWT 保护的 FastAPI 提供服务,并支持基于租户的隔离、速率限制和 Prometheus 可观测性。
## 演示

*针对实时 API 的完整 pipeline:创建账户 → 爬取(受 SSRF 防护) →
LLM 标注 → 索引语料库 → 混合 RAG 查询 → API 密钥 + playground。*
([MP4](docs/media/dataforge_demo.mp4) · 使用 `make demo` 自行运行。)
### 🔥 在线:**https://crucible-ai-k00p.onrender.com/forge/login.html**
创建一个账户(例如 `demo` / `demopass123`)并运行 pipeline。公开的
演示在**离线**环境下运行(FakeLLM + 内存 RAG,在 Render 免费层级的单个容器中
——闲置约 15 分钟后的首次请求冷启动耗时约 50 秒)。部署你自己的实例:
[](https://render.com/deploy?repo=https://github.com/Vivianmxmf/crucible-ai)
· 参见 [DEPLOY.md](DEPLOY.md)。
## 架构
生产环境拓扑结构(公开演示运行的是精简的离线子集 —— 参见
*[推迟项](#whats-deferred-to-the-server)*):
```
Crawl ──▶ Annotate ──▶ Embed & Index ──▶ Serve
```
| 层级 | 组件 |
|-------|-----------|
| **Web UI** | 无依赖的纯 JS "Editorial" SPA(6 个页面),与 API 同源部署 —— 无构建步骤 |
| **API** | FastAPI (async) · JWT 认证 · 基于 `owner_id` 的多租户 |
| **Queue** | Celery + Redis —— 异步爬取 / 标注任务 |
| **Crawl** | Playwright —— 隐身指纹 + SSRF 防护 |
| **Annotate** | LangChain + GPT-4o-mini(离线下为确定性的 FakeLLM) |
| **Stores** | Postgres(行记录) · Qdrant(稠密向量) + BM25(稀疏) |
`frontend/src/` 包含一个可选的 React 脚手架;实际发布的 UI 是上述的纯 JS SPA。
## 快速开始
一条命令即可启动 API + Editorial Web UI 并打开你的浏览器
(离线模式:FakeLLM + 内存向量,无需密钥/Docker/GPU):
```
make demo # serves UI + API at http://localhost:8899/forge/login.html (Ctrl+C stops both)
```
然后体验完整的 pipeline:**爬取 → 标注 → 索引 → 查询**。其他目标:
`make test` (pytest),`make loadtest` (Locust P95<200ms / 100+QPS 达标检测),
`make help`。
## 性能
使用 Locust 测量(带外播种以隔离服务路径,因此
这些数字反映的是请求处理能力,而非一次性的 bcrypt 注册):

| 指标 | 结果 |
|--------|--------|
| 峰值吞吐量 | **~609 req/s**(单 worker,32 个用户) —— 约为 100 QPS 目标的 6 倍 |
| 峰值 P95 | **54 ms** —— 比上限低约 4 倍的 200 ms |
| P95 < 200 ms 维持至 | **~576 req/s**(约 64 个用户);仅在接近 96 个用户时超过 200 ms |
| 失败率 | 跨越 **38,000+** 次请求为 **0**,包括 160 个用户的过载情况 |
## 模块
核心模块 —— 所有路径均位于 `backend/app/` 下:
| 领域 | 模块 | 功能描述 |
|------|--------|--------------|
| **API** | `api/routes/auth.py` | 注册 / 登录 → JWT (HS256) |
| | `api/routes/data.py` | 针对受 owner 作用域限制的 `DataItem` 进行 CRUD |
| | `api/routes/crawler.py` | 异步爬取 endpoint(Playwright 懒加载) |
| | `api/routes/annotation.py` | 对每个条目进行 LLM 自动标注 |
| | `api/routes/rag.py` | 混合 RAG 索引 + 查询(可选 HyDE) |
| **Crawler** | `crawler/playwright_crawler.py` | 真实 + Fake 浏览器后端 |
| | `crawler/anti_crawl.py` | UA 池、代理池、隐身初始化 JS |
| | `crawler/sign_generator.py` | MD5 / HMAC-SHA256 签名辅助工具 |
| | `crawler/url_guard.py` | SSRF 白名单 —— 环回 / RFC1918 / 元数据 IP |
| **RAG / LLM** | `llm/annotator.py` | FakeLLM(本地)或 LangChain + GPT-4o-mini(服务器) |
| | `llm/rag_service.py` | BM25 ⊕ 向量 ⊕ RRF + reranker · 基于 owner 的配额 |
| | `llm/reranker.py` | Cosine(离线) / CrossEncoder(服务器,懒加载) |
| | `llm/ragas_lite.py` | 离线 RAGAS —— 忠实度、相关性、精确度 |
| **Vector DB** | `vectordb/in_memory.py` | 默认的进程内存储 |
| | `vectordb/qdrant_store.py` | 生产级 Qdrant 包装器(懒加载导入) |
## 本地设置(无需安装浏览器,无需调用 LLM)
```
bash scripts/setup_local.sh # creates .venv, installs lean deps
source .venv/bin/activate
PYTHONPATH=backend pytest -q # 120 tests
PYTHONPATH=backend python scripts/generate_sample_data.py
PYTHONPATH=backend uvicorn app.main:app --reload --app-dir backend
# 打开 http://localhost:8000/docs
```
重度依赖(Playwright + Chromium、sentence-transformers、mitmproxy、RAGAS、
Detoxify)**仅**由目标服务器上的 `scripts/server_migrate.sh` 安装。
它们都不会在本地测试循环中运行。
## 服务器设置(Postgres + Redis + Qdrant + Celery)
```
git clone https://github.com/Vivianmxmf/crucible-ai.git && cd crucible-ai
export DATAFORGE_SECRET_KEY=$(openssl rand -hex 32)
bash scripts/server_migrate.sh # docker compose up db/redis/qdrant + alembic upgrade head
docker compose up -d api worker frontend
```
`scripts/server_migrate.sh` 会在 compose 网络**内部**针对
Postgres 运行 Alembic(不是本地 SQLite 路径),因此部署的 schema 是权威的。
## API 接口
| 方法 + 路径 | 认证 | 备注 |
|-------------|------|-------|
| `POST /api/auth/register` | — | 用户名 + 密码(≤ 72 UTF-8 字节;bcrypt) · 受速率限制 |
| `POST /api/auth/token` | — | OAuth2 密码授权 → Bearer JWT · 受速率限制 |
| `GET /api/health/` | — | 存活状态 |
| `GET /api/health/ready` | — | DB 就绪状态 |
| `GET /metrics` | — | Prometheus 展示 |
| `* /api/data/` | ✅ | CRUD,受 owner 作用域限制,复合唯一键 `(owner_id, url)` |
| `POST /api/crawler/run` | ✅ | 受 SSRF 防护的 Playwright 抓取 · 受速率限制 |
| `POST /api/annotation/{id}/run` | ✅ | FakeLLM(默认) / LangChain |
| `POST /api/rag/index` | ✅ | ≤ 200 个文档 · ≤ 50 KB / 文档 · 基于 owner 的配额 · 受速率限制 |
| `POST /api/rag/query` | ✅ | 混合检索,可选 HyDE |
## 安全模型
- 在 `local` / `test` 之外的环境中启动时,使用 HS256 的 JWT 会**拒绝占位符密钥**。
- bcrypt 哈希;超过 72 字节的密码会被预先拒绝(无静默截断)。
- 所有读取 + 写入 endpoint 均需 `Bearer` token;数据受 `owner_id` 作用域限制。
- 跨租户读取 / 写入返回 404,绝不泄露存在性。
- 爬取的 URL 通过带 DNS 解析的 `assert_safe_url` 处理,阻断
环回 / RFC1918 / 本地链路 / 多播 / 元数据 IP (AWS, GCP, Azure,
Alibaba ECS)。初始 URL 和重定向后的最终 URL 均会被
验证;Playwright 的 `context.route` 会重新检查每个子资源。注意
DNS 重绑定的 TOCTOU 窗口 —— 关于明确的限制,请参见 `backend/app/crawler/url_guard.py`。
## 可观测性与运维
- **速率限制**(slowapi)作用于易受滥用影响的路由(认证 + 写入),
支持代理识别:客户端 IP 是从 `--forwarded-allow-ips` 解析的,而不是
可伪造的原始 `X-Forwarded-For`。
- **指标**:在 `/metrics` 处提供 Prometheus 展示
(`prometheus-fastapi-instrumentator`)。
- **结构化日志**:每个请求输出一行 JSON,带有经过验证的
`X-Request-ID` 用于关联。
- **单容器部署**(`Dockerfile.demo` → Render / Fly):SPA + API 共享一个
单一 origin;如果启动时未注入 JWT 密钥,则会自动生成。
## 测试
```
PYTHONPATH=backend pytest -q backend/tests
# 120 个通过,0 个失败
```
测试仅限离线运行:
- 在 SQLite `:memory:` 上进行异步 SQLAlchemy(强制执行 FK pragma)
- 用于 Playwright 的 `FakeBrowserBackend`
- 用于 LangChain / sentence-transformers 的 `FakeLLM` + `fake_embed`
- 用于 Qdrant 的 `InMemoryVectorStore`
- 通过同步 sqlite3 进行 Alembic 迁移冒烟测试
| 类别 | 测试数 |
|----------|-------|
| 安全性 (JWT, bcrypt, 过期, 篡改) | 10 |
| URL 防护 / SSRF | 9 |
| 爬虫 (fake 后端, 工厂, 反爬, 签名) | 17 |
| 分块器 | 6 |
| 向量存储 | 5 |
| 标注器 + FakeLLM + 嵌入器 | 7 |
| 混合 RAG + RAGAS-lite | 13 |
| FastAPI endpoint (认证, 数据, 爬虫, RAG, 标注, 统计, 密钥) | 41 |
| 可观测性 (速率限制, `/metrics`, 日志) | 9 |
| 单一 origin 前端服务 | 2 |
| Alembic 冒烟测试 | 1 |
| **总计** | **120** |
## 推迟到服务器的功能
- 真实的 `playwright install --with-deps chromium` (≈ 300 MB)
- `langchain`, `langchain-openai`, `sentence-transformers`, `torch`, `qdrant-client`
- `mitmproxy`(JS 逆向工程练习)
- `ragas` + `datasets`(替换 RAGAS-lite)
- Detoxify(可选 GPU)
- 通过 `docker compose` 运行的 Postgres + Redis + Qdrant
唯一提交的数据文件是合成样本集
(`data/sample/pages.jsonl`, ~3 KB, 11 个页面)。
## 许可证
[MIT](LICENSE) © 2026 Weijia Han
标签:AI训练数据平台, AV绕过, BeEF, DLL 劫持, FastAPI, RAG, 后端开发, 大语言模型, 搜索引擎查询, 测试用例, 爬虫, 特征检测, 自定义请求头, 请求拦截, 逆向工具