第 00 章:环境准备¶
目标:把 MiniHarness 跑起来,知道代码在哪里、测试怎么跑、每个文件对应什么。读完整本手册不装 Node.js、不装 TypeScript;必需的 pip 基础件有六个:SSE 传输用的
httpx、跨进程锁用的filelock、文件观察用的watchdog、YAML 配置用的pyyaml、持久化帧容器用的zstandard、图片管线用的pillow。
在 system-map 中的位置¶
准备章(体裁:准备)。模块总图与 Capstone 见 system-map Fig S6;全章验收见 功能模块表 第 00 行。
0.1 前置知识¶
- Python 3.10+。核心实现以标准库为骨架:
unittest、json、sqlite3、threading、dataclasses、asyncio;成熟开源库优先补齐关键能力——httpx(SSE 传输 + Web 出站)、filelock(跨进程锁)、watchdog(文件观察)、pyyaml(YAML 配置)、zstandard(持久化帧容器)、pillow(附件图片管线),无语义等价库处才手写。 - 基本的事件 / 回调 / 上下文概念。
- 了解一个 Agent 回合的 wire 形状:
user message → assistant(可能带 tool call)→ tool result → assistant。
如果你不熟悉最后一条,先去 docs/report/05-roadmap.md 的「§6 从 0 到掌握的完整路线图」里 P0 前置知识 一行(必读 / 必做 / 验收),再对照手册第 4 章的回合时序。
怎么读这套手册¶
克隆仓库时 miniharness/ 已是完整实现。默认推荐 走读对照:先跑该章测试,再读对应源码,最后做检查点练习。若要在空目录亲手复现章内骨架,见 guides/learning-paths.md 的空白复现模式。模块在整体架构中的位置见 system-map.md。
0.2 目录结构¶
mini-deepseek-harness-python/ ← 仓库根
├── README.md ← 项目总览
├── ROADMAP.md ← 完整路线图(从 0 到 1 复现 dsh)
├── miniharness/ ← 可运行代码包(随章节逐步构建,家族布局见 architecture.md §1)
│ ├── core/
│ │ ├── session/ ← 第 1 章:事件溯源会话
│ │ ├── scope.py ← 第 2 章:Context + 事件总线 + 作用域
│ │ ├── tools.py ← 第 3 章:工具注册表 + 执行管线
│ │ └── agent_loop/ ← 第 4 章:Agent Loop 状态机
│ ├── llm/ ← 第 4 章:StreamChunk 协议 + 适配器 + 重试
│ ├── boot/ ← 第 5 章:启动与组合
│ ├── seams/ ← 第 6 章:进阶扩展口
│ ├── cli/ protocol/ preset/ extensions/ interaction/ client/
│ ├── goal/ plan/ jobs/ skills/ commands/ attachment/ web/
│ ├── example_plugins.py ← 第 5 章 boot 演示插件
│ └── demo.py ← 端到端演示(无 key 可跑)
├── tests/ ← 每章验收测试(unittest)
│ ├── test_session.py
│ ├── test_bus.py
│ ├── test_tools.py
│ ├── test_loop.py
│ ├── test_persistence_boot.py
│ ├── test_seams.py
│ └── …(cli/composition/goal/plan/jobs/skills 等随对应家族展开)
└── docs/ ← 文档
├── index.md ← 文档入口(报告 + 手册索引)
├── chapters/ ← 00-setup.md ~ 15-schemastery.md(本章所在目录)
└── report/ ← 分析报告(MkDocs 站点)
每个 miniharness/ 文件的"第 N 章"标注,就是它对应的手册章节。想快速定位一个概念:先在手册找章节,再按章节号找文件。完整目录树见 architecture.md §1.2(比下列摘要更长)。
0.3 跑起来¶
# 在仓库根目录
python -m unittest discover -s tests -t . # 全部测试,应当 OK
python -m miniharness.demo # 端到端演示(假模型 + 工具 + 持久化)
如果 python 不是 3.10+,用 python3。跑完 demo 会输出一个完整回合的日志,最后提示"演示完成"并给出临时目录路径——那是一个可回放的会话存档,第 5 章会解释它。
0.4 环境变量¶
启动行为由环境变量驱动。常用变量如下(更多见 docs/architecture.md 映射表;webui 见 webui/README.md):
| 变量 | 默认 | 作用 |
|---|---|---|
MINIHARNESS_HOME |
~/.miniharness |
CLI 数据主目录:--profile headless 会话与 miniharness sessions 落在 <HOME>/sessions,用户预设落在 <HOME>/.agent-presets(cli/headless.py、cli/session_cmds.py、preset/presets.py) |
MINIHARNESS_WEB_HOST |
127.0.0.1 |
--profile web 监听地址(web/launcher.py;--host CLI 参数优先) |
MINIHARNESS_WEB_PORT |
0(OS 分配) |
--profile web 监听端口(--port CLI 参数优先) |
MINIHARNESS_WEB_TOKEN |
空(无门) | 可选认证门:配置后 /api/* 全域强制、WS 升级拒绝写 HTTP 401;监听非回环具体地址无 token 启动即拒绝,通配地址(0.0.0.0/::)一律拒绝(web/auth.py、web/host.py,docs/interface-wire.md §1.1) |
MINIHARNESS_WEBUI_DIST |
web/static/(教学 vanilla) |
静态服务前端根,指向 webui/dist/ 即承载产品化前端(web/frontend.py) |
MINIHARNESS_WEBUI_PROXY |
http://127.0.0.1:8899 |
仅 webui 开发期:Vite dev server 的 /api 与 /api/remote.mux 代理目标(webui/vite.config.ts) |
MINIHARNESS_MAX_STEPS |
50 |
Agent Loop 死循环守卫步数上限(第 4 章) |
DEEPSEEK_API_KEY |
— | 真实 DeepSeek 适配器 / headless 凭据 |
DEEPSEEK_BASE_URL |
https://api.deepseek.com/anthropic |
可选,覆盖官方 Messages 端点(兼容代理) |
Windows 控制台(GBK 代码页)查看
presets/sessions输出的中文会乱码(数据本身是 UTF-8,未损坏):设PYTHONIOENCODING=utf-8(如set PYTHONIOENCODING=utf-8 && miniharness presets list)即可正常显示。
0.5 三条学习纪律¶
- 先跑测试,再读代码。每个文件都配了验收测试,测试就是"始终成立的性质"清单。先看测试想验证什么,再去看实现,比顺着代码读效率高。
- 每章完成"检查点练习"。练习都是 10~20 行的小改动,改完要么让测试通过,要么新增测试固定你的行为。
- 每章末尾做"回到 dsh"对照。打开真实仓库对应源码,只读关键 50 行,体会"约定一样、实现简化"在哪里。
0.6 简化立场:与上游的差异¶
MiniHarness 是清晰的 Python 复现(以可复现、可学习为核心),但不是逐字节移植。下面是简化清单,每一条在对应章节都有详细说明。读手册前先扫一眼,避免在简化处花时间找"上游为什么没有"。
| MiniHarness 简化 | 真实 dsh |
|---|---|
同步事件总线为教学主体 + aemit/awaterfall/aparallel/aserial async 变体(agent/pre-step、agent/request-error 已 async 化) |
异步(@deepseek-ai/cordis 基于 fiber/async) |
服务按隔离标签键控的全局 store(ctx.get 缺省返回 None;ctx.isolate(name) 换标签实现 per-agent 隔离;不再使用 declarative provides 字段,改为 apply 期 provide 动态登记) |
反射 reflect 全量协议(inject/provide/get/set/isolate/intercept + ctx.<name> 属性代理) |
工具体执行体直接 await(async 约定);同步工具函数经 _maybe_await 解包;阻塞调用以 asyncio.to_thread 显式放行(第 12 章) |
isConcurrencySafe 并行池 + 串行屏障 |
| LLM 流式 async 约定 + httpx 异步 SSE 传输(abort 置位即关闭连接,真取消;per-read idle 300s 同上游) | fetch + AbortSignal 原生异步流 |
同步门面经进程级常驻单事件循环驱动(core/agent_loop/resident_loop.py 懒加载单例;主线程 Ctrl+C 协作取消) |
常驻单事件循环(Node 进程固有) |
JSON/YAML 配置 + 补丁(pyyaml 硬依赖承载 YAML;!!js 仅 process.env.<NAME> 子集) |
YAML cordis.yml(同样的 id/insert/replace 语义) |
LLM 失败以异常抛出(finish 带内 {kind:'error'|'aborted'} 与异常同走 agent/request-error waterfall) |
LlmError 编码 CONTEXT_WINDOW_EXCEEDED / EMPTY_RESPONSE(可重试)等 |
agent/turn-stopping(串行终点检查点,见第 4/13 章)、system-prompt/assemble 两个 waterfall 都在 mini 中提供 |
上游都有 |
| JSONL 载体与上游一致(zstd 拼接帧容器 + 一行一事件 + format.ts 目录布局,明文模式可配;教学章节用简化明文形态);另有一个仅用于演示「扩展口可换实现」的 SQLite 教学后端(上游无对应实现,第 5 章) | JSONL 默认 checksum + Zstandard 帧容器(session-persistence-jsonl);无 SQLite 持久化后端(SQLite 仅用于 session-query 检索域) |
assistant/message source 带 {kind, provider, model} |
消息 {id, role, content, source} 全字段 |
检查点¶
python -m unittest discover -s tests -t .全部通过python -m miniharness.demo输出一次完整的回合日志- 能说出
core/session、core/scope、core/tools、llm/、core/agent_loop、core/session/persistence、boot/各自管什么 - 读完 system-map Fig S6 后,从 Capstone 清单中至少完成一项(
demo、examples/chat_demo.py、plan_goal_demo.py --approve、或--profile web+ webui 构建)