首页
/ DeepTutor v0.3.0 发布解析:统一 PromptManager 架构、CI/CD 自动化与本地优先部署

DeepTutor v0.3.0 发布解析:统一 PromptManager 架构、CI/CD 自动化与本地优先部署

2026-09-05 21:46:56作者:晏闻田Solitary

DeepTutor v0.3.0 是一次以开发者体验为核心的版本:它将分散在 10 多个 agent 模块中的提示词加载逻辑收敛到统一的 PromptManager 单例,引入 GitHub Actions 自动化测试与 Docker 镜像发布流水线,并将部署路径简化为一条 docker run 命令、把 LLM 配置聚焦到 Ollama 与 LM Studio 等本地推理端。读完本文,你可以理解 PromptManager 的缓存与多语言回退机制是如何在源码中落地的,并能直接复现 v0.3.0 的容器化部署与升级流程。

版本概览

v0.3.0(发布日期 2026-01-06)围绕三条主线展开,完整记录见 v0.3.0 发布说明

  1. 统一 PromptManager 架构:集中式提示词管理,替代各 agent 自行维护的 _load_prompts 方法;
  2. GitHub Actions 与 CI/CD:依赖自动更新、自动化测试、Docker 镜像自动发布;
  3. 预构建 Docker 镜像:从 GitHub Container Registry 拉取镜像,约 30 秒完成部署。

此外还有 Local-First LLM 配置:设置页只保留本地推理端 Ollama(默认)与 LM Studio,移除 OpenAI、Gemini、Azure 等云端 provider,对齐项目"隐私优先、自托管 AI 辅导"的定位。

统一 PromptManager 架构

从分散加载到单例收敛

v0.3.0 最重要的重构是:把所有 agent 模块的提示词加载收敛到一个集中式的 PromptManager 单例。发布说明列出了四项核心改进:

  • 全局缓存(global caching):提示词加载一次后驻留内存,并支持模块级失效(module-level invalidation),可在不动全局缓存的情况下只刷新某个模块;
  • 语言回退链(language fallback chain):zh → enen → zh,保证任何语言配置下都能取到可用提示词;
  • ISO 639-1 合规:所有 cn/ 提示词目录统一重命名为 zh/,消除 cn 这一非标准语言代码;
  • agent 代码瘦身:删除各模块中重复的 _load_prompts 方法与类级缓存。

发布说明中该实现位于 deeptutor/core/prompt_manager.py,并从 deeptutor/core/__init__.py 导出 get_prompt_manager()。从当前仓库的源码结构看,这一模块后来被重组到了 deeptutor/services/prompt/ 包中,核心实现见 PromptManager,对外导出见 prompt 包入口

from deeptutor.services.prompt import get_prompt_manager, PromptManager

# 获取全局单例
pm = get_prompt_manager()

# 为某个 agent 加载提示词
prompts = pm.load_prompts("solve", "solve_agent", language="en")

# 从已加载的配置中安全取值
system_prompt = pm.get_prompt(prompts, "system", "base")

源码中的关键机制

对照 manager.py,发布说明中的每一项特性都能在源码中找到对应实现:

