Capstone
贯穿项目:Hamauls Orion One Project Through All 17 Stages
Hamauls Orion 是一个私有化多模态推理 Agent 平台:能读懂你的文档与图片、能多步推理、能调用工具、能接受评测、能上线扛压。它不是一个额外的项目,而是整条学习路线的载体——第 1 到第 17 阶段共 17 个里程碑 M1–M17,全部落在同一个仓库上。每个阶段结束,你都在这个系统里多交付一块真实组件;学完全部阶段,它就是一个可以演示、可以压测、可以写进简历的完整产品。
总览
★
为什么是「一个项目串到底」:真实的工程能力体现在接口设计、性能取舍、失败恢复与长期维护上,而这些只有在一个持续演进的代码库里才会暴露。每阶段一个独立小 demo 永远练不到三件事:① 接口怎么设计才不会被后面的需求推翻;② 性能瓶颈真实出现在哪里(你只能在系统长复杂之后才看到);③ 三个月后回来改自己的代码是什么体验。所以 Hamauls Orion 从第 1 天就建仓库,之后每一阶段都往同一个系统里加东西。
下面这张图是 Hamauls Orion 的目标态架构(第 17 阶段完成时的样子)。你在早期阶段只需要实现最下面一层的极小一部分,但它能让你始终知道「我现在做的这块,最终会嵌在哪里」。
text┌──────────────────────────────────────────────────────────────────────────┐
│ 客户端层 │
│ React + TS 聊天界面 · 文档上传 · 引用溯源面板 · 工具调用可视化 │
│ 协议:HTTP/2 + SSE(流式) ← 第 1、4 阶段 │
└───────────────────────────────┬──────────────────────────────────────────┘
│ SSE / HTTP
┌───────────────────────────────▼──────────────────────────────────────────┐
│ 接入层 Gateway(FastAPI) │
│ 鉴权 · 限流(按 token)· 超时预算 · 幂等键 · 熔断 · 背压 · 会话管理 │
│ ← 第 4 阶段(M4) │
└───────────────────────────────┬──────────────────────────────────────────┘
│ gRPC(HTTP/2 + protobuf,内部 mTLS)
┌───────────────────────────────▼──────────────────────────────────────────┐
│ 编排层 Orchestrator │
│ 查询改写 · DAG 规划(拓扑排序)· 多 Agent 分工 · 工具路由 · 状态检查点 │
│ ← 第 14 阶段(M14) │
└───┬─────────────────┬──────────────────┬────────────────────┬────────────┘
│ │ │ │
┌───▼──────────┐ ┌────▼───────────┐ ┌────▼──────────┐ ┌───────▼──────────┐
│ 检索服务 │ │ 推理服务 │ │ 工具服务 │ │ 多模态服务 │
│ Retriever │ │ Inference │ │ ToolHub │ │ Vision │
│ │ │ │ │ │ │ │
│ HNSW 向量 │ │ vLLM/SGLang │ │ MCP servers │ │ 版面分析 / OCR │
│ BM25 倒排 │ │ 量化 / 投机解码 │ │ SQL 只读 │ │ VLM 问答 │
│ RRF 融合 │ │ 前缀缓存复用 │ │ 沙箱代码执行 │ │ 图像向量化 │
│ 交叉编码器重排│ │ KV 量化 │ │ 日历 / 邮件 │ │ │
│ 上下文压缩 │ │ │ │ │ │ │
│ ← 第 3、13 │ │ ← 第 8、9、10 │ │ ← 第 14 │ │ ← 第 11 │
└───┬──────────┘ └────┬───────────┘ └───────┬───────┘ └───────────────────┘
│ │ │
┌───▼─────────────────▼─────────────────────▼──────────────────────────────┐
│ 数据与模型层 │
│ Postgres + pgvector(文档 / 元数据)· Redis(缓存 / 幂等键 / 队列) │
│ 对象存储(原始文件 / 权重)· 领域微调模型(LoRA 合并) │
│ ← 第 3、6、7、9 阶段 │
└───────────────────────────────┬──────────────────────────────────────────┘
│ OTel 全链路 trace + 指标
┌───────────────────────────────▼──────────────────────────────────────────┐
│ 评测与安全层(第 15 阶段 · M15) │
│ 黄金评测集 · LLM-as-Judge · CI 回归门禁 · 输入注入检测 · 输出护栏 │
│ 红队用例 · 可观测面板(TTFT / TPOT / 排队 / 成本) │
└──────────────────────────────────────────────────────────────────────────┘
↑ 部署层(第 16 阶段 · M16):Docker → K8s → 灰度 → 压测 → 告警
| 非功能目标(SLO) | 数值 | 由谁保证 |
|---|---|---|
| 首 token 延迟 TTFT | P95 < 1.5 s | 第 4 阶段(排队与流式)+ 第 16 阶段(推理优化) |
| token 间隔 TPOT | P95 < 60 ms | 第 16 阶段(量化、批调度、投机解码) |
| 端到端准确率 | 自建评测集 ≥ 基线 +30% | 第 6、9、13 阶段 |
| 引用可核验率 | ≥ 95% | 第 13 阶段(引用溯源) |
| 多步任务成功率 | > 70%(10 步以上任务) | 第 14 阶段(Agent 编排) |
| 每千次请求成本 | 可核算、可解释 | 第 16 阶段(成本模型 + 缓存) |
| 故障恢复 | 注入延迟/丢包/下游故障不雪崩 | 第 4 阶段(熔断、降级、重试) |
| 缓存命中率 | 确定性请求命中率可统计 | 第 3 阶段(LRU)+ 第 13 阶段(语义缓存) |
一、仓库结构与模块划分
这份目录结构从第 1 阶段就建立,之后 16 个阶段只是往里填内容。早期不要为了「将来可能需要」而过度设计——先建目录与接口,实现可以留 TODO。
texthamauls-orion/
├── pyproject.toml / uv.lock / Makefile / README.md
├── configs/ # 所有可调参数(hydra 风格,支持命令行覆盖)
│ ├── base.yaml
│ ├── train/{sft.yaml, dpo.yaml, grpo.yaml}
│ └── serving/{vllm.yaml, gateway.yaml}
├── src/hamauls_orion/
│ ├── core/ # M1:配置、结构化日志、异常体系、通用类型
│ │ ├── settings.py # Pydantic Settings(环境变量注入)
│ │ ├── logging.py # structlog 配置,带 request_id 串联
│ │ └── errors.py # Retryable / Fatal 异常分层
│ ├── data/ # M1、M6:数据管线与版本管理
│ │ ├── pipeline.py # 并发调用 + 限流 + 断点续跑
│ │ ├── clean.py # polars 清洗、去重、质量报告
│ │ └── version.py # 数据版本哈希与血缘
│ ├── scratch/ # M5:不依赖框架的教学实现
│ │ ├── autograd.py # 手写计算图与反向传播
│ │ └── optim.py # SGD / Adam / AdamW
│ ├── models/ # M8、M9:模型层
│ │ ├── transformer.py # 自研 GPT(RoPE / RMSNorm / SwiGLU / GQA)
│ │ ├── kv_cache.py # 增量解码 + 显存核算
│ │ └── adapters.py # LoRA / QLoRA 适配
│ ├── ranker/ # M6、M7:排序与训练
│ │ ├── baseline.py # LightGBM 基线
│ │ └── cross_encoder.py # 重排模型
│ ├── train/ # M7、M9:训练管线
│ │ ├── loop.py # 通用训练循环(AMP / 断点续训 / 早停)
│ │ ├── sft.py / dpo.py / grpo.py
│ │ └── tracking.py # 实验追踪(wandb / MLflow)
│ ├── index/ # M3:检索内核(本项目最有特色的部分)
│ │ ├── hnsw.py # 手写 HNSW 近似最近邻
│ │ ├── bm25.py # 倒排索引 + BM25
│ │ ├── cache.py # LRU + LFU 混合缓存(含 TTL 与并发保护)
│ │ └── scheduler.py # 优先队列调度器(含老化防饥饿)
│ ├── rag/ # M13:检索增强管线
│ │ ├── pipeline.py # 改写 → 混合召回 → RRF → 重排 → 压缩 → 生成
│ │ ├── compress.py # 上下文压缩与 token 预算
│ │ └── cite.py # 引用溯源(论断 → 原文 span)
│ ├── reason/ # M10:推理与测试时计算
│ │ ├── cot.py / sc.py # 思维链、自一致性
│ │ ├── prm.py # 过程奖励模型打分
│ │ └── budget.py # 推理预算路由
│ ├── mm/ # M11:多模态
│ │ ├── vlm.py # VLM 推理封装
│ │ └── ingest.py # PDF/扫描件 → 版面结构化
│ ├── agent/ # M14:Agent 与工具
│ │ ├── loop.py # ReAct / Plan-Execute 循环
│ │ ├── multi.py # 多 Agent 分工 + A2A 消息契约
│ │ ├── memory.py # 记忆分层与检查点
│ │ └── mcp/ # 自建 MCP servers(检索 / SQL / 沙箱)
│ ├── serving/ # M4、M16:服务层
│ │ ├── gateway.py # SSE 流式网关
│ │ ├── timeout.py # 分层超时预算
│ │ ├── retry.py # 分类重试 + 幂等键
│ │ ├── resilience.py # 熔断 / 限流 / 背压
│ │ └── vllm_backend.py # vLLM 接入
│ ├── guard/ # M15:护栏
│ │ ├── injection.py # 提示注入检测
│ │ └── output.py # 输出护栏(PII / 敏感 / 幻觉引用)
│ ├── evals/ # M15:评测
│ │ ├── metrics.py # Recall@k / MRR / NDCG / 编辑距离
│ │ ├── judge.py # LLM-as-Judge(含与人工一致性检验)
│ │ ├── gate.py # CI 回归门禁
│ │ └── datasets/ # 黄金评测集(版本化)
│ └── observability/ # M1、M15:可观测
│ ├── tracing.py # OTel span 组织
│ └── metrics.py # TTFT / TPOT / 排队 / 成本
├── proto/hamauls_orion.proto # M4:gRPC 契约
├── tests/{unit,integration,snapshots}/
├── scripts/ # 入口脚本(bench_*.py, loadtest, migrate)
├── bench/ # M2、M3、M16:基准与压测报告
│ ├── recall_vs_qps.md
│ ├── loadtest.md
│ └── cost_model.md
├── docs/
│ ├── architecture.md # 第 17 阶段:让人 10 分钟看懂
│ ├── perf/{roofline.md, latency-budget.md}
│ ├── net/{timeout-budget.md, diagnosis.md}
│ ├── exp/{baseline.md, alignment.md, rag-ablation.md}
│ ├── safety/redteam.md
│ └── report/engineering-report.md
├── docker/{Dockerfile, docker-compose.yaml}
└── k8s/{deployment.yaml, hpa.yaml, canary.yaml}
二、17 个里程碑总览
下面这张表是「学习进度」与「项目进度」的合一双清单。阶段验收 = 里程碑验收。每个阶段的详情页里也都有对应的里程碑卡片。
| M | 阶段 | 里程碑 | 核心交付 | 验收标准 |
|---|---|---|---|---|
| M1 | 01 编程与工程基础 | 仓库骨架与并发数据管线 | Hamauls Orion monorepo + CI 全绿 + asyncio 评测管线 | 干净机器上 clone 后一条命令跑通 |
| M2 | 02 计算机组成原理 | 性能剖析与容量模型 | roofline 报告 + 显存核算脚本 + 一次已验证优化 | 能定量解释任意慢算子 |
| M3 | 03 数据结构与算法 | 从零实现检索索引 | HNSW + BM25 + 缓存 + 调度器 + 召回率曲线 | 100 万向量上 Recall@10 ≥ 0.95 |
| M4 | 04 计算机网络 | 服务协议与流式网关 | SSE 网关 + gRPC 契约 + 可靠性六件套 | 弱网下流式不中断、能重连、能降级 |
| M5 | 05 数学与优化 | 从零反向传播与优化器 | 手写 autograd + 优化器 + 梯度校验 | MNIST 子集 > 95% 准确率 |
| M6 | 06 机器学习 | 检索排序基线与指标 | LightGBM 重排 + 指标库 + 冻结评测集 | 指标可复现,成为后续对照基线 |
| M7 | 07 深度学习 | PyTorch 训练管线 | 通用训练循环 + 实验追踪 + 配置化 | 断点续训后 loss 曲线连续 |
| M8 | 08 Transformer 与 LLM 架构 | 从零实现 GPT 并对齐权重 | 自研 Transformer + KV Cache + 投机解码 | 与 HF 参考实现 logits 一致 |
| M9 | 09 预训练与后训练(RL) | 领域微调与对齐 | SFT + LoRA + DPO/GRPO + 数据卡 | 领域准确率 +15pt 且通用能力不退化 |
| M10 | 10 推理模型与测试时计算 | 推理链与验证器 | CoT + 自一致性 + PRM + 预算路由 | 准确率 +10pt,有准确率-成本曲线 |
| M11 | 11 多模态与生成模型 | 多模态理解与检索 | VLM 封装 + 版面结构化 + 图文索引 | 含图表文档问答显著优于纯文本 RAG |
| M12 | 12 世界模型与具身智能 | 仿真决策 Agent(进阶) | 仿真适配 + 规划器 + 误差漂移分析 | 成功率 > 随机基线 3 倍 |
| M13 | 13 上下文工程与应用 | 混合检索 RAG 管线 | RRF 融合 + 重排 + 压缩 + 引用溯源 | 消融表完整、引用可核验率 ≥ 95% |
| M14 | 14 Agent 工程 | MCP 工具与多 Agent 编排 | 3+ MCP server + 编排循环 + 检查点 | 10 步以上任务成功率 > 70% |
| M15 | 15 评估·可观测·安全 | 评测、护栏与可观测 | 黄金集 + Judge + CI 门禁 + OTel + 红队 | CI 能真的拦住指标退化 |
| M16 | 16 推理优化与部署 | 推理优化、部署与压测 | vLLM + 量化 + K8s 灰度 + 压测报告 | 给出明确的容量与成本结论 |
| M17 | 17 综合项目与求职 | 收口:整合、演示、复盘 | README + 演示 + 技术报告 + 简历条目 | 陌生人能按 README 复现部署 |
✔
如果时间紧,怎么取舍:M12(世界模型 / 具身)是唯一可以整体跳过的里程碑——它的知识价值高,但对「应用 / 工程路线」的求职帮助相对最小。跳过不会破坏其它里程碑的依赖关系。反之,M1–M4 绝对不能跳:它们提供的仓库骨架、性能直觉、索引实现与协议设计,是后面 13 个里程碑的地基。M15(评测与护栏)是最容易被跳、但最不该跳的一环——它恰恰是 2026 年岗位中最稀缺的能力。
三、关键接口契约(早定下来,后面少返工)
这些契约在第 1–4 阶段就定下,之后所有模块围绕它们实现。提前定接口的价值在于:它逼你思考边界,而边界清晰是系统可演进的前提。
python# src/hamauls_orion/core/types.py —— 全项目共享的数据契约(第 1 阶段就写好)
from dataclasses import dataclass, field
from typing import Protocol, AsyncIterator, Any
@dataclass(frozen=True, slots=True)
class Doc:
doc_id: str
text: str
meta: dict = field(default_factory=dict)
score: float = 0.0
@dataclass(frozen=True, slots=True)
class Chunk:
chunk_id: str
doc_id: str
text: str
start: int # 原文偏移 —— 引用溯源必需
end: int
vec: list[float] | None = None
@dataclass
class Answer:
text: str
citations: list[tuple[str, int, int]] # (doc_id, start, end)
trace_id: str
usage: dict[str, int] = field(default_factory=dict) # tokens / cost
# ---- 三个核心接口:所有实现都必须满足,这是可替换性的保证 ----
class Retriever(Protocol):
"""检索器。第 3 阶段手写实现,第 13 阶段可能换成 pgvector,接口不变。"""
async def retrieve(self, q: str, k: int = 20, **filters) -> list[Doc]: ...
async def ingest(self, docs: list[Doc]) -> int: ...
class Generator(Protocol):
"""生成器。让「NullPushChannel 精神」在这里延续:
本地模型 / vLLM / 商业 API / mock 都可替换,上层代码零改动。"""
async def generate(self, prompt: str, **kw) -> str: ...
def stream(self, prompt: str, **kw) -> AsyncIterator[str]: ...
class Tool(Protocol):
"""工具。第 14 阶段的 MCP server 都要实现它。
注意:tools 必须声明 side_effect,用于决定是否需要幂等保护与人工审批。"""
name: str
description: str
side_effect: bool # True = 有副作用 → 必须幂等 + 可能需审批
schema: dict # JSON Schema,用于参数校验与 function calling
async def call(self, **kw) -> Any: ...
| 契约 | 定义位置 | 冻结于 | 变更成本 |
|---|---|---|---|
| Doc / Chunk / Answer | core/types.py | 第 1 阶段 | 高(全局可见)—— 早期宁可多想五分钟 |
| Retriever 接口 | core/types.py | 第 1 阶段 | 中(检索实现可替换) |
| Generator 接口 | core/types.py | 第 1 阶段 | 低(正是为了可替换而设计) |
| Tool 接口 + side_effect 标记 | core/types.py | 第 1 阶段 | 低 |
| gRPC 服务契约 | proto/hamauls_orion.proto | 第 4 阶段 | 中(protobuf 字段号不能复用,需谨慎) |
| 评测集格式与指标定义 | evals/metrics.py | 第 6 阶段 | 高(所有实验都依赖它) |
| Trace / 指标命名规范 | observability/ | 第 4 阶段 | 中(改名会丢历史数据连续性) |
四、明确不做的事(防止项目失控)
一个能持续 12 个月的项目,成败往往取决于「不做什么」。下面这些是刻意排除的范围——如果你发现自己在做这些,说明方向跑偏了。
不做自己的前端框架
用现成组件库(Ant Design / shadcn)。前端只是为了让系统可演示,不是学习目标。花两周做 UI 美化是典型的时间黑洞。
不做通用模型训练框架
不重复造 PyTorch / vLLM / LangChain。手写实现只用于学习和理解(如 scratch/ 目录),生产路径一律使用成熟库。
不做多租户商业化
单租户 + 简单的 tenant 字段即可。计费、发票、配额管理不在范围。它们是产品问题而非技术问题。
不追求前沿 SOTA 指标
目标是「完整的工程系统」而不是「刷榜」。评测集是自建的,指标用于对比自己的迭代,而不是与论文比较。
不做移动端 App
Web 响应式即可。原生 App 会带来完全不同的技术栈与发布流程。
不做自研向量数据库
HNSW 要手写(为了理解),但生产检索走 pgvector 或 faiss/hnswlib。学习实现与生产选型是两件事。
⚠
一个非常常见的失败模式:在学习过程中不断重构。今天觉得目录结构不好重排一次,明天觉得要换框架再重写一次,结果 6 个月后仓库很漂亮但没有任何可运行的东西。对策:把「能跑通」放在「写得漂亮」之前,每个里程碑只做必要重构。前四个里程碑尤其要克制——那时你对需求的理解一定是错的,过度设计只会被推翻。
五、怎么把它用起来
第 1 天就建仓库
不要等「准备充分」。第一个 commit 只要 README + pyproject + 目录骨架就够了。M1 的内容会在第 1 阶段结束前把它填成可跑的样子。
每阶段开始前,先读该阶段的里程碑
在阶段详情页里找到「项目里程碑」区块,先看清本阶段要交付什么、验收标准是什么——再开始学知识。带着交付目标去学,效率完全不同。
每阶段结束做一次自检
对照验收标准逐条验证,并把证据(数字、截图、报告)存进
docs/。这些证据在第 17 阶段写简历与技术报告时就是素材。维护一份 CHANGELOG
每个里程碑完成时写一条:做了什么、关键决策、遇到的坑、数字变化。这份记录后来会直接变成面试时的「技术决策故事」。
允许跳过,但不要跳过依赖
M12 可以整体跳过;但 M1–M4 不能。若某阶段内容已掌握(比如你有 10 年后端经验),可以压缩到验收标准通过为止,不必按周数走完。
★
最终的 Definition of Done(第 17 阶段):① 陌生工程师读完
README.md + docs/architecture.md,能在 30 分钟内本地部署并跑通一次带引用的问答;② 有 3–5 分钟的演示视频,覆盖多模态问答、多步 Agent 任务、引用溯源三个场景;③ 有完整压测报告,能回答「单卡支撑多少并发 / P99 多少毫秒 / 每千次请求多少钱」;④ 你能在 5 分钟内讲清最难的三个技术决策及其取舍,并回答「如果重做你会改什么」;⑤ 简历上有 4–6 条 STAR 结构、带量化数字的项目条目。做到这五条,这个项目就替代了「三年 AI 工作经验」在简历上的位置。ℹ
一句话记住 Hamauls Orion 的意义:它把你的学习从「我读过什么」变成「我建成了什么」。在 2026 年的求职市场里,后者是可以被验证、被演示、被追问的;前者只能靠自述。同一套知识,用 17 个里程碑穿起来,就同时获得了「学习路线」和「作品集」两个身份。