qinghuan
← 从零建立基础 / 全部笔记

单元 01 / 从零建立基础

P0 · 必会主线L0 · 零基础

先分清 AI、机器学习、语言模型与 Agent

用分类问题分清 AI、机器学习、语言模型和 Agent,再判断自己的任务是否需要模型。

本篇目录 · 按需要跳转

读完这篇,你能做什么

能为三个实际任务写出输入、输出和验收标准,并说明程序规则或模型各承担什么。

学习理由、准备要求与知识点

为什么学它

分清哪些事由模型完成、哪些由应用代码完成,才不会把调用接口、检索资料或执行工具误称为训练模型。

先读这些内容

这篇可以直接开始,不需要先读其他笔记。

知识点清单

  • AI、机器学习与深度学习的关系
  • 训练与推理的区别
  • 分类任务与生成任务
  • 模型参数与应用代码
  • 语言模型的预测目标
  • Agent 的工具和状态组成
  • 微调与检索增强的区别
  • 幻觉及证据核对

运行前先确认完整算法使用 Java 17 标准库;JDK 源码基线为 OpenJDK 17 GA。示例是内存中的机制模型,外部服务接入需要另外配置和验证。

01先弄懂它是什么

假设要把学习问题分成“Java 基础”和“数据库”两类,可以先写关键词规则,也可以用带标签的历史问题训练模型,让它预测新问题属于哪类。两种方法最终都由程序执行,区别在于规则主要由人写出来,还是从数据里学出来。选方案前,先明确给什么输入、要什么输出、分错了有什么后果,再判断是否需要模型。

几个常见名称可以按范围理解:人工智能是较大的领域,机器学习研究怎样从数据改善任务表现,深度学习使用多层神经网络,大语言模型则主要通过大规模语言建模学习。这些词不能当作可随意替换的接口名。分类是在有限标签中选择,生成则是逐步延长一段序列;模型能写出流畅句子,也还需要外部证据确认其中的事实。

训练阶段根据样本和目标函数更新模型参数。目标函数是衡量表现的计算规则;参数是模型里通过训练确定、用于预测的内容。推理阶段通常固定参数,根据当前输入计算输出。提示、检索和工具结果是推理时提供的输入,通常不会直接修改模型权重。

微调会继续更新参数;RAG 则把找来的资料放进当前上下文,也就是这次提供给模型的内容,两者解决的问题不同。Agent 还要在模型之外记录任务做到哪一步、执行工具并决定何时停止,所以可靠性也取决于应用代码。

文中这几个词,先认一认

样本与标签
样本是一次输入记录,标签是用于学习或评估的目标。例如问题文本是样本,“数据库”是分类标签;标签也可能标错。
参数
训练时确定、预测时使用的数值或结构。本篇最小模型只保存一个最常出现的标签作为参数。
基线
先用一个便宜、能重复运行的简单方法作比较,看看复杂方案是否真的带来收益。
泛化
换成没有用于训练的新数据,模型仍能达到任务要求,而不只是记住旧样本。

还有陌生词?到术语小抄里看一个具体例子 ↗

02看看它怎么工作

先建立一个简单、容易解释的多数类基线:训练标签为Java、Java、数据库时,无论新问题是什么,都回答Java。这个模型不理解句子,却能帮助看出标签分布对分数的影响。若测试集百分之九十都是Java,它可能得到很高准确率。因此,还要查看各类别的召回率,即某一类实际样本中被正确识别的比例,并考虑答错的业务代价;不能把高分自动解释为“理解能力强”。

程序将每种标签出现次数累加,选择次数最多者;并列时按字符串字典序选择,使同一数据得到相同模型。训练输出是一个冻结的标签,预测只读取它。必须先划分训练集和测试集,再统计训练标签;先统计全部数据再划分会把测试信息带进模型,得到偏乐观的评价。

对语言模型,可以把“选择一个类别”换成“为词表中的各个候选 Token 计算下一步出现的概率”,但真实模型不是本篇计数器。Transformer 通过大量矩阵运算,把输入上下文变成用于预测的数值表示;训练目标、分词和采样另有专章。这里保留的共同机制是:定义目标、从数据得到参数、固定参数做预测、用独立证据评价,再决定是否升级方案。

正在加载流程图…

训练标签只流向模型构造;测试标签只流向评价,避免测试信息回流。
查看流程图源码(Mermaid)
flowchart LR
  D["已标注问题"] --> S["先划分数据"]
  S --> T["训练集计数"]
  T --> M["冻结多数标签"]
  S --> E["独立测试集"]
  M --> P["输出预测"]
  E --> P
  P --> R["分类型核对错误"]

