AI工程化从零到一:手把手搭建稳定可控的RAG系统实战指南 这些年我见过太多做AI项目的翻车现场模型选型没问题提示词写得也溜结果一上线就崩——要么回答质量不稳定要么成本直接失控要么响应慢到用户骂人。问题出在哪出在很多人只会“用模型”不会“做工程”。所以我整理了这套ai-engineering-from-scratch的学习路线。它的目标很明确让一个只写过增删改查的后端工程师或者刚毕业的学生在没有AI基础的情况下一步步建立起完整的AI工程化能力。不是教你调一个API而是教你如何把一个模型能力变成稳定、可控、可评估、可维护的产品功能。这套路径我自己走了一遍里面既有技术选型的思考也有大量从实际项目里踩出来的坑。今天把整个思路和实操过程拆开讲清楚希望能给正在转型或者准备入坑的朋友一条更顺的路。1. 项目到底是什么AI工程化不是“调库”而是一整套系统能力1.1 从“跑通模型”到“交付系统”很多人对AI工程有误解以为会用Python调一下OpenAI的接口、能把返回结果打印出来就算入门了。但实际上从“跑通一个demo”到“交付一个系统”中间隔着的距离不比从零学到跑通demo短。ai-engineering-from-scratch想解决的就是这段距离。这里有个很关键的认知转变传统软件开发中代码行为是可预期的——输入相同输出几乎确定。但AI应用天然带有不确定性同样的输入今天返回的结果和明天可能不一样甚至同一个请求重复两次结果都不一样。这种不确定性会让所有传统软件工程的方法论失效。你不能用普通单元测试去验证一个LLM的输出对不对也不能用传统的监控指标去判断线上质量是否下降。所以AI工程化的本质是把“不确定性”包进一层工程化的壳里——通过上下文管理、检索增强、输出约束、评估体系、灰度机制把不可控的模型行为变成可控的产品行为。这套路线的标题里有两个关键词ai-engineering和from-scratch。前者代表方向是AI工程后者代表路径是从零开始不打折扣地建立地基。它不是一份“三天精通大模型”的速成课而是一张按依赖关系排好的学习地图。1.2 为什么这个能力现在值得投入我判断一个技术方向值不值得学就一个标准它能不能帮你解决“真实世界中持续存在、且愿意付费”的问题。AI工程恰好满足。现在企业落地AI的主要瓶颈已经不再是模型能力不够而是没人能把模型能力稳定地接到业务流程里。你可以观察到招聘市场上“AI应用工程师”“LLM应用工程师”这类岗位越来越多薪资也高于同级别后端。但真正能胜任的人很少因为大多数候选人只会写提示词没有工程化的基本功。另外从技术演进角度看工具链越来越成熟LangChain、LlamaIndex、向量数据库、Agent框架层出不穷。但框架越成熟越需要人理解底层原理。框架解决的是“通用的80%”剩下那20%的定制需求永远需要你从原理层去处理。没有from-scratch的底子遇到框架解决不了的问题就只能干瞪眼。1.3 谁适合走这条路我的结论比较明确这套路线最适合两类人一类是有后端开发经验、想转型AI应用方向的工程师。你懂API、懂数据库、懂系统设计只需要补齐大模型原理、检索和评估层面的知识就能快速上手。另一类是计算机相关专业的学生趁在校期间从零系统化地建立知识体系毕业时直接具备AI工程岗位的实战能力。老实说它不适合那种想“零基础从文科转码”的读者。我坚持认为写提示词可以不写代码但做AI工程必须会写代码。如果连JSON都处理不明白、连HTTP异步请求都没理解工程化这条路会走得非常痛苦。所以前置条件只有一个至少能熟练使用Python理解基本的数据结构。2. 知识体系设计一张按依赖关系排好的学习地图2.1 第一层地基Python工程能力与数据结构很多学习路线一上来就讲Transformer我认为这是错的。跳过了地基直接上模型后面会频繁返工。我在这套路线里第一层安排的是Python工程化基本功。不是语法教程而是“用Python组织一个真实项目的能力”虚拟环境管理、类型注解、异常处理、日志规范、配置文件管理、单元测试。这些内容在普通Python教程里不会成体系地出现但它们是所有后续内容的载体。这里多说一句数据结构的优先级被我刻意调低了。AI工程日常面对的主要是列表、字典和JSON嵌套结构最复杂的也就是一个对象数组的筛选排序。真正影响开发效率的不是数据结构算法题刷得多深而是你是否能清晰地把嵌套的JSON结构转化为业务实体。所以这一层的重点我用一句话概代码写出来能让人看懂能保持改动三个月不出问题。2.2 第二层地基模型原理与调用心智模型第二层进入大模型基础。这里我的建议是不要一上来读Attention Is All You Need的原始论文也不要一上来研究微调。先建立“调用者视角”的心智模型。你要理解这几个问题的答案Token是什么为什么上下文长度按Token算温度temperature和top-p分别控制什么调高调低有什么区别模型为什么会产生“幻觉”它的本质是概率生成还是事实检索为什么同样的提示词模型表现会时好时坏这几个问题理解透了使用模型时的很多困惑就自然解开了。比如你知道了温度影响的是采样分布的随机性就能明白为什么客服场景要把温度调低甚至调为0而创意写作场景则需要更高温度。在技术实现上我会要求大家手写一个最基本的调用封装包含超时控制、重试逻辑、日志记录。用代码库也好直接requests调用也罢重点不是“会调”而是“稳定地调”。很多人第一次做AI项目遇到的问题——线上偶发超时导致整个流程失败、重试导致重复计费——就是在这一层没学好。2.3 第三层核心上下文工程、RAG与向量检索这是整套路线中工程含量最高的一部分也是ai-engineering-from-scratch的精华所在。先说上下文工程。上下文是模型回答质量的决定性因素。你需要学会如何在有限的上下文窗口内放入最有价值的参考信息如何设计system prompt来固定模型的行为边界如何利用few-shot examples来引导输出格式。这里有一个我反复强调的原则不要把模型当作数据库要把模型当作推理器。知识应该存在你的业务系统里模型只负责根据给定知识做推理。然后是RAG检索增强生成。RAG是目前落地最广泛的AI应用模式它解决了大模型“知识陈旧”和“领域不相关”的核心问题。你需要理解它的完整链路文档加载与切分——切分粒度直接决定检索质量Embedding向量化——选择什么模型、维度多少、如何批量处理向量存储与检索——Milvus、Qdrant还是传统库pgvector重排序rerank——向量相似度检索的结果往往不够精确需要重排序模型二次过滤送入大模型生成——如何把检索结果组织成模型友好的上下文格式。很多人不重视切分这一步认为就是按字符切分而已。实际上切分策略决定了检索的上限。你按固定长度硬切很容易把一个完整的语义单元截成两段。我一般建议优先按文档结构切分Markdown标题、段落、代码块、表格尽可能保持语义完整性再结合重叠窗口避免切分断点处的信息丢失。2.4 第四层进阶Agent、工具调用与复杂任务编排Agent是目前AI工程里最热也最容易被神话的概念。我一向的观点是先学会不用Agent解决问题再考虑用Agent。这一层要掌握的核心技术是工具调用function calling / tool use。它本质上不是让模型自由发挥而是给模型一套明确的“工具箱”让它学会在合适的时机选择工具并填入参数。这个过程中模型的角色从“直接生成答案”变成“编排计划并调工具”。工程上你需要维护好工具的描述信息模型依赖描述来选工具参数Schema的准确性模型按Schema生成JSON参数Schema错了后续全部崩掉工具执行结果的返回格式模型需要看到结构化结果才能继续决策循环调用的终止条件避免死循环烧钱。你可以自己从零实现一个极简的Agent循环这比直接用现成框架更能理解本质。等理解了循环机制再上LangChain、CrewAI、MetaGPT这些框架你就能读懂它们的源码也才能根据业务场景改造它们。3. 从零到一手写一个AI知识助手全流程3.1 项目选题与需求拆解理论说再多都不如做一个完整项目。我在路线里安排了一个压轴实战从零搭建一个私域知识问答助手。假设你是一家服务商手里有几百份产品文档、售后FAQ和工单记录需要做一个人人可用的智能客服。先说需求拆解。做这个项目前先把“能做什么”定义清楚用户输入一个问题返回准确的答案答案需要给出参考来源方便运营人员复核针对“不知道”的问题明确回复不知道而不是硬编支持多轮追问先问“你们支持哪些退款方式”再追问“哪个到账最快”。这四个需求看似简单但每个都对应一个工程决策。引用来源需要检索层返回document id并映射到原文拒绝硬编需要阈值判断和提示词约束多轮追问需要会话记忆管理。3.2 技术选型与架构设计我的选型原则很简单先用最朴素的组件把链路跑通再替换复杂组件。很多人一上来就上全套分布式、微服务、Kafka这种架构用在几十个QPS的场景上就是灾难。我从不用技术复杂度作为简历亮点我只用“恰到好处的工程复杂度”。这个项目的初始版本我会选择后端Python FastAPI异步支持好写起来直观向量库先上pgvector。为什么不用Milvus因为项目初期数据量在十万级以内PostgreSQL自带的pgvector够用了还能少维护一个中间件。等数据量上来了再平滑迁移到专门的向量库Embedding模型选择一个本地部署的国产开源模型比如BGE系列避免每次调用外部API的延迟和成本LLM走通用大模型API第一版快速验证。切分使用基于结构的PDF/HTML解析先按标题层级切块再补充段落边界。整体架构是一个简单的三层结构数据预处理层离线、查询服务层在线、评估监控层。这个架构没有花哨之处但每一层都清晰可扩展。3.3 核心实现步骤与代码要点我挑三个阶段的关键实现细节来讲。第一阶段是离线索引构建。核心代码如下# 文档结构切分示例 def split_document_by_structure(doc_elements): chunks [] current_section_title None current_buffer [] for element in doc_elements: if element[type] heading: # 遇到新的标题把buffer中积累的内容作为一个chunk输出 if current_buffer: chunks.append({ content: \n.join(current_buffer), meta: {section: current_section_title} }) current_buffer [] current_section_title element[text] else: current_buffer.append(element[text]) # 处理最后的buffer if current_buffer: chunks.append({ content: \n.join(current_buffer), meta: {section: current_section_title} }) return chunks这里最关键的是meta信息保留。很多教程只存content不存标题和路径导致检索到结果后用户只看到一段文字却不知道来自哪个文档。我习惯在每个chunk里保留“文档名章节路径原文ID”方便后续引用溯源。第二阶段是查询链路。流程是query改写 → 向量检索top 20 → 重排序top 5 → 携带上下文调用LLM → 解析输出并返回引用。# 检索增强生成的核心链路 async def answer_question(query: str, history: list[dict], session_id: str): # 1. 改写问题将带指代的多轮问题转成独立问题 rewritten_query await rewrite_with_history(query, history) # 2. 向量检索取 top 20 query_embedding embed_model.encode(rewritten_query) candidates vector_store.search(query_embedding, top_k20) # 3. 重排序取 top 5 reranked rerank_model.rerank(rewritten_query, candidates, top_k5) # 4. 组装上下文并调用 LLM context build_context(reranked) prompt build_prompt(context, query, history) llm_response await llm_client.call(prompt) # 5. 引用来源映射 sources [format_quote(r) for r in reranked] return {answer: llm_response, sources: sources}第三阶段是会话管理。这里我踩过一个坑把完整的聊天历史全部塞进上下文导致Token消耗爆炸式增长。正确做法是维护一个滑动窗口只保留最近4-6轮对话并对每轮历史做摘要压缩保证既不丢失关键信息也不撑爆上下文。3.4 上线前的评估与迭代机制工程做得再好没有评估体系就是盲飞。我强烈建议每个AI项目上线前准备至少100条覆盖主要场景的评测集并人工标注“标准答案”或“期望答案要点”。评测集按难度分层简单题答案就在原文中直接命中中难题需要跨段落拼接信息或者需要结合多个文档对抗题提问方式模糊或故意用错误说法引导期望模型拒绝回答。评测指标不是只看一个而是组合看检索命中率前5个结果是否包含正确答案所在片段生成相关性模型回答和问题的相关度引用准确率模型引用的来源是否真的支撑其答案拒绝率对抗题中正确拒绝的比例。有了这套评测体系每次改动Prompt、调整切分参数、更换Embedding模型都能用一套固定的测试集对比分数。改动的效果不再靠“感觉还行”而是通过数字判断。4. 实操中最容易踩的坑与排障思路4.1 检索质量差切分和Embedding的锅各占一半做RAG最常见的抱怨是“检索结果不对”。大部分情况下问题根源不在向量检索本身而在上游的两件事切分策略和Embedding模型选择。我做过一个很直观的对比实验同一批文档用固定长度500字符切分检索精确率只有56%改用结构切分先按标题再按段落精确率提升到81%。原因很简单固定长度切分会把一个完整的逻辑单元劈成两截向量化后两段各自的语义都残缺不全。多做这一步改造成本几乎为零但效果却天差地别。Embedding模型同样重要。通用Embedding模型在专业领域效果会明显下降。解决方式是在专业数据上微调Embedding模型或者至少做一个领域词汇表的扩充。如果数据量不够微调退而求其次用更好的商用Embedding API也能显著提升。4.2 模型“一本正经胡说八道”阈值与证据约束幻觉是LLM的固有属性你无法彻底消灭它但可以工程化地压制它。我在项目里做了三道防线第一道是检索侧的相似度阈值过滤。当用户提问和所有检索结果的相似度都低于某个阈值比如0.35直接判定为“知识库覆盖不到”返回兜底话术不进入LLM生成环节。这道防线挡住大量“明知不知道还硬答”的情况。第二道是Prompt约束明确要求模型只能基于提供的参考材料回答当材料不充分时明确回复“根据现有文档无法回答”。加上这句话比不加这句话能显著减少编造的情况。第三道是输出后校验用一个小模型或规则模型检查回答中是否包含关键实体与参考资料的一致性。比如用户问“退款到账时间”如果模型回答里没有出现任何与到账时间相关的数字或日期就标记为低置信度让审核人工介入。这道防线成本高一些适合高价值场景。4.3 成本失控Token预算要精细到每轮对话很多项目第一版上线惊喜地发现效果不错然后下个月账单来了傻眼了。成本失控的罪魁祸首往往是上下文填充太猛——把大段历史、大段知识一股脑塞进去每轮调用都消耗大量Token而其中大多数都是冗余内容。我用的成本控制手段有检索结果严格控制数量经过重排序后只保留最相关的3-5个片段每个片段不超过800字历史会话采用摘要化压缩每隔几轮把前面的内容总结成50字的要点而不是保留原文区分“复杂推理”和“简单查询”两种路径。简单查询用成本低的小模型只有复杂推理才走大模型设置每日Token消耗告警超过预算阈值自动降级到只返回检索原文。有一条经验可以分享Cost per useful answer每次有效回答的成本比单次调用成本更适合作为优化指标。优化时你不是要压单次成本而是要提高回答准确率——准确率高用户不用反复追问总成本反而下降。4.4 接口稳定性超时、限流与降级策略最后一个坑来自接口层。大模型API的延迟不稳定是常态高峰期可能从500ms飙到5秒。如果线上不做超时控制和降级策略一次偶发超时就能让用户感受“系统不行”。我的工程处理方式是所有LLM调用统一走一个异步封装设置合理的超时时间通常读3秒、写5秒。超时后自动降级优先返回检索到的原文列表让用户自己找答案不让用户干等。重试机制要加上“指数退避抖动”避免服务恢复瞬间所有请求同时涌进来。注意一个细节重试时如果请求已进入模型计算LLM调用无法保证幂等重试可能导致重复计费。因此重试标志和日志必须配套区分“网络层失败可重试”和“业务层已抵达不可重试”。5. 学习建议与路线图的补充分享5.1 实操优先级先做完整闭环再优化细节我的核心建议就一句在学的第一周先把一个最简单的“读文档 → 检索 → 回答”闭环跑通。不用上重排序不用做复杂的切分甚至Embedding都可以先用通用模型。跑通的这个闭环给你一个完整的地图之后所有优化都是在给地图打补丁。很多人学AI工程失败的原因是一头扎进去研究Prompt技巧、研究各种框架API学了两个月还在“看完最后一个教程才开始动手”。AI工程和其他工程一样动手前你只能理解20%的知识剩下的80%是在解决问题中学会的。从第一个星期就开始做项目从第一个月起就维护一个自己的评测集这样你会比那些一路看书的人快得多。5.2 建立自己的最小复盘机制我在整个from-scratch路线的最后加了一个容易被忽视的环节建立自己的复盘模板。每做完一个功能或修完一个Bug回答三个问题——根因是什么下次怎么提前发现这个经验能否沉淀成脚本或配置这三个问题看着简单但持续执行下来你会发现自己的成长速度远超身边人。因为大多数人的经验是零散的而工程能力恰恰来自把零散经验组织成可复用的方法论。我从2019年开始带团队带过几十名工程师凡是成长快的无一例外都愿意做这种“额外”的总结工作。5.3 最后说一个心态上的建议如果你真的想把AI工程这条路走通请接受一件事你永远有学不完的新东西。模型在变、框架在变、最佳实践在变。这套ai-engineering-from-scratch提供的不是一份一劳永逸的答案而是一种应对变化的底层能力——理解原理、快速验证、持续复盘。有了这三板斧再复杂的新技术出来你也能在短时间内把它工程化落地。先把第一个闭环跑起来吧哪怕它非常简陋。跑起来之后你会发现接下来的每一条学习路径都有明确的方向了。