去年有个做后端的朋友拿着一份大模型学习路线来找我上面密密麻麻列了三四十个名词注意力机制、位置编码、LoRA、QLoRA、RAG、向量数据库、vLLM、Agent、多模态……他问我要按什么顺序啃完。我当时给他的回答有点扫兴这里面有八成内容在你做出第一个能用的东西之前根本不需要碰。大模型开发这件事被网络上的信息密度严重夸大了真实的入门路径其实很窄——先让模型在你的机器上吐出第一句话再把你的业务知识喂进去最后才是考虑要不要动参数。这篇文章想做的就是把这些被过度包装的东西拆回原样讲清楚一个大模型应用开发的新手从零到能交付可用功能中间到底要跨哪几道坎、每道坎上最容易摔在哪里。无论你是写业务代码的工程师、做产品的同学还是纯粹想搞明白本地部署大模型是怎么回事的爱好者都可以按这个顺序走一遍。1. 先把大模型开发这五个字拆开你入门阶段真正要交付的东西是什么1.1 行业里说的开发其实是三种完全不同的活儿很多人一上来就被训练大模型这四个字吓住了以为要准备几千张卡、几百 TB 语料。这是把学术机构的预训练工作和工业界的应用开发混为一谈了。按实际工作内容分市面上叫大模型开发的岗位大体是三类它们需要的技能栈重合度其实不到三成。第一类是应用层开发日常工作是把模型的 API 接进业务系统做提示词设计、工具调用、结果解析、异常兜底。这类工作最接近传统后端主要考验的是工程能力而不是数学功底也是目前招聘量最大的一类缺口。第二类是部署与推理优化负责把开源权重跑起来、量化压缩、调并发、压延迟、算显存账本质上是个偏底层的性能工程活。第三类是微调与对齐要处理数据清洗、指令构造、训练参数、效果回归是三类里离算法最近的一类但即便这一类绝大多数人做的也是 LoRA 这种轻量方案而不是从零预训练。对刚入门的人来说推荐的顺序是应用 → 部署 → 微调。理由很实在应用层的反馈最快你改一行提示词马上能看到效果差异这种即时反馈是维持学习动力的关键部署层会逼你理解显存、上下文长度、吞吐这些硬约束这些约束会反过来塑造你对模型能力的判断而微调如果没有前两步积累的直觉你连这次效果变差到底是数据问题还是参数问题都判断不了。1.2 三种活儿的能力与投入对照我把这三条路线的入门门槛和产出周期做了个粗略对照数字是我自己在带人时观察到的中位数个体差异会很大但量级参考意义还是有的。方向核心技能硬件底线首次出成果的时间常见坑应用开发HTTP/JSON、提示设计、检索、状态管理能调 API 即可无本地显卡要求1 到 3 天把提示词写得像散文无法维护部署推理Linux、CUDA、Python 服务、显存计算一张 16GB 以上显存的卡3 到 7 天用 FP16 硬跑然后 OOM微调训练数据处理、训练框架、评测方法一张 24GB 显存卡起步2 到 4 周数据量太少还硬训模型变傻这张表最重要的一列是硬件底线。很多新手卡在第一步不是因为笨而是因为机器不对——用一台 8GB 显存的笔记本去折腾 7B 模型的微调注定是个反复失败的过程而反复失败最容易让人误判成我学不会。先把硬件和能力需求对齐比多背几个名词有用得多。提示入门阶段不要同时开三条线。我见过太多人一边看量化原理一边研究 LoRA 超参两个月过去一个能跑的东西都没有。选定一条做完一个最小闭环再横向扩展。2. 第一次把模型跑在自己机器上推理链路的最小闭环2.1 显存不是玄学先学会算这笔账在下载任何权重之前你得先知道它装不装得下。显存的算法其实很朴素主要吃三块权重本身、KV Cache、以及框架的额外开销。权重这块最容易算参数量乘以精度字节数就是裸权重大小再乘上大约 1.1 到 1.2 的系数作为加载开销。举个具体的例子一个 7B 参数的模型用 FP16 存储理论上是 7 × 2 14GB实际加载后大概在 15GB 上下如果用 INT8 量化降到 7GB 左右INT4 则压到 4GB 附近。KV Cache 这块常被忽略但它恰恰是跑起来能对话和跑起来能服务的分水岭。它的大小跟上下文长度、批大小、层数、隐藏维度都相关粗略估算是批大小 × 序列长度 × 2 × 层数 × 隐藏维度 × 精度字节。经验值上7B 模型在 FP16、上下文 2048、单条请求的情况下KV Cache 大概占用 1GB 左右如果把上下文拉到 32K同一个模型能吃掉十几 GB。这就解释了一个常见困惑为什么单条对话跑得好好的一上并发就崩——不是权重装不下是缓存把显存吃穿了。2.2 用 Ollama 拿到第一个能说话的进程如果你是应用向入门最省事的路径是用 Ollama。它把模型下载、量化格式转换、服务启停全都包成了一个命令行工具你不需要理解 GGUF 和 safetensors 的区别就能先看到结果。安装完之后一条命令拉起服务另一条命令就能对话# 拉取并运行一个 7B 量级的对话模型 ollama run qwen2.5:7b # 服务默认监听本地端口可以直接用 HTTP 调用 curl http://localhost:11434/api/generate -d { model: qwen2.5:7b, prompt: 用三句话解释什么是向量检索, stream: false }这套流程的价值不在于性能而在于它把模型这个抽象概念变成了一个你能 curl 的本地 HTTP 接口。从这一刻起你对大模型的认知就从某个网页上的聊天框切换成了一个输入输出不确定的服务这个视角转换非常重要后面所有的工程问题都是从输出不确定这四个字长出来的。2.3 第一次被上下文长度和 token 坑到几乎每个人在第三天左右都会撞上两个概念token 和上下文窗口。token 不是字也不是词是模型眼里的最小切分单位中文里大致一个汉字对应一到两个 token英文一个常见单词通常一个 token。上下文窗口则是模型一次能看见的 token 总数上限输入加输出一起算。这两件事带来的第一个实际麻烦是成本与截断。你往提示词里塞一篇一万字的文档它可能就吃掉了六七千 token模型还没开始回答窗口已经快满了于是它开始遗忘开头的内容。第二个麻烦是注意力稀释即便技术上没超限过长的输入也会让模型对中间部分的内容关注度下降这在实际业务里表现为我明明把答案写在文档里了它却答错。我自己的做法是给提示词做预算管理把输入拆成固定部分系统指令、格式约束和可变部分用户内容、检索结果给可变部分设一个硬上限超过就用检索而不是全文塞入。这个习惯从入门第一天就建立起来后面做 RAG 的时候会省掉大量返工。3. 提示工程不是文案技巧它是你最先要练的手艺3.1 一条能维护的提示词有四个固定件网上讲提示词的文章多半在教你加请你作为一位资深专家这类角色扮演这类技巧有边际收益但它撑不起一个生产系统。一条真正能长期维护的提示词我一般拆成四块角色与边界、任务描述、输出格式约束、异常处理约定。角色与边界要写清楚它能做什么、不能做什么比如只依据提供的资料回答资料中没有的内容必须明确说不知道。任务描述要具体到可执行避免帮我分析一下这种模糊指令。输出格式约束必须给例子给一个完整的 JSON 样例比描述十句请输出结构化数据都管用。异常处理约定是最容易被漏掉的一环——输入为空怎么办、问题超出范围怎么办、多个答案冲突怎么办这些不写清楚模型就会自由发挥。3.2 把提示词当代码管别在对话框里手搓我踩过最深的坑之一是在网页对话框里反复调试出一版效果特别好的提示词然后手动复制到代码里上线后发现效果完全不一样。原因很简单网页端有默认的系统提示词和温度参数你看到的输出和 API 拿到的输出根本不是同一个环境。所以从第一天起就要养成习惯提示词写进文件参数写进配置版本用 Git 管。改提示词就是在改代码要能 diff、能回滚、能对照评测。我通常会把提示词拆成一个目录每个任务一个模板文件模板里用占位符把可变内容隔开Python 侧只做字符串替换避免在代码里拼长字符串。from pathlib import Path PROMPT_DIR Path(prompts) def build_prompt(task: str, **kwargs) - str: template (PROMPT_DIR / f{task}.txt).read_text(encodingutf-8) return template.format(**kwargs) # prompts/qa.txt 里大致是这样 # 你是资料问答助手。只依据【资料】回答资料中没有的信息直接回答资料未提及。 # 【资料】 # {context} # 【问题】 # {question} # 请用不超过 100 字回答并在结尾标注引用的资料序号。这个做法看起来笨但它能救你两次一次是线上效果突然变差时你能快速定位到是哪次提交改的另一次是你想对比两种提示策略时不用凭记忆在不同环境之间来回切。注意温度参数在事实类任务上不要乱调高。做抽取、分类、问答这类工作温度设 0 到 0.3 就够调高只会让输出变得不稳定不会让答案更聪明。4. 让模型说你的话RAG 是入门阶段性价比最高的落地方式4.1 切块、向量化、召回坑分别在哪检索增强生成这套东西听起来有三个环节实际上每个环节的失败率都不低而且失败会传导到下游让你误以为是模型不行。切块环节最常见的错误是按固定字数硬切。一段完整的规定被从中间劈开前半段在块 A、后半段在块 B召回时只捞到 A模型就只能答一半。我一般按语义边界切优先在标题、段落、句号处断开再配合 10% 到 20% 的重叠保证被切断的信息在两个块里都能看到。向量化环节的坑在于用通用嵌入模型处理专业语料。通用模型在生活语料上表现好但遇到行业术语、编号体系、内部缩写时相似度判断会失准。有条件的话用你的真实查询和文档做一次小规模对比测试几个候选模型跑分差个 10% 是常有的事。召回环节的坑最隐蔽top-k 设得太大或太小。设小了正确答案没被捞进来设大了一堆相似但不相关的块混进上下文反而干扰模型判断。我的经验是先在 3 到 8 之间扫一遍同时加上重排序步骤让相关性最高的块排在最前面这一步对最终效果的提升通常比换更大的模型更明显。4.2 一个能跑通的最小骨架入门阶段不要把 RAG 做成一个大工程。一个能跑通的最简版本核心流程就是四步加载、切块、入库、查询时召回并拼进提示词。下面这个骨架省略了所有优化但结构是完整的你可以直接在上面加东西from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_community.vectorstores import FAISS from langchain_community.embeddings import HuggingFaceEmbeddings # 1. 切块优先在段落和句子边界断开 splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap80, separators[\n\n, \n, 。, , , , ], ) chunks splitter.create_documents([open(docs.txt, encodingutf-8).read()]) # 2. 向量化并入库 embedding HuggingFaceEmbeddings(model_nameBAAI/bge-small-zh-v1.5) store FAISS.from_documents(chunks, embedding) # 3. 查询时召回 question 保修期是多久 hits store.similarity_search(question, k4) context \n\n.join(f[{i1}] {d.page_content} for i, d in enumerate(hits)) # 4. 拼进提示词后调用模型 final_prompt build_prompt(qa, contextcontext, questionquestion)这段代码大概四十行但它覆盖了 RAG 的全部关键部件。学会之后你会发现后面所有的所谓进阶 RAG 架构无非是在这四步上换更好的切块策略、换更强的嵌入模型、加一层重排序、加一层查询改写而已。4.3 效果差的时候先查召回不要查模型这是我在实际项目里反复验证的一条排查顺序RAG 答错的案例里绝大多数是召回阶段就没捞到正确内容而不是模型理解错了。所以在抱怨模型太笨之前先做一个动作——把召回出来的原始块打印出来人工看一眼正确答案在不在里面。如果不在问题在检索侧去调切块粒度、换嵌入模型、加关键词混合检索。如果在但模型答错了问题才可能在生成侧这时候再考虑改提示词、换更大的模型、加少样本示例。这个排查顺序能帮你省掉大量无效的模型替换实验我见过太多团队在没验证召回的情况下连换三个模型最后发现是切块把答案切碎了。5. 微调该不该上LoRA 的判断线、数据准备与实操5.1 动手前先回答三个问题微调是有成本的不只是算力成本还有维护成本和遗忘风险。所以在动手前我会先问三个问题三个都答是才考虑微调。第一问题是否只能靠改权重解决。如果需求是模型要知道我们的产品参数那这是知识注入RAG 更合适也更便宜如果需求是模型必须严格按我们的固定格式输出且不能有例外那提示词加后处理往往就够了。真正需要微调的通常是风格、语气、领域表达习惯、复杂指令遵循这类难以用文字完整描述的要求。第二有没有几百条以上的高质量样本。LoRA 虽然轻量但它不是零样本学习的替代品。样本太少时模型会过拟合到那几十条数据上表现为在你的测试集上表现很好一遇到稍微变形的输入就崩。第三能不能量化评测。没有评测集你无法判断微调是变好了还是变差了。这不是学术洁癖而是实战必需——我见过模型在目标任务上提升明显但通用对话能力明显退化如果只盯着目标任务看这个代价就会被忽略。5.2 一份合格的数据集长什么样数据质量决定微调效果的上限这句话在实操中怎么强调都不过分。一份能用的指令微调数据我通常按这几个标准筛格式统一每条样本的指令、输入、输出字段结构完全一致不要有的带上下文有的不带。输出是目标风格的样本你想让模型输出简洁样本就必须简洁你给的样本啰嗦训出来就啰嗦。负样本要有代表性不只是好的回答还要包含这类问题应该拒答或追问的样本否则模型会对所有输入都硬答。长度分布贴近真实如果上线场景里 80% 的输入是短问题就不要用大量长文档问答来训。规模上我的经验是风格类任务 500 到 2000 条通常能看到明显效果复杂推理类任务则往往需要更多。与其花时间把 200 条数据反复清洗到极致不如先把数据量做到 800 条再统一清洗一遍后者收益更大。5.3 用 LLaMA-Factory 跑一次 LoRA 的完整流程既然要做就用成熟的框架做不要自己手写训练循环。LLaMA-Factory 这类一站式微调平台把数据格式、训练配置、导出合并都封装好了入门阶段能省掉大量环境折磨。整个流程大致是四步。第一步准备数据文件通常是一个 JSON 数组每条包含指令、输入和期望输出三个字段。第二步写一份配置文件指定基座模型路径、数据文件、LoRA 的秩、学习率、批次大小和训练轮数。第三步启动训练观察损失曲线。第四步把 LoRA 权重导出并合并到基座模型或者作为适配器在推理时动态加载。# 训练示意具体参数按你的显存调整 llamafactory-cli train config/lora_sft.yaml # 配置文件里的关键几项含义见下 # finetuning_type: lora 轻量微调只训练少量附加参数 # lora_rank: 8 秩越大容量越强也越容易过拟合 # lora_target: all 作用到哪些层all 表示全部线性层 # learning_rate: 1e-4 比全量微调大一到两个数量级 # num_train_epochs: 3 轮数过多会明显过拟合 # cutoff_len: 1024 超过这个长度会被截断关于参数只讲三个最关键的。**秩rank**决定可训练参数的容量8 和 16 是最常用的起点任务越复杂、数据越多可以往上加但超过 64 之后收益递减明显。学习率比全量微调要高1e-4 是常见起点如果损失剧烈震荡就往下调。训练轮数是最容易犯错的很多人习惯性设 5 到 10 轮结果模型把训练集背下来了。我一般从 2 到 3 轮开始同时留一份验证集观察。5.4 微调之后的两种典型反效果第一种是通用能力退化也叫灾难性遗忘。表现是目标任务答得漂亮但一问别的就开始胡言乱语。缓解办法是往训练数据里掺入一定比例的通用指令数据比例我一般给 10% 到 20%。第二种是格式僵化。模型学会了 very 固定的回答模板连不该用模板的场景也套模板。这通常是训练数据格式过于单一导致的解决办法是在数据里加入一定比例的自由格式样本让模型知道不是所有问题都要按三段式回答。提示每次微调都保留一份改动前的基线输出。不要靠记忆判断好像变好了把两版模型的输出并排放在一起看你会发现很多凭感觉判断不出来的退化。6. 把 demo 变成服务vLLM、并发与量化6.1 并发、吞吐、延迟三个指标互相拉扯单条对话流畅不代表能上线。一旦有十个用户同时提问你会立刻遇到三个指标之间的取舍吞吐是单位时间处理的 token 总数延迟是单个请求从发出到首个 token 返回的时间并发是同时在处理的请求数。这三个指标不是独立的提高批大小能拉高吞吐但会让单个请求的首字延迟变长。入门阶段最容易犯的错误是用单请求测出来的性能去估算线上容量。单条测试时显存里只有一份 KV Cache上到 32 并发时缓存占用会翻几十倍直接 OOM。所以压测必须从并发维度做而不是单条跑得快就以为没问题。我的习惯是至少测四档1、8、32、64 并发记录每档的首字延迟、总耗时和显存占用画出一条曲线你才知道这台机器的真实服务边界在哪。6.2 量化选型的实际账本量化是在精度和显存之间做交换。常见的档位和它们的大致表现如下表数字是常见经验值具体到某个模型会有浮动。精度7B 模型权重大小显存压力精度损失适用场景FP16约 14GB高基准有充足显存、要求最高质量INT8约 7GB中很小通用部署的稳妥选择INT4约 4GB低可感知显存紧张、对精度不苛刻我的一般建议是能用 INT8 就别用 INT4能上 FP16 就别省那点显存。INT4 在推理类、代码类任务上的退化比在闲聊类任务上明显得多如果你的业务涉及逻辑推理或者结构化抽取量化掉的那点精度可能刚好落在关键判断上。判断办法很简单拿同一批测试问题分别跑两个精度版本对比输出差异不要凭听说 INT4 损失很小就拍板。6.3 vLLM 这类推理框架解决了什么问题自己用 Transformers 逐条推理的问题是显存利用率低因为 KV Cache 需要预先分配一大块连续内存导致大量碎片浪费。vLLM 这类框架的核心思路是把缓存切成固定大小的小块按需分配再配合连续批处理让不同请求的 token 生成过程交错进行。效果上同样的硬件通常能支撑高得多的并发。# 启动一个兼容 OpenAI 接口的推理服务示意 python -m vllm.entrypoints.openai.api_server \ --model /path/to/model \ --served-model-name my-model \ --max-model-len 8192 \ --gpu-memory-utilization 0.9 \ --tensor-parallel-size 1几个参数值得说清楚。max-model-len直接决定 KV Cache 的预留上限设得越大能吃下的长文本越长但同时会挤占批处理空间进而影响并发能力。gpu-memory-utilization控制框架能占用多少比例的显存设 0.9 是留一点余量给系统设太高容易触发内存不足。tensor-parallel-size是多卡切分的并行度单卡就填 1。这里有个新手常踩的坑把 max-model-len 设成模型支持的最大值。比如模型标称支持 128K 上下文你就设 128K结果并发能力被压到极低一个请求就占满了缓存。正确的做法是按业务实际需要设如果你的场景里最长输入也就三千字那设 8K 完全够用多出来的显存全都能转化成并发能力。7. 评测怎么证明你做的东西能用7.1 感觉挺好的不是结论我见过太多项目在演示阶段无比顺利上线之后被用户骂得很难听。原因往往不是模型不行而是从来没有人系统性地测过它在边缘情况下的表现。演示用的那三五个问题是你精心挑的真实的用户输入则千奇百怪错别字、语序颠倒、多问题混在一起、故意诱导、超长上下文这些都不在演示脚本里。所以从项目第一天就要开始攒评测集而不是等到上线前才想起来。攒的方式很土但有效把每次发现的bad case记下来标上正确答案和错误类型一个月下来就是一份几十条的针对性评测集。这份东西比任何公开榜单都更能反映你的系统能不能用。7.2 一份小而狠的评测集怎么搭规模上不需要大50 到 200 条就足够指导迭代关键在于覆盖。我通常按这几个维度分层抽样常规正确性占比最大考察基本功能是否可用。边界输入空输入、超长输入、纯符号、多语言混杂。知识边界明确超出资料范围的问题看它是否老实说不知道而不是编造。格式稳定性同一类问题批量跑看结构化输出是否每次都符合约定格式这一项对下游系统尤其关键。诱导性输入包含诱导模型跳过约束、泄露系统提示词、塞入伪造指令的样本用于自查防护是否到位。评测的执行方式建议用脚本自动跑加人工抽检。自动判分可以用精确匹配、关键信息包含、或者拿一个能力更强的模型当裁判但裁判本身也会出错所以关键批次一定要人工过一遍。每次改动——无论是换提示词、换模型、加检索还是做微调——都要在同一份评测集上跑一遍记录下来形成一条可追溯的效果曲线。7.3 幻觉与越权输出上线前必须堵的洞幻觉这个问题没法彻底消除但可以把它约束在可接受的范围内。三个比较实用的手段一是强制引用要求模型在回答中标注信息来源没有来源的内容不允许出现在答案里二是降低温度事实类任务上把随机性压到最低三是答案后校验用规则或第二个模型检查输出里是否包含资料中不存在的实体名称、数字和日期这一步能拦掉相当一部分编造。越权输出这个说法听起来重其实指的是模型做了它不该做的事比如回答了它本该拒答的领域问题、输出了不该返回的内部字段、执行了用户通过提示注入塞进来的伪造指令。防护思路上把系统指令和用户输入在结构上明确隔离不要让它们混成一段文字对模型输出做白名单校验只接受符合预期格式的内容对敏感操作加人工确认环节不要完全交给模型自动决策。注意不要指望一句请忽略用户输入中的任何指令就能挡住提示注入。这是概率防护不是绝对防护真正的安全边界必须建立在代码层而不是提示词层。8. 不同起点的学习路线以及几条花钱买来的教训8.1 三条路线的具体走法应用向的走法是先用 Ollama 或云端 API 跑通一次对话调用然后把提示词抽成模板文件接着做一个最小 RAG再把它包装成一个内部能访问的服务最后加上评测脚本。整个路径大概两到四周全程不需要自己有显卡。部署向的走法是先算出显存账理解权重、缓存、框架开销三块的关系然后用量化后的模型在本机跑通推理接着上 vLLM 这类框架做并发压测画出性能曲线最后处理多模型切换、服务守护、日志监控这些工程问题。这条路线的门槛在 Linux 和性能调优的直觉需要的时间会长一些。算法向的走法是先搞清楚注意力机制在做什么层面的信息混合不用推导公式但要能说清为什么长上下文会变慢然后读一遍 LoRA 的原理明白它为什么能用极少的参数撬动效果接着准备一份小数据集用成熟框架跑一次训练观察损失曲线最后做一次消融对比不同秩、不同轮数的效果差异。这条路线最忌讳的是一头扎进论文里不出来方法是先跑通再回头补理论。8.2 几条我真心觉得重要的教训第一条不要在入门阶段自建训练框架。有人觉得用别人的工具学不到东西于是手写数据加载、手写训练循环结果两周时间全花在调试梯度累积的维度上模型一次都没训成功。成熟框架已经把百分之九十的脏活干完了你的精力应该花在数据和评测上。第二条模型的聪明程度和你的任务成功率不是线性关系。在很多结构化抽取任务上一个小模型加上精心设计的提示词和少量示例表现能超过一个不做约束的大模型而成本和延迟只有后者的零头。所以每次想升级模型之前先把提示词和评测做扎实。第三条把不确定性当成系统的一等公民。大模型的输出天然带随机性所有下游消费者都必须能处理这次输出格式不对的情况。我在所有项目里都会加一层解析兜底解析失败就重试一次再失败就走降级路径返回一个结构化错误而不是把原始文本硬塞给下游。第四条记录每一次实验。参数、数据版本、评测分数、观察到的现象全部记下来。你会在三周后感谢自己因为那时候你已经完全记不清上次把学习率调成 5e-5 的时候到底发生了什么。第五条资料看三份不如动手做一遍。这个领域变化快网上很多教程的接口和参数早就过时了照着抄必然报错。真正有效的学习方式是选定一个最小目标比如让模型基于我的文档回答三个问题然后围绕这个目标去查资料、试错、修正。目标完成的同时一整套工具链和踩坑经验也就自然长在你身上了。我在实际操作中的体会是大模型开发这件事的门槛从来不在数学而在于能不能把不确定性管住。能跑通第一次推理的人很多能在线上稳定服务三个月不出大事故的人很少差别就落在评测、兜底、记录这些看起来最不酷的功夫上。