按顺序看,每一步做了什么

  1. 明确问题类别、错误代价和允许的输入范围。
  2. 在拟合之前划分训练与评估数据。
  3. 只统计训练标签,固定并列规则,生成模型参数。
  4. 在评估集输出预测,按类别查看正确与失败样本。
  5. 将复杂模型与基线在相同数据和指标上比较。

03对照实现代码

OpenJDK 17 HashMap 源码 (新标签页)↗

OpenJDK 17 GA,jdk-17+35 · HashMap.merge

下方为原创 Java 教学片段,调用已核验的 JDK API 说明局部机制;不是该类原样源码,也不实现神经网络。完整程序见算法模块。

核心机制代码 · java
Map<String, Integer> counts = new HashMap<>();
for (String label : labels) {
    // 新标签从 1 开始;已有标签累加,计数是训练得到的中间状态。
    counts.merge(label, 1, Integer::sum);
}
// HashMap 不保证遍历顺序;选最优标签时必须显式处理并列。

HashMap.merge 在这里相当于“第一次见到标签就记一票,以后再见到就把新票加上去”。真实 API 在键不存在或旧值为 null 时,直接接纳传入的非空值;已有非空值时,才调用合并函数。若这个函数返回 null,映射会被删除。本例使用 Integer::sum,它把新旧计数相加且不会返回 null,因此实现的是累计次数。

HashMap使用哈希定位桶,并可能扩容或在条件满足时树化;下面完整算法只依赖映射接口的计数语义,没有重新实现桶或红黑树。平均常数查找需要合理的哈希分布,不是任意恶意输入下的无条件承诺。

merge是一次API调用,不代表普通HashMap因此具备并发安全。训练函数将映射保存在局部变量中并单线程构造,返回不可变字符串,避免多线程共享一个可变计数器。

这个源码桥梁解释数据统计如何成为可执行模型。真实大语言模型的张量、自动微分和训练优化不在HashMap中;学习下一步应阅读语言建模与Transformer材料,而不是把计数代码包装成神经网络源码。

代码先调用谁,再调用谁

  1. fit接收训练标签
  2. HashMap.merge更新每类计数
  3. 扫描计数并显式比较并列标签
  4. 返回冻结的多数标签
  5. predict在新输入上使用模型参数

04动手写一个例子

多数类分类基线

输入非空标签列表,输出频次最高的标签;并列选字典序最小者。空列表、null或空白标签拒绝。将代码保存为Main.java,执行javac --release 17 -encoding UTF-8 Main.java和java Main运行自测。

输入 1
Java, Java, SQL
输出 1
Java
输入 2
B, A
输出 2
A

对每个标签进行一次计数,不能边统计边假设当前领先者已经是最终答案,因为后续样本可能改变频次。计数完成后,每个标签的统计都对应完整训练集。

第二轮遍历只记住目前最好的标签和票数。票更多就换成新标签;票数相同,就按字符串字典序选较小者,例如 A 排在 B 前面。这两层规则能明确比较任意两个候选,所以不管 HashMap 先拿出哪个标签,最后胜出的都一样,不会被它的遍历顺序左右。

空训练集无法估计多数类别,返回任意默认标签会掩盖数据缺失。本题选择抛异常,调用方可据此展示“尚无训练数据”。预测过程不再更新计数,确保训练和推理职责清晰。

为什么这样写是对的处理完前i条训练记录后,counts[x]恰好等于该前缀中标签x出现的次数;扫描已访问类别后,best是其中按频次降序、字典序升序排列的第一项。

时间 平均O(C+kL)额外空间 O(k)辅助空间

C为输入标签总字符数,k为不同标签数,L为最大标签长度;哈希与校验读取字符,并列字符串比较最多k次。本程序仅存原字符串引用和计数,不复制原标签字符,额外结构空间O(k)。

保存为 Main.java,运行 javac --release 17 -encoding UTF-8 Main.java,再运行 java Main。程序包含固定输入自测,断言失败时会抛出错误。

展开收起代码 · Main.java · 完整可运行程序Java · 34 行

长行可在代码区域内左右滚动,按 Tab 可把焦点移入代码区。

