内容
<div align="right">
**英文** | [中文](README.zh.md)
</div>
<div align="center">
<img src="docs/assets/pharos-banner.svg" alt="Pharos — 团队文档库导航" width="880">
# Pharos
[](https://github.com/Laurent00TT/pharos/actions/workflows/ci.yml)
[](LICENSE)


[](docs/learning/)
**将PDF、扫描件、docx、pptx和xlsx转换为本地知识库,您可以向其提问——具有企业访问控制和引用,您可以追溯到页面。**
每个RAG组件都在其自身的基础上进行优化,然后合并到一个仓库中:多身份认证、观测性和systemd监督一应俱全。
</div>
> **语言说明。** 代码、CLI和提交历史记录均为英文;文档——包括12部分的学习系列——均以中文编写。本README是英文入口,涵盖了系统的概述、架构和运行方式。对于更深入的内容,您需要阅读中文文档(或使用机器翻译)。
---
> 亚历山大灯塔建在图书馆旁边,引导船只靠岸。 **Pharos的作用相同,但它照亮的是您团队的文档库。**
这不仅仅是另一个分块工具。这里的每个重要决定都基于测量结果,经过多轮对抗性评审,并已在77个真实文档和7,652个分块上运行。安装只需一行命令:`pip install -e '.[dev]'`(src-layout,可编辑)。
## 两个出口,一套语义
一个知识库,每个消费者都有一个入口:
| 出口 | 命令 | 使用者 | 功能 |
|---|---|---|---|
| **HTTP API** | `pharos serve` | curl、脚本、前端 | 封闭式QA:`/v1/ask`运行检索→接地→DeepSeek→带有引用的答案,以及六个检索端点 |
| **MCP** | `pharos mcp` | Claude Code等代理 | 代理RAG:何时检索,如何重写,是否跳转——代理决定 |
两个入口共用一套语义,通过两条规则维持:工具合约只有一个源(`toolcore`,因此stdio和HTTP端不会漂移),身份由服务端决定(代理无法编辑自己的权限)。
## 架构
<div align="center">
<img src="docs/assets/architecture.svg" alt="Pharos架构:消费者→守护进程→后端服务" width="100%">
</div>
**为什么需要常驻守护进程?**嵌入式Qdrant仅允许一个客户端并持有独占锁,而8B模型加载需要一两分钟。在早期的stdio-direct设计下,每个代理会话都会启动自己的进程——争夺锁并每次重新加载模型。Pharos颠倒了这一点:守护进程拥有重资源,MCP缩小为一个薄的HTTP适配器,启动时间毫秒级,每个会话共享一个已经预热的后端。背后的权衡在[docs/DESIGN.md](docs/DESIGN.md)(中文)中。
<details>
<summary><b>生产形态:从单个节点到三个独立可扩展的层</b></summary>
<br/>
单个节点的瓶颈在于GPU模型、嵌入式Qdrant和应用逻辑都位于一个进程中,因此水平扩展立即遇到天花板。拆分后,有三个层可以独立扩展:
- **`推理`**(FastAPI on `:8900`)——GPU前向传递独立出来,返回全宽向量,客户端再截断,两侧保持等效;
- **`pharos`**——应用层完全摆脱torch(设置`inference_url`后不加载模型),这使得 `--scale pharos=N` 成为可能;
- **Qdrant服务端**——副本共享一个真实数据源,前面有 `nginx` 进行负载均衡;任意副本的 `docker kill` 均不会被注意到。
```bash
docker compose --env-file .env.compose up -d --scale pharos=3 # 入口:http://127.0.0.1:8080
```
有一点需要明确:**吞吐量上限是单个推理卡的前向速度(GPU序列化),添加副本并不能提高它。** 副本实际上为您带来的并发性是非GPU部分的并发性,以及故障隔离和滚动升级。完整的描述在 [docs/SCALE_OUT.md](docs/SCALE_OUT.md)(中文)。
</details>
## 入门指南
服务在systemd下运行——开机启动,故障重启。日常使用中,团队成员需要自己的API密钥,然后:
```bash
conda activate pharos
pip install -e '.[dev]' # src-layout,可编辑安装
python -m pharos ask "我们有关于X的什么信息?" # 封闭式QA,答案带有引用
python -m pharos health
```
对于Claude Code的代理模式:复制 `.mcp.json.example` 到 `.mcp.json`(gitignored),填写您的 `PHAROS_API_KEY` 和本地路径,您就可以得到 `rag` 工具——前提是守护进程正在运行。没有守护进程时,`pharos mcp --direct` 也可用:它通过stdio通信,加载GPU模型本身,并且不依赖任何驻留内容。
构建索引,作为管理员(语料库是MinerU解析输出的目录):
```bash
sudo systemctl stop pharos # 单客户端锁,因此先停止
python -m pharos index --corpus <parsed_dir> --dest ~/rag_real
sudo systemctl start pharos
```
## 想要了解RAG,而不仅仅是使用它?
仓库中还包含一个 **[RAG学习和面试准备集](docs/learning/)**:该系统——反复被自己的数据矛盾并反复修复——被拆分成 **12部分和4,122行** 的教程。它从分块、混合检索、权限模型和生成接地一直到代理使用、评估方法和多副本扩展。每个部分都有代码锚点、测量数字、面试框架和您可以自己运行的实验。 **用中文编写。**
| 您想要什么 | 哪些部分 |
|---|---|
| 每个RAG层的权衡,以及主流选项的样子 | [01 概述](docs/learning/01-rag-overview.md) · [02 分块](docs/learning/02-parsing-chunking.md) · [03 检索](docs/learning/03-retrieval.md) |
| 企业权限、生成接地、代理 | [04 ACL](docs/learning/04-acl-security.md) · [05 生成](docs/learning/05-generation-grounding.md) · [06 代理](docs/learning/06-agentic-mcp.md) |
| RAG应该如何评估(该系统花费最多心思的部分) | [07 评估](docs/learning/07-evaluation.md) |
| 系统设计、单节点到副本、工程方法 | [08 服务](docs/learning/08-service-architecture.md) · [09 扩展](docs/learning/09-scale-out.md) · [10 故事](docs/learning/10-methodology-stories.md) |
| 面试突击 | [11 问题银行](docs/learning/11-interview-qa.md) |
## 安全模型
- **身份回答“谁在提问”,ACL回答“他们可以看到什么”。** X-API-Key首先解析为身份;该身份的租户和主体然后在每个请求中被传递给检索层,ACL在那里进行硬过滤以强制可见性。整个链路在 `acl_regression` 的五用户矩阵中得到验证。
- **全程关闭。** 未识别或缺失的密钥是401。格式错误的密钥文件拒绝启动。绑定到非环回地址强制密钥模式——库不会在LAN上未经保护地暴露。默认情况下,没有附加权限的文档对任何人不可见。
- **会话彼此隔离。** 跨调用重复数据删除按身份和会话分桶,因此一个人永远不会看到另一个人的状态。 **它也不会泄漏细节:** 日志记录身份名称而非密钥,错误不会溢出内部信息,每个检索到的段落都标记为`trust: untrusted`以防止提示注入。
- 默认情况下绑定到 `127.0.0.1`。HTTPS和公开暴露是明确不目标——如果您需要远程访问,请隧道进入。
<details>
<summary><b>三种身份模式和配置</b></summary>
<br/>
| 模式 | 触发器 | 用途 | 身份来源 |
|---|---|---|---|
| **密钥** | 设置 `PHAROS_KEYS_FILE` | **团队部署(默认)** | 每个请求的X-API-Key产生自己的身份(名称+租户+主体) |
| **旧版** | 仅设置 `PHAROS_API_KEY` | 单用户,或仅作为门槛 | 一个密钥,启动时绑定身份 |
| **开放** | 两者均未设置 | 本地开发,仅限环回 | 启动时绑定的单个身份 |
```bash
python -m pharos keys new alice --tenant demo --admin # 发布身份;密钥仅打印一次
python -m pharos keys new bob --tenant demo --principals g_eng
# 在.env中设置PHAROS_KEYS_FILE=~/pharos.keys.json;添加PHAROS_HOST=0.0.0.0以访问LAN
sudo systemctl restart pharos
```
配置位于存储库根目录的单个 `.env` 文件中(参见 [.env.example](.env.example); 所有内容均以 `PHAROS_*` 为前缀):`PHAROS_KEYS_FILE`、`PHAROS_CORPUS_DIR`、`PHAROS_INDEX_DIR`(默认为 `~/rag_real`)、`PHAROS_COLLECTION`、`PHAROS_PORT`(8787)、`PHAROS_HOST`(非环回绑定强制密钥模式)、`PHAROS_LOG_DIR`和 `DEEPSEEK_API_KEY`(`/v1/ask` 需要)。完整的部署、密钥和操作规程在 [docs/OPERATIONS.md](docs/OPERATIONS.md)(中文)中。
</details>
## 测试
```bash
python -m pytest tests -q # 完整CPU套件:产品层+引擎层,包括ACL谓词
python -m pytest tests -q --ignore=tests/engine # 仅产品层(假检索器+MockLLM;无GPU,无网络)
```
两者都不触及GPU、Qdrant服务器或网络,[CI](.github/workflows/ci.yml)在每次推送时运行它们。套件大小、产品/引擎拆分和测量出处在 [docs/TESTING.md](docs/TESTING.md) §1中——该数字的单一权威。GPU端到端零泄漏回归(`eval/acl_regression.py`,在WSL + 4090上)、并发基准测试、备份演练和安全审查记录均在同一文档中。
## 文档索引
以下所有文档均为中文。
| 文档 | 涵盖内容 |
|---|---|
| [docs/OVERVIEW.md](docs/OVERVIEW.md) | **系统概述(权威入口)**:整体图景、组件地图、如何阅读本文档集 |
| [docs/learning/](docs/learning/) | **RAG学习和面试文档(12部分)**:从分块到评估,带有代码锚点和面试框架 |
| [docs/DESIGN.md](docs/DESIGN.md) | 目标、架构、关键决策(包括被拒绝的替代方案)、多身份和可观测性、风险 |
| [docs/IMPLEMENTATION.md](docs/IMPLEMENTATION.md) | 模块地图、请求路径、锁模型、检索层缝隙 |
| [docs/API.md](docs/API.md) | HTTP API合约:端点、参数、身份验证、状态状态机 |
| [docs/OPERATIONS.md](docs/OPERATIONS.md) | **团队运维手册**:部署、密钥、测量容量、备份和恢复、故障排除 |
| [docs/SCALE_OUT.md](docs/SCALE_OUT.md) | 从单个节点到多个副本(阶段A-F):三层拆分、负载均衡、等效验证 |
| [docs/TESTING.md](docs/TESTING.md) | 测试矩阵及其背后的证据:单元测试、ACL回归、GPU冒烟测试、基准测试、演练、安全 |
| [docs/ROADMAP.md](docs/ROADMAP.md) | 项目进展和**明确不构建的内容**(附原因) |
| [docs/COMPONENT_NOTES.md](docs/COMPONENT_NOTES.md) · [docs/PROVENANCE.md](docs/PROVENANCE.md) | 记录继承组件的异议;出处和测量基准中断 |
组件级设计和评估位于 [docs/components/](docs/components/)(分块器/嵌入器/生成器/mcp-server);方法论位于 [docs/methodology/](docs/methodology/)。
## License
[MIT](LICENSE)。
<div align="center">
<br/>
<sub>Pharos · 自建多格式代理RAG · 本地4090 / WSL <code>pharos</code></sub>
</div>