Vivianmxmf/crucible-ai

GitHub: Vivianmxmf/crucible-ai

Crucible 是一个将原始网页经爬取、LLM 标注、混合 RAG 索引转化为受治理可查询数据集的端到端 AI 训练数据平台。

Stars: 0 | Forks: 0

# Crucible [![在线演示](https://img.shields.io/badge/demo-live-22c55e?logo=render&logoColor=white)](https://crucible-ai-k00p.onrender.com/forge/login.html) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/bddd516b5f210823.svg)](https://github.com/Vivianmxmf/crucible-ai/actions/workflows/ci.yml) ![Python](https://img.shields.io/badge/python-3.11+-3776AB?logo=python&logoColor=white) ![Tests](https://img.shields.io/badge/tests-120%20passing-brightgreen) [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE) Crucible 将原始网页直接转化为可查询、受治理的数据集: 隐身爬虫为 LLM 标注器提供数据,再由其驱动混合(稠密 + 稀疏) 检索引擎,所有这些均通过受 JWT 保护的 FastAPI 提供服务,并支持基于租户的隔离、速率限制和 Prometheus 可观测性。 ## 演示 ![Crucible 演示 — 登录 → 爬取 → 标注 → 索引 → 查询](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/46f0095d6e210829.gif) *针对实时 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 秒)。部署你自己的实例: [![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](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 注册): ![吞吐量与 P95 延迟](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/8e09ad9c41210835.png) | 指标 | 结果 | |--------|--------| | 峰值吞吐量 | **~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, 后端开发, 大语言模型, 搜索引擎查询, 测试用例, 爬虫, 特征检测, 自定义请求头, 请求拦截, 逆向工具