资讯动态

从零搭建AI工程体系:分块、检索与生成全链路实战

发布时间:2026/10/1 4:49:24 来源:尧图企业网站定制
1. 从零搭建AI工程体系为什么我劝你别一上来就调包“ai-engineering-from-scratch”这个标题我第一次看到的时候心里咯噔了一下。过去两年多我面过不下五十个号称“做过AI项目”的候选人绝大多数人的经历高度雷同调一个开源大模型API套一层LangChain接一个向量数据库前端用Streamlit糊一个聊天框然后简历上写“主导AI应用落地”。真到了线上出问题——检索召回率突然掉到30%、推理延迟从800ms飙到6秒、上下文窗口被悄悄截断——能说清楚底层发生了什么的人十个里挑不出一个。这就是“from scratch”的价值所在。它不是让你真的从晶体管开始造计算机而是要求你把AI工程这条链路上每一个环节的“黑盒”至少打开一次知道里面齿轮怎么咬合。这篇文章面向的是那些已经会用现成工具、但总感觉脚下踩的是棉花的人——你想知道RAG的检索为什么时好时坏想知道tokenizer到底对你的中文文本做了什么想知道量化到4bit之后模型为什么突然变“笨”。我会按照一个真实项目的推进顺序把AI工程从零搭建的核心环节拆开讲每个环节都告诉你为什么这么选、坑在哪里、怎么验证。先给一个全局认知一个完整的AI工程体系从下到上大致分四层——数据层采集、清洗、分块、向量化、模型层选型、微调、量化、推理优化、编排层检索、重排、提示词管理、上下文组装、应用层接口、缓存、监控、评测。市面上大部分教程直接从第三层开始教因为那一层最容易出“能跑通的demo”。但真正决定一个AI应用能不能上生产的是第一层和第二层的功夫。我见过太多项目编排层写得花里胡哨结果底层分块策略一塌糊涂检索出来的内容驴唇不对马嘴再好的提示词也救不回来。所以这篇东西的定位很明确给那些想认真把AI工程当一门手艺来学的人提供一条从零开始的、可复现的路径。不需要你有博士学位但需要你愿意动手写代码、愿意看日志、愿意为了搞清楚一个参数的含义去翻源码。下面我按实际搭建顺序从环境准备一路讲到线上监控中间该踩的坑我都替你踩过了。2. 环境准备与工具链选型别在第一步就埋雷2.1 硬件与基础环境的现实考量“from scratch”的第一个现实问题是你到底有什么硬件。我见过太多人一上来就想着微调7B模型结果用一张消费级显卡跑了两天两夜loss还没降下去。先把预期摆正——如果你只有一张8GB显存的卡你的主战场应该是推理优化和RAG而不是全量微调。全量微调7B模型FP16精度下光模型权重就要14GB加上优化器状态和梯度没有80GB显存根本别想。这不是劝退是让你把精力花在刀刃上。我的建议是分两条路走。第一条路是纯CPU小模型适合学习和验证流程。用llama.cpp跑一个量化后的3B模型在16GB内存的笔记本上就能跑起来虽然慢但整个RAG链路、分块策略、检索逻辑都能完整验证。第二条路是单卡GPU参数高效微调一张RTX 3090或409024GB显存用LoRA或QLoRA微调7B模型这是目前个人开发者性价比最高的方案。QLoRA把基座模型量化到4bit7B模型权重只占约3.5GB剩下的显存留给LoRA适配器和激活值24GB绰绰有余。基础软件栈方面Python版本我强烈建议锁在3.10或3.11。3.12虽然新但很多AI库的wheel包还没跟上你会在编译某些依赖时浪费大量时间。CUDA版本跟着你的显卡驱动走但注意PyTorch对CUDA版本有要求装之前先去PyTorch官网查对应关系别直接pip install torch了事。虚拟环境用conda或uv都行uv现在速度快得离谱装依赖能省不少时间。注意千万不要在系统Python里直接装AI相关的包。我见过有人把系统的numpy升级了结果整个系统的包管理工具全挂了。虚拟环境是底线。2.2 核心工具链的取舍逻辑工具链选型这块我的原则是每一层只选一个工具选定了就别轻易换。AI工程领域工具迭代极快今天LangChain明天LlamaIndex追新是追不完的。你需要的是理解每一层解决什么问题然后选一个社区活跃、文档齐全的用起来。层级推荐工具选择理由替代方案模型推理llama.cpp / vLLMllama.cpp适合CPU和消费级GPUvLLM适合生产级高吞吐Ollama封装太厚不利于理解底层向量化sentence-transformers模型全、接口统一、社区大FlagEmbedding中文场景更强向量检索FAISS / QdrantFAISS轻量适合本地Qdrant适合服务化Chroma太简单不利于理解索引结构编排自己写强烈建议自己写编排逻辑不复杂自己写才能完全掌控LangChain抽象层太多出问题难排查评测RAGAS / 自己写RAGAS提供标准指标但建议自己实现一遍理解原理—重点说一下为什么我建议自己写编排层。LangChain这类框架的问题在于抽象层太厚一个简单的检索问答它内部可能经过七八层封装。当检索结果不对时你根本不知道是分块的问题、embedding的问题、还是它内部某个默认参数的问题。自己写编排层代码量其实不大——无非是“查询改写→向量检索→重排→上下文组装→调用模型”这几步加起来两三百行。但这两三百行每一行你都能控制出问题能定位到具体环节。等你把流程跑通了再考虑要不要用框架来简化。2.3 项目目录结构的约定从零搭建目录结构一开始就要定好不然后面文件一多就乱。我习惯这样组织ai-engineering/ ├── data/ # 原始数据和处理后数据 │ ├── raw/ │ ├── processed/ │ └── chunks/ ├── models/ # 本地模型权重和微调产物 ├── src/ │ ├── data/ # 数据清洗、分块 │ ├── embedding/ # 向量化 │ ├── retrieval/ # 检索和重排 │ ├── generation/ # 模型调用和提示词 │ └── evaluation/ # 评测 ├── configs/ # 配置文件 ├── scripts/ # 一次性脚本 ├── tests/ # 测试 └── notebooks/ # 实验记录这个结构的关键是把数据、模型、代码三者分开。数据目录不进版本控制模型权重不进版本控制代码和配置进版本控制。配置文件用YAML把分块大小、检索top-k、模型路径这些参数都抽出来方便做实验对比。我吃过亏——早期把参数硬编码在代码里想对比不同分块大小的效果得改代码、重启、再跑效率极低。抽到配置文件后改个数字就能跑一组实验效率天差地别。3. 数据层分块策略决定了整个系统的上限3.1 文档解析与清洗的隐藏陷阱数据层是整个AI工程里最脏最累、但回报最高的环节。我敢说一个RAG系统最终效果的上限在数据分块那一步就已经决定了。模型再强检索出来的内容不对生成的东西就是胡编。先说文档解析。你的原始数据可能是PDF、Word、HTML、Markdown每种格式的解析都有坑。PDF是最麻烦的——扫描版PDF需要OCR文字版PDF的排版信息在解析后大量丢失表格会变成一堆乱序的文字。我试过用PyMuPDF解析一份带表格的技术文档表格内容被拆成单字散落在不同段落里检索出来完全没法用。后来我的做法是PDF先转成Markdown用专门的工具保留标题层级和表格结构再基于Markdown做分块。这一步多花的时间在后面检索效果上会加倍还回来。清洗环节要处理的问题包括页眉页脚重复文本、乱码字符、多余空白、HTML标签残留、参考文献编号。这些噪声如果不清理会严重干扰向量化——一段包含大量页眉噪声的文本它的embedding会被噪声拉偏检索时匹配度下降。我的清洗流程通常是去页眉页脚用正则匹配重复出现的行→ 去特殊字符保留中英文、数字、常用标点→ 合并断行PDF解析后经常一行一个词→ 统一标点符号。实操心得清洗规则不要一次性写太复杂。先跑一遍看输出针对具体问题加规则。我见过有人写了一百多条正则结果把正文里的正常内容也误删了。清洗的目标是去噪不是把文本洗成白纸。3.2 分块策略的深度拆解分块是数据层最核心的决策。市面上最常见的做法是固定长度分块比如每500个token一块重叠50个token。这个做法简单但问题很大——它会在句子中间切断导致语义不完整。你检索到一个块开头是半句话结尾是半句话模型拿到这种上下文生成质量必然下降。我的做法是基于语义结构的分块优先级从高到低按标题层级分→按段落分→按句子分→按固定长度分。具体来说先用Markdown的标题结构把文档切成大块每个大块内部再按段落切如果某个段落超过阈值比如800token再按句子边界切。这样每个块都是语义完整的单元。分块大小怎么定这取决于你的embedding模型和检索场景。一般来说embedding模型有最大输入长度比如512token超过这个长度会被截断。所以块大小不应该超过embedding模型的最大长度。但也不能太小——太小的块缺乏上下文检索时容易匹配到但生成时信息不足。我的经验值是256到512token之间具体看文档类型。技术文档可以小一点256因为概念密集叙述性文档可以大一点512因为需要上下文才能理解。重叠overlap要不要加要加但不要加太多。重叠的目的是防止关键信息刚好落在两个块的边界上被切断。一般设块大小的10%到20%就够了。我见过有人设50%重叠结果存储和检索成本翻倍效果提升微乎其微。还有一个容易被忽略的点元数据。每个块除了文本内容还应该带上来源文件名、标题路径、页码、块序号。这些元数据在检索时可以用来过滤比如只搜某个文档在生成时可以用来标注引用来源。没有元数据的块就是一个孤立的文本片段价值大打折扣。3.3 向量化模型的选择与验证向量化模型的选择直接决定了检索的语义匹配能力。英文场景下all-MiniLM-L6-v2是轻量级首选速度快、效果够用。中文场景下BGE系列如bge-base-zh-v1.5是目前社区公认效果最好的开源选择之一。但选模型不能只看排行榜必须在你的数据上验证。验证方法很简单准备一组“查询-相关文档块”的配对比如20个查询每个查询标注出它应该匹配到哪些块。然后用候选embedding模型跑一遍看召回率。我试过在技术文档场景下某个排行榜很高的模型反而不如一个更小的模型因为技术文档里大量专业术语小模型在通用语料上训练得更充分对术语的表示反而更准。向量维度也是个考量。维度越高表示能力越强但存储和检索成本也越高。768维是常见选择1024维效果更好但成本增加30%左右。我的建议是先用768维跑通如果检索效果不达标再考虑升级维度或换模型。不要一上来就追求最高维度性价比不划算。注意embedding模型和生成模型最好来自同一语言体系。用英文embedding模型处理中文文本检索效果会惨不忍睹。这不是模型好坏的问题是训练语料分布的问题。4. 检索层从向量相似到真正的相关性4.1 向量检索的原理与参数调优向量检索的本质是在高维空间里找距离最近的邻居。你把查询也向量化然后计算它和所有文档块的向量距离通常用余弦相似度取最近的top-k个。听起来简单但有几个参数直接决定效果。top-k取多少太小可能漏掉相关块太大引入噪声还会增加生成模型的上下文负担。我的经验是如果后续有重排环节top-k可以取大一点20到50让重排去筛选如果没有重排top-k取3到5就够了。我见过有人top-k设100然后把100个块全塞给模型结果模型被无关信息干扰生成质量反而下降。相似度阈值要不要设要设。向量检索的一个问题是即使查询和文档完全不相关它也会返回top-k个结果——因为总得有最近的邻居。如果不设阈值模型会拿到一堆无关内容然后基于这些内容胡编。设一个最低相似度阈值比如0.6低于这个值的块直接丢弃。如果所有块都低于阈值就告诉用户“没有找到相关信息”而不是硬编一个答案。索引类型怎么选FAISS提供了多种索引。IndexFlatL2是暴力搜索准确但慢IndexIVFFlat是倒排索引快但可能漏掉一些结果。数据量小几万块以下用暴力搜索就行数据量大再考虑倒排。我试过在10万块数据上暴力搜索单次查询约50ms倒排索引约5ms但召回率下降约5%。这个取舍看你的场景——如果对延迟不敏感暴力搜索的准确性更值得。4.2 重排提升相关性的关键一步向量检索有个根本局限它把查询和文档分别编码成向量然后比较向量距离。这个过程丢失了查询和文档之间的细粒度交互信息。比如查询是“如何配置超时时间”一个文档块讲的是“配置数据库连接”另一个讲的是“超时参数设置”向量检索可能给这两个块相似的分数因为它俩都包含“配置”和“超时”相关的语义。但真正相关的是第二个。重排rerank就是来解决这个问题的。它把查询和每个候选块拼在一起送进一个交叉编码器cross-encoder让模型直接判断这个查询和这个块的相关性。因为查询和文档在模型内部有充分的交互判断准确率远高于向量相似度。代价是慢——交叉编码器要对每个候选块单独跑一次前向传播没法像向量检索那样预计算。所以标准流程是向量检索召回top-50 → 重排模型精排取top-5 → 送给生成模型。重排模型我推荐BGE-reranker系列中文效果很好。实测下来加了重排之后检索准确率能提升20%到30%这个投入非常值得。实操心得重排模型的输入长度有限制通常是512token。如果你的块超过这个长度会被截断。所以分块时控制大小不仅是为了embedding也是为了重排。4.3 混合检索关键词与向量的互补纯向量检索有个盲区它对精确匹配不敏感。比如查询里有一个产品型号“XG-2000”向量检索可能返回一堆讲“产品型号”的块但就是漏掉真正包含“XG-2000”的那个块。因为embedding模型把“XG-2000”编码成了一个泛化的“型号”概念丢失了精确字符信息。解决办法是混合检索同时跑向量检索和关键词检索BM25然后把两路结果融合。融合算法常用RRFReciprocal Rank Fusion它不依赖分数绝对值只看排名把两路排名加权求和。这样既能抓住语义相似又能抓住精确匹配。BM25的实现可以用rank_bm25库轻量好用。中文需要先分词jieba就行。混合检索的代码量不大但效果提升明显尤其是在技术文档、法律文书这类包含大量专有名词的场景。5. 生成层提示词工程与上下文管理5.1 提示词的结构化设计生成层的核心是提示词。很多人写提示词就是一句话“根据以下内容回答问题{context} 问题{question}”。这种写法能用但效果不稳定。我的做法是把提示词结构化分成几个明确的部分角色定义告诉模型它是什么角色。“你是一个技术文档助手基于提供的文档片段回答用户问题。”约束条件明确告诉模型什么能做、什么不能做。“只使用提供的文档片段中的信息回答。如果文档中没有相关信息直接说‘文档中未找到相关信息’不要编造。”上下文检索到的文档块每个块标注来源。问题用户查询。输出格式如果需要结构化输出在这里指定。“用JSON格式输出包含answer和sources两个字段。”这个结构的关键是约束条件。不写约束模型会倾向于用自己训练时学到的知识来回答而不是基于你提供的上下文。这在RAG场景下是致命的——用户问的是你私有文档里的内容模型用通用知识回答答案可能完全错误。5.2 上下文窗口的精细管理上下文窗口是生成层最稀缺的资源。模型的上下文长度有限比如4K、8K、32K你塞进去的每个token都在消耗这个预算。检索回来的块不能无脑全塞进去要做筛选和压缩。筛选的策略前面说了——重排取top-k。压缩则是另一个思路如果某个块只有一部分和查询相关可以把不相关的部分去掉只保留相关句子。这个可以用一个小模型来做或者用简单的句子相似度筛选。我试过在技术文档场景下把每个块压缩到只保留最相关的2到3句话上下文长度减少60%生成质量基本不变。还有一个技巧是上下文排序。把最相关的块放在上下文的开头和结尾中间放次相关的。这是因为模型对上下文首尾的信息注意力更强“迷失在中间”现象。实测下来这个简单的调整能提升5%到10%的答案准确率。5.3 生成参数的温度与采样生成模型的参数里temperature和top_p直接影响输出的稳定性和多样性。RAG场景下我建议temperature设0.1到0.3top_p设0.9。温度太低0会导致输出过于死板有时会陷入重复温度太高0.7以上会导致模型自由发挥偏离检索到的内容。max_tokens也要设。不设的话模型可能生成超长回答浪费计算资源。一般设512到1024就够了除非你的场景需要长回答。还有一个容易被忽略的参数是repetition_penalty。中文生成时模型有时会重复某些短语设1.1到1.2的重复惩罚能有效缓解。6. 评测与监控没有度量就没有优化6.1 离线评测集的构建“from scratch”最容易被跳过的一步就是评测。很多人做完系统随便问几个问题觉得“还行”就上线了。但“还行”是感觉不是度量。没有度量你根本不知道改一个参数是变好了还是变差了。离线评测集不需要很大50到100个查询就够了但必须有标注。每个查询标注出它应该检索到哪些块用于评检索以及标准答案用于评生成。标注工作很枯燥但这是唯一能客观衡量系统效果的方法。检索评测指标用召回率相关块被检索到的比例和MRR第一个相关块的排名倒数。生成评测可以用RAGAS的指标faithfulness答案是否忠于上下文、answer_relevancy答案是否切题、context_precision上下文是否精确。这些指标可以用模型自动算虽然不完全准确但作为相对比较够用了。6.2 线上监控的关键指标上线之后监控比评测更重要。你需要知道系统在真实流量下的表现。关键指标包括延迟检索延迟、重排延迟、生成延迟分开监控。生成延迟通常是瓶颈占总延迟的70%以上。检索命中率用户查询中有多少能检索到高于阈值的块。如果这个比例很低说明你的知识库覆盖不够或者embedding模型不匹配。用户反馈点赞/点踩、追问率、会话轮数。追问率高通常意味着首次回答质量差。Token消耗每次查询消耗的输入和输出token数。这个直接关系到成本也反映了上下文管理是否高效。我习惯在每次查询时记录一条结构化日志查询文本、检索到的块ID和分数、重排后的块ID和分数、生成的答案、各阶段延迟、token消耗。这些日志是排查问题的金矿。当用户反馈“回答不对”时你能回溯到具体是哪个环节出了问题。6.3 常见问题速查表问题现象可能原因排查方向解决方法检索不到相关内容分块太大/太小、embedding模型不匹配检查分块大小和embedding模型调整分块策略换用领域匹配的embedding模型检索到但答案不对重排缺失、上下文噪声多检查重排环节和上下文组装加重排压缩上下文调整top-k答案编造提示词约束不足、温度太高检查提示词和生成参数加强约束降低温度设相似度阈值延迟过高生成模型太大、上下文太长分阶段测延迟量化模型压缩上下文用流式输出中文效果差embedding模型是英文的检查模型语言换中文embedding和重排模型精确匹配失败纯向量检索检查是否有混合检索加BM25混合检索用RRF融合7. 我踩过的坑与最后几条实在建议第一个坑是过早优化。我一开始就想着用最好的模型、最复杂的架构结果搭了两周还没跑通一个完整流程。后来退回来用最小的模型、最简单的分块先把“数据→检索→生成”这条链路跑通再逐步替换组件。这个顺序很重要——先有能跑的再有好的。第二个坑是忽略数据质量。我曾经花大量时间调检索参数效果始终不理想后来发现是原始PDF解析出来的文本里混入了大量页眉页脚embedding被噪声带偏了。重新做数据清洗后同样的检索参数效果提升了一大截。数据层的投入回报是乘数级的。第三个坑是不记录实验。我早期改参数很随意改完跑一下觉得“好像好点了”但过两天就忘了改了什么、为什么改。后来我强制自己每次实验都记录改了什么参数、预期是什么、实际结果是什么。这个习惯让我少走了很多弯路。最后说一个心态上的建议AI工程是一个迭代的过程不存在一次做对的方案。你的第一个版本一定是粗糙的但只要你把评测和监控搭起来每一次迭代都有方向系统就会越来越好。最怕的是没有度量凭感觉改改来改去原地打转。从零搭建的意义不在于一次搭出完美系统而在于你清楚每一个环节为什么这么设计出了问题知道去哪里找原因。这种掌控感是调包永远给不了的。

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

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

免费获取报价 →
↑