单例模式PromptManager.__new__ 保证全局只有一个实例(manager.py#L49-L52),模块级的 get_prompt_manager() 函数则维护了一个惰性初始化的全局引用(manager.py#L238-L247)。

全局缓存与键设计:类属性 _cache{module}_{agent}_{lang}[_{subdir}] 为键缓存整个提示词字典(_build_cache_keymanager.py#L83-L92)。因此同模块同 agent 不同语言、或不同子目录(如 solve 模块的 solve_loop)的提示词互不干扰。缓存失效则分两级:clear_cache() 清空全部,clear_cache("research") 只删除以 research_ 开头的键(manager.py#L207-L219)——这正是发布说明里"module-level invalidation"的落地方式。若外部直接改写了 YAML 文件,还有 reload_prompts() 强制绕过缓存重新加载(manager.py#L221-L235)。

语言回退链LANGUAGE_FALLBACKS 定义了 zh: ["zh", "cn", "en"]en": ["en", "zh", "cn"]manager.py#L23-L26)。查找时按"主语言 → 区域变体归并 → 兜底英文"的顺序逐目录尝试,任何一个目录命中即停止。值得注意的是回退链中保留了 cn 这一历史代码——这与"所有 cn/ 目录已重命名为 zh/"的迁移历史相吻合:新目录用标准代码,查找链兼容旧命名,避免破坏存量提示词文件。

容错取值get_prompt(prompts, section, field, fallback) 对"section 不存在 / 层级不是字符串 / 嵌套字段缺失"三种情况统一返回 fallback 而非抛异常(manager.py#L174-L205),使得 agent 侧的提示词读取完全无样板代码。

十个 agent 模块的迁移

发布说明列出了本版本迁移到 PromptManager 的 10 个文件,覆盖了当时仓库中主要的 agent 工作流:

模块 迁移文件(v0.3.0 时的路径)
research research/agents/base_agent.py
solve solve/base_agent.py
guide guide/agents/base_guide_agent.py
question question/agents/generation_agent.pyquestion/agents/validation_agent.pyquestion/validation_workflow.py
ideagen ideagen/idea_generation_workflow.pyideagen/material_organizer_agent.py
co_writer co_writer/edit_agent.pyco_writer/narrator_agent.py

从当前仓库结构看,co_writer/edit_agent.py 等文件已重组至 deeptutor/co_writer/deeptutor/agents/ 之下(如 deeptutor/agents/question 目录),提示词资产则集中在各模块的 prompts/{zh,en}/ 目录中——例如 question 模块的 pipeline.yaml

遗留代码清理

与新增同步进行的是删除:

  • 删除 deeptutor/agents/solve/utils/prompt_loader.py(独立提示词加载器);
  • 移除 BaseAgent 上的 use_prompt_loader 参数;
  • 清理所有模块中的 _PROMPT_CACHE 类级缓存;
  • 移除 solve/__init__.py 中的 PromptLoader 导出。

这意味着提示词加载从此只有一个入口,"双轨加载"(旧 PromptLoader 与新 PromptManager 并存)被彻底关闭,后续维护只需关注一处。

数据驱动的前端配置端点

发布说明还提到新增了 /api/v1/config/agents 端点,用于"数据驱动的前端配置"(data-driven frontend configuration)。当前仓库中对应的路由是 agent_config.py,提供 GET /agentsGET /agents/{agent_type} 两个端点——前端无需硬编码 agent 列表与元数据,而是从后端动态获取,这与此前 agent 模块统一注册到运行时注册表的重构方向一致。

GitHub Actions 与 CI/CD 自动化

v0.3.0 引入了三套自动化工作流:

工作流 说明
dependabot.yml 依赖自动更新(pip、npm、GitHub Actions、Docker 四类生态)
tests.yml push / PR 触发的自动化测试
docker-publish.yml 自动将 Docker 镜像发布到 GHCR

当前仓库的 .github/workflows 目录下保留了 tests.yml 与镜像发布流水线(现名 docker-release.yml),可以据此还原这套 CI 的完整构成:

tests.yml 在 push 到 main/dev 分支或对应 PR 且路径命中 deeptutor/**tests/**requirements/**web/** 等范围时触发,串行编排了四个检查:

  1. Lint and Format:Python 3.11 环境下安装 ruff==0.16.0,依次执行 ruff check .ruff format --check .
  2. Web Node Tests:Node.js 22 + npm ci --legacy-peer-deps(依赖锁定文件为 web/package-lock.json),执行 npm run test:node
  3. Import Check:在 Python 3.11/3.12/3.13 矩阵(外加 3.14 实验性、失败不阻塞)上安装 requirements/server.txt 后,逐个 import 关键模块做冒烟校验,其中明确包含 from deeptutor.services.prompt.manager import PromptManager 这一项——PromptManager 作为核心基础设施被纳入导入健康检查;
  4. Python Tests:与 import-check 相同的版本矩阵,追加安装 requirements/partners.txtpytest pytest-asyncio,并在 data/user/settings/main.yaml 中写入最小运行配置(system.language: enlogging.level: WARNING)后执行 pytest -q tests deeptutor/learning/tests

四个 job 的结果最终汇入 test-summary,以 Markdown 表格写入 PR 摘要(GITHUB_STEP_SUMMARY),任一失败即整体失败。这套流水线正是 PromptManager 重构能在 10 个 agent 模块上安全落地的质量保障基础。

预构建 Docker 镜像:约 30 秒完成部署

v0.3.0 提供了 GitHub Container Registry 上的预构建镜像,发布说明给出的部署命令是:

docker run -d --name deeptutor \
  -p 8001:8001 -p 3782:3782 \
  --env-file .env \
  -v $(pwd)/data:/app/data \
  ghcr.io/hkuds/deeptutor:latest

参数含义:

  • -p 8001:8001:后端 API 端口;-p 3782:3782:前端 Web 服务端口;
  • --env-file .env:从本地 .env 注入环境变量(如密钥类配置);
  • -v $(pwd)/data:/app/data:把宿主机当前目录下的 data/ 挂载到容器内 /app/data,知识库、记忆与用户数据(如 data/user/settings/main.yaml)持久化在容器外,升级镜像不丢数据。

发布说明称使用该预构建镜像可在约 30 秒内完成部署,省去本地构建 Dockerfile 的耗时。仓库根目录同时提供 docker-compose.ymlcompose.yaml 等编排文件,适合需要多服务协同的场景。

Local-First LLM 配置

v0.3.0 简化了设置页,使其只面向本地 LLM provider:

  • Ollama(默认)
  • LM Studio
  • ❌ 移除云端 provider(OpenAI、Gemini 等)

发布说明将这一取舍定位为对齐 DeepTutor "privacy-first、self-hosted AI tutoring" 的产品愿景:提示词、知识库与对话全部在用户自己的硬件上完成推理,数据不出本机。

值得说明的是同一份发布说明的 "What's Changed" 部分收录了 PR #34(Dynamic LLM Provider Support, Local & Cloud),表明动态 provider 能力在本版本开发周期内也在演进——即"设置页聚焦本地端"与"底层支持动态 provider 注册"是不同层面的两件事,前者是产品策略,后者是基础设施能力。

测试佐证:PromptManager 的行为契约

发布说明中的每一项 PromptManager 特性,都有对应单元测试固化,见 test_prompt_manager.py

  • 单例契约PromptManager() 两次实例化为同一对象,get_prompt_manager() 返回的也是该对象(test_singleton_pattern);
  • 缓存契约:同一 (module, agent, language) 两次 load_prompts 返回同一字典对象(prompts1 is prompts2);
  • 模块级失效clear_cache("research") 之后 solve 的缓存保留、research 的缓存被清(test_clear_cache_module_specific);
  • 多语言加载:对 research/pipelinesolve/solve_agent(含 solve_loop 子目录)分别验证 en 语言加载;
  • 容错取值get_prompt 对嵌套字典与缺失字段的行为(test_get_prompt_helper)。

语言解析相关的测试见 test_parse_language.py,与 parse_language(PromptManager 内部的语言代码归一化入口)配套。

升级方式

发布说明给出的升级路径:

git pull origin main
docker pull ghcr.io/hkuds/deeptutor:latest

源码部署执行第一条命令后重启服务;容器部署执行第二条命令后用前文的 docker run 参数重新拉起容器即可,由于数据目录挂载在容器外,升级对用户数据无破坏性。

小结

v0.3.0 表面是一次发布说明,实质是 DeepTutor 从"功能开发期"走向"工程化运营期"的转折点:

  • 架构上PromptManager 单例 + 全局缓存 + 语言回退链消除了 10 个 agent 模块的重复加载逻辑,且用模块级缓存失效保留了灵活性;
  • 流程上,ruff 格式化、多 Python 版本矩阵的导入检查与 pytest 流水线、GHCR 镜像自动发布,让每次合并都有质量门禁;
  • 部署上,一条 docker run 加数据目录挂载即可完成本地化部署,配合 Ollama/LM Studio 的本地推理配置,形成完整的自托管闭环。

对后续版本的读者,理解 v0.3.0 的这一层架构,是理解当前仓库中 deeptutor/services/prompt 包、.github/workflows 流水线以及 Dockerfile 部署形态的起点。

登录后查看全文
热门项目推荐
相关项目推荐