新闻详情

新闻详情

首页 / 资讯中心 / 详情

AI工程从零到一:手写Transformer与实战学习路线

发布时间:2026/9/29 9:23:50来源:尧图网络
AI工程从零到一:手写Transformer与实战学习路线
很多人都问过我一个问题AI engineering from scratch到底是什么套路是像读《Build a Large Language Model from Scratch》那样把每一行代码都手敲一遍还是说只要会用几个现成框架搭一条流水线就算入门我的答案可能和你想的不太一样。真正值得“从零开始”的不是重新发明矩阵乘法而是亲手把一个模型从数据集处理开始经过架构设计、训练、评估、部署完整地走通一遍。这个过程帮你建立的不是“能跑通”的幻觉而是“出问题时知道去哪里排查”的掌控感。这篇文章就是我个人的实战记录。我会用一条主线把从零到一的 AI 工程路径串起来先讲我为什么决定手写一个迷你模型再带你搭一个最小可行的 Transformer 语言模型然后聊聊真正项目里最花时间、也最容易被忽略的“模型驾驭工程”harness engineering接着延伸到提示工程和 AI Agent 的工作流最后给出一份可以直接抄作业的八周学习路线。无论你是刚入门的技术爱好者还是已经调了一段时间 API 但觉得心里没底的开发者这篇文章都值得你花二十分钟读完。1. 从零开始不是重复造轮子而是建立掌控感1.1 我为什么决定从零手写一个迷你模型两年前我第一次接触大语言模型时和大部分人一样直接调 Hugging Face 的接口跑通了文本生成、对话问答当时觉得自己已经“会了”。直到有一次线上服务里模型输出突然开始重复同一个词我盯着日志完全懵了——不知道是数据问题、训练参数问题还是模型结构本身的问题。因为对我来说模型就是一个黑盒我只能换个更大的模型试试或者干脆重启。那次之后我决定必须自己动手把一个小模型从头到尾实现一遍。当时正好看到社区里越来越多人在讨论build a reasoning model from scratch还有人专门复现《Build a Large Language Model from Scratch》这本书的代码。我想与其看别人造轮子不如自己造一个小的。于是我给自己定了一个目标不借助任何现成的 Transformer 库只用 PyTorch 的张量运算写一个约 10M 参数的小语言模型用莎士比亚的文本从头训练最后让模型能生成有点模样的英文句子。这个目标听起来不大但它恰好把数据、模型、训练、推理这条主链路全部覆盖了。1.2 从零构建的边界哪些要自己写哪些可以用库这里要先说清楚“从零”的边界。我见过有些人一刀切觉得连 PyTorch 都不能用必须从用 C 语言写张量库开始。我不赞成这种极端做法因为“从零”的核心目的是理解关键机制而不是重复实现底层数学库。我给自己画了一条线可以用的包括 PyTorch 的张量计算、自动求导、Adam 优化器必须自己写的是数据分词器、token 嵌入、多头注意力、前馈网络、LayerNorm、残差连接、训练循环和采样函数。也就是说直击 Transformer 和语言模型训练的本质但不在矩阵乘法的底层上浪费时间。这样做的原因很简单项目里的绝大多数问题都出在架构设计、数据质量和训练配置上而不是出在基本算子上。你需要能够把一个 bug 定位到是注意力掩码算错了还是学习率太大导致 loss 炸了而不是去关心内存对齐之类的问题。这条边界能让你在有限的时间里获得最大的掌控力。1.3 从零开始的收益与代价收益是实实在在的。手写过一个模型之后再看那些大模型的论文很多地方都变得好懂了。比如当我看到“RoPE 位置编码”这个概念时因为我之前用 OpenAI 的接口永远看不到位置编码的代码但手写模型时我做过最简单的位置编码表所以我能迅速理解它是在解决相对位置的问题而不是又一个黑魔法。代价也必须要说时间成本真的很高。我那时用一周的业余时间才把模型跑通中间踩了无数坑包括损失不下降、生成结果全是重复的“[UNK]”符号、显存不足导致崩溃。如果我只是想快速做一个产品原型这种从零开始的成本完全不划算。所以我给所有人的建议是在时间和精力允许的情况下从零走一遍这条路线但不要在工作项目里从零写模型。学习归学习生产归生产。2. 搭建最小可行模型数据、架构、训练一条线2.1 数据集从莎士比亚到指令对我选择的数据集是著名的小型文本集TinyShakespeare大约 1MB包含了莎士比亚戏剧中常用的字符集。用它的好处是数据量小训练快不需要联网下载大文件而且字符集比较稳定适合初学者观察模型是否真的学到了语言模式。处理流程是这样的读取原始文本统计所有出现的字符构建一个char → id的映射表。把整段文本转换为一个长整型数组。设定block_size 128即每个训练样本的上下文长度每次从数组中随机切一段长度为 128 的序列作为输入再把序列右移一位作为目标输出。创建一个批量大小为 64 的 DataLoader自动打乱并分批。这里有一个容易踩的坑如果你直接拿整段文本去切块而没有做随机偏移采样那么每个 batch 里的样本会高度相关训练会非常不稳定。我当时就是因为贪图简单每个 epoch 都用同样的切法结果损失下降得很诡异。后来改成每次随机取起始位置训练效果立刻正常了。2.2 模型架构一个极简 Transformer 的核心模块我实现的 MiniTransformer 只有四个核心组件TokenEmbedding、PositionalEncoding、一个单层的DecoderBlock内含多头注意力与前馈网络、以及输出层Linear。这里给出最核心的注意力计算代码我用的是单头便于调试import torch.nn as nn class SelfAttention(nn.Module): def __init__(self, embed_dim, head_size): super().__init__() self.key nn.Linear(embed_dim, head_size, biasFalse) self.query nn.Linear(embed_dim, head_size, biasFalse) self.value nn.Linear(embed_dim, head_size, biasFalse) self.register_buffer(tril, torch.tril(torch.ones(block_size, block_size))) def forward(self, x): B, T, C x.shape k self.key(x) # (B,T,head_size) q self.query(x) # (B,T,head_size) v self.value(x) # (B,T,head_size) wei q k.transpose(-2, -1) * C ** -0.5 wei wei.masked_fill(self.tril[:T, :T] 0, float(-inf)) wei torch.softmax(wei, dim-1) out wei v return out很多人不理解为什么要有masked_fill这一步。因为在语言模型里我们不能让模型在预测第 t 个词时看到第 t1 个词的信息否则就变成了“作弊”。这个下三角矩阵就是未来的遮罩确保注意力只被允许看到当前位置和之前的位置。前馈网络我用了一个简单两层 MLP先把嵌入维度从embed_dim映射到4 * embed_dim再用 GELU 激活最后映射回原维度。真正训练的时候这个 MLP 和注意力层之间要用 LayerNorm 和残差连接包起来训练才能稳定。2.3 训练循环损失函数、优化器、学习率调度训练一个语言模型本质上就是最大化训练集上每个 token 出现的对数概率。我使用的是交叉熵损失优化器选择了 AdamW并且加了 warmup cosine 的学习率调度。简单解释一下为什么必须加 warmup模型刚初始化时梯度方向非常不稳定如果用很大步长去更新参数很容易把损失推到爆炸区。先让学习率从一个很小的值线性增长到预设最大值模型就能在前期保持稳定后面再用余弦退火逐步降到一个很小的值类似于“先大步探索再小步精调”。训练循环的核心代码看起来就是这样optimizer torch.optim.AdamW(model.parameters(), lr1e-3) for step in range(max_steps): x, y get_batch(train) logits model(x) loss F.cross_entropy(logits.view(-1, vocab_size), y.view(-1)) optimizer.zero_grad() loss.backward() norm torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) optimizer.step()那个clip_grad_norm_是我加的第二道保险。它会把梯度矩阵的总体范数限制在 1.0防止出现梯度爆炸。我一开始没加这一行训练到第 2000 步时 loss 突然从 1.8 跳到 500 多就是梯度爆炸了。2.4 验证与生成如何确认模型真的学会了训练结束后我干的第一件事不是看 loss 曲线而是让模型自己生成一段话。生成的方法很简单输入一个种子文本逐 token 预测把预测出的 token 追加到输入后面再继续预测下一个这就是自回归生成。但这里有个新手特别容易搞错的点生成时不能直接用logits.argmax()取概率最大的 token否则模型会陷入重复循环。更好的做法是引入温度参数和 top-k 采样。温度大于 1 时概率分布更平滑输出更多样温度小于 1 时更保守。我当时设置温度为 0.8top-k 取 50生成出来的效果才接近像样的英文句子。我还在训练过程中定期算一遍验证集上的困惑度perplexity。困惑度越低说明模型对验证集的预测能力越好。我还打印出几组注意力权重发现模型确实学会了一种基于近邻位置的注意力模式而不仅仅是把前面的 token 平均一下。那一刻的成就感远比我后来用几千亿参数的大模型调 API 来得强烈。3. 工程化不只是训练harness engineering 在真实项目中的分量3.1 什么是 harness engineering为什么它比训练更耗时模型训练出来之后事情远没有结束。在真实项目里真正消耗团队精力最多的是围绕模型建立一整套“驾驭系统”也就是英文里常说的harness engineering。你可以把它理解为给模型戴上缰绳设计测试、评估、监控和兜底机制让它在生产环境中稳定输出。我在好几个项目里统计过时间分配真正做模型训练和微调的大概只占总时长的 25%剩下的时间都在写评测集、调提示词、处理失败样本、做回归测试、设计降级方案。你训练出一个“聪明”模型只是起点让它在各种奇葩输入面前都不“翻车”才是工程。为什么这步这么重要因为大模型本质上是概率系统同样的提示词换几个词输出可能就完全不一样。如果没有一套标准化的评估体系你根本没法判断一次迭代到底是变好了还是变坏了。我见过有团队把某个样例调好了结果其他案例全挂了就是因为缺少一个能同时跑几百条用例的回归测试框架。3.2 用 CodeBuddy 搭建一套模型评估与测试框架的案例最近我尝试用 CodeBuddy 这个 AI 辅助编程工具来加速评估框架搭建。当时的需求是给一个多轮对话模型做回归测试覆盖回答准确性、相关性、拒绝回答不该答的时候要明确拒绝安全性这四类指标。我以前的做法是手写一堆 if-else 去模板化生成测试用例效率很低。这次我换了个方式先让 CodeBuddy 根据我给定的种子意图自动生成一批难度递增的测试问题。比如种子意图是“查询天气”它会生成“今天北京天气怎么样”“明天上海会下雨吗”“过去一年的气温统计”等几十个变体。我再把这些用例按类别组织成 JSON 文件作为评估集的输入。CodeBuddy 的提示指令模板我写得很简单核心就是这样一段话你是一个测试用例生成器。给定一个用户意图生成 20 个测试问题必须覆盖 1. 简单直接表达2. 带多余信息3. 带否定词4. 跨话题混合5. 恶意诱导。 输出为 JSON 数组。然后用 Python 写了一个轻量评估循环对每个测试问题调用模型接口再让 CodeBuddy 帮我把模型回答与预期行为做比对输出一个四档分类结果。这个流程帮我节省了大量体力活评估覆盖度从之前的手工 30 条提升到了 300 多条。这里有个关键心得评估框架的指标不仅要看“正确率”还要看“错误分布”。我发现模型在面对带否定词的问句时错误率特别高。如果不做这种分类统计我永远只会得到“整体还行”这样的模糊结论而不会知道具体薄弱点在哪里。3.3 让模型在可控范围内输出提示工程 结构化输出评估框架架好之后下一步就是约束模型输出。真实业务中我们通常希望模型返回结构化格式比如 JSON 对象方便下游程序解析。但模型经常输出多余的解释文字甚至私自改变字段名。我常用的方案有两层。第一层是提示工程在系统提示里明确要求输出 JSON并且给出一个 few-shot 示例示例里写清字段名和类型。第二层是后处理兜底用正则或一个小的修复函数从模型输出中提取 JSON 片段再用json.loads解析解析失败就报错重试。后来我发现一个更稳的做法是让模型输出一个受约束的格式比如直接在提示里给定模板让模型“填空”。这比让模型自由发挥然后靠解析器去猜要可靠得多。你甚至可以结合工具比如用 CodeBuddy 帮你自动生成一个 Pydantic 数据模型模型输出直接丢进 Pydantic 校验校验失败就再次请求模型修复。这些工作看着不起眼但生产环境的稳定性往往就靠这一层层“护栏”。没有护栏模型一上线就会因为一个边缘 case 把下游系统搞崩。4. 提示工程与AI智能体从手写模型到真实产品4.1 提示工程的核心原则上下文、格式、示例当你开始把模型接入真实产品时提示工程几乎成了日常操作。很多人以为提示工程就是“把问题说得清楚一点”但实际远不止如此。我总结下来有三条核心原则几乎可以应用到所有场景。第一条明确角色与上下文。如果不告诉模型“你是一个客服助手”它默认会用百科全书的语气回复你。给一段精确定义角色的系统提示比你在问题里写十句“请用礼貌语气”有效得多。第二条用 few-shot 示例规范格式。不要只告诉模型“输出 JSON”给它两个具体例子一好一坏模型就能迅速学会你期望的格式。示例的质量直接决定输出的质量。第三条拆分步骤降低复杂度。把复杂问题拆成多个互相独立的子问题比一次性让模型“一步到位”更可靠。这样不仅错误率低还能分别定位哪个子问题的输出有问题。我在多个模型上做过实验同一个问题有上下文定义、有示例、有步骤的提示比简单直接的提示成功率高出 30% 以上。这不是玄学是因为模型本质上是模式匹配器你给出的模式越清晰它匹配到正确路径的概率越高。4.2 一个完整的AI Agent 工作流从规划到执行提示工程再往上走一步就是 AI Agent。所谓 Agent核心是一个循环模型接收任务判断需要调用哪些工具执行工具调用观察结果再决定下一步。我写过一个非常简单的 ReAct 风格的 Agent骨架代码现在还能派上用场。class SimpleAgent: def __init__(self, llm, tools): self.llm llm self.tools tools def run(self, task, max_steps5): messages [{role: system, content: 你是助手可以调用工具。每次回复先给计划再执行。}] messages.append({role: user, content: task}) for _ in range(max_steps): resp self.llm(messages) action parse_action(resp) # 例如: {tool: search, input: xxx} if action is None: return resp result self.tools[action[tool]](action[input]) messages.extend([resp, role_result(result)]) return 达到最大步数这个 Agent 能跑通关键在于每次调用工具后要把工具返回的结果拼进messages作为下一次模型推理的上下文。这样才能形成“观察-思考-行动-再观察”的闭环。真实产品里Agent 的难点往往不是逻辑循环而是模型在循环里多次犯错。比如它可能在调用工具时生成了不存在的工具名或者在应该停止时继续回复。我通常会在每一轮加上校验和重试机制而不是把大模型的输出当作可信的指令直接执行。4.3 避坑经验模型幻觉、上下文长度、成本控制必须坦白说Agent 的幻觉问题比单轮问答严重得多。因为 Agent 在循环中积累了多轮工具输出模型很可能会“编造”一个不存在的工具结果来迎合用户的假设。我的应对方法是在系统提示里反复强调“工具返回值是唯一事实来源不要自己补充”并且在工具调用环节强制校验工具名和参数格式任何校验失败都直接中止不让模型继续编。上下文长度是另一个高频坑。Agent 每轮都会把历史消息拼进去几轮之后 token 数就会爆炸。我的做法是做一个简单的上下文裁剪只保留最近的 N 轮并且把工具调用的结果压缩成摘要。对于长文档用检索而不是全量塞入上下文。最后是成本。很多人低估了 Agent 的 token 消耗一个只有五步的 Agent 可能消耗 5000-8000 token。我建议上线前先用一个粗粒度 token 统计器估算单次任务成本再根据预算倒推最大步数和模型选择。我吃过一次亏一个功能上线后 API 账单比预估贵了四倍就是因为循环内每一步都加入了大量历史消息。5. 从零到一的学习路径与资源推荐5.1 按周规划的实战路线如果说这篇文章有价值那么下面这部分我不想让你看完就忘。我根据自己和身边朋友的经验整理了一份八周从零入门 AI 工程的路线每个阶段都有明确产出。第 1 周Python 基本功 线性代数复习。不需要学得多深能写清楚循环和类能理解矩阵乘法和点积的含义即可。产出用 Python 手写一个二维矩阵乘法函数。第 2 周手写一个两层神经网络只允许用 NumPy不允许用深度学习框架。用交叉熵损失和反向传播在 MNIST 上分类。产出模型在验证集上达到 90% 以上准确率。第 3-4 周阅读《Build a Large Language Model from Scratch》前七章同时复现代码。这本书从一开始的注意力机制讲到 GPT 结构非常适合作为从零构建语言模型的导引。产出在个人电脑上训练一个能生成连贯句子的 GPT 风格小模型。第 5-6 周自己选一个感兴趣的数据集中文小说、代码、专利文本都可以完成数据清洗、分词、训练一个 30M 参数级别的语言模型并评估模型困惑度。产出一个可以在命令行交互的简单对话模型雏形。第 7 周给模型做指令微调。准备几百条高质量的指令问答对用标准监督微调流程把通用语言模型变成能回答具体问题的助手。产出一个能稳定回复固定指令集的模型。第 8 周搭一个最小评估框架为你的模型生成 50 条测试用例统计正确率然后写一个两页纸的总结报告包含你遇到的三个问题及解决方案。产出你已经不是一个只会调 API 的人而是一个具备工程思维的人。5.2 必须关注的开源项目与工具除了上面这本书我还强烈建议你把一些核心工具加入日常武器库。Hugging Face 的transformers和datasets是目前最主流的生态不要只是 pip install 然后调用而是遇到问题就去读它的源码看模型前向传播每一步在做什么。tokenizers库也值得研究你想真正理解 BPE 分词做了什么光看文档是不够的必须自己跑几个例子观察切分结果。PyTorch 不必多说了写作本文时它已经是很多 AI 工程的基础。实验日志我用 WB虽然你可以换任何一款但关键是养成记录每个超参数及其对应结果的习惯这比记忆力可靠得多。Agent 开发方面LangChain 或 LLaMAIndex 可以看看但我不建议在刚入门时沉迷因为这些框架往往帮你隐藏了底层的消息处理逻辑。你最好先学会手写循环再去考虑要不要用框架。5.3 我的几点体会走到这里你已经从理论看到实践从手写模型看到生产化的评估和 Agent。我把这几年里最重要的几点体会放在最后。首先不要被“大模型”三个字吓住。把一个 10M 参数的模型完整地训练、评估、部署和训练一个大模型的本质流程几乎完全一样。你从小的入手才能真正体会到每一层的作用然后迁移到更大的模型时才能理解为什么有人要调学习率为什么要做数据清洗为什么评估集比训练集更投入精力。其次能定位 bug 的工程师永远比能训练大模型但调试不了模型的人更稀缺。我见过太多只会把模型代码跑通就沾沾自喜的人结果线上输出出问题时完全不知道是从哪里开始排查。从零手写模型最大的价值就是把你训练成一个遇到问题能快速缩小范围、定位根因的人。最后给自己留一本实验笔记。把每一次训练的数据、参数、loss 曲线、生成样例都记录下来。一个月后你会感谢这个习惯因为 AI 工程里最珍贵的不是代码而是你的判断力——而判断力正是从无数次记录下来的成功与失败中长出来的。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

