工具基础
Written: 2026.06 前置阅读:第 13 讲:应用入口与环境前置校验 本附录覆盖项目中所有跨模块复用的基础工具类,包括设计思路、实现细节和使用模式。1. common.py:UTC 时间与 JSON 读写
1.1 设计思路
整个项目的时间戳统一使用 UTC 时间,避免时区混乱。所有需要持久化的时间(trace 记录、版本号、入库报告)都用utc_now(),所有文件系统中的时间标识都用 utc_file_stamp()。
1.2 JSON 读写封装
项目统一使用ensure_ascii=False, indent=2 格式写 JSON,保证中文字符可读、层级清晰。
1.3 列表报告工具
模板方法模式:通用的 JSON 文件扫描 + 按修改时间排序逻辑,被质量报告和状态页复用。1.4 重点掌握
| 优先级 | 内容 | 原因 |
|---|---|---|
| ★★★ 必会 | write_json() 的统一格式设计(ensure_ascii=False, indent=2) | 整个项目的持久化都依赖这个约定 |
| ★★★ 必会 | read_json(path, default=...) 的容错模式 | 避免文件损坏导致进程崩溃 |
| ★★ 理解 | utc_now() vs utc_file_stamp() 的使用场景区别 | UTC 规范是系统间协作的基础 |
| ★ 了解 | list_json_reports() 的模板方法模式 | 用于状态页报告列表 |
2. utils.py:稳定哈希与指纹
2.1 设计思路
入库和检索都需要稳定的 ID 生成——同一个文件重新入库时产生相同的 chunk_id,才能正确覆盖旧数据。stable_hash() 用 SHA-256 将任意数量的参数拼接后生成确定性的 hex 字符串。file_fingerprint() 只读文件元数据(路径 + 修改时间 + 大小),不读内容,大幅减少增量入库的 IO。
2.2 重点掌握
| 优先级 | 内容 | 原因 |
|---|---|---|
| ★★★ 必会 | stable_hash() 的确定性设计 | chunk_id/faq_id 的稳定性依赖于此 |
| ★★★ 必会 | file_fingerprint() 为什么用 mtime+size 而不是内容哈希 | IO 成本与可靠性之间的工程权衡 |
| ★★ 理解 | normalize_source_from_path() 的命名约定 | 入库脚本的 source 推断依赖目录命名规范 |
3. json_store.py:JSON 文件型 Store 基类
3.1 设计思路
知识库版本清单 (kb_versions.json) 和文件索引清单 (documents.json) 都是本地 JSON 文件存储。它们共享相同的能力:加载 → 补齐字段(兼容历史版本) → 读/写 → reload。JsonFileStore 把这些共性抽成基类,子类只需实现 empty_data() 和 normalize_data()。
3.2 子类示例:KnowledgeBaseVersionStore
3.3 重点掌握
| 优先级 | 内容 | 原因 |
|---|---|---|
| ★★★ 必会 | JsonFileStore 的模板方法模式(empty + normalize) | 两个核心清单 Store 都基于此模式 |
| ★★ 理解 | reload() 的使用场景(多步入库之间的数据同步) | 避免入库脚本多步写入时互相覆盖 |
| ★ 了解 | 为什么用 JSON 而不是 SQLite | 教学项目优先可调试性(JSON 可直接打开查看) |
4. schemas.py:Pydantic 数据模型
4.1 设计思路
所有 API 层的请求/响应都用 Pydantic BaseModel 定义,FastAPI 自动做参数校验和序列化。内部流转的数据结构用 Python dataclass(性能更好,不需要校验)。4.2 内部流转的 dataclass
4.3 重点掌握
| 优先级 | 内容 | 原因 |
|---|---|---|
| ★★★ 必会 | RetrievalDebugRequest 的所有字段含义 | 是 /api/retrieval/debug 的诊断请求结构 |
| ★★★ 必会 | RetrievalDebugResponse 的字段含义 | 诊断检索质量时要看意图、计划、FAQ/Doc 命中 |
| ★★ 理解 | FeedbackRequest.rating 的 pattern 约束 | 防止前端传自定义值污染数据 |
| ★ 了解 | RetrievalHit / RetrievalResult 的 dataclass 设计 | 内部流转的数据结构 |
5. config/settings.py:配置管理
5.1 设计思路
使用 pydantic-settings 从进程环境变量和本机.env 加载全部配置。Docker Compose 部署时,.env.compose 先由 Compose 注入到 API 容器的环境变量里,再由 Settings 读取。每个配置项有明确的默认值,注释标注了用途。model_config 设置 env_file=".env",用于本机 API 调试;容器模式不要把 .env.compose 复制成 .env。
5.2 重点掌握
| 优先级 | 内容 | 原因 |
|---|---|---|
| ★★★ 必会 | get_settings() 的 @lru_cache(maxsize=1) 单例模式 | 整个项目的配置入口 |
| ★★★ 必会 | validation_alias(如 DASHSCOPE_API_KEY)的用途 | .env 变量名与代码字段名的映射 |
| ★★ 理解 | 检索参数组的默认值和可覆盖性 | 调整这些参数不需要改代码 |
| ★ 了解 | model_config 的 case_sensitive=False | Windows/Linux 环境变量兼容 |
6. config/logging_config.py:结构化日志
6.1 设计思路
项目统一使用 Python 标准 logging + 自定义格式化器,输出 JSON 格式的结构化日志。get_logger(name) 为每个模块提供带模块名的 logger 实例。
6.2 重点掌握
| 优先级 | 内容 | 原因 |
|---|---|---|
| ★★ 理解 | JSON 格式化日志的设计目的 | 方便 log 分析工具解析 |
| ★ 了解 | get_logger(name) 的 handler 防重复逻辑 | 避免多次调用时添加重复 handler |
7. memory/base.py:MySQL 惰性连接基类
7.1 设计思路
ChatHistoryStore 和 FeedbackStore 都需要 MySQL 连接,但不是每个请求都立即需要。_MySqlStore 基类提供惰性初始化的引擎属性——第一次访问 engine 时才创建连接,创建后缓存复用。pool_pre_ping=True 在连接被 MySQL 服务端断开后自动探活重连。
7.2 重点掌握
| 优先级 | 内容 | 原因 |
|---|---|---|
| ★★★ 必会 | 惰性引擎的 pool_pre_ping=True 设计 | 生产环境中 “MySQL gone away” 是高频问题 |
| ★★ 理解 | _execute_ddl() 封装的 DDL 执行模式 | 被 ChatHistoryStore 和 FeedbackStore 的建表逻辑复用 |
| ★ 了解 | 为什么不用 ORM 而用原生 SQL | 教学项目优先可读性,ORM 增加学习成本 |
8. 本讲小结
common.py提供了项目级的 UTC 时间规范 和 JSON 读写容错utils.py的stable_hash()是基于 SHA-256 的 确定性 ID 生成器json_store.py通过 模板方法模式(empty_data + normalize_data)提供可复用的 JSON 文件 Storeschemas.py用 Pydantic 定义请求/响应模型,FastAPI 自动校验settings.py用 pydantic-settings 加载.env配置,@lru_cache单例memory/base.py的_MySqlStore提供了 惰性 MySQL 连接 的公共能力

