happy-llm:从Token、RAG到Agent的LLM系统学习路线 📅 发布时间:2026/8/28 5:06:24 👁 浏览次数: 1. 背景与核心概念1.1 happy-llm 是什么在早期学习大语言模型时很多开发者都会遇到一个相似的问题网上资料太多太杂有人讲 Transformer 原理有人讲 LangChain有人讲微调但内容之间缺少连贯性。你跟着一个教程跑通了 demo换一个框架又看不懂了因为你缺少的是一个完整的知识骨架。Datawhale 社区的 happy-llm 项目就是为了解决这个问题而出现的。它是一套围绕大语言模型学习与实战的开源教程集合目标是用相对轻松的方式带着开发者从 LLM 的基本概念一路走到应用开发。项目内容通常包含几个层次语言模型基础、Prompt 工程、向量检索与 RAG、Agent 开发、模型微调与部署等。这类项目有一个很鲜明的特点它不只是一份“说明文档”而是把学习路径、示例代码、实验练习和踩坑笔记整合在一起。你可以像读一门公开课一样按章节推进也可以把它当成一本随时查阅的工具书。1.2 为什么系统学习 LLM 而不是只看 API现在很多开发者学 LLM 的第一步是直接调用大模型 API写一个messages数组然后拿到回复。这个上手路径确实很快三分钟就能出结果但长期看会有一个瓶颈一旦业务需求从“简单问答”升级到“解析复杂文档”“稳定输出 JSON”“在私有知识库中查询”你会发现靠堆积 Prompt 解决不了所有问题。你还需要理解 Token 是怎么计算的上下文窗口会对长文本处理产生什么影响向量检索为什么能解决“模型不知道的知识”Agent 的 Tool Calling 是怎么让模型调用外部函数的模型推理时 FP16、BF16 这些精度选项到底影响什么。这些内容恰好是 happy-llm 这类课程希望系统讲解的。它不是为了让你背诵概念而是通过可运行的实验让你对 LLM 的能力边界、常见工程方案和底层机制形成自己的判断。1.3 从 LLM Wiki 到开源课程学习资料形态在变化在 LLM 学习资料的热门讨论中Andrej Karpathy 提出的 LLM Wiki 范式经常被提到。所谓 LLM Wiki,可以简单理解成一种将零散的大模型知识沉淀为结构化、可持续更新的知识库形态。传统的静态博客文章很难跟上 LLM 生态的更新速度而 Wiki 或开源课程仓库则可以通过社区贡献持续维护。happy-llm 这类项目本质上也是这种思路把大模型学习中的理论、代码、工具链和常见坑位以一个中心化仓库的形式沉淀下来。它和学习笔记的区别在于笔记是给自己看的开源课程是给一群学习者看的标准路径。如果你已经工作过两三年习惯用传统软件开发的思维理解一切那么接触 happy-llm 时最重要的心态转变是以前是“需求 - 方案 - 代码 - 测试”现在更常见的是“模型能力 - 提示词 - 检索增强 - 工具调用 - 评估迭代”。这是两种不同的工程节奏。2. 环境准备与项目获取2.1 拉取开源仓库在开始学习之前需要先把 happy-llm 项目拉到本地。如果你还不熟悉 Git 操作这里给一份完整的命令流程。# 1. 进入你希望存放项目的目录 cd ~/workspace # 2. 克隆仓库 git clone https://github.com/datawhalechina/happy-llm.git # 3. 进入项目目录 cd happy-llm如果你已经克隆过项目后续想要同步最新内容可以执行git pull origin main需要注意开源项目的默认分支可能是main也可能是master具体以仓库实际分支为准。如果拉取失败可以先访问 GitHub 仓库页面确认分支名。2.2 创建虚拟环境LLM 相关项目的 Python 依赖通常比较重强烈建议使用虚拟环境隔离避免污染系统 Python。以 Python 3.10 或 3.11 为例# 创建虚拟环境 python3 -m venv .venv # 激活虚拟环境 source .venv/bin/activateWindows 环境下的激活命令如下.venv\Scripts\activate项目里一般会提供requirements.txt或pyproject.toml安装核心依赖pip install -r requirements.txt如果项目文档建议使用某个特定版本的 Python尽量按文档要求来。版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。2.3 推荐的学习路径与项目结构拿到仓库后不建议直接从头读到尾。更高效的方式是先看目录结构。常见的开源 LLM 学习项目通常包含以下模块具体以你拉取到的仓库目录为准模块内容basics/LLM 基础、Token、Transformer 概念prompt/Prompt 工程实践rag/Embedding、向量数据库、检索增强生成agent/Agent、Function Calling、工具调用finetune/LoRA 等微调方法deploy/模型推理与部署建议按照“基础 - Prompt - RAG - Agent - 部署”的顺序推进因为每部分之间都有依赖关系。比如你完全不理解 Embedding直接看 RAG 代码会卡在向量检索的环节。3. 核心知识拆解3.1 LLM 基础Token 与上下文窗口在学习 happy-llm 时第一个必须搞清楚的概念是 Token。Token 可以简单理解成模型处理文本的最小单位。英文中一个单词可能被拆成多个 Token中文一个字有时也会被拆成多个 Token。模型一次能接收的 Token 数量就是上下文窗口。比如一个模型的上下文窗口是 8192 Token那么用户问题、检索到的资料、历史对话、系统提示词加在一起不能超过这个数量。这里常有一个误区上下文窗口很大不代表你一次性塞入的资料都会被有效利用。实践中模型对中间位置信息的关注度可能不如开头和结尾所以做 RAG 时需要对检索结果做取舍而不是把所有资料全部塞给模型。# 示例使用 tiktoken 统计 Token 数量 import tiktoken enc tiktoken.get_encoding(cl100k_base) text 你好欢迎学习 happy-llm 项目。 tokens enc.encode(text) print(字符数:, len(text)) print(Token 数:, len(tokens)) print(Token 列表:, tokens)运行这段代码后你会直观感受到中文文本的 Token 消耗通常比英文字符更多这对后续控制 Prompt 长度和估算成本很有帮助。3.2 精度问题FP16、FP32、BF16 到底差在哪在 LLM 部署和微调过程中精度是绕不开的话题。网络热词里有“LLM 大模型之精度问题(fp16, fp32, bf16)”说明很多开发者在实际运行模型时都被精度问题困扰过。先解释基本概念FP32即单精度浮点数占用 32 bit。训练或推理时精度高但显存开销大。FP16即半精度浮点数占用 16 bit。显存占用降低但在计算时容易出现数据溢出导致数值不稳定。BF16即 Brain Floating Point占用 16 bit。它保留了和 FP32 相同的指数位因此数值范围更大不容易溢出但尾数位少精度略低。在实际推理中很多模型可以使用 FP16 或 BF16 加载。FP16 需要担心的是梯度或中间激活值溢出BF16 在训练中更受青睐因为它兼具低显存和稳定的数值范围。# 示例对比不同精度的显存占用与数值误差 import torch dummy torch.randn(10, 10) for dtype in [torch.float32, torch.float16, torch.bfloat16]: t dummy.to(dtype) mem_bytes t.element_size() * t.nelement() print(f{dtype}: 数据元素 {t.numel()}, 占用 {mem_bytes / 1024:.2f} KB)这个实验虽然简单但能帮助你建立直观认识同样的数据使用 FP32 时占用的内存是 FP16/BF16 的两倍。3.3 Embedding 与向量检索基础RAGRetrieval-Augmented Generation检索增强生成是大模型应用落地中最常用的方案之一。RAG 的核心思想是在模型回答问题之前先从外部知识库中检索相关内容把检索结果拼进 Prompt再让模型基于这些材料作答。要实现检索就需要 Embedding。Embedding 本质上是一个把文本转换成向量的过程向量在空间中的距离可以近似反映语义相似度。常见的做法是用余弦相似度衡量两个向量是否接近。# 示例使用数学方式计算两个向量的余弦相似度 import math def cosine_similarity(vec_a, vec_b): dot sum(x * y for x, y in zip(vec_a, vec_b)) norm_a math.sqrt(sum(x * x for x in vec_a)) norm_b math.sqrt(sum(y * y for y in vec_b)) if norm_a 0 or norm_b 0: return 0.0 return dot / (norm_a * norm_b) v1 [1.0, 0.0] v2 [0.8, 0.6] print(相似度:, cosine_similarity(v1, v2))在实际工程中你不会自己实现余弦相似度而是使用向量数据库或向量索引库完成。但理解这个数学基础有助于你调试检索效果。3.4 Agent、MCP 与 RAG 的关系很多人会混淆 RAG、Agent 和 MCP 这三个概念。简单来说RAG 解决的是“模型不知道的知识怎么补充”。Agent 解决的是“模型需要多步推理和调用工具才能完成任务”。MCPModel Context Protocol解决的则是“模型与外部工具、数据源之间的接入标准化”。在一个完整的业务系统里它们经常组合出现。例如一个智能客服系统先用 RAG 检索售后政策再通过 Agent 判断是否需要查询订单系统最后通过 MCP 标准化接口调用真实业务服务。happy-llm 项目中通常会把这三部分拆开讲但你必须明白它们不是互相替代的关系而是层层叠加的关系。4. 从 happy-llm 出发的完整实战下面我们来做一个完整实验构建一个最小可运行的 RAG 问答程序。为了让示例不依赖特定云服务这里采用“OpenAI 兼容接口”的方式编写代码。实际使用时你需要把 API 地址和 API Key 替换为自己所在环境可用的服务并确认调用方式符合服务商使用条款与合规要求。4.1 准备项目结构先创建一个实验目录llm-practice/ ├── .env ├── rag_demo.py └── requirements.txtrequirements.txt内容如下openai tiktoken python-dotenv安装依赖pip install -r requirements.txt4.2 配置环境变量创建.env文件写入你的模型服务配置OPENAI_API_KEYyour-api-token OPENAI_BASE_URLhttp://localhost:8000/v1 EMBEDDING_MODELtext-embedding-model CHAT_MODELchat-model-name这里的OPENAI_BASE_URL是关键。很多本地推理服务或私有化部署服务都提供 OpenAI 兼容接口你不需要重新学习一套 SDK只需要把 base_url 指过去即可。4.3 实现向量化与检索rag_demo.py的第一个能力是文本向量化和相似度检索。这里用numpy计算余弦相似度避免引入过重的向量数据库依赖。# 文件路径llm-practice/rag_demo.py import os import numpy as np from dotenv import load_dotenv from openai import OpenAI load_dotenv() client OpenAI( api_keyos.getenv(OPENAI_API_KEY), base_urlos.getenv(OPENAI_BASE_URL), ) EMBEDDING_MODEL os.getenv(EMBEDDING_MODEL, text-embedding-model) CHAT_MODEL os.getenv(CHAT_MODEL, chat-model-name) def embed_texts(texts): 将文本列表转换为向量列表。 resp client.embeddings.create(modelEMBEDDING_MODEL, inputtexts) return [item.embedding for item in resp.data] def cosine_similarity(vec_a, vec_b): 计算余弦相似度。 a np.array(vec_a) b np.array(vec_b) return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))4.4 构建检索问答流程接下来是核心的 RAG 流程。我们首先准备一个很小的知识库然后根据用户问题检索最相关的片段最后把片段拼进 Prompt 让模型回答。# 文件路径llm-practice/rag_demo.py KNOWLEDGE_BASE [ happy-llm 是 Datawhale 社区维护的大语言模型学习项目适合从零开始学习 LLM。, RAG 是检索增强生成核心思想是先从外部知识库检索资料再让模型基于资料回答。, FP16 和 BF16 都占用 16 bit 内存FP16 容易溢出BF16 数值范围更稳定。, Agent 的核心能力是推理和工具调用MCP 是模型与外部工具之间的标准化接入协议。, ] def build_prompt(question, context): 根据检索结果构造 Prompt。 return ( 你是一个乐于助人的技术助手。请严格基于下面的参考资料回答用户问题。\n 如果参考资料中没有答案请直接说明资料中未提及。\n f\n参考资料\n{context}\n\n f用户问题{question}\n ) def ask_rag(question): 完整的 RAG 问答流程。 # 1. 对知识库和问题做向量化 doc_vectors embed_texts(KNOWLEDGE_BASE) question_vector embed_texts([question])[0] # 2. 计算相似度取最相关的一条 scored [] for idx, doc_vec in enumerate(doc_vectors): score cosine_similarity(question_vector, doc_vec) scored.append((score, KNOWLEDGE_BASE[idx])) scored.sort(keylambda x: x[0], reverseTrue) best_score, best_context scored[0] # 3. 构造 Prompt 并请求模型 prompt build_prompt(question, best_context) resp client.chat.completions.create( modelCHAT_MODEL, messages[ {role: system, content: 你是一名技术助手。}, {role: user, content: prompt}, ], temperature0.3, ) return resp.choices[0].message.content, best_score if __name__ __main__: question 什么是 RAG answer, score ask_rag(question) print(命中得分:, score) print(模型回答:, answer)4.5 运行与预期结果在项目目录下执行python rag_demo.py预期会先输出问题与知识库中最相关片段的相似度得分然后输出模型回答。由于我们的知识库已经包含“RAG 是检索增强生成”的描述模型应该能给出和参考资料一致的答案。这个 demo 最大的价值不在于性能而在于它完整揭示了 RAG 的三步流程向量化 - 相似度检索 - 拼接 Prompt。后续你只需要把固定知识库替换成真正的向量数据库并引入更复杂的召回策略就能得到一个生产可用的雏形。5. 常见问题与排查思路实际学习 happy-llm 和动手写 RAG 示例时大概率会遇到下面这些问题。这里按现象、原因、解决思路三个维度整理成一张排查表。问题现象常见原因解决思路调用 Embedding 接口报 401 或 403API Key 配置错误或没有该模型服务权限检查.env中的 Key、base_url确认模型服务可用返回内容为空或报超时模型服务地址不可达或模型加载耗时过长先用curl测试接口连通性再看模型 logs中文 Token 数远超预期对编码方式不熟悉中文拆分的 Token 更多用 tiktoken 统计优化 Prompt 长度FP16 推理出现 NaN 或结果异常数值溢出模型敏感层不稳定尝试使用 BF16或开启混合精度RAG 检索到的资料相关性差Embedding 模型不匹配领域或没有对文本做切分调整切分粒度选择领域适配的 Embedding 模型Agent 调用工具时返回格式不稳定模型对 Function Calling 格式理解不足给工具描述补充示例必要时做输出校验5.1 常见问题补充说明第一个值得展开的问题是“调用 API 超时”。这类问题在本地实验尤其常见因为你可能只启动了 API 服务但服务内部的模型还没有完全加载。排查时可以遵循以下步骤先用命令行检查服务进程是否存活。直接访问 API 根路径确认服务返回正常。尝试用一个极短的 Prompt 调用模型观察是否超时。逐步增加 Prompt 长度定位是不是模型推理时间过长。第二个值得强调的是“RAG 检索效果差”。很多初学者以为换一个更强的 LLM 就能解决问答质量但实际上 RAG 的瓶颈往往在检索环节。文档没有正确切分、Embedding 模型和业务领域不匹配、相似度阈值设置不合理都会导致检索结果不相关。遇到这个问题时先不要去调 Prompt而是把检索到的片段打印出来人工检查。5.2 边界情况与安全注意事项如果你在实验中使用真实业务数据必须注意安全边界。不要在没有授权的情况下把敏感数据上传到外部模型服务也不要把内部 API Key 提交到 GitHub。建议在.gitignore中加入.env或者使用环境变量注入配置。涉及大规模数据导入、数据库操作或生产环境变更时务必先在测试环境验证并做好备份。Permission 遵循最小权限原则只给程序必需的访问范围。6. 最佳实践与工程建议6.1 从课程代码到工程代码的转换happy-llm 中的示例代码通常以“讲清楚原理”为目标它们可能没有完整的异常处理、日志监控和生产级配置。当你把示例代码应用到真实项目时需要额外补充以下能力增加重试机制API 调用可能因为网络抖动或服务限流失败。增加结构化日志记录每次请求的 Token 消耗、耗时、命中的知识片段。增加配置隔离开发、测试、生产环境使用不同的模型服务和 API Key。增加输出校验对模型返回的 JSON 或 Function Calling 结果做格式校验避免异常输出直接进入业务流程。下面是加入重试的调用示例# 文件路径llm-practice/call_with_retry.py import time from tenacity import retry, stop_after_attempt, wait_exponential retry(stopstop_after_attempt(3), waitwait_exponential(multiplier1, min2, max10)) def chat_once(client, model, messages): return client.chat.completions.create( modelmodel, messagesmessages, temperature0.3, )使用tenacity库是 Python 生态中非常常见的重试方案。它可以在 API 出现瞬时错误时自动重试并采用指数退避策略减少对服务端的压力。6.2 关于 Function Calling 与输出校验在 Agent 类应用里模型需要输出结构化的工具调用参数。很多开发者只关注“模型有没有调用工具”却忽略了输出校验。我的建议是把模型返回的 tool_calls 当作不可信的用户输入处理必须经过完整的格式解析和参数校验。比如模型返回一个 JSON 字符串你不能直接json.loads之后就用还需要确认关键字段是否存在、类型是否正确、枚举值是否合法。如果模型频繁返回格式错误可以从几个方向调整在工具描述中补充示例。降低 temperature让输出更稳定。在系统提示词中明确输出格式。对模型返回结果做“二次校验 纠错提示”把错误信息返回给模型让它重新生成。6.3 评估是 RAG 和 Agent 项目的核心很多开发者在搭建完 RAG 后凭感觉评估“效果还行”这在 demo 阶段没问题但生产环境必须建立量化评估。你可以从这三个维度开始评估维度说明检索命中率问题是否能检索到正确知识片段回答正确率模型回答是否忠实于检索到的资料拒答准确率资料不足时是否正确拒绝回答定期从真实用户问题中抽取样本人工标注正确答案再跑一遍流程记录指标变化。这个方法不需要一开始就搭建复杂的评测平台用脚本就能完成但它能让你的优化方向更清晰。6.4 工程安全与合规最后强调安全合规。无论是使用开源模型还是云服务 API都需要注意只在你拥有合法授权的环境与数据范围内实验。不要把未脱敏的个人信息或商业保密数据作为 Prompt 发送给外部模型服务。对模型服务地址、API Key 等敏感配置进行访问控制。上线前进行权限审计确保程序运行账号拥有的是最小权限。涉及删除、更新、导入等危险操作时先在测试环境完整验证并备份。7. 总结围绕 datawhalechina/happy-llm 这份开源学习资料本文走完了一条完整的实践路线先理解 LLM 学习中的关键概念如 Token、上下文窗口、精度选择、Embedding、RAG、Agent 和 MCP再通过一个最小可运行的 RAG 问答程序看到“向量化 - 检索 - 生成”如何在代码中落地最后落到工程实现讨论了错误重试、结构输出校验、效果评估和安全边界。相比直接调用 API我更推荐你跟着 happy-llm 的项目内容把实验亲手敲一遍。尤其建议花时间做三件事第一用 tiktoken 统计不同语言的 Token 消耗建立对成本和上下文窗口的直觉第二尝试把示例里的知识库替换成自己的文档体会切分和检索对结果的影响第三尝试给 RAG 程序加一个工具调用迈入 Agent 开发的门槛。LLM 应用开发和传统软件工程最大的不同在于模型的行为存在不确定性但你可以通过检索、提示词设计、输出校验和评估体系把这套不确定性约束在可控范围内。希望这篇教程能帮你少踩一些坑更快跑通自己的第一个 LLM 应用。