从FP32到FP8:模型推理中的数值精度、混合精度与量化实践 2026/9/29 10:22:41

从FP32到FP8:模型推理中的数值精度、混合精度与量化实践

在开始之前先啰嗦两句。我最近在整理模型部署和推理优化的笔记,第一件事就想把数值精度这块掰扯清楚,因为后面所有优化——不管是算子融合、KV Cache 量化还是 TensorRT 加速——全都绕不开它。网上讲 FP32/FP16/BF16/INT8 的材料很多,但到了…

阅读更多 →
外墙裂缝目标检测YOLO数据集:6,296张图像助力建筑病害智能识别| 外墙裂缝检测 YOLO数据集 建筑健康监测 无人机巡检 目标检测8030期 2026/9/29 10:22:41

外墙裂缝目标检测YOLO数据集:6,296张图像助力建筑病害智能识别| 外墙裂缝检测 YOLO数据集 建筑健康监测 无人机巡检 目标检测8030期

外墙裂缝目标检测YOLO数据集:6,296张图像助力建筑病害智能识别| 外墙裂缝检测 YOLO数据集 建筑健康监测 无人机巡检 目标检测8030期 在建筑结构健康监测与城市安全管理领域,外墙裂缝的自动化检测是预防高空坠物、评估建筑老化程度的重要手段。本文解析的…

