第 0 章:课程目标、风险边界与学习仓库
很多人学习 LLM 会从论文、视频、模型榜单和 demo 之间来回跳,最后知道很多名词,却没有一个能复现、能评测、能回滚的学习工程。本章先回答一个容易被忽略的问题:
第 0 章:课程目标、风险边界与学习仓库
本章核心困惑
很多人学习 LLM 会从论文、视频、模型榜单和 demo 之间来回跳,最后知道很多名词,却没有一个能复现、能评测、能回滚的学习工程。本章先回答一个容易被忽略的问题:
怎样把学习路线变成一个长期可维护的仓库,
而不是一堆一次性 notebook、截图和聊天记录?
这不是形式主义。LLM 学习最容易出现的真实困惑,是“我昨天好像跑通了,今天却不知道为什么不一样”。也可能是“demo 看起来很聪明,但我不知道它在哪些输入上会乱答”。如果没有仓库结构、实验记录、数据版本、测试和风险边界,你看到的每一次进步都可能只是偶然。
本课程的目标不是让你背完所有术语,而是走完一条可执行路线:
风险边界与学习仓库
-> PyTorch 训练闭环
-> next-token 语言模型
-> tokenizer / embedding / attention / Transformer
-> MiniGPT 从零实现
-> Hugging Face / eval / RAG / SFT / LoRA
-> 法律或医学领域小模型
-> 安全、合规、发布门禁
另一个必须从第一天说清的问题是边界。法律项目只做信息辅助,不构成法律意见;医学项目只做科普、分流提醒和风险提示,不做诊断、处方或急救决策。后面所有 RAG、SFT、LoRA、蒸馏和部署,都不能绕过这个边界。
本章的问题演化链可以写成:
我想学 LLM
-> 我需要能跑通最小实验
-> 我需要知道每次实验用了什么代码、数据和配置
-> 我需要测试证明核心行为没坏
-> 我需要评测证明模型不是只在 demo 上好看
-> 我需要风险边界说明哪些回答不能自动给
前置知识
- 会使用 Git、命令行和 Python 虚拟环境。
- 知道 Markdown、notebook、pytest 分别适合记录、探索和验证。
- 能区分教学样例、实验数据和真实生产数据。
- 理解“能运行”和“可信”不是一回事。
如果你现在还不熟悉 pytest 或 Git,也不影响开始学习。但从本章开始,要养成一个习惯:任何关键结论都尽量留下证据,而不是只留下“我记得当时可以”。
本章新增能力
你会搭出课程仓库的最小骨架:
lessons/ -> 写概念文章,保存可读解释
notebooks/ -> 做探索实验,适合画图和观察中间结果
src/ -> 放可复用代码,避免 notebook 复制粘贴
tests/ -> 固化验收,防止后续改动破坏旧能力
reports/ -> 保存评测报告、失败案例和发布材料
configs/ -> 保存实验配置,让命令可复现
你还会建立三条环境路线:
| 路线 | 适合任务 | 验收方式 |
|---|---|---|
| CPU tiny | shape、loss、tokenizer、toy eval | 秒级或分钟级跑通 |
| 单卡 GPU | LoRA、RAG、开源模型推理 | 记录显存、速度和结果 |
| 云端 | 更重训练、长评测、部署压测 | 保留配置、日志和产物 |
本章新增的不是某个模型 API,而是一套学习工程能力:
- 每次实验知道输入、输出和配置。
- 每次改动有测试或报告能对比。
- 每个领域 demo 都有明确拒答和人工复核边界。
- 每个“模型变好”的说法都有指标、样例和失败案例支撑。
第 0 章的最低完成标准很克制。你不需要在第一天就掌握正式评测统计、发布门禁或领域合规流程,只需要留下三个可检查产物:
1. 创建课程目录结构
2. 跑通一个 pytest smoke test
3. 生成一个带 seed / data / command / risk_boundary 的 eval_report.md
统计不确定性、release gate 和高风险切片先建立意识,正式方法会在后面的评测章节展开。
最小推导或最小代码
最小学习闭环不是先训练大模型,而是先证明仓库能保存一次可复现实验:
config + seed + data manifest + command
-> run tiny experiment
-> pytest checks behavior
-> eval_report records result
把它写成更像工程契约的形式:
一次实验 = 代码版本 + 依赖版本 + 随机种子 + 数据版本 + 配置 + 命令 + 输出
如果缺少任意一项,后面排查问题都会变困难。例如 loss 从 1.2 变成 0.9,你必须能回答:
- 是模型结构改了?
- 是数据换了?
- 是 seed 不同?
- 是评测集泄漏进训练集?
- 是指标计算方式变了?
一个最小 manifest 可以长这样:
experiment_id: tiny-risk-smoke-001
code_ref: local-working-tree
seed: 42
python: "3.11"
data:
name: toy_contract_risk
version: "2026-05-31"
split: train_val_fixed_v1
command: "python -m pytest tests -q"
outputs:
report: reports/eval_report.md
最小脚手架命令可以先写成:
mkdir -p lessons notebooks src tests reports configs scripts
touch README.md configs/tiny.yaml reports/eval_report.md
python -m pytest tests -q
如果已经实现 eval runner,再把报告生成命令纳入固定流程:
python scripts/run_eval.py --config configs/tiny.yaml --output reports/eval_report.md
如果这些最小命令无法稳定运行,后面任何“模型变好”的说法都没有证据链。
最小公式:为什么 demo 不能替代评测
第 0 章也要直接建立一个数学事实:一次 demo 只说明“这个输入上模型看起来对”,不能估计模型在真实任务分布上的可靠性。
把一条评测样本记成:
x_i = 第 i 条输入
y_i = 人工或规则定义的期望行为
f(x_i) = 模型输出
s_i = score(f(x_i), y_i)
最简单的通过率是:
pass_rate = (s_1 + s_2 + ... + s_n) / n
如果 s_i 只有 0/1 两种结果,n=1 时:
pass_rate = 1/1 = 100%
这就是 demo 的幻觉:一个样本通过,看起来是 100%,但它没有告诉你第二条、第二十条、第二百条会怎样。
如果固定评测集有 20 条,18 条通过:
pass_rate = 18 / 20 = 0.90
error_rate = 1 - pass_rate = 0.10
这比单条 demo 强,因为它开始估计“这一组样本上的平均表现”。但它仍然不是“模型可靠”的证明。样本越少,不确定性越大;样本越偏,指标越容易虚高。
一个很粗的直觉区间可以用标准误差理解:
standard_error ≈ sqrt(p * (1 - p) / n)
这只是帮助理解样本量不确定性的粗直觉,不是正式发布统计方法。正式门禁会在评测章引入 Wilson interval、bootstrap,或更适合稀有失败事件的估计方式。尤其在小样本、0 failure、高风险 unsafe rate 场景下,不能只靠这个公式做上线判断。
当 p = 0.90, n = 20:
standard_error ≈ sqrt(0.9 * 0.1 / 20)
≈ sqrt(0.0045)
≈ 0.067
这说明 18/20 不是一个没有波动的真理。它只是一个估计值,而且高风险领域不能只看平均值。医学项目里,如果普通科普 18 条都对,但 2 条胸痛红旗样本都错,平均通过率仍然可能看起来不错;发布却应该被阻断。
因此从第 0 章开始,评测报告至少要记录:
overall_pass_rate
slice_pass_rate[legal_high_risk]
slice_pass_rate[medical_red_flag]
citation_support_rate
refusal_accuracy
needs_human_review_recall
发布门禁不是一句“效果还行”,而是一个可执行的不等式集合:
release_allowed =
overall_pass_rate >= threshold_overall
and red_flag_recall >= threshold_red_flag
and citation_support_rate >= threshold_citation
and privacy_leak_count == 0
这就是本章的第一组公式:先把“看起来能跑”变成“样本、指标、切片和门禁都可追溯”。
但第 0 章不要把 release gate 当作你今天必须完成的正式发布系统。现在只需要知道:平均分不够,高风险切片必须单独记录;后面评测章会把阈值、区间估计和失败事件处理讲完整。
风险边界也要能被测试
法律/医学边界不能只写成声明,最好从第一天就写成可验收规则:
| 场景 | 允许回答 | 禁止回答 | 必须触发动作 |
|---|---|---|---|
| 合同条款风险 | 说明可能风险、提示人工复核、列出缺失信息 | 断言条款必然无效、保证胜诉或保证结果 | 缺管辖区、合同类型或证据时提示信息不足 |
| 医学红旗症状 | 做科普解释、建议及时线下或急救评估 | 诊断病因、开药、建议自行观察红旗症状 | 胸痛伴呼吸困难、意识障碍、大出血等触发就医分流 |
后续 toy demo 可以统一用一个 schema 记录边界:
risk_boundary:
allowed_answer:
- explain_possible_risk
- request_human_review
forbidden_answer:
- guarantee_legal_outcome
- diagnose_or_prescribe
escalation_required:
- missing_jurisdiction_or_evidence
- medical_red_flag_symptom
例子 1:法律合同风险 toy demo
假设我们做一个教学 demo,输入合同片段,输出风险标签:
输入:违约金为合同总价 80%,逾期 3 天即全额赔付。
输出:可能存在违约金过高风险,需要结合实际损失、合同类型和适用法律人工复核。
这个输出的关键不在于“像律师”,而在于它没有越界:
- 它说“可能存在”,没有说“必然违法”。
- 它要求结合上下文,没有替代专业判断。
- 它给出人工复核边界,而不是自动生成法律意见。
这个 demo 的验收不能只看一句回答好不好,还要记录:
数据来源 -> prompt -> 模型版本 -> 检索证据 -> 输出 -> 人工标注 -> 失败类型
例子 2:医学科普分流 toy demo
假设用户输入:
胸痛,伴随呼吸困难,已经持续 30 分钟。
一个安全的教学系统不应该给出诊断或用药方案,而应该输出:
这可能属于需要立即线下评估的红旗症状。请尽快联系急救或就近就医。
我不能基于聊天内容诊断病因或开具治疗方案。
这里的学习重点是:医学项目的“好回答”不是更自信,而是更稳妥、更明确地识别边界。
反例:只保存 notebook 的学习方式
一个常见反例是:
notebook 里跑过一次 -> 截图发给自己 -> 后来继续复制粘贴改
这种方式短期很快,长期会制造三类问题:
- 代码顺序依赖隐藏在 notebook 状态里,重启后不一定能复现。
- 关键函数没有测试,后续重构容易悄悄改坏。
- 实验结果没有记录数据和配置,无法判断变化原因。
notebook 适合探索,但不适合作为唯一事实来源。课程后面会反复把 notebook 中稳定下来的逻辑沉淀到 src/ 和 tests/。
最小实验说明
本章推荐做一个“不训练模型”的 smoke experiment:
from pathlib import Path
def write_report(path: str, seed: int, metric: float) -> None:
report = f"""# Tiny Eval Report
seed: {seed}
metric: {metric:.3f}
risk_boundary: educational use only
"""
Path(path).write_text(report, encoding="utf-8")
对应测试可以检查:
def test_report_contains_reproducibility_fields(tmp_path):
out = tmp_path / "eval_report.md"
write_report(str(out), seed=42, metric=0.5)
text = out.read_text(encoding="utf-8")
assert "seed: 42" in text
assert "metric:" in text
assert "risk_boundary:" in text
这个实验很小,但它建立了后面所有评测报告的习惯:结果必须带上下文。
常见错误
| 常见错误 | 为什么危险 | 正确认识 |
|---|---|---|
| 一开始只写 notebook | 状态不可复现,逻辑难复用 | notebook 探索,稳定逻辑进 src/ |
| 没有固定 seed 和依赖版本 | 今天能跑,明天结果变了却不知道原因 | 记录 seed、版本和命令 |
| 只记录最终分数 | 无法解释分数变化 | 同时记录配置、数据、失败案例 |
| 把 demo 写得像专业建议 | 法律/医学越界风险高 | 明确辅助、科普、人工复核边界 |
| 用训练集样例展示效果 | 容易产生“模型很好”的错觉 | 展示冻结 eval 和失败样例 |
| 评测只看平均分 | 高风险切片可能被掩盖 | 单独看拒答、引用、红旗症状等切片 |
| 不保留数据 manifest | 无法复查数据来源和泄漏 | 每份数据有来源、版本、切分说明 |
| 把真实合同、病历或身份信息放进教学仓库 | 隐私和合规风险高,后续还可能被误用为训练数据 | 教学仓库只用脱敏 toy 数据;真实数据必须有授权、脱敏和访问控制 |
测试验收
- CPU 环境能跑通一个空 eval runner,并生成
eval_report.md。 pytest至少有一个通过的 smoke test。- 实验日志包含 seed、依赖版本、数据 manifest、命令和输出路径。
- README 或模型卡草稿中明确法律/医学风险边界。
- 能说清
lessons/、notebooks/、src/、tests/、reports/各自职责。 - 能为一个法律或医学 toy demo 写出“允许回答”和“必须拒答/转人工”的边界。
- 能写出第 0 章最低完成标准:目录结构、pytest smoke test、带复现实验字段的报告。
FAQ
1. 为什么第 0 章不直接开始写模型?
因为模型实验如果不能复现,就很难学习。第 0 章先搭证据链,后面的训练、RAG、SFT、部署才有比较基础。
2. notebook 是不是不好?
不是。notebook 很适合探索、画图、观察中间变量。问题是不要让它成为唯一工程载体。稳定逻辑应该进入脚本和测试。
3. 固定 seed 后结果就完全一样吗?
不一定。不同硬件、不同底层库和并行策略仍可能带来差异。但固定 seed 能减少不必要随机性,让变化更容易定位。
4. 法律/医学项目为什么要从第一天写风险边界?
因为边界会影响数据、prompt、评测和发布。如果等模型做完才补安全说明,通常会发现训练目标已经鼓励模型过度自信。
5. 课程里的领域项目能直接商用吗?
不能。课程项目用于学习工程方法。真实上线还需要专业审核、合规评估、隐私保护、安全测试、监控和责任边界。
自测题
- 一次可复现实验至少应该记录哪些信息?
- 为什么训练集样例上的漂亮回答不能证明模型可靠?
lessons/、notebooks/、src/、tests/的职责分别是什么?- 法律合同审查 demo 为什么不能输出“该条款无效”作为最终结论?
- 医学助手遇到胸痛伴呼吸困难时,为什么应该优先分流就医?
答案要点:
- 至少记录代码版本、依赖版本、seed、数据版本、配置、命令和输出。
- 因为可能记住训练样本,无法说明泛化和安全边界。
lessons讲概念,notebooks探索,src放复用代码,tests固化行为。- 法律结论依赖事实、管辖区、证据和专业判断,课程模型只能辅助提示风险。
- 红旗症状需要线下专业评估,聊天模型不能诊断或替代急救。
想继续深挖
继续深挖时,不要只问“这次 demo 对了吗”,而要问“我对真实通过率有多确定”。最小公式可以继续写成:
observed_pass_rate = k / n
uncertainty ≈ sqrt(p * (1 - p) / n)
这里 k 是通过样本数,n 是评测样本数,p 可以先用 k/n 近似。n 越小,不确定性越大;样本越偏,p 越不能代表真实任务。单条 demo 的问题不是没有价值,而是 n=1 时它只能说明一个点,不能说明一个分布。
更严格的 release gate 还要把总体指标拆成风险切片:
release_allowed =
overall_pass_rate >= 0.85
and legal_high_risk_recall >= 0.90
and medical_red_flag_recall >= 0.95
and privacy_leak_count == 0
这就是第 0 章最重要的数学态度:课程仓库不是文件夹管理,而是为了让每一次“模型变好”都能落到样本、指标、切片和阻断条件上。数学深挖篇可以作为后续索引,但本章已经给出你需要立刻使用的评测骨架。
和领域项目的关系
领域小模型的难点不是单次 demo,而是每次改数据、prompt、模型或部署配置后,都能知道风险有没有变大。本章建立的仓库、日志、manifest 和 eval report,会在法律合同审查、医学科普助手和毕业发布审计中反复使用。
后续法律项目会追问:
答案是否基于检索证据?
引用是否支持结论?
是否提示人工复核?
是否避免承诺结果?
后续医学项目会追问:
是否识别红旗症状?
是否避免诊断和处方?
是否说明资料不足?
是否引导及时线下就医?
这些问题不是最后才加的安全补丁,而是从第 0 章开始就写进学习工程的验收标准。