Main.java · 完整可运行程序 · Java
import java.util.*;
public class Main {
    static String fit(List<String> labels) {
        if (labels == null || labels.isEmpty()) throw new IllegalArgumentException("empty training set");
        Map<String,Integer> counts = new HashMap<>();
        for (String label : labels) {
            // 不擅自修正类别名称,空白标签由数据清洗层处理。
            if (label == null || label.isBlank()) throw new IllegalArgumentException("invalid label");
            counts.merge(label, 1, Integer::sum);
        }
        String best = null; int frequency = -1;
        for (var e : counts.entrySet()) {
            // 明确并列次序,不能依赖 HashMap 的遍历顺序。
            if (e.getValue() > frequency || e.getValue() == frequency && e.getKey().compareTo(best) < 0) {
                best = e.getKey(); frequency = e.getValue();
            }
        }
        return best; // 冻结训练结果;后续预测不再修改计数。
    }
    static void check(String expected, String actual) { if (!expected.equals(actual)) throw new AssertionError(actual); }
    static void rejects(List<String> input) {
        try { fit(input); throw new AssertionError("expected rejection"); }
        catch (IllegalArgumentException expected) { /* 空数据不是一个已训练模型。 */ }
    }
    public static void main(String[] args) {
        check("Java", fit(List.of("Java", "SQL", "Java")));
        check("A", fit(List.of("B", "A")));
        check("only", fit(List.of("only")));
        rejects(List.of());
        rejects(Arrays.asList("Java", null));
        rejects(List.of(" "));
        System.out.println("PASS 6 tests");
    }
}

这些特殊情况也要试一试

  • 没有样本时拒绝训练,不能偷偷指定默认类别。
  • 类别频次相等时使用固定字典序,保证结果可复核。
  • 标签中空白与null单独校验;业务类别别名要在训练之前统一。
进阶选读 · 后续再读:代价敏感分类与分布漂移

场景漏掉数据库问题比误报Java问题的代价更大,或者上线后类别比例变化。

做法先列一张“真实类别与预测类别”的交叉表,也就是混淆矩阵,再写清每一种分错要付出什么代价。在独立验证集上,按这些代价加权比较损失。如果线上问题的类别比例会随时间改变,就按时间段检查这种分布漂移;不能反复拿最终测试集挑参数。

复杂度固定c类时统计混淆矩阵O(n)、存储O(c²);这只是评估复杂度,不代表训练任意模型都如此。

好处与代价多数类模型透明且便宜,但忽略输入内容;复杂模型必须用独立数据证明收益,并保留回退策略。

05项目里怎么用

真正上线前,先收集有代表性的匿名问题并说明标签定义。例如“索引是什么”可能属于数据库也可能属于集合,需要标注规则或允许“信息不足”。标签争议应被记录,不能强行让裁判把所有模糊问题判成模型错误。基线的价值是建立测量纪律,不是鼓励用简单规则包办开放任务。

选择RAG还是微调要看失败位置:事实缺失、文档更新频繁,优先检查检索;回答格式或任务习惯不稳定,先做提示和契约验证,再评估微调。无论采取哪种方法,都要用来源和业务校验检验输出。模型复述了一段看似专业的解释,只能证明它生成了这段文字。

Agent的模型建议、工具执行和最终展示应分层记录。模型可能提议查资料,但具体资料范围由应用根据身份决定;模型可能生成计划,但持久状态与停止预算由程序管理。首次学习可先完成纯函数和固定测试集,再逐步接入外部服务,避免把网络错误与建模错误混为一谈。

容易踩的坑

  • 把训练集准确率当作未见数据表现,遗漏数据泄漏。
  • 只看总体准确率,忽略少数类别全部预测错误。
  • 把提示里的新事实称为模型参数已更新。
  • 把Agent当成一个必然会自行完成任务的模型名称。

几种做法,怎么选

表格有四列,窄屏可左右滑动查看代价和适用条件。

方案优势代价与限制适用条件
关键词规则容易解释、部署成本低覆盖有限,规则冲突需维护明确字段和少量固定模式
统计或神经网络模型能从样本学习复杂关系需要数据、评估和漂移管理存在可测量的预测目标
检索与受控工具可使用当前授权资料和业务能力需要处理来源、权限及失败状态问答与需要外部行动的任务

06检验是否读懂了

先自己想、自己写,再展开答案核对。场景题是假设的练习情境;遇到还没学过的内容,可以做完基础后再回来。

先用自己的话解释

01训练与推理最关键的区别是什么?

展开参考答案与推导

训练根据目标函数更新参数;推理使用确定的参数处理输入。应用写入聊天历史通常不等于训练,后续请求只是在不同上下文上计算。

