ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AI工程从零开始:RAG问答系统搭建全攻略

AI工程从零开始:RAG问答系统搭建全攻略 这个项目标题我盯着看了很久——ai-engineering-from-scratch。说实话市面上讲AI工程化的教程和课程已经不少了但绝大多数都默认你已经有了一定的机器学习背景、知道了什么是损失函数、什么是反向传播然后一上来就扔给你几十个概念。真正从零开始、把一个完全不懂AI工程的人带到能独立搭建一个AI应用这条路走过来的人反而没那么多。我自己的经历是从传统后端开发转到AI应用方向最开始也踩了无数坑。今天这篇东西我尽量还原我当时摸索出来的路径和思考方式不堆概念只讲实操。适合还没入门但很想入门的开发者和学生也适合已经做了一两个AI demo、但始终觉得不知道下一步该学什么的朋友。看完你能建立起一条清晰的学习主线和第一个完整项目的动手路线并且避开我当年没人提醒的那些坑。1. AI工程化到底在做什么先把概念掰开揉碎1.1 不是训练模型是让模型干活很多人想到AI工程第一反应是训练模型。这是最大的认知误区。AI工程化真正要解决的问题和传统软件开发有本质不同。传统开发是你写了代码机器执行你的逻辑而AI工程是你把意图和数据提供给模型模型以概率的方式给你一个结果。这中间引入了两个巨大的不确定性一是模型的行为不完全由代码控制二是数据的质量直接决定系统的上限。所以AI工程的核心工作变成了如何在一个充满不确定性的系统里通过流程设计和工程手段把结果稳定控制在可接受范围内。打个比方写传统代码像你亲手做菜每一道程序都是你的一道工序完全可控做AI工程像你雇佣了一个非常聪明但偶尔走神的大厨你需要设计一套机制——告诉他做菜标准、给他备好菜、配好调料、做好品控——让他每次都做出水平以上的菜。这套机制就是AI工程。围绕这个目标AI工程化的工作流大致是数据准备 → 向量化 → 检索与上下文构建 → 模型生成 → 输出评估 → 部署与监控。拆成环节来看每个环节都不难但连起来是一个完整的系统工程任何一个环节出问题最终效果都会大打折扣。1.2 from scratch到底指什么一条完整的学习主线From scratch不是让你从写神经网络开始而是指你应该从零到一掌握上面那套工程链路并亲手实现一遍。我做过的总结是一个合格的AI工程师至少需要四块能力语言与工具基础Python、命令行、Git大模型应用核心提示工程、上下文管理、RAG检索增强、Agent调用链系统与部署能力Docker、云服务、异步处理 评估与迭代能力指标设计、模型对比、回归测试。这四块能力的权重在不同团队不一样但底层逻辑都绕不开它们。如果你直接去看当前最热门的职位要求——前端也好后端也好测试也好你会发现很多岗位的核心技能点已经从调API演变成如何设计一条高质量、可监控、可复用的AI数据链路。这个演化非常快所以从零开始学AI工程不是上一个培训班就能搞定的事情你需要自己动手搭项目在真实的问题中把链路跑通。2. 从零开始的技术栈选型别一上来就背八股2.1 Python到底要学到什么程度我见过很多人卡在Python还没学完这个阶段迟迟不敢动手做AI项目。实际上AI工程日常开发用到的Python知识非常集中。你不需要成为Python专家但下面这些必须熟练列表字典的基本操作、函数与类、文件读写、异常处理、装饰器只看懂即可、async/await并发能写出简单的并发任务。除此之外最实用的一个技能是pip和venv管理能创建虚拟环境安装第三方包解决依赖冲突。很多人AI项目跑不起来就是卡在环境问题而非AI问题。我给一个自测标准你能否不查资料用Python写一个脚本从一个PDF里读取所有文本按段落切分用openai的SDK批量向量化然后存入一个向量数据库如果你能独立完成这条链路里70%的代码你的Python基础就已经足够上手了。2.2 大模型应用开发的四大件选型问题是我最常被问到的。很多人一上来就问我应该学LangChain还是直接调API我的回答始终是先裸手调API再用框架。在大模型应用开发这个领域你绕不开四样东西第一模型调用层。你至少要熟练OpenAI SDK的写法兼容OpenAI接口的国产模型也都支持这格式理解什么是chat completion、什么是流式输出、什么是temperature和top_p参数以及它们如何影响生成结果。第二提示工程。好的提示词是AI应用的灵魂。你要学会几类经典的写法角色设定、few-shot示例、步骤引导、输出格式约束。这个看起来人人都会但实际调优非常吃经验。第三数据链路。包括文档解析、文本清洗、分块、向量化、存储、检索。这是RAG检索增强生成的主干也是我见过最多人做得最粗糙的部分。第四部署与监控。模型服务、向量库服务、API服务和前端如何连接如何记录每一次请求的输入输出如何追踪响应延迟和成本。这些是生产环境才会暴露出来的问题但一开始学就应该有意识。框架方面LangChain和LlamaIndex我都用过第一遍学习建议用原始API裸写跑通之后再引入框架。因为框架抽象度太高很多细节被藏着调试起来反而更痛苦。等你理解背后的原理再用框架就会觉得它是一个顺手的工具而不是一个黑盒子。2.3 基础设施Docker和云的取舍从零开始不代表你要从自己买服务器裸机开始。我的建议是本地开发用Docker隔离环境部署统一走云服务。Docker是最值得提前学的工具。它解决的问题很简单你的项目用Python 3.11向量数据库用Milvus模型API走远程朋友的环境是Python 3.8。没有Docker一次联调就能让人崩溃。有了Docker Compose一个命令就能把依赖的全部服务拉起来。AI工程的项目依赖之复杂远超传统Web开发所以我强烈建议在项目起步阶段就把Docker引入。云服务主要用的是GPU算力但如果你的项目走的是API调用路线只调现成的模型接口大部分情况下本地开发一台普通电脑就够用了不需要GPU。真正需要云GPU的场景是把开源模型部署成自己的服务这个可以放到第二阶段再学。第一阶段的从零路径把精力集中在数据链路上性价比最高。3. 动手做第一个AI工程搭建一个企业级RAG问答系统技术选型说再多不如动一个真实项目。我当时就是从给同事做一个简历知识库问答开始的现在把它改成通用的文档问答场景这依然是AI工程最典型、最有复现价值的入门项目。3.1 项目背景与整体设计场景是这样的你手上有一批公司制度文档、产品手册、培训资料分散在Word、PDF、Markdown里同事每天要花大量时间翻文档找答案。你想做一个内部AI问答系统让同事用自然语言提问系统基于文档内容给出带着引用的回答。这个项目看起来简单但包含了AI工程的全链路数据清洗、文本分块、向量化、检索、上下文注入、提示词设计、输出评估、接口部署。做完它你的AI工程能力基本可以覆盖多数应用场景。整体架构如下图我说的是逻辑架构不是代码结构设计用户提问 → 检索模块向量检索 关键词检索 → 合并排序 ↓ 上下文拼装 → LLM生成 → 返回带引用的回答这里选择RAG而不是微调模型是为了适应场景里文档持续更新的特点。RAG的核心思路是不把知识存进模型参数而是把知识切成块存进外部数据库在回答时把相关知识检索出来一并交给模型做参考。好处是更新知识只需更新数据库无需重新训练模型成本低且可控性强。3.2 数据准备最脏最累却决定成败的环节数据环节做得好坏取决于你对两个底层原则的理解。第一个原则是脏进脏出数据质量决定了效果天花板。AI系统对输入数据极度敏感文档里残留的页眉、页脚、表格错位、扫描版PDF乱码都会在检索阶段制造大量干扰。我处理过一份产品手册第8页的页眉是第8页共42页这个字符串被切进文本块导致用户问说明书有多少页时系统只能召回这个碎片给不出任何有价值的内容。数据清洗的优先级永远高于一切花哨的模型。第二个原则是分块策略需要实验不能拍脑袋。文本分块有两个方向性指标一是块大小二是块重叠度。块太大检索时会把很多无关内容带进上下文浪费token还容易产生错误答案块太小单块包含的信息量不足模型理解不了完整逻辑。我实测过一批中文技术文档按256字符分块重叠50字符检索命中率比512字符无重叠的方案高大约17%。下面是我当时用的一个朴素但可靠的清洗与分块流程import re from typing import List def clean_text(text: str) - str: # 去掉页眉页脚常见噪声字段按你的文档调整 text re.sub(r第\s*\d\s*页[共\s\d页]*, , text) # 多余空行压缩 text re.sub(r\n{3,}, \n\n, text) return text.strip() def split_into_chunks(text: str, chunk_size: int 256, overlap: int 50) - List[str]: 按段落优先、长度兜底的分块策略。 if not text: return [] chunks: List[str] [] current for paragraph in text.split(\n\n): # 段落超过上限则按句子继续切分 while len(paragraph) chunk_size: current paragraph[:chunk_size] chunks.append(current) paragraph paragraph[chunk_size - overlap:] current if len(current) len(paragraph) chunk_size: current \n\n paragraph else: chunks.append(current) current paragraph if current: chunks.append(current) return chunks这段代码的核心在于段落优先、长度兜底策略。直接按固定长度切会把一个完整的语义段落拦腰截断导致检索到的块语义不完整。先按段落天然边界走段落过长再按句子边界二次切分这样才能让每个文本块尽量自洽。3.3 向量化与检索核心逻辑拆解数据准备好之后你需要把文本块批量向量化存入向量数据库。这里有几个关键的实操决策。第一个决策是选embedding模型。我当时对比了几款最终选择了中文效果比较稳定的BGE系列的API版本当时我用的是bge-m3维度1024既支持中文检索理解能力强也可以兼顾相似度计算。如果预算紧张想完全开源可私有化也可以部署bge-large-zh服务。需要注意模型一旦定下来就不要随便换不然后面所有库里的向量全部作废要整套重新向量化。第二个决策是向量化代码怎么写。互联网上有太多教程把向量化弄得很复杂实际上核心代码非常简单。下面是我当时批量向量化的一个实用脚本from openai import OpenAI import json client OpenAI(base_urlhttps://你的API地址, api_key你的Key) def embed_texts(texts: list[str]) - list[list[float]]: # 一次请求最大批量实测16条最稳妥 results [] batch_size 16 for i in range(0, len(texts), batch_size): batch texts[i:ibatch_size] resp client.embeddings.create( modelbge-m3, inputbatch ) results.extend([item.embedding for item in resp.data]) return results chunks split_into_chunks(raw_text) vectors embed_texts(chunks) # 批量写入向量库同时保存原始文本块的id与内容映射 for idx, vec in enumerate(vectors): collection.upsert(ids[str(idx)], vectors[vec])这里有一个小坑如果数据量很大比如几万条文本块一次性embed很慢接口还容易超时。我当时做了一个简单的断点续传每处理1000个块就把本地缓存索引保存下来出错了从最后一次成功的断点继续而不是从头重跑。第三个决策是检索策略。纯向量检索在实际项目中效果并不够用因为用户问题里经常出现文档里没有按语义方式出现的精确关键词——比如产品型号AB-2024X、员工工号E1023。我的做法是使用混合检索向量检索召回语义相近的内容BM25关键词检索召回精确匹配的内容两者按一定比例合并再做一次去重和重排序。重排序我用的方案是给每组候选块计算分数取前5个块拼进上下文。这个向量关键词重排的组合远比我最初纯向量检索效果好实测用户满意度提升非常明显。3.4 生成链路模型选择与提示设计检索到的相关文本块需要组装成上下文与用户问题一起交给生成模型。这个环节最常见的错误是把所有检索结果一股脑塞进去导致上下文里有大量无关内容和互相矛盾的陈述。正确的做法是只保留高置信度的前几个块并在提示词里明确告诉模型哪些可以参考、哪些不属于内容。我当时的提示模板长这样SYSTEM_PROMPT 你是一名严谨的文档问答助手。你的任务是依据提供的参考资料回答用户问题。 规则 1. 只能依据参考资料回答若参考资料不足以回答请直接说根据现有资料无法确认。 2. 回答时在句末标注参考资料编号例如[1][2]。 3. 严禁编造参考资料中没有的内容。 参考资料 {context} def build_messages(question: str, candidate_chunks: list[dict]) - list[dict]: context \n\n.join( f[{idx1}] {chunk[text]} for idx, chunk in enumerate(candidate_chunks) ) return [ {role: system, content: SYSTEM_PROMPT.format(contextcontext)}, {role: user, content: question} ]生成模型我用的gpt-4o-mini或者国内效果对标的模型temperature调到了0.2。这里不要迷信大模型检索质量不行再强的生成模型也会一本正经地胡编。先尽力把检索做到位模型只是最后一步的表达者不是多知者。如果你愿意在成本上做一点调整还有一个经验为了控制上下文长度和成本可以给候选块做一个压缩——如果候选块太长把无关的段落截掉只保留最相关的句子。我用关键词匹配语义打分先选出每个块里最相关的句子拼成精简上下文后模型回答准确率和完整度反而上升了因为无效信息减少了。3.5 评估与上线AI工程的最后一公里我们接入合同审查场景后有一个问题始终没有被很好解决——模型回答对错谁来负责这就是评估体系要回答的问题。没有评估就没有优化依据。我最开始做评估是纯人工测试20个问题看一眼结果就打分。后来发现问题太多第一代码改了一个检索参数20个问题都得重新测一遍效率太低第二人工打分主观性太强同一个答案我今天觉得合格明天觉得不行第三没有回归测试概念上次通过的案例改了代码又挂了。后来我搭建了一个轻量级回归评估集80个高频问题每个问题标注了标准答案或答案包含的关键点。评估时用LLM作为评判员给每次回答打完全正确/部分正确/错误三档并给出错误原因。代码改动后一键跑评估集看整体通过率和错误分布。这带来的变化是巨大的每次改动都有了依据而不是凭感觉好像好了。上线这步我用的FastAPI写了一个简单的查询服务Docker打包部署在公司的内网服务器上。接口层面只暴露两个端点一个接收问题返回答案和引用另一个接收用户反馈标记错误答案。反馈数据日积月累就是我后续优化检索和提示词的最宝贵素材。这里特别提醒一点AI应用上线一定要有日志和反馈机制。日志记录每次提问的原文、检索到的候选块、生成答案、延迟和token消耗反馈机制让真实用户标记这答案不对。这两套数据组合起来你才能真正知道线上系统在哪里出错、为什么出错。没有这两样你的系统就是瞎子摸象只能靠用户口头抱怨才能发现问题。4. 从零开始的避坑清单我踩过的14个坑4.1 数据侧的坑坑1格式转换引入隐形噪声。PDF转文本时不小心把图片里的OCR识别错误也放进库这种错误在检索时很难被发现但它会把你答案的质量拉到很低。坑2重复数据没有去重。同一份文档被同步了好几次检索时命中了两份几乎一样的块模型会以为在收到佐证反而增加了重复内容在上下文里的比重。我在项目初期就吃过这个亏问题问得越简单重复数据影响越明显。坑3分块不记录原始位置信息。当时我切块后只存了文本和向量没存文档名、章节路径、页码。结果检索到一个好答案却不知道它来自哪份文档引用信息根本给不出来。后来我重建了索引强制每个块带上源文档ID和标题路径这才解决了引用问题。4.2 检索侧的坑坑4向量模型中途更换导致全库失效。这个我上文提过但值得再强调。模型一换所有旧的嵌套向量跟新模型算出的向量不在一个空间里相似度计算完全失真等于要重新embed整个库。坑5TopK参数拍脑袋。一开始我用TopK10把一堆不太相关的块都塞进上下文结果模型被无关信息干扰错误率上升。后来我结合重排序压缩到TopK5左右效果好很多。TopK没有标准答案要看你文本块的粒度和实际数据的噪声程度。坑6检索不到就去调模型而不是先查检索列表。这是原则性错误。问答系统出错80%以上是检索的问题。排查时必须先看检索到的候选块里有没有正确答案——如果候选里压根没有那再怎么调提示词也没用如果候选有但模型没用对那才是提示词和模型层的事。4.3 评估侧的坑坑7评估集设计得太随机。没有按问题类型分层事实型、流程型、观点型导致评估结果没有参考价值。后来我按业务场景分了类每一类单独统计通过率立刻就能看到哪个环节最薄弱。坑8用LLM评估LLM时没有参考答案约束。直接让评判模型打分它会偏宽松。我采用了给参考要点列表让评判模型逐项核对命中/缺失的方式评估稳定性明显提升。坑9只看准确率不看失败原因。我建议记录每次评估失败的具体错误类型——是检索缺失还是模型幻觉还是上下文太长丢失关键信息。按错误类型统计才真正有用。我见过很多人只盯着一个数字看飞快调了一圈参数仍然原地踏步就是因为分类信息没沉淀下来。这9个坑是我印象最深的另外还有几个偏细节的经验也放在这里供参考坑10异步处理文档要控制并发数防止被限流坑11Prompt里引用编号要和上下文实际编号对齐不然引用像乱码一样不可用坑12线上输入要做长度限制超长问题先截断或拆解不然会浪费tokens坑13不要一开始就追求复杂的Agent工具链先把单一RAG链路做稳再考虑让模型主动调用工具坑14模型服务尽量透出温度参数给你自己控制因为在不同问题类型下温度0.2和0.7的效果差别明显不是所有场景都适合低温。5. 写在最后的几条个人体会这个从零开始的路径我实际走下来大概花了三个月——不算长但中间充满曲折。我最想强调的有三点。第一先跑通再优化。不要一开始就想着做一个完美的AI系统。第一次做出来的效果大概率不好这很正常。关键是你能把整条链路从数据到部署跑通哪怕是做一个只有20条文档的小型知识库问答也比看十篇教程强得多。跑通之后你才有资格谈优化。第二永远不要停止记录失败。我坚持过一个习惯每次系统出错就记录当时的输入、检索结果、模型输出并在旁边写下失败原因的判断。翻看这些记录我能清晰地看到自己的认知是怎么一步步提升的——从最开始觉得模型不行、得换更大模型到后来发现是检索到的块不对、切分策略有问题。这个认知转变是AI工程最核心的分水岭。第三AI工程会一直变但链路永远不变。今天你用LangChain明天可能出来一个更优秀的框架今天的主流模型明年可能就是过时的。但数据清洗→分块→向量化→检索→上下文组装→生成→评估→迭代这条链路在未来很长时间内都不会变。从一开始就抓住它你学任何新工具都会比别人快得多。如果你刚拿到一个AI项目大脑一片空白先从搭建一个能跑的RAG问答系统开始不要多想动手。这是我从零到一最笨也最有效的方法。
返回列表