四条安装路径怎么选:从 pip 到 compose
装一个项目之前,最值得花的十分钟不是照着 README 抄命令,而是先搞清楚这几条安装路径各自把哪些东西替你做掉了、又把哪些前置条件推给了你。DeepTutor 的 README 在「Get Started」开头一句写死了这件事:DeepTutor ships four installation paths(README.md:206),四条路共享同一套 workspace 布局——设置落在你启动目录下的 data/user/settings/,或者由 DEEPTUTOR_HOME 与 deeptutor start --home 显式指定。
本文所有行号与数值对应我们采集的仓库快照:HEAD 456f9c2,采集日 2026-08-10,deeptutor/__version__.py 里的版本号是 1.5.11。你自己 clone 之后行号可能已经漂了,文件名与字段名是稳的。
一、四条路的原文口径
先把 README 各 Option 的关键要素摆在一张表里,后面几节都是在解释这张表为什么长这样:
| 路径 | 命令主干 | 前置条件(README 原文口径) | README 位置 |
|---|---|---|---|
| Option 1 · PyPI | pip install -U deeptutor → deeptutor init → deeptutor start | Python 3.11–3.13,PATH 上有 Node.js 20+ | README.md:211-218 |
| Option 2 · 源码 | git clone → venv → python -m pip install -e . → ( cd web && npm ci --legacy-peer-deps ) → deeptutor init → deeptutor start --dev | 建议 Python 3.11–3.13 + Node.js 22 LTS,理由是对齐 CI 与 Docker | README.md:229-246 |
| Option 3 · Docker | 拉 ghcr.io/hkuds/deeptutor:latest(stable)或 :pre | :pre 标注为 pre-release,when available | README.md:295-296 |
| Option 4 · CLI Only | python -m pip install -e ./packaging/deeptutor-cli → deeptutor init --cli → deeptutor chat | README 明写「installed from a source checkout, not from PyPI」 | README.md:372-386 |
端口这一侧只有两个数要记:后端默认 8001、前端默认 3782,浏览器开 http://127.0.0.1:3782(README.md:220-222)。前端端口的默认值在代码里也能对上——deeptutor/services/config/launch_settings.py:15 的 DEFAULT_FRONTEND_PORT = 3782,deeptutor/services/config/runtime_settings.py:18 里同样是 "frontend_port": 3782。
二、最反直觉的一处:第四条路「装哪个包」,仓库里有四处表述
如果这篇只让我留一段,我留这一段。
Option 4 叫 CLI Only,README 给的装法是从源码 checkout 里装子包目录:python -m pip install -e ./packaging/deeptutor-cli,并且在正文里单独用一句话强调过 It isn't published to PyPI yet(README.md:755)。但仓库里同一件事至少有四处表述:
- README:没上 PyPI,只能从源码 checkout 装(
README.md:372、README.md:755)。 AGENTS.md:直接把pip install deeptutor-cli # CLI-only写成安装方式(AGENTS.md:78、AGENTS.md:126)。requirements/cli.txt头注:Public install: pip install deeptutor-cli(requirements/cli.txt:7)。SKILL.md:写pip install deeptutor-cli用于 CLI-only(SKILL.md:20)。
再看发布侧。.github/workflows/pypi-release.yml 的校验清单里只要求 deeptutor-<version>-py3-none-any.whl 这一个产物,不含 deeptutor-cli(.github/workflows/pypi-release.yml:139-141)。
四处文档口径与一处 CI 清单摆在这儿,差异是可核实的;以我们实读的仓库状态为准。至于哪一处”是对的”、为什么没同步,我们不推断,说完就停。
对你的实际影响只有一条:如果你打算走 Option 4,README.md:372-386 的源码 checkout 装法与 AGENTS.md:78/SKILL.md:20 的 pip 装法,指向的是两条不同的路径。这两条是否都可行,我们没有核实,也没有查过 PyPI 的实际状态;你在动手之前自己去包索引确认一次即可。
顺带记一下这条路的行为差异:deeptutor init --cli 与全量应用共享同一套 data/user/settings/ 布局,但跳过后端/前端端口的提问、embedding 默认关,同时仍然写出 system.json、auth.json、integrations.json、model_catalog.json、main.yaml、agents.yaml 六个文件(README.md:388)。也就是说,你之后想用知识库那条线,得回头把 embedding 那一项补上。
三、为什么一个 pip 包会要求你装 Node.js
Option 1 的前置条件里那句「PATH 上要有 Node.js 20+」是第二处容易愣住的地方——明明是 pip install。
答案在打包侧。MANIFEST.in 只有两行:recursive-include deeptutor_web * 与 recursive-include deeptutor_web/.next *(MANIFEST.in:1-2)。而 deeptutor_web 这个包在 git 里只入库了一个 __init__.py(git ls-files deeptutor_web 数得 1),它的实际内容由 scripts/prepare_web_package.py 从 web/.next/standalone 拷进来(scripts/prepare_web_package.py:31-53),拷之前如果找不到 web/.next/standalone/server.js 就直接报错退出(scripts/prepare_web_package.py:38-42)。
发布工作流那边把逻辑说得更直白:只产 wheel、不产 sdist,注释给的理由就是完整 wheel 里内含打包好的 Next.js 资源(.github/workflows/pypi-release.yml:115-125)。
把这三处并排放着看:wheel 里带的是已经构建好的 Next.js standalone 产物;同时 README 把 PATH 上的 Node.js 20+ 列为 Option 1 的硬前置条件(README.md:211-218)。这两件事同时成立,所以 pip 装完不等于零 Node 依赖,这条前置条件不是可选项;至于 Node 在运行期具体承担什么角色,我们读到的这几处并没有写明,也没有构建或运行过,本文不推断。
Node 版本上还有一处细微差别值得单独拎出来:Option 1 写的是 Node.js 20+(README.md:211-218),Option 2 建议 Node.js 22 LTS 并给出理由是「对齐 CI 和 Docker」(README.md:229-246)。这个建议在两处都能对上:Dockerfile 的 frontend-builder 与 node-runtime 两个 stage 用的都是 node:22-slim(Dockerfile:23、Dockerfile:59),CI 的 tests.yml 里 Node 侧也是 node-version 22(.github/workflows/tests.yml:134-140)。你要复现构建问题,用 22 比用 20 更接近上游跑的那套环境。
四、Python 版本上限不是随手写的
pyproject.toml:12-18 写的是 requires-python = ">=3.11,<3.14",并且在注释里给了上限的理由:3.14 上 pip 找不到部分编译依赖(例如 faiss-cpu)的 wheel,会退化成注定失败的源码构建,注释引用了 issue #664。CLI-only 子包的约束一致,同样是 >=3.11,<3.14(packaging/deeptutor-cli/pyproject.toml:9-12)。
CI 那边的做法与这个上限是配套的:测试矩阵跑 Python 3.11/3.12/3.13,另外以 experimental: true(即 continue-on-error)额外跑一次 3.14(.github/workflows/tests.yml:67、:84-90)。
还有一处坑在 extras 上:graphrag 与 rag-lightrag 两个分组都带 python_version < '3.14' 的 marker,注释写明否则 pip 会静默把 deeptutor 回退到最后一个不带这些 extra 的版本 1.4.5(pyproject.toml:197-215)。这类「装完了、版本却不是你以为的那个」的情况没有报错提示,所以装完之后值得先把版本号确认一遍。
另外 math-animator 这个 extra 只有 manim>=0.19.0 一项,但注明系统前置需要 LaTeX、pkg-config、cairo、cmake、ffmpeg,这些都在 pip 之外装(pyproject.toml:193-195)——只 pip install ".[math-animator]" 是不够的。至于 requirements/ 下那七个文件各自管什么、与 pyproject 的分组怎么对应,我们另有一篇专门讲,这里不展开。
五、容器这一路:形态不止一种,且它会执行外部程序
Option 3 在 README 里只是一句「拉镜像跑起来」,但 CONTAINERIZATION.md 把部署形态明确拆成了三种(CONTAINERIZATION.md:22-31):
docker run:rootful、可写 rootfs、单个 bind mount;docker compose:额外带 PocketBase 与 sandbox-runner 两个 sidecar;podman compose -f compose.yaml:rootless、只读 rootfs、tmpfs。
单容器那一路有个省事的点:只需要发布 3782,8001 的发布是可选的(README.md:307)。
需要如实说明的是 sandbox-runner 这个 sidecar 的性质。它由 Dockerfile.runner 构建(110 行、单阶段、不含 app 代码,只 COPY 一个 deeptutor/services/sandbox/runner/server.py 到 /app/server.py,见 Dockerfile.runner:19、:98),在 docker-compose.yml 里不开 ports:,只在内部网络以 http://sandbox-runner:8900 可达(docker-compose.yml:110-115、:146)。它的存在意味着这套部署会在容器里执行命令与外部程序:它挂载了 ./data/user/workspace、./data/users 与只读的 ./data/cli-apps(docker-compose.yml:119-144),runner 镜像里预装了 git、curl、ripgrep、jq、build-essential、nodejs 等 apt 包(Dockerfile.runner:26-35)。
仓库自己也把这块的边界写在注释里了,原样记录两条:其一,every command in this container shares one filesystem view,并注明 per-command isolation 是 roadmap item(docker-compose.yml:119-144、:124);其二,非 admin 账号之间可以互读对方的 settings、chat_history.db 与 knowledge_bases,注释写的是这种跨用户可见性在 invite-only 的信任姿态下被接受、不再做进一步限制。而 compose.yaml(podman 那一份)明确不含 sandbox-runner sidecar,会退化到 bwrap 或者受 sandbox_allow_subprocess 控制的受限子进程(compose.yaml:38-42)。
这几件事不是”安全建议”,是选路时必须知道的既有事实:你选哪份 compose,决定的不只是端口映射,还包括代码执行发生在哪个容器里、隔离到什么程度。五个 compose 文件各自干什么,我们另有一篇专门讲,这里不铺开。
六、Windows 侧不能省的三件事
- 仓库自带 Windows 批处理:
scripts/start_backend.bat(24 行)与scripts/start_frontend.bat(12 行)(ls scripts,行数用wc -l)。scripts/一共 9 个文件,7 个.py加这 2 个.bat。 - Option 2 与 Option 4 都要先自建 venv(
README.md:229-246、README.md:372-386)。Windows 侧建 venv 与激活的具体写法,请以 README 这两个命令块里的原文为准,本文没有逐字转录;直接照抄面向 macOS/Linux 的那一行,在 Windows 上通常是走不通的,动手前先把命令块整块看完。 - 中文用户名路径是仓库里点过名的问题:
.pre-commit-config.yaml把 pip-audit 整段注释掉了,注释写明原因是 pip-api 在含非 ASCII(中文)用户名路径的 Windows 上会 UnicodeDecodeError,引用了pip-api的 issue #123(.pre-commit-config.yaml:74-82)。如果你的 Windows 用户目录是中文的,这类路径编码问题在别的环节也值得先留个心眼。
七、一条能自己走完的决策路径
不列参数表,按你的处境倒推:
- 只想在本机把完整应用跑起来、不打算改代码 → Option 1。代价是你得先在 PATH 上备好 Node.js 20+,并接受配置落在你启动目录下的
data/user/settings/。 - 要读源码、改代码、提 PR → Option 2。它在 Option 1 之外还要
git clone、自建 venv、以-e .从源码装,并多一步npm ci --legacy-peer-deps,启动命令也换成deeptutor start --dev(见第一节表)。换来的是本机有一份可改的web/源码树与--dev这个启动模式;--dev具体带来什么运行时行为,我们没有构建也没有运行过,不下结论。Node 用 22 LTS,与 CI、Dockerfile 一致。顺带一提,CONTRIBUTING.md写明分支策略是dev与multi-user两条,并明确写着「不要直接向main提 PR」(CONTRIBUTING.md:36-42)——打算提 PR 的话这条先看。 - 不想污染本机环境,或要多用户 / 沙箱形态 → Option 3,并且要先决定用三种部署形态里的哪一种;带 sandbox-runner 的那一路涉及容器内执行命令,上一节的事实要先看完。
- 只要命令行、不要 Web UI → Option 4。动手前先把第二节列的那四处表述对一遍,自己确认走哪条装法。
有一个维度我们没有依据,就不比:四条路在资源占用、启动耗时、稳定性上的差别。我们没有安装、没有构建、没有运行过任何一条,任何这方面的结论都不该由本文给出。
八、你可以照着核的五步
grep -n "four installation paths" README.md,从这一行往下读四个 Option 的折叠块,确认前置条件与命令主干。cat MANIFEST.in,再git ls-files deeptutor_web,然后打开scripts/prepare_web_package.py:31-53——把「wheel 里的前端从哪来」这条链走通。sed -n '12,18p' pyproject.toml,读requires-python那段注释,确认<3.14的理由与 issue 编号。- 对比
README.md:372、AGENTS.md:78、requirements/cli.txt:7、SKILL.md:20四处关于 deeptutor-cli 的表述,再看.github/workflows/pypi-release.yml:139-141的产物清单。 - 打开
docker-compose.yml:110-146与compose.yaml:38-42,确认 sandbox-runner 在两份文件里的有无差异。
需要说明的边界:本文只读了 README 的 Get Started 段、pyproject.toml 的元数据与 extras 段、MANIFEST.in、几处 CI 工作流片段与 compose / Dockerfile 的注释,没有逐行读完这些文件;web/ 下的前端实现、deeptutor_cli/ 的 Typer 定义我们都没有读,所以 README 与 SKILL.md 列出的 CLI 子命令与选项没有与代码逐条核对。文中出现的端口、版本与默认值都是仓库里的默认配置与文档口径,不是运行结果的保证。
本文依据 DeepTutor 官方仓库(github.com/HKUDS/DeepTutor)的 README、AGENTS.md、
pyproject.toml 与 deeptutor/ 下的源码整理,核对日 2026-08-10,对应仓库快照 456f9c2(版本 1.5.11)。
本文内容为仓库源码与文档口径,我们没有安装、部署或运行过该项目,也没有调用过其中任何一个模型 API,
因此不涉及生成质量、响应速度与教学效果的任何描述。
参数与默认值随版本变动,请以仓库最新代码与 --help 的实际输出为准。
安全相关做法请结合自身环境评估,本文不构成安全方案建议。