02为什么多数类基线也值得实现?

展开参考答案与推导

它暴露类别分布,建立可重复的最低比较对象。复杂模型若没有超过基线,优先检查数据、指标和任务定义,而不是先增加工具。

03微调与RAG可以同时使用吗?

展开参考答案与推导

可以。微调改变模型行为或参数,RAG提供请求相关资料;仍需单独验证检索覆盖、答案支持和行为约束,二者都不保证事实正确。

换个情况,还会处理吗

01基线准确率百分之九十五,能否上线?

展开参考答案与推导

先检查类别比例、各类召回和错误代价;若少数关键类别全部漏掉,总体高分没有满足业务目标,再用独立测试样本估计稳定性。

02更新提示后模型说记住了偏好,怎样核验?

展开参考答案与推导

查看应用是否持久保存偏好、是否在新会话按身份读回;一句自然语言承诺不能证明参数更新或跨会话存储成功。

03问答引用了过期文档,应先微调吗?

展开参考答案与推导

先检查语料版本、检索过滤和引用映射;如果正确资料根本未进入上下文,微调不能替代当前知识管道的修复。

写代码试一试

01加入第三个并列标签,结果应是什么?

输入 / 条件
C,B,A
输出 / 预期
A

提示 把并列比较当成显式规则。

展开参考答案与推导

三个频次均为一,逐项应用字典序最小规则,最终为A;可以置换输入顺序验证稳定性。

02训练和测试为什么不能共用计数器?

输入 / 条件
训练A,A,B;测试B,B
输出 / 预期
模型仍预测A

提示 在fit结束时冻结参数。

展开参考答案与推导

若读取测试标签更新计数,测试已参与拟合。应新建评估逻辑,只比较预测和目标,不再调用merge修改模型。

03如何增加每类召回统计?

输入 / 条件
真实A,A,B;预测A,A,A
输出 / 预期
A召回1,B召回0

提示 分别统计每类真实数量与预测正确数量。

展开参考答案与推导

对真实类累加分母,真实和预测相等时累加该类分子;分母为零的类别标记不可计算,不编造满分。

读完之后,独立完成

课后作业:自己做一遍

本篇共 10 道作业,先完成 8 道基础与综合任务,再按前置知识挑战进阶题。其中包含 1 道思维拓展,试着换个条件,看看原来的办法是否还管用。不附参考答案。

这次练什么

能为三个实际任务写出输入、输出和验收标准,并说明程序规则或模型各承担什么。

本篇重点加练

训练、推理、检索与微调的边界决定解决问题的路径,需要用任务变化检验理解。

  • 训练与推理的区别
  • 微调与检索增强的区别

重点内容会多练几次。先说清楚怎么做,再试试空数据、出错或条件改变时会发生什么。

先自己做,卡住时记下问题,再回来查。问答题写清“为什么、什么时候适用”;动手题留下输入、输出和运行步骤,方便下次重做。

基础必做

  1. 作业 01原理问答

    用自己的话画AI、机器学习和深度学习的关系,并为同一模型分别写训练与推理阶段的输入、输出和资源需求。

    提交内容
    一份独立书面回答或标注图,包含自造例子、概念边界及判断依据。
    怎样算完成
    • 逐项回应题目要求,区分事实、假设与个人判断。
    • 能用自己的例子解释适用条件,记录尚未弄懂的点。

    练到的知识点AI、机器学习与深度学习的关系 · 训练与推理的区别

  2. 作业 02代码推演

    将垃圾邮件识别、续写一句话、修改网页按钮颜色三个任务分类;说明哪些改动涉及应用代码,哪些可能涉及模型参数。

    提交内容
    手工推演记录,写明输入约定、中间状态、最终判断;可运行时附程序对照记录。
    怎样算完成
    • 推演包含中间过程,数据形状、单位、顺序或状态前后一致。
    • 主动检查至少一个边界或异常条件,能解释手算与运行差异。

    练到的知识点分类任务与生成任务 · 模型参数与应用代码

  3. 作业 03原理问答

    为“新增一本资料、改变输出格式、掌握一种长期行为习惯”分别写出问题诊断,列出做选择前需要知道的数据与能力条件。

    提交内容
    概念或合同说明、关系图与自造案例,明确事实、假设和适用条件。
    怎样算完成
    • 关键概念有明确边界,能用案例检验声明。
    • 未获证据支持的假设单独标注。

    练到的知识点训练与推理的区别 · 微调与检索增强的区别

