资讯动态

从零手搓AI工程:RAG全链路实战与避坑指南

发布时间:2026/10/2 16:52:07 来源:尧图企业网站定制
1. 从零手搓AI工程为什么我不建议你直接调包很多人一听到“AI工程”这四个字第一反应就是打开某个云平台调一个现成的大模型接口写几行胶水代码然后对外宣称自己做了个AI应用。我承认这条路确实能在半天内跑通一个Demo但如果你真的想在这个领域站稳脚跟靠这种“调包式开发”是走不远的。ai-engineering-from-scratch这个项目标题本身就点出了一个核心命题从零开始构建AI工程能力。它不是让你去造一个比肩顶尖实验室的大模型而是让你亲手把AI应用从数据到推理的整条链路摸一遍知道每个环节到底在发生什么。我见过太多简历上写着“精通大模型应用开发”的人被问到“你的向量检索为什么用余弦相似度而不是欧氏距离”“温度参数调到0.7的时候模型输出分布发生了什么变化”“上下文窗口超了之后你的截断策略是什么”这类问题时直接卡壳。原因很简单——他们从来没有从零搭过一遍。调包能让你快速看到结果但看不到结果背后的因果链。而这个项目要解决的恰恰是这个断层。这篇文章适合三类人第一类是有一定编程基础、想系统理解AI工程全貌的开发者第二类是做过后端或数据工程、想转型AI方向的工程师第三类是在校学生或刚入行的新人想通过一个完整项目把零散的知识点串起来。我会把从环境搭建、数据处理、模型接入、检索增强、服务部署到效果评估的完整链路拆开讲每个环节都告诉你“为什么这么做”以及“我踩过哪些坑”。全文基于我在实际项目中反复验证过的做法不是教科书式的罗列而是能直接抄作业的实操记录。2. 动手之前先想清楚AI工程到底在工程什么2.1 把AI工程拆成四层来看很多人把AI工程等同于“写Prompt”这其实只看到了最上面那一层。我习惯把AI工程分成四层来看从下往上依次是基础设施层、数据层、模型层、应用层。基础设施层解决的是算力、存储、网络这些底层问题数据层处理的是原始数据的采集、清洗、切分、向量化模型层负责推理、微调、参数调优应用层才是大家最熟悉的Prompt编排、对话管理、工具调用。为什么要把这个分层讲清楚因为从零做AI工程最容易犯的错误就是“跳层”。比如一上来就研究Prompt怎么写结果发现检索出来的内容全是噪音模型再强也救不回来。或者模型效果不好以为是Prompt的问题实际上是数据切分粒度太粗关键信息被切散了。分层思维能帮你快速定位问题出在哪一层而不是盲目地调参数。2.2 从零构建的核心取舍哪些轮子必须自己造“从零开始”不等于“所有东西都自己写”。合理的做法是核心链路的每个环节都要亲手实现一遍但底层依赖可以用成熟库。比如向量检索你可以用现成的向量数据库但你必须自己实现一遍文本切分、向量化、相似度计算的过程哪怕只是在一个小数据集上跑通。这样你才能理解向量维度、距离度量、索引类型这些概念到底意味着什么。我在实际项目中的取舍原则是这样的凡是影响最终效果的环节必须自己掌控凡是纯工程效率的环节可以用现成方案。文本切分策略、检索排序逻辑、上下文组装方式、输出解析规则这些直接影响模型输出质量必须自己写。而像HTTP服务框架、日志库、配置管理这些用成熟的就行没必要重复造轮子。2.3 一个最小可用的AI工程链路长什么样在动手之前先明确我们要构建的最小链路包含哪些模块。我把它归纳为六个核心模块数据摄入模块负责读取原始文档支持多种格式纯文本、Markdown、PDF提取后的文本等文本切分模块把长文档切成适合模型处理的片段需要处理重叠、边界、元数据保留向量化模块调用嵌入模型把文本片段转成向量需要处理批量、并发、失败重试向量存储与检索模块存储向量并支持相似度检索需要处理索引构建和查询优化上下文组装与推理模块把检索结果和用户问题组装成Prompt调用大模型生成回答服务与评估模块对外提供API接口并有一套评估机制来衡量效果这六个模块构成了一个完整的闭环。接下来我会逐个拆解每个模块的实现细节和踩坑经验。3. 数据摄入与文本切分最容易被低估的脏活累活3.1 原始数据格式的坑比你想象的多做AI工程第一个拦路虎往往不是模型而是数据。你拿到的原始文档可能是PDF、Word、HTML、Markdown甚至是一堆截图。我试过直接拿PDF提取的文本做切分结果发现页眉页脚混在正文里、表格内容错位、段落之间没有换行切出来的片段根本没法用。我的处理流程是这样的先统一转成纯文本再做结构化清洗。PDF用解析库提取文本后要过一遍正则去掉页眉页脚和页码HTML要先提取正文区域再转文本Markdown相对友好但要注意代码块和表格不能被切散。清洗完之后我还会做一步“段落合并”把因为换行被拆散的句子重新拼起来。提示数据清洗阶段多花一小时后面检索效果能提升一大截。不要急着把原始文本直接灌进切分模块。3.2 切分粒度不是越小越好也不是越大越好文本切分是RAG检索增强生成系统里最关键的环节之一。切得太粗检索出来的片段包含太多无关信息模型容易被干扰切得太细一个完整的语义单元被拆散检索时可能只命中半句话模型拿到的上下文不完整。我常用的切分策略是按语义边界切分辅以固定长度兜底。具体做法是优先按段落、标题、列表项这些自然边界切分如果某个段落超过设定阈值比如500个字符再按句子边界切分如果句子还是太长才按固定长度硬切。切分的时候要保留一定的重叠overlap我一般设置重叠长度为片段长度的10%到15%这样能避免关键信息刚好落在切分边界上被丢掉。还有一个容易被忽略的点每个片段要带上元数据。至少包含来源文档ID、片段在原文中的位置、所属章节标题。这些元数据在检索时可以用于过滤和排序在生成回答时可以作为引用来源展示。3.3 向量化批量、并发与失败处理文本切分完之后下一步是把每个片段转成向量。这里有几个实操细节值得展开讲。首先是批量处理。嵌入模型通常支持一次传入多个文本批量调用比逐条调用效率高得多。但批量大小要控制好太大容易超时或触发限流太小则浪费网络往返。我的经验值是每批16到64条具体看模型提供方的限制。其次是并发控制。如果你有几千个片段要处理串行调用会非常慢。可以用线程池或异步IO来并发调用但一定要设置并发上限否则很容易被限流甚至封禁。我一般设置并发数为5到10配合指数退避重试。最后是失败处理。网络抖动、限流、模型服务临时不可用这些都会导致部分片段向量化失败。我的做法是记录每个片段的处理状态失败的片段进入重试队列重试超过三次的单独记录下来人工排查。千万不要因为几个片段失败就中断整个流程也不要默默跳过——失败的片段如果不处理检索时就会出现盲区。4. 向量存储与检索相似度计算背后的门道4.1 向量数据库选型从零开始也要知道怎么选虽然这个项目强调从零构建但向量存储这一层我建议用现成的向量数据库因为自己实现一个高性能的向量索引确实超出了“AI工程”的范畴属于底层基础设施。不过选型的时候要知道自己在选什么。常见的向量数据库分两类一类是专用向量数据库另一类是传统数据库扩展了向量检索能力。选型时重点看几个指标索引类型支持HNSW、IVF等、距离度量支持余弦、欧氏、内积、过滤能力能否在向量检索的同时按元数据过滤、持久化与扩展性。我个人的选择逻辑是数据量在百万级以下、对延迟要求不极端用轻量级的本地向量库就够了数据量更大或者需要分布式部署再考虑专用向量数据库。不要一上来就上重型方案增加运维复杂度。4.2 余弦相似度为什么成了默认选择大部分嵌入模型输出的向量比较相似度时默认用余弦相似度。为什么因为余弦相似度衡量的是向量方向的一致性对向量长度不敏感。而嵌入模型在训练时通常会对向量做归一化这时候余弦相似度和内积是等价的。但这里有个坑如果你的向量没有归一化余弦相似度和内积的结果会不一样。有些向量数据库默认用内积如果你传入的是未归一化的向量检索结果可能不符合预期。我的做法是在向量化之后统一做L2归一化然后检索时用余弦相似度或内积都可以结果一致。4.3 检索策略Top-K不是唯一答案最简单的检索策略是取相似度最高的K个片段。但实际用下来单纯按相似度排序有几个问题一是可能检索到多个内容重复的片段浪费上下文窗口二是相似度高不一定代表对回答有用三是忽略了片段的多样性。我常用的改进策略有三种。第一种是相似度阈值过滤设置一个最低相似度阈值低于阈值的片段直接丢弃避免引入噪音。第二种是多样性重排在Top-K结果中如果多个片段来自同一文档的相邻位置只保留最相关的一个把位置留给其他来源的片段。第三种是混合检索除了向量检索同时做关键词检索然后把两路结果融合排序。关键词检索能弥补向量检索对专有名词、数字不敏感的缺陷。5. 上下文组装与推理Prompt不是越长越好5.1 上下文窗口的分配策略检索到相关片段之后要把它们和用户问题一起组装成Prompt发给模型。这里最核心的问题是上下文窗口怎么分配。模型有最大输入长度限制检索结果、系统指令、对话历史、用户问题都要占额度。我的分配原则是系统指令精简到最少必要对话历史只保留最近几轮检索结果按相关性排序后截断用户问题永远完整保留。具体比例要看场景但一般来说检索结果占大头因为这是回答的事实依据。还有一个细节检索结果的排列顺序会影响模型注意力。有研究表明模型对上下文开头和结尾的内容注意力更强中间部分容易被忽略。所以我会把最相关的片段放在最前面次相关的放在最后面中间放补充信息。5.2 温度参数与输出稳定性温度参数控制模型输出的随机性。温度越低输出越确定、越保守温度越高输出越多样、越有创造性。在AI工程应用中这个参数的选择取决于场景。做事实问答、信息提取这类任务时我通常把温度设得很低接近0让模型尽量输出确定的内容。做创意生成、头脑风暴时温度可以调到0.7到1.0。但要注意温度调高之后模型“胡编”的概率也会上升需要配合更严格的输出校验。还有一个相关参数是Top-P也叫核采样。它控制模型从概率最高的词汇中采样的范围。我一般固定Top-P为0.9左右主要调温度。两个参数不要同时大调否则输出会非常不可控。5.3 输出解析别让模型自由发挥模型输出的是自然语言但你的下游系统可能需要结构化数据。这时候就需要输出解析。最简单的做法是在Prompt里明确要求模型按JSON格式输出然后写一个解析器去提取。但这里有个坑模型不总是严格遵守格式要求。它可能在JSON外面包一层解释文字可能少写一个括号可能把数字写成字符串。我的做法是解析失败时先尝试用正则提取JSON部分再失败就触发一次重试重试时在Prompt里强调格式要求。如果连续失败就降级到人工处理或返回默认值。注意不要假设模型每次都能输出合法JSON。生产环境里一定要有兜底逻辑。6. 服务化与效果评估上线只是开始6.1 API服务设计同步还是异步把AI工程链路包装成API服务时第一个决策是同步还是异步。同步接口实现简单客户端发起请求后等待结果返回。但大模型推理耗时可能从几百毫秒到几十秒不等同步接口容易超时而且并发能力受限于线程数。异步接口的做法是客户端发起请求后立即返回一个任务ID然后通过轮询或回调获取结果。这种方式适合耗时较长的任务但增加了客户端复杂度。我的选择是简单问答用同步接口设置合理的超时时间复杂任务用异步接口。同步接口的超时时间要根据实际推理耗时分布来定一般设置在P99耗时的1.5倍左右。6.2 评估体系没有评估就没有优化AI工程和传统软件工程最大的区别在于输出没有绝对的对错。传统接口返回的数据要么对要么错但AI生成的回答很难用简单的断言来判断。所以需要一套评估体系。我常用的评估方法分三层。第一层是自动化指标比如检索命中率、回答与参考答案的相似度、格式合规率。这些可以自动化跑适合回归测试。第二层是模型评估用一个更强的模型来给当前模型的输出打分评估相关性、准确性、完整性。第三层是人工评估定期抽样人工打分校准自动化评估的偏差。评估数据集要覆盖典型场景和边界情况。我一般会准备三类测试用例常见问题、长尾问题、对抗性问题故意诱导模型出错的输入。每次修改Prompt或调整检索策略后都跑一遍评估集对比指标变化。6.3 我踩过的三个典型坑第一个坑是检索结果污染。有一次上线后发现模型经常答非所问排查后发现是向量库里混入了一批测试数据这些数据跟正式数据混在一起被检索出来了。教训是测试数据和正式数据必须物理隔离用不同的集合或命名空间。第二个坑是上下文超长导致截断。有一次用户输入了一个很长的文档让模型总结检索模块正常返回了片段但组装Prompt时没有检查总长度结果超出模型限制被截断模型只看到了前半部分内容。教训是组装Prompt前必须计算总token数超长时要有明确的截断策略。第三个坑是并发下的状态污染。早期版本我把对话历史存在全局变量里结果多个用户并发请求时历史串了。教训是任何跟请求相关的状态都必须绑定到请求上下文不能用全局变量。7. 从零构建之后我真正学到了什么把这条链路完整走一遍之后最大的收获不是某个具体技术点而是对AI系统不确定性的敬畏。传统软件里你输入A必然得到B但在AI工程里同样的输入可能得到不同的输出而且你很难完全解释为什么。这种不确定性要求你在设计系统时处处考虑容错、降级和兜底。另一个收获是对数据质量的重视。模型能力再强如果喂给它的上下文是垃圾输出也一定是垃圾。数据清洗、切分、检索这几个环节的投入产出比远比调Prompt参数高得多。最后一点体会是从零构建的价值在于建立直觉。当你亲手处理过几千个文本片段、调试过检索排序、处理过各种格式异常之后再去看那些封装好的框架和平台你会知道它们帮你做了什么、隐藏了什么、以及在什么情况下会出问题。这种直觉是调包调不出来的。如果你也在做类似的事情我的建议是先用小数据集把整条链路跑通不要追求一步到位。跑通之后再逐个环节优化。每优化一个环节跑一遍评估集看指标变化。这样你不仅知道“怎么做”还知道“为什么有效”。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