从零构建AI工程:部署、量化、微调与推理优化实战

📅 发布时间:2026/10/1 6:31:11
从零构建AI工程:部署、量化、微调与推理优化实战
项目标题: ai-engineering-from-scratch项目正文: 原始描述为空以下内容基于对ai-engineering-from-scratch这一项目主题的合理演绎与专业补全我决定认真记录一下自己从零开始把AI工程能力搭起来的全过程。这个项目名就一句话——ai-engineering-from-scratch但它背后是我过去大半年踩过的所有坑、做过的所有选择和最终沉淀下来的方法论。如果你也是懂点AI但不知道怎么落地成工程的人这篇文章应该能帮你少走很多弯路。先说清楚我当时的处境Python会一点机器学习理论知道个大概PyTorch能跑通官方demo但真要我搭一个能上线、能扛并发、能持续迭代的AI系统脑子里一团浆糊。网上教程要么只讲模型训练不管部署要么只讲API调用不讲工程化没有一个东西能把从零到上线整条链路串起来。所以这个项目的目标很明确以终为始从一个真实可用的AI产品倒推我需要掌握的所有工程能力。很多人问市面上有那么多现成的AI框架和平台为什么还要从零啃一遍我的回答是框架能帮你跑起来但理解不了底层逻辑一旦出问题就是瞎猜。从零搭一遍你会知道每个环节的瓶颈在哪、为什么这么设计、哪里能优化这才是工程能力的根。1. 我为什么决定从零重学AI工程1.1 事情的起点一张离谱的API账单触发这个项目的原因特别现实。我做了一个小工具调用大模型API给用户做文本处理上线两周用户没多少账单倒是先炸了——日均调用费用比我预想的高出一个数量级。我去看调用日志发现很多请求都是相似的输入模型一遍遍重复思考相同的问题根本没有做任何缓存或复用。那一刻我很清楚问题不在模型在工程。我不懂怎么做请求合并、不懂怎么做语义缓存、不懂怎么设计提示词的复用策略所以每一笔请求都真金白银地烧掉了。从那时起我决定彻底搞明白AI系统背后的工程链路而不是继续当API搬运工。1.2 学AI和搞AI工程是两码事市面上的AI课程绝大多数教你的是什么是模型的结构、训练的原理、调参的套路。这些当然重要但它们在真实落地中只占很小一部分。我当时列过一个AI产品上线需要什么的清单数据获取与清洗链路环境依赖管理避免我电脑上能跑Prompt的设计、评测与版本管理模型选型与成本评估开源模型本地部署量化、推理框架、显存计算微调的训练闭环数据→训练→评估→迭代Agent逻辑与工具调用开发上线后的服务化、并发控制、缓存与监控看到这个清单我就明白了我缺的不是AI知识是把AI变成稳定服务的系统工程能力。这个项目就是要逐个击破这些环节而且要从最底层开始不能只会调包。2. 从零搭建第一套AI工程底座2.1 硬件环境和我做的取舍工欲善其事必先利其器。我当时的硬件是一台自己攒的台式机AMD Ryzen 9 5950X16核128GB内存一张RTX 409024GB显存。这个配置做中小规模开源模型的微调和部署完全够用但放到大厂集群里就是个弟弟。现在回头看对于绝大多数从零开始的个人开发者或小团队一张24GB显存的显卡就是性价比最优解——它在能跑7B/14B模型微调和价格还能承受之间找到了平衡点。系统我选了Ubuntu 22.04。有人会纠结Windows能不能搞我的建议是能但别折磨自己。很多AI底层库比如bitsandbytes、flash-attention在Linux上就是顺滑在Windows上则可能要编译半天甚至直接失败。一个稳定干净的Ubuntu环境能帮你省掉大量环境层面的幺蛾子。2.2 环境隔离是第一条命从零开始的第一步是别再直接往全局Python环境里装包了。头一个月我没少为环境崩溃吃苦头——今天装了个torch明天升级了numpy后天另一个项目全废了。后来老老实实上虚拟环境世界清净了。我先后试过venv、conda和最近很火的uv。venv太轻但想管理Python版本的时候不够用conda够全面但依赖解析慢、环境容易臃肿uv是Rust写的快得离谱而且可以直接通过uv venv创建环境、uv pip install装包兼容requirements和pyproject。我的最终环境管理方案是用uv创建和管理虚拟环境用git管理代码版本用DVC管理数据和模型文件。这套组合对单人项目足够轻量对未来协作也不会拖后腿。这个阶段我给自己定的验收标准是任何环境哪怕是刚拉下来的新机器一条命令能复现出完全相同的运行环境。这个习惯后来在部署阶段救了我无数次。3. Prompt Engineering从玄学变成科学3.1 告别口胡式写提示词我最开始写Prompt的方式非常简单粗暴——在对话框里反复试觉得这个效果不错就复制下来写进代码。直到项目跑起来才发现这样的Prompt有太多隐患换个输入场景输出格式就崩了模型升级后同一段Prompt效果明显下降无法判断Prompt改坏了还是改好了因为没有量化指标后来我领悟到一个关键点Prompt Engineering的本质不是写一段话而是设计一套行为约束协议。你需要用工程方法管理它们就像管理代码一样。我给自己定了三条规矩。第一Prompt必须带有明确的输出格式约束用JSON结构而不是自然语言描述你输出一个结论第二Prompt必须包含示例few-shot示例本身就是最有效的约束第三每个Prompt都要有版本号改动必须记录。3.2 我第一次真正把Prompt当代码管现在我的每个Prompt都放在项目里的prompts/目录下每个文件都有版本信息并且配套一个评测用例集。比如一个分类系统的Prompt我会准备200条带标准答案的输入每次改Prompt就跑一遍这200条看准确率有没有下降。这本质上给Prompt上了测试用例让改动有据可依。这一步做完效果立竿见影。Prompt改动从凭感觉变成了看指标回归风险大幅降低。更关键的是这套评测集后来成为微调方案的评估基准——模型的微调效果好不好标准就是能不能超过原来的Prompt baseline效果。这个经验我特别想分享给所有刚入门的同学折腾Prompt之前先搭评测集。没有评测的Prompt只是口嗨。4. 模型选型API调用的隐性成本到底有多吓人4.1 大模型API的账单里全是细节回到开头说的账单问题。当时我用的是很强的商用API质量确实好但跑实际业务时会发现账单里全是隐性成本输入Token和输出Token价格不同很多新手不看这个模型上下文越长输入Token占比越高开销越大有些服务还收图片/工具调用的额外费用系统Prompt每次都跟着请求走这部分钱是纯消耗我举一个真实例子一个典型对话请求用户输入约200 Token系统Prompt加历史上下文可能有3000 Token。如果模型的输入价格是输出价格的一半那么这单请求的大头其实是那3000个每次都重复的背景信息而用户真正关心的输出只有几十个Token。很多不懂的人以为省钱要减少输出长度实际上首先该优化的是系统Prompt和上下文长度。4.2 什么时候该转向本地部署商用API适合快速验证但一旦业务量上来、或者对数据隐私有要求就必须评估本地部署。我的判断标准是三个每月API费用超过一张入门级显卡的折旧成本业务对响应延迟有硬性要求API的往返延迟通常几百毫秒起步数据敏感不能出内网三条里面中两条就值得考虑本地部署了。当然本地部署有更大的工程成本这正好是我项目计划里要啃的硬骨头。5. 开源模型本地部署从量化到推理框架5.1 量化让模型瘦身的关键技术本地部署的第一步是搞懂量化。FP16格式的7B模型需要约14GB显存而我的4090总共才24GB看起来能装下但实际上推理时KV Cache、激活值、中间buffer都要占显存装上没跑几步就OOM了。这时候量化就派上用场了。量化简单说就是把模型的权重从16位浮点数压缩到4位或8位整数。最直观的理解是一张照片原本用1600万色表示现在压缩到256色看起来画质略有损失但文件小了一大截。具体到模型把FP16权重压成4-bit之后7B模型权重体积能降到约4GB左右4090跑起来非常轻松。我对比试过三种主流量化方案GGUF llama.cpp特别适合CPU推理和低配环境量化格式成熟生态好但GPU利用率不如专用推理框架高适合部署到没有独显的小机器上做轻量推理。GPTQ在GPU上推理效率很高显存占用低是目前比较成熟的GPU量化方案但安装步骤稍多需要跑校准数据集。AWQ新一代的4-bit量化相比GPTQ在保持精度的同时表现更好我实测下来在7B级别模型上生成质量与FP16差距很小推荐优先尝试。我的建议如果显存紧张就GGUF如果要用GPU跑并发服务就AWQ或GPTQ。量化不是玄学它在精度损失和部署成本之间给了你一个可以调节的旋钮。5.2 推理框架vLLM还是TGI还是llama.cpp模型有了量化和推理框架的选择就是核心问题。我最常用的三个vLLM主打高吞吐的GPU推理服务框架核心优势是PagedAttention显存管理和continuous batching连续批处理。连续批处理的意思是新的请求不需要等当前批次全部跑完就能动态加入这使得GPU的利用率大幅提升非常适合做在线API服务。我部署QA服务首选它就是因为它能在单卡上扛住很高的并发量。Text Generation InferenceTGIHugging Face出的推理服务功能完整、和生态集成好支持很多高级技巧如structured output。缺点是资源占用略高自定义细节不如vLLM透明。llama.cpp适合轻量部署、边缘设备、CPU推理部署极其简单一个二进制文件就能跑。我做过的实测数据可以让各位有个概念同样的7B模型、同样的4090用llama.cpp的默认配置单路生成大约40-60 tokens/s用vLLM开启连续批处理并发拉到10路之后每路的响应时间虽然略涨但总吞吐量能达到600 tokens/s以上。差异来源就是有没有高效利用显存做批处理。所以如果做在线服务直接上vLLM别纠结。5.3 显存与并发计算给所有从零开始的你很多人问我我这台电脑能不能跑xx模型其实计算逻辑非常简单记住一句话模型权重 KV缓存 激活变量 余量 显存。以7B模型为例FP16权重约14GB量化成4-bit后约3.5-4GB。KV Cache的大小取决于上下文长度和并发数粗略按2GB预留。加上推理框架自己的buffer总共至少需要留2-4GB余量。我手里这张24GB的4090跑7B模型的4-bit量化服务同时带上几千Token上下文实测能支撑20路左右并发不崩溃。如果跑14B模型4-bit量化约7-8GB权重加上KV Cache和其他开销24GB显存也能跑但并发量和上下文长度都得压缩吞吐明显下降。跑34B以上级别的模型单卡基本就力不从心了要么用多卡推理成本陡增要么继续用API。这个算力边界项目过程中一定要心里有数。6. 微调实操数据清洗比训练参数更重要6.1 被低估的数据工程部署关过后我发现通用模型在处理领域专有名词和特定风格时还是不够好于是决定走微调路线。一开始很兴奋觉得马上要训练自己的大模型了结果第一次尝试直接翻车——训练完的模型不仅没变好反而变得更差了甚至开始重复无意义的话。排查很久发现问题出在数据上。我收集的对话数据有大量重复样本同一句话出现几百次、低质兜底回复比如抱歉我还不会回答这个问题、以及前后不一致的标注。全量喂进去训练模型学会了这些垃圾模式自然就退化。数据清洗我做了三轮第一轮去除明显无意义和模板化回复一个小脚本搞定第二轮语义去重。用句子嵌入模型把所有样本转成向量计算相似度把相似度超过0.85的重复样本删掉只保留一条。这一步直接砍掉接近四成数据第三轮人工抽样审查。随机抽出100条看质量不符合要求的打上标签再写规则把类似特征的数据筛选掉清洗完的数据集从5万条降到1.8万条但训练出来的效果反而好了非常多。这个经历让我确信微调项目里数据工程的时间和精力投入应该至少占70%。参数调得再好喂垃圾进去出来的还是垃圾。6.2 LoRA参数的一线经验正式微调我用了LoRA低秩适配没有全量微调。原因很实在4090单卡的显存放不下7B模型的全量微调梯度即使能放下训练速度和显存压力也很吃紧而LoRA只训练一小部分新增参数显存占用小、速度快效果在7B级别上已经足够好——相当于在原有模型旁加了一个领域知识插件。在训练参数上我吃过好几次亏给几个可以直接参考的默认起点rank秩先从32起步。太小如8表达力不够太大如128虽然拟合能力强但容易过拟合且显存压力大alpha一般设成rank的一半如16LoRA的缩放比例稳定省心学习率建议1e-4到2e-5之间。我第一次直接套用全量微调的3e-5训练时loss跳得很厉害降到1e-4附近才稳定LoRA可训练参数少学习率建议比全量微调略高epoch数3个epoch上下就够。我试过5个epoch训练集Loss还在降但验证集效果反而变差明显过拟合了6.3 评估闭环没有评测的微调等于白做微调最忌讳的就是感觉变好了。我当时的做法是把之前做Prompt评测的那200条用例复用过来作为微调后的模型和Prompt baseline的对比基准。具体流程是先跑一遍baseline Prompt未微调模型 优秀Prompt记录指标微调结束后用同一个评测集分别跑微调后的模型可以用同一个Prompt也可以微调后适当简化Prompt看效果。我这次微调的目标是在保持通用能力的前提下让领域问答的准确率提升8个百分点最终实测确实提升了约11个百分点说明方向和投入都是值得的。这里还是要强调在你打算烧钱训练之前先固化评测集。没有评测的训练效果好坏全靠脑补基本等于白练。7. 从模型到产品Agent与工具链的精髓7.1 Agent的本质是一个运输调度系统单模型能做的事情终究有限真正让AI变得好用的是Agent——让模型去调动工具解决复杂问题。很多新手把Agent想得很神其实剥开来看Agent的核心就是一个循环理解用户请求→规划步骤→调用工具获取信息→根据结果决定下一步→直到得到最终答案。我习惯把这个循环称为感知-决策-行动-再感知。我之前做过一个信息整理Agent它需要抓取网页、做文本摘要、查离线资料库。一开始我尝试把所有能力塞进一个超长Prompt让模型自主完成一切结果它经常幻觉式地编造搜索结果。后来我把任务拆成明确的工具调用search_web(query)、fetch_page(url)、query_knowledge_base(question)、final_answer(response)让模型只能在这几个函数里选择调用编造的空间就大大缩小了。7.2 工具调用的开发要点做工具调用有几个细节必须注意每个工具的描述要极其具体包括输入参数的含义、返回结果的格式。模型是靠这些描述来决定调用哪个工具的描述含糊它就会胡乱调用工具返回结果要结构化最好直接给JSON减少模型二次解析的难度和幻觉要有超时与错误处理。工具必然有失败模型需要知道这个工具挂了换个方案。我给每个工具都封装了try/except返回统一格式的错误码模型看到错误码后可以选择重试或换策略最关键的是限制工具数量。工具一多模型的选择准确率会下降。我实测过超过8个工具以后模型的选择准确率开始明显波动所以能合并的工具尽量合并这套Agent跑通之后我才真正体会到AI应用开发和传统后端开发的结合点在哪里说白了就是AI负责理解和决策后端负责确定性和可靠性两者互补缺一不可。8. 把服务送上线的最后一公里8.1 服务化不要直接暴露推理接口模型服务和业务API应该是分开的。我当时踩了一个坑把业务服务和模型推理服务放在同一个进程里结果一个慢查询直接把整个API拖死。后来拆成了两个服务业务层用FastAPIPython Web框架负责用户认证、请求校验、业务逻辑模型推理层用vLLM起一个独立服务负责专属的计算密集任务。业务层通过HTTP或gRPC去调推理服务。这样两边可以独立重启、独立扩容模型推理服务挂了业务层还能返回友好提示不至于整个系统崩溃。8.2 三个必须做好兜底的工程细节上线阶段我总结了三个绕不开的坑第一是并发控制。推理服务不是无限并发的盲目堆并发会让显存OOM。我在vLLM层面设置了max-num-seqs参数控制最大并发batch数同时在上游加了一个简单的信号量限流超过阈值直接返回排队提示宁可暂时不可用也不能大面积崩溃。第二是缓存策略。前面说的API账单问题一半其实就是缓存没做。我给系统加了语义缓存——用句子嵌入模型把每次请求转成向量放到向量数据库里新请求进来先算相似度如果和之前某条历史请求的相似度超过0.92就直接返回缓存的答案不再调用模型。实测命中率能达到30%左右账单直接降了一截这个优化收益立竿见影。第三是监控与日志。没有监控的线上服务等于盲人开车。我上了三件套指标监控用Prometheus加Grafana看QPS、延迟分布、显存占用日志收集用ELK方案搜错误日志和调用链告警用简单的Webhook通知。我给自己设了一条告警P95延迟超过3秒就通知我。上线第一周就抓到过几次问题——真不是模型慢是某个工具函数在数据量大时出现了性能瓶颈。没有监控的话这种问题根本意识不到。8.3 一个让我印象深刻的宕机案例有一次深夜服务突然大量超时。我查了一圈日志才发现是某个合作伙伴的数据源接口突然变慢而我的工具调用在等待该接口返回时没有设置超时导致一批请求全部卡在那里。修复方法很小——给所有外部工具调用加上了超时重试机制5秒超时重试一次失败则返回错误码但这件事说明了一个大道理AI系统的稳定性不是靠模型而是靠外层工程防护。模型本身不会超时但你的工具、你的网络、你的依赖服务随时会。所以从设计第一行代码起就得假设外部一切不可靠。9. 项目复盘从零到一最值钱的三个认知项目走到这里系统已经从最初的API搬运工进化成一个包含语义缓存、本地模型推理、Agent工具链、监控告警的完整AI工程架构。回头看整段经历有大量具体的坑和教训但让我从零到一真正脱胎换骨的是三个核心认知。第一AI工程的本质是不确定性管理。模型输出天生不确定工具调用可能失败外部依赖随时会挂网络延迟无法预判。一个好的AI系统不是依赖模型足够聪明而是靠工程手段把这些不确定性约束住——评测集约束输出质量、缓存约束成本、超时重试约束外部故障、监控约束可观测性。理解了这一点做AI工程和非AI工程其实没有本质区别只不过多了一层概率行为需要额外理解。第二一切效果判断都要有量化基准。无论是Prompt改得好不好、微调该不该上、量化损不损精度、缓存命中率高不高都要有可量化的评估指标。没有基准的判断都是感觉感觉在工程里是最靠不住的东西。我现在做任何AI功能改动的第一步永远是先跑断言、跑评测集、对比指标否则宁可不改。第三通用能力不可能一步到位小粒度迭代是捷径。很多人做AI项目一上来就想训练一个大模型解决所有问题结果就是钱烧了、时间花了、什么都没有。我更倾向的做法是每个功能都先用最简单的方式打到底先用API、先用确定性代码验证有真实需求后再逐步引入缓存、本地部署、微调等手段。每一步的价值都有数据可依整个项目的风险也被摊薄了。这个ai-engineering-from-scratch项目最初只是为了解决一张让我肉疼的API账单最后却重塑了我对整个AI系统构建方式的认知。如果你也在纠结从哪里开始我的建议很简单找一个真实问题按先跑通电路→钉好护栏→持续量化优化的顺序干下去。AI工程没那么玄乎它就是把这个充满不确定性的黑盒一步步变成你手里可控工具的过程。