Files
LLM_Proxy/PROJECT_MEMORY.md
2026-03-13 01:14:39 +08:00

221 lines
7.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 项目记忆(LLM_Proxy)
适用范围:`LLM_Proxy` 仓库根目录
## 基础约束
- 所有文本文件使用 `UTF-8`,无 BOM。
- 所有文本文件统一使用 `LF` (`\n`),禁止 `CRLF` (`\r\n`)。
- 运行日志统一使用英文。
- 代码注释和 docstring 目标规范为中文。
- Python 字符串风格默认使用双引号 `"..."`。
- Python `docstring` 统一使用三重双引号 `"""..."""`。
- 只有在减少转义、提升可读性时,普通字符串才使用单引号 `'...'`。
- 涉及代码、配置、架构的修改时,优先保持控制平面与数据平面职责清晰。
## 项目定位
- 这是一个基于 Flask + gevent 的 OpenAI 兼容代理服务。
- 核心能力是将 `/v1/chat/completions` 请求路由到配置中的上游 Provider。
- 系统同时提供后台管理、认证、用户白名单、Provider 管理、模型探测和请求统计能力。
## 启动与装配链路
- 入口文件:`main.py`
- 启动关键点:
- 使用 `gevent.monkey.patch_all()`
- 支持 `--config` 指定配置文件,默认使用项目根目录 `config.yaml`
- 调用 `Application.run()`,由 gevent `WSGIServer` 提供服务
- 组合根:`src/application/application.py`
- 当前装配顺序:
- 初始化 `ConfigManager`
- 初始化应用日志和访问日志
- 创建 `AppContext`
- 初始化 SQLite 连接工厂和仓储
- 初始化 `ProviderManager` 并加载 Provider
- 组装 Service 和 Controller 并注册路由
## 当前分层
- `src/application`
- 组合根与运行时上下文
- `src/presentation`
- HTTP 路由、鉴权入口、页面渲染、请求和响应适配
- `src/services`
- 用例编排和业务逻辑
- 当前已拆分为:
- `AuthenticationService`
- `UserService`
- `ProviderService`
- `ModelDiscoveryService`
- `SettingsService`
- `ProxyService`
- `LogService`
- `src/repositories`
- SQLite 数据访问
- `src/config`
- 配置快照管理、显式 Provider schema / factory、Provider 运行时注册
- `src/external`
- 上游响应适配、流式探测、Provider 运行时对象
- `src/hooks`
- Hook 协议和动态扩展点
- `src/utils`
- 数据库、网络、IP 处理等通用工具
## 架构关键点
- 当前是单进程分层单体。
- 控制平面:
- 认证
- 用户管理
- Provider 配置管理
- 系统设置管理
- 数据平面:
- `/v1/chat/completions`
- `/v1/models`
- 模型路由
- 上游转发
- 响应适配
- 请求日志记录
## 配置与 Provider 运行时
- `ConfigManager`
- 提供配置快照读取
- 提供原子写回
- `get_raw_config()` 返回 `deepcopy`,避免调用方误改内部缓存
- `provider_config`
- 负责 `ProviderConfigSchema`、`RuntimeProviderSpec`、`ProviderRuntimeView`
- 负责批量 `build_provider_schemas(...)`、配置规范化和校验
- `ProviderManager`
- 只接收已构建好的 `ProviderConfigSchema`
- 负责把 schema 转成运行时 `LLMProvider`
- 维护 `model -> provider` 映射、只读 `ProviderRuntimeView` 注册表和 Hook 缓存
- 对外优先暴露只读接口:`get_provider_view()`、`list_provider_views()`、`list_model_names()`
- `LLMProvider`
- 运行时 Provider 对象
- 当前会复制 `model_list`,避免共享可变引用
## 核心请求流程(chat/completions)
1. `ProxyController.chat_completions` 接收 `POST /v1/chat/completions`
2. 标准化客户端 IP
3. 读取 `chat.whitelist_enabled`
4. 如果开启白名单,则按 IP 查询用户,并要求 `whitelist_access_enabled=1`
5. 校验请求体必须包含 `model`
6. 补齐 `stream_options.include_usage=true`
7. 用 `ProviderManager.get_provider_for_model(model)` 获取目标 Provider
8. `ProxyService.proxy_request(...)` 转发到上游
9. `response_adapter` 处理普通响应或 SSE 响应
10. 响应完成后通过回调写入 `request_logs` 并同步更新 `daily_request_stats`
## 模型路由规则
- 配置中每个 Provider 至少声明:
- `name`
- `api`
- `model_list`
- 系统内部模型 key 格式:
- `{provider_name}/{model_name}`
- 代理接口请求体中的 `model` 必须使用该格式
- 转发给上游前,`ProxyService` 会只移除 `provider_name/` 前缀,保留真实模型名剩余部分原样不变
## 模型探测链路
- `ProviderController.fetch_models()`
- `ModelDiscoveryService.fetch_models_preview(...)`
- 自动尝试候选端点:
- `/v1/models`
- `/models`
- 支持从 `chat/completions` 风格 URL 反推模型列表端点
## Hook 机制
- 配置字段:`providers[].hook`
- 路径规则:
- 绝对路径直接加载
- 相对路径默认相对项目根目录 `hooks/`
- Hook 模块必须导出 `Hook` 类
- 可选方法:
- `header_hook(ctx, headers) -> headers`
- `input_body_hook(ctx, body) -> body`
- `output_body_hook(ctx, body) -> body`
- `ProviderManager` 负责 Hook 动态加载和缓存
## 认证与会话
- 是否开启认证取决于 `admin.username` 和 `admin.password` 是否都存在
- `AuthenticationService` 当前使用进程内内存 Session
- 服务重启后 Session 全部失效
- 当前不适合多实例横向扩展
## 用户与白名单
- `UserService` 对按 IP 查询用户做了内存缓存
- 用户变更时会主动失效对应缓存
- 白名单控制依赖:
- `chat.whitelist_enabled`
- 用户 `whitelist_access_enabled`
## 日志与统计
- 访问日志写入 `logs/access.log`
- 应用日志写入 `logs/app.log`
- `LogRepository.insert()` 在一个事务内同时写:
- `request_logs`
- `daily_request_stats`
## 主要路由
- 代理接口:
- `POST /v1/chat/completions`
- `GET /v1/models`
- 认证接口:
- `GET /login`
- `POST /api/login`
- `GET /logout`
- `POST /api/logout`
- 用户管理:
- `GET /api/users`
- `POST /api/users`
- `GET /api/users/<id>`
- `PUT /api/users/<id>`
- `DELETE /api/users/<id>`
- `POST /api/users/<id>/toggle`
- Provider 管理:
- `GET /api/providers`
- `POST /api/providers`
- `GET /api/providers/<name>`
- `PUT /api/providers/<name>`
- `DELETE /api/providers/<name>`
- `GET /api/providers/fetch-models`
- `PUT /api/providers/chat-whitelist`
- 页面:
- `GET /`
- `GET /users`
- `GET /providers`
## 数据库结构
- 默认路径:`data/requests.db`
- `users`
- `id`
- `username`
- `ip_address`
- `whitelist_access_enabled`
- `created_at`
- `updated_at`
- `request_logs`
- `ip_address`
- `request_model`
- `response_model`
- `total_tokens`
- `prompt_tokens`
- `completion_tokens`
- `start_time`
- `end_time`
- `daily_request_stats`
- 唯一键:`(stat_date, ip_address, request_model, response_model)`
## 当前风险与注意事项
- 历史文件里有较多中文乱码的注释和 docstring,修改相关文件时优先逐步修复,避免继续扩散。
- `output_body_hook` 在非流式分支如果返回 `None`,可能把响应体变成 `null`;新增 Hook 时要注意返回值约定。
- 认证 Session、用户 IP 缓存、Provider 映射和 Hook 缓存都在单进程内存中,不适合多实例部署。
## 4+1 架构文档维护
- 4+1 Mermaid 文档文件:`docs/architecture-4plus1.md`
- 涉及以下变更时,必须同步更新该文档:
- 模块职责变化
- 分层依赖变化
- 主请求链路变化
- Provider 重载链路变化
- 运行时缓存或内存状态变化
- Hook 机制变化
- 部署拓扑变化
- 如果代码提交没有修改 4+1 图,变更说明中需要明确声明“架构未变化”。