综合应用

  1. 作业 04面试场景

    语言模型连续两次给出不同计划。列出还需哪些工具与状态才能执行计划,说明文本预测与真实行动之间有哪些待验证环节。

    提交内容
    场景分析与决策记录,包含信息缺口、约束、备选方案和验证计划。
    怎样算完成
    • 方案回应给定约束,列出至少一种替代方案及代价。
    • 每项关键结论说明所需证据,不能核实的部分明确标注。

    练到的知识点语言模型的预测目标 · Agent 的工具和状态组成

  2. 作业 05编程实践

    用纸面或本地文本构造一个“规则过时”的问答案例,分别设计提供检索资料与调整模型的实验方案,并制作逐项证据核对表。

    提交内容
    可复现的最小程序或实验材料、自写测试、环境说明与运行记录;题目允许纸面实验时提交完整案例表。
    怎样算完成
    • 提交物按说明可以重现;测试覆盖正常、边界与失败场景。
    • 运行证据与断言能核验声明的行为,注明模拟与真实执行范围。

    练到的知识点微调与检索增强的区别 · 幻觉及证据核对

  3. 作业 06排错实验

    收集三条自造的听起来合理但缺证据的回答,逐条写出核验问题、资料来源要求和无法确认时的记录方式,不要求调用付费模型。

    提交内容
    最小故障输入、复现步骤、观测记录、定位依据及回归用例。
    怎样算完成
    • 其他人可按记录复现故障,并区分现象与已验证原因。
    • 定位过程有观测依据,回归用例可以再次暴露原问题。

    练到的知识点语言模型的预测目标 · 幻觉及证据核对

  4. 作业 07编程实践

    制作三个离线演示档案:仅改变检索资料、仅改变应用提示、替换一份模型版本记录。用表格记录各自哪些输入或产物改变,检验你对训练与推理的分类。

    提交内容
    可复现的小程序或题目允许的离线实验、自写测试、输入和运行记录。
    怎样算完成
    • 输入、环境和运行过程可重现,测试覆盖声明的重点条件。
    • 验证目标由合同确定,模拟结果不冒充真实服务证据。

    练到的知识点训练与推理的区别 · 微调与检索增强的区别

  5. 作业 08面试场景

    团队声称“上传了新文档,所以模型参数已经学会其中知识”。设计一个不读取模型内部参数也可执行的核验计划,说明哪些结论仍无法仅凭表现确定。

    提交内容
    场景评审记录,包含约束、备选方案、未决信息和验证计划。
    怎样算完成
    • 方案回应题目约束,取舍能对应到可核验的事实。
    • 给出失败或条件变化时的检查方式。

    练到的知识点训练与推理的区别 · 微调与检索增强的区别

进阶挑战 · 掌握前置后选做

  1. 作业 09设计评审

    比较一个纯规则学习计划器和一个带模型的计划器,制定能检验引入模型是否有价值的小型评测,不以回答流畅度作为唯一依据。

    提交内容
    设计评审文档或对照实验报告,包含前置条件、方案取舍、验收证据与尚未验证的范围。
    怎样算完成
    • 比较使用一致条件与事先声明的标准,记录失败与未知结果。
    • 说明方案的适用前提、未覆盖风险及后续验证方法。

    练到的知识点分类任务与生成任务 · Agent 的工具和状态组成 · 微调与检索增强的区别

思维拓展

先写出你的猜想,再用例子或实验验证。答案可以不同,但要说清依据、适用情况,以及还有什么没弄懂。

  1. 作业 10思维拓展 · 条件变化

    如果资料每日更新变为十年稳定、任务从查事实变为固定风格改写,你会重新考察哪些选型条件?提出可检验的比较标准,不预设某一种方法总更好。

    提交内容
    变更前后条件表、重新评审的方案、检验用例与新增代价。
    怎样算完成
    • 只改变明确列出的条件,比较口径保持一致。
    • 修改方案说明收益、代价与仍未验证的范围。

    练到的知识点训练与推理的区别 · 微调与检索增强的区别

完成后,再检验一次

给每题标记“独立完成 / 查阅后完成 / 尚未完成”。查过资料或没做出的题,记下卡在哪里。隔一天换一组输入再试,能解释结果和出错原因,再把这个知识点标为掌握。

继续阅读

先看能帮你完成当前练习的部分。例子跑通后,再读更深入的解释。

打开资料库,找下一份学习材料 ↗