Jakub-Syrek/GenericRagGenerator

GitHub: Jakub-Syrek/GenericRagGenerator

一个完全本地化的RAG服务,通过RESTful API对文档、代码仓库和多源项目进行索引、检索与基于引用的智能问答。

Stars: 0 | Forks: 0

# GenericRagGenerator [![100% 本地](https://img.shields.io/badge/100%25-LOCAL-16a34a?style=for-the-badge&logoColor=white)](#) [![REST API](https://img.shields.io/badge/REST-API-0EA5E9?style=for-the-badge&logo=openapiinitiative&logoColor=white)](#rest-api) [![无云端](https://img.shields.io/badge/NO-CLOUD-DC2626?style=for-the-badge)](#) [![自托管](https://img.shields.io/badge/SELF--HOSTED-3B82F6?style=for-the-badge&logo=homeassistant&logoColor=white)](#) [![数据不离开本地](https://img.shields.io/badge/your%20data-stays%20on%20your%20box-7C3AED?style=for-the-badge&logo=lock&logoColor=white)](#) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/Jakub-Syrek/GenericRagGenerator/actions/workflows/ci.yml) [![测试](https://img.shields.io/badge/tests-115%20passed-brightgreen)](https://github.com/Jakub-Syrek/GenericRagGenerator/tree/main/tests) [![评估](https://img.shields.io/badge/eval-24%2F24-brightgreen)](https://github.com/Jakub-Syrek/GenericRagGenerator/blob/main/eval/sample-result.md) [![Python](https://img.shields.io/badge/python-3.11%2B-3776AB?logo=python&logoColor=white)](https://www.python.org/) [![FastAPI](https://img.shields.io/badge/FastAPI-0.115-009688?logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com/) [![Ollama](https://img.shields.io/badge/Ollama-local-000000?logo=ollama&logoColor=white)](https://ollama.com/) [![LlamaIndex](https://img.shields.io/badge/LlamaIndex-0.12-FB923C)](https://docs.llamaindex.ai/) [![ChromaDB](https://img.shields.io/badge/ChromaDB-embedded-FACC15)](https://www.trychroma.com/) [![Ruff](https://img.shields.io/badge/lint-ruff-d7ff64?logo=ruff&logoColor=black)](https://github.com/astral-sh/ruff) [![mypy](https://img.shields.io/badge/types-mypy-2A6DB2)](http://mypy-lang.org/) [![bandit](https://img.shields.io/badge/security-bandit-FFC107)](https://github.com/PyCQA/bandit) [![detect-secrets](https://img.shields.io/badge/secrets-detect--secrets-FF5722)](https://github.com/Yelp/detect-secrets) [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://pre-commit.com/) [![Docker](https://img.shields.io/badge/docker-ready-2496ED?logo=docker&logoColor=white)](Dockerfile) [![Windows 服务](https://img.shields.io/badge/Windows%20service-NSSM-0078D4?logo=windows&logoColor=white)](scripts/install-windows-service.ps1) 本地检索增强生成 (RAG) 服务,以**完全符合 RESTful 标准的 HTTP API** 形式提供(22 个 endpoint,OpenAPI / Swagger 文档位于 `/docs`)。 上传文档、整个代码仓库的 ZIP 压缩包,或是多来源的项目,然后即可通过相同的接口从 curl、Postman、IDE 插件或内置浏览器 UI 中**查询 / 聊天 / 搜索**该索引。无论你是将其作为前台进程 (`run.ps1`)、Windows 服务 (NSSM) 还是 Docker compose 堆栈启动,提供的 API 都是完全相同的—— 没有“服务”与“API”的区别,每一次安装都是一个具备网络通信能力的 HTTP 服务器。 回答严格基于已索引的内容生成,并会引用确切的源文件(对于代码,还会包含行号范围)。 ## 可导入的内容 - **普通文档**:`.pdf`、`.txt`、`.md` / `.markdown`、`.rst`、`.html` / `.htm`、`.docx`。 - **源代码**(约 30 种语言):Python、TypeScript / JavaScript / TSX / JSX、Java、Kotlin、Scala、Go、Rust、C / C++ / headers、C#、Ruby、PHP、 Swift、shell(bash / zsh / sh)、PowerShell、SQL,以及常见的配置 格式(YAML、TOML、JSON、XML、INI、CSS、SCSS)。 - **整个代码仓库**:拖入一个 `.zip` 压缩包;安全的提取器会拒绝 路径穿越、软链接、超大文件,并自动跳过诸如 `.git/`、`node_modules/`、`__pycache__/`、`dist/`、`build/`、`target/`、 `vendor/` 和 IDE 缓存等冗余文件。 每个 chunk 都附带了 `kind` (`code`/`doc`)、`language`、可选的 `line_start`/`line_end` 以及 `repository_id` 元数据。聊天 UI 中的来源标签会为代码渲染出 `repo/path/to/file.py:42-101` 的格式,而对于文档则显示纯路径。 ## 技术栈 | 层级 | 选择 | |-------------------|-------------------------------------------------------------------| | 后端 | Python 3.11 + FastAPI | | LLM 运行时 | [Ollama](https://ollama.com)(本地、开源) | | 聊天模型 | `llama3.1:8b`(可通过 `CHAT_MODEL` 配置) | | Embedding 模型 | `nomic-embed-text`,带有 `search_query:` / `search_document:` 前缀 | | RAG 编排 | [LlamaIndex](https://docs.llamaindex.ai) | | 向量数据库 | [ChromaDB](https://www.trychroma.com)(内置、磁盘存储) | | Chunking | `MarkdownNodeParser` (md) / `CodeChunker` (code) / `SentenceSplitter` (默认) | | 前端 | 纯 HTML + CSS + ES6(符合 CSP 标准,无内联脚本) | | 安全 | bandit + detect-secrets + pip-audit、安全响应头、slowapi、可选 API key | | CI | GitHub Actions (ruff + mypy + bandit + pytest + pip-audit) | ## 前置条件 1. Python 3.11+ 2. 在本地运行 Ollama:`ollama serve` 3. 拉取所需的模型(只需一次): ollama pull llama3.1:8b ollama pull nomic-embed-text ## 本地运行 ``` python -m venv .venv .\.venv\Scripts\Activate.ps1 pip install -r requirements.txt Copy-Item .env.example .env .\run.ps1 ``` 然后打开 。从侧边栏上传文档*或*项目 ZIP,接着在聊天面板中提问即可。助手会逐 token 流式输出回答,并为它从向量数据库中提取的每一个 chunk 显示引用标签。 ## 可选:安装为 Windows 服务 NSSM ([nssm.cc](https://nssm.cc)) 将 `.venv` 中的 uvicorn 进程封装为一个标准的 Windows 服务,具备自动启动、日志轮转和故障重启功能。 `scripts/` 目录下的两个 PowerShell 辅助脚本可实现此操作: ``` # 1. 安装 NSSM 一次(管理员 PowerShell): winget install NSSM.NSSM # 或:choco install nssm # 或:手动将 nssm.exe 放到 PATH 中的某个位置 # 2. 从项目根目录开始,在*提权的* PowerShell 中: .\scripts\install-windows-service.ps1 ``` 该脚本会注册名为 `GenericRagGenerator` 的服务, 绑定到 `127.0.0.1:8000`(默认的 `local` 模式),将 stdout/stderr 捕获并轮转记录到 `.\logs\service-*.log`(10 MB 轮转)中,并在发生故障 5 秒后重启进程。 通过 `-Mode` 提供两种安装配置: | 模式 | 绑定 | 适用场景 | |-----------|--------------|--------------------------------------------------------| | `local` | `127.0.0.1` | 单用户 / 个人电脑。API 仅可在本地访问。 | | `public` | `0.0.0.0` | 共享主机 / 企业部署。除非在 `.env` 中设置了 `API_KEY`(或 `AUTH_PASSWORD` + `JWT_SECRET`),否则将拒绝安装。 | ``` # 仅本地(默认):API 在 http://127.0.0.1:8000 .\scripts\install-windows-service.ps1 # 在自定义端口上公开绑定(必须先在 .env 中设置 auth) .\scripts\install-windows-service.ps1 -Mode public -Port 9000 # 公开 + 隐藏 Swagger / Redoc / OpenAPI .\scripts\install-windows-service.ps1 -Mode public -DisableDocs ``` 运维命令: ``` Get-Service GenericRagGenerator # status Restart-Service GenericRagGenerator # reload after .env / code changes Stop-Service GenericRagGenerator # graceful stop (15 s window) .\scripts\uninstall-windows-service.ps1 ``` 生产环境注意事项: - Ollama 本身通过其安装程序作为服务运行;两者可以在同一台机器上 并行运行。 - 当主机为共享状态时,请在最低权限的本地账户下运行该服务 (`nssm set GenericRagGenerator ObjectName .\rag-user `) 而不是使用 `LocalSystem`。 - 在安装服务前于 `.env` 中设置 `API_KEY`,从而确保公开接口 从首次启动起即受保护。 ## 在 Docker 中运行(适合企业环境) ``` docker compose up -d docker exec ggrag-ollama ollama pull llama3.1:8b docker exec ggrag-ollama ollama pull nomic-embed-text ``` 该 compose 堆栈在运行应用和 Ollama 时遵循以下原则: - 应用镜像中使用非 root 用户(`UID 10001`)且不含 shell; - `read_only: true` 只读根文件系统,仅为 `/tmp` 和 `/home/app/.cache` 挂载 tmpfs; - 两个服务均配置了 `cap_drop: ALL` 和 `no-new-privileges: true`; - 在 `/api/health` 上配置了健康检查; - 为 Chroma 数据和 Ollama 模型缓存使用独立的命名卷。 有关完整的威胁模型和企业部署指南,请参阅 [`SECURITY.md`](SECURITY.md)。 ## REST API 无论你选择哪种运行模式(`run.ps1`、Windows 服务、Docker compose 堆栈),相同的接口都会暴露在相同的端口上——不存在“服务”与“API”的区别。交互式 OpenAPI 文档位于 `/docs` (Swagger UI) 和 `/redoc`;在生产环境中设置 `DOCS_ENABLED=false` 可隐藏这两者以及 `/openapi.json`。 | Method | Path | 用途 | |--------|-------------------------------------|--------------------------------------------------------| | GET | `/api/health` | 服务 + Ollama 可达性(始终无需认证) | | POST | `/api/auth/login` | 验证凭据,颁发 JWT bearer | | GET | `/api/auth/whoami` | 回显已认证的主体 + 权限范围 | | POST | `/api/admin/reset` | 清除索引中的所有 chunk(仅限管理员权限) | | GET | `/api/documents` | 列出已索引的文档 | | POST | `/api/documents` | 上传单个文档(multipart) | | GET | `/api/documents/{id}` | 文档详情(类型、语言、预览) | | GET | `/api/documents/{id}/chunks` | 列出从单个文档生成的所有 chunk | | DELETE | `/api/documents/{id}` | 移除文档及其所有 chunk | | GET | `/api/repositories` | 列出已索引的代码仓库 | | POST | `/api/repositories` | 上传项目 ZIP (multipart) | | GET | `/api/repositories/{id}` | 代码仓库详情及其逐文件导入列表 | | GET | `/api/repositories/{id}/files` | 列出从单个代码仓库导入的所有文件 | | DELETE | `/api/repositories/{id}` | 移除代码仓库及其所有 chunk | | GET | `/api/projects` | 列出已索引的多来源项目 | | POST | `/api/projects` | 将多个原始文件作为一个项目上传 (multipart) | | GET | `/api/projects/{id}` | 项目详情及其逐文件导入列表 | | GET | `/api/projects/{id}/files` | 列出导入到单个项目中的所有文件 | | DELETE | `/api/projects/{id}` | 移除项目及其所有 chunk | | POST | `/api/search` | 仅检索的相似度搜索(不调用 LLM) | | POST | `/api/query` | 同步 RAG 回答(单个 JSON,非流式) | | POST | `/api/chat` | 流式 RAG 回答 (NDJSON) | ### 认证 在所有受保护的路由上均支持以下两种流程: - **静态 `X-API-Key`** —— 在环境中设置 `API_KEY`,然后 在每次请求中发送 `X-API-Key: `。使用常数时间进行比较 (`hmac.compare_digest`);适合服务间通信。 - **交互式 JWT bearer** —— 在环境中设置 `AUTH_PASSWORD` *和* `JWT_SECRET`,然后执行: TOKEN=$(curl -s -X POST http://127.0.0.1:8000/api/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"…"}' | jq -r .access_token) curl http://127.0.0.1:8000/api/auth/whoami -H "Authorization: Bearer $TOKEN" Bearer token 使用 HS256 签名,携带 `sub` + `scopes` 声明,并在 `JWT_EXPIRES_MINUTES`(默认 60)后过期。从 `/api/auth/login` 获取的 token 携带 `admin` 权限范围,这是调用 `/api/admin/reset` 所必需的。 如果未配置 `API_KEY` 或 `JWT_SECRET`,认证将被禁用,所有 endpoint 将以 `anonymous` 主体的身份运行——这适用于本地开发,但在生产环境中绝对不要使用。 ### 资源负载 ``` POST /api/projects // multipart files=&files=&name= ``` ``` POST /api/query { "messages": [{"role": "user", "content": "How does slugify work?"}], "document_ids": ["..."], "repository_ids": ["..."], "project_ids": ["..."] } // returns { "answer": "...", "sources": [...] } ``` ``` POST /api/search { "query": "how does slugify work?", "top_k": 10, "document_ids": ["..."], "repository_ids": ["..."], "kinds": ["code", "doc"] } // returns { "query": "...", "results": [...], "total": N } ``` ``` POST /api/admin/reset // Authorization: Bearer // returns { "chunks_removed": N } ``` ## 架构 经过几次抽象提取使得代码更加实用——其余部分仅是原生的 FastAPI / Pydantic / `logging`: | 位置 | 为什么不直接写成内联代码 | |---------------------------------|----------------------------------------------------------------------------------------------------------| | `services/chunking.py` | `Chunker` 协议 + `ChunkerRegistry`。另一种选择是采用 `if kind == "code" elif language == ...` 链式判断,并且每次增加新格式都要扩充代码。 | | `services/index_catalog` | `IndexCatalog` 是唯一一个导入 `chromadb` 的类。将 ChromaDB 替换为 Qdrant/pgvector 只需修改这一个文件。 | | `services/rag_service.py` | 组合根。Handler 依赖于外观接口,而不是直接依赖底层的 LlamaIndex/Chroma/Ollama 三件套。 | | `security/_PrefixedOllamaEmbedding` | nomic-embed-text 需要 `search_query:` / `search_document:` 前缀;这是唯一知道该逻辑的类。 | ## 可选的检索功能 默认全部关闭——开启环境开关即可启用。当设置为 `false` 时,每个开关都会保持仅使用密集检索的单进程默认路径不受影响。 | 标志 | 默认值 | 增加的功能 | |----------------------------------|---------|--------------------------------------------------------------------------------------------------------------------------| | `RETRIEVAL_MODE=hybrid` | `vector`| BM25 词法检索通过与密集命中结果结合 Reciprocal Rank Fusion 进行融合。有助于查询罕见词汇(函数名、错误码)。 | | `CACHE_ENABLED=true` | `false` | 在 `/api/search` 和 `/api/query` 上使用 LRU + TTL 响应缓存。每次导入 / 删除 / 清除操作都会使其自动失效。 | | `RERANKER_ENABLED=true` | `false` | FlashRank ONNX cross-encoder(约 80 MB,一次性下载)在检索后对候选列表进行重新排序。 | | `PARSER_SANDBOX_ENABLED=true` | `false` | PDF / DOCX / HTML 解析器在子进程中运行并设有时间限制。负载格式错误只会导致该 worker 崩溃。 | | `OLLAMA_RETRY_*` | 开启 | 针对瞬态 Ollama 错误(`ConnectError`、`ReadTimeout`、`RemoteProtocolError`)使用由 Tenacity 驱动的指数退避重试。 | 其他内置功能(始终开启,无需设置标志): - **导入时基于内容哈希去重。** 每次上传均以原始负载的 SHA-256 作为键值;重新上传相同字节会在调用 Ollama embedding 前直接短路返回,并在响应中返回之前的记录且附带 `deduplicated=true`。 - **基于主体的 ACL。** 当配置了 `API_KEY` / `JWT_SECRET` 时, 每个 chunk 都会标记上上传者的主体名称。读取、 列表和删除路径均受所有者权限范围限制,因此 JWT 用户只能看到其自己的文档 / 代码仓库 / 项目。静态 API key 和 任何携带 `admin` 权限范围的 JWT 可绕过此过滤器。匿名 模式(未配置凭据)保持单租户状态。 聊天流每行发出一个 JSON 事件: - `{"type": "sources", "sources": [...]}` 位于开头且仅输出一次,其中每个 source 包含 `document_id`、`filename`、`kind`、`language`、 `repository_name`(如果是通过 repo 导入的),以及针对代码 chunk 的 `line_start` / `line_end`。 - `{"type": "delta", "content": "..."}` 对应每一批生成的 token。 - 成功时输出 `{"type": "done"}`,如果 Ollama 或 Chroma 在流式传输过程中失败,则输出 `{"type": "error", "message": "..."}`。 ## 项目结构 ``` backend/app/ api/ HTTP routes (auth, admin, documents, repository, projects, search, query, chat, health) services/ RagService (facade), chunking (Strategy/Registry), index_catalog (Repository), document_loader models/ Pydantic schemas security/ Headers middleware, API-key + JWT auth, rate limiter config.py Settings (env-driven) dependencies.py FastAPI DI providers (cached singletons via lru_cache) main.py FastAPI entry, middleware wiring, static frontend mount frontend/ Static UI (documents + repository forms, source chips) eval/ RAG quality eval (corpus + runner + sample report) sample_repo/ Synthetic mini_parser fixture (code + HTML + Markdown) tests/ Pytest suite (unit + API integration with TestClient) data/ Runtime (uploads + Chroma persistence) - gitignored logs/ Windows-service stdout / stderr (NSSM-managed) - gitignored scripts/ PowerShell helpers (install / uninstall Windows service) Dockerfile Multi-stage, non-root, healthcheck docker-compose.yml App + Ollama + hardening SECURITY.md Threat model and deployment guidance ``` ## 质量评估 ``` .\.venv\Scripts\python.exe -m eval.run_eval ``` 下载四篇维基百科文章的引言(RAG、Vector database、Word embedding、Photosynthesis),将 `eval/sample_repo/` 打包为 ZIP,通过现有的 API 推送两套语料库,在 `/api/chat` 上运行 24 个预设问题,并从以下四个维度对每个回答进行评分: - **`retrieval_top1_precision`** —— Top-1 来源与预期文件匹配。 - **`answer_substring_match`** —— 回答包含任何预期 子字符串(不区分大小写)。 - **`kind_precision`** —— 对于标记为代码/文档类型的问题,Top-1 来源属于 预期的类型。 - **`ooc_refusal_rate`** —— 正确拒绝对语料库范围之外的试探。 结果保存在 `eval/results/` 下(带时间戳的 JSON + Markdown)。已提交的基准线位于 [`eval/sample-result.md`](eval/sample-result.md)。 在 `llama3.1:8b` + `nomic-embed-text` 下的最新本地运行结果: - **24/24** 综合通过 - retrieval_top1 1.0, answer_match 1.0, kind 1.0, ooc_refusal 1.0 - 预热后平均延迟约为每轮 0.6 秒 ## 开发工作流 ``` # 一次性设置 pip install -r requirements.txt pre-commit install # 每次更改时 pre-commit run --all-files pytest ``` `pre-commit` 会运行: - 空格 / EOL / 大文件规范检查、 - `ruff` (代码检查 + 格式化)、 - 对 `backend/` 运行 `mypy`、 - `bandit`(Python 安全隐患排查)、 - 基于文件 `.secrets.baseline` 运行 `detect-secrets`。 CI 在 push 和 PR 时会运行相同的 pre-commit 套件,并加上 `pip-audit` (仅记录安全公告但不阻断;详见 `SECURITY.md`)。 针对实时 Ollama 运行的集成式端到端检查不包含在 CI 中,而是存放在 `smoke_test.py` 和 `eval/` 包中。 ## 配置项 | 变量 | 默认值 | 用途 | |-----------------------------|-------------------------------|-------------------------------------------------------------| | `OLLAMA_HOST` | `http://localhost:11434` | Ollama 的访问地址。 | | `CHAT_MODEL` | `llama3.1:8b` | 聊天补全模型。 | | `EMBEDDING_MODEL` | `nomic-embed-text` | Embedding 模型。 | | `EMBEDDING_QUERY_PREFIX` | `"search_query: "` | 添加到查询 embedding 前的前缀(nomic 非对称机制)。 | | `EMBEDDING_DOCUMENT_PREFIX` | `"search_document: "` | 添加到文档 embedding 前的前缀。 | | `CHUNK_SIZE` / `CHUNK_OVERLAP` | `800` / `120` | 按字符计算的句子分割器窗口大小。 | | `TOP_K` | `8` | 检索器 top-k。仅在语料库较小或为合成数据时才需调高;在真实索引上操作只会过度填充 prompt。 | | `API_KEY` | *(未设置)* | 设置后,将使用 `X-API-Key` 对 `/api/documents`、`/api/repositories`、`/api/chat` 进行访问限制。 | | `CORS_ORIGINS` | `["http://localhost:8000", ...]` | 针对浏览器的严格白名单。 | | `RATE_LIMIT_CHAT` | `30/minute` | 对 `/api/chat` 应用的基于单个 IP 的 slowapi 限制。 | | `RATE_LIMIT_UPLOADS` | `10/minute` | 供反向代理使用(slowapi 无法包装 `UploadFile`)。 | | `AUTH_USERNAME` | `admin` | `POST /api/auth/login` 接受的用户名。 | | `AUTH_PASSWORD` | *(未设置)* | 登录时接受的密码。启用 bearer 流程时必填。 | | `JWT_SECRET` | *(未设置)* | 用于签发 JWT bearer 的 HS256 签名密钥。启用登录时必填。 | | `JWT_EXPIRES_MINUTES` | `60` | 签发的 bearer token 的有效期。 | | `DOCS_ENABLED` | `true` | 在生产环境中设置为 `false` 可隐藏 `/docs`、`/redoc` 和 `/openapi.json`。 | | `RETRIEVAL_MODE` | `vector` | `vector` (仅密集检索) 或 `hybrid` (密集检索 + BM25 通过 RRF 融合)。 | | `CACHE_ENABLED` | `false` | 用于 `/api/search` 和 `/api/query` 的 LRU+TTL 响应缓存。 | | `CACHE_MAX_ENTRIES` | `256` | LRU 驱逐前的最大缓存响应数。 | | `CACHE_TTL_SECONDS` | `300` | 缓存响应的 TTL(以秒为单位)。 | | `RERANKER_ENABLED` | `false` | 在检索出的候选列表上运行 FlashRank cross-encoder。 | | `RERANKER_MODEL` | `ms-marco-MiniLM-L-12-v2` | FlashRank ONNX 模型名称。 | | `RERANKER_TOP_K` | `5` | 重新排序后保留的命中结果数。 | | `PARSER_SANDBOX_ENABLED` | `false` | 在子进程沙箱中运行 PDF / DOCX / HTML 解析器。 | | `PARSER_SANDBOX_TIMEOUT_SECONDS` | `10.0` | 每个沙箱解析在被杀掉之前的时钟时间限制。 | | `OLLAMA_RETRY_ATTEMPTS` | `3` | 遇到 Ollama 瞬态错误时的总尝试次数(包含首次)。 | | `OLLAMA_RETRY_BACKOFF_MIN_SECONDS` | `1.0` | 初始指数退避窗口时间。 | | `OLLAMA_RETRY_BACKOFF_MAX_SECONDS` | `8.0` | 指数退避窗口时间的上限。 | ## 安全 完整的威胁模型、范围内/范围外的保证、部署指南以及公开的依赖安全公告均位于 [`SECURITY.md`](SECURITY.md)。简而言之: - 优先考虑本地 / 企业网络环境目标;在没有反向代理的情况下 不适合直接暴露在公共互联网中。 - 将 Bandit + detect-secrets + pip-audit 集成到了 pre-commit / CI 中。 - 加固响应标头(CSP、XFO DENY、HSTS、Referrer-Policy、 Permissions-Policy)、严格的 CORS、可选的 API key、基于 IP 的速率 限制。 - ZIP 导入强制执行路径穿越 / 软链接 / 大小限制,并将特定的命名 领域错误映射到具体的 HTTP 状态码。 ## 提交与风格规范 - 在代码、注释、提交记录和标识符中仅使用英语。 - 公共函数需记录 `@param` / `@returns`(JSDoc 风格的文档字符串)。 - SOLID 原则 + DI:依赖通过 FastAPI 的 `Depends` 和 构造函数参数注入,严禁使用模块全局变量。 - 函数规模应保持在 30 行左右的上限;ruff 会强制执行 pylint 的语句 / 分支 限制。 - 错误在每个外部边界处都会被转换为明确的领域 异常(`EmbeddingError`、`ChatGenerationError`、`VectorStoreError`、 `StorageError`、`UnsafeArchiveError`、`RepositoryError`、 `EmptyDocumentError`、`UnsupportedFormatError`)。 - 提交是原子性的并会立即推送;`main` 分支上的 CI 必须保持通过状态。
标签:AI风险缓解, AV绕过, ChromaDB, FastAPI, LlamaIndex, LLM评估, Ollama, RAG, RESTful API, 大模型, 提示词优化, 本地部署, 请求拦截, 逆向工具