阅读更多 →
Linux下GCC多版本安装与切换全攻略:从update-alternatives到源码编译 2026/9/29 10:22:41

Linux下GCC多版本安装与切换全攻略:从update-alternatives到源码编译

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Model-Optimizer实战:模型瘦身的四层工程化方法论 2026/9/29 10:22:41

Model-Optimizer实战:模型瘦身的四层工程化方法论

1. 项目概述:这不是一个“一键压缩”的玩具,而是一套面向真实推理场景的模型瘦身工作流“Model-Optimizer”这个名称在当前技术社区里被反复提及,但它绝不是某个新发布的、带图形界面的傻瓜式软件,更不是营销话术包装下的概念产品…

阅读更多 →
45种时频域特征提取MATLAB代码:一站式信号分析工具箱 | 特征提取 MATLAB代码 时频域分析 故障诊断 信号处理8029期 2026/9/29 10:22:41

45种时频域特征提取MATLAB代码:一站式信号分析工具箱 | 特征提取 MATLAB代码 时频域分析 故障诊断 信号处理8029期

45种时频域特征提取MATLAB代码:一站式信号分析工具箱 | 特征提取 MATLAB代码 时频域分析 故障诊断 信号处理8029期 在信号处理、故障诊断与机器学习特征工程中,如何从原始时序数据中高效提取多维度特征,往往是决定模型效果的关键环节。本文介…

阅读更多 →
2026年Hermes Agent/OpenClaw怎么部署?阿里云合规部署及Token Plan配置教程 2026/9/29 10:22:34

2026年Hermes Agent/OpenClaw怎么部署?阿里云合规部署及Token Plan配置教程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