☰
AI工程从零开始:完整落地路径与RAG系统实战
2026/9/30 4:15:05 网站建设 项目流程

1. 从零开始做AI工程,先想清楚你要解决什么问题

最近“AI engineering”这词被讨论得非常热,几乎每周都有新的工具、新的框架、新的最佳实践冒出来。但真当你想自己从零开始上手时,会发现网上教程要么是某一框架的API说明书,要么是单点技术(比如某个模型怎么微调、某个RAG组件怎么用)的孤立演示,很少有人能告诉你一条完整的、经历过真实业务检验的路径。

我花了不少时间把“ai-engineering-from-scratch”这件事捋了一遍,结合自己的实操踩坑经历,写下这篇东西。它不是某个框架的入门教学,而是一套我验证过的、把一个AI想法从“运行在笔记本上的Demo”变成“能交付给真实用户使用的系统”的方法论。这套方法论的核心我认为是“工程闭环”——问题定义、数据、模型、评估、部署、迭代,六件事环环相扣,缺一个,项目大概率会烂尾。

先说一个反直觉的结论:从零开始做AI工程,第一步绝对不是装环境、跑模型,而是把“我想做一个AI产品”翻译成“我要解决什么具体问题、用什么指标判断做成功了”。我见过太多人卡在第2周就放弃,原因不是技术难度,而是他根本不知道自己为什么要做这件事。

这篇内容适合几类人:刚入门但不想走弯路的AI学习者、需要把AI能力集成到现有产品里的工程师、以及想系统梳理AI工程体系的技术负责人。如果你已经有经验,这篇文章里的排查实录和架构取舍也可以作为对照参考。

2. 从零开始的全局架构:AI工程不是“训练模型”这一个环节

2.1 先拆解AI工程的实际构成

很多人把AI工程等同于“训练模型”或者“调API”,这是个非常大的误解。一个能上线的AI系统,通常由六个环节组成,缺一不可:

  1. 问题定义层:你要解决什么业务问题?这个问题的输入和输出是什么?边界在哪里?
  2. 数据工程层:数据从哪里来?怎么清洗?怎么切分训练集/验证集/测试集?如果做RAG应用,知识库的切分和处理是核心。
  3. 模型基座层:用大模型API还是开源模型自部署?选哪个规模和版本?需不需要微调?
  4. 推理服务层:模型怎么部署?用什么框架做推理加速?如何处理上下文窗口和并发请求?
  5. 评测观测层:怎么定义“回答得好”?用离线评测集还是在线用户反馈?怎么追踪模型输出的质量和成本?
  6. 迭代闭环层:根据评测结果,反向调整数据、提示词、检索策略或模型,形成飞轮。

这六个环节有一个很深的逻辑关系:前面的环节出错,后面的环节无法弥补。我遇到过数据标签有明显错误还强行微调的案例,结果模型训练完,loss曲线很好看,但业务指标全面恶化。原因很简单——垃圾进垃圾出,模型学到了错误模式,甚至把错误模式泛化了。所以这六个环节不是“可选步骤”,而是“必须走的完整链路”。

2.2 为什么从零开始最容易踩的坑是“没有终点”

做传统软件开发,需求评审画个原型就能对齐预期。但AI项目有个特性:模型输出的质量是不确定的,一开始谁也无法保证最终效果是什么样。

没有终点具体体现在:你不知道做到什么程度算“好”。比如客服机器人,有用户说“能回答常见问题就行”,但等做出来,业务方发现回答的准确率到不了95%,又说“这个没法上线”。这其实就是没有在项目开始前定义好评测标准和可接受的性能区间。

要避免这个局面,我在项目定义阶段会强制做三件事:

  • 写清楚用户使用截图级别的输入输出示例,至少10组。
  • 定义清楚“不可接受的坏输出”长什么样,比如幻觉编造价格、答非所问。
  • 和业务方对齐一个明确的验收指标,比如“常见问答的准确率超过85%,且无严重幻觉事件”,并把这个指标落实到离线评测集上。

这本质上是一种风险前置。如果你自己拿不定主意,可以用一个假想的用户故事来推演整个流程,看看在哪个环节可能翻车。这个推演过程非常有用,能帮你提前意识到数据、成本、延迟这些约束条件。

2.3 技术栈选型:从零开始时别追求“最先进”,要追求“最少依赖”

我见过不少项目死在技术栈选型上:一上来就要基于Llama 3做全量微调,甚至要自己从零预训练,结果算力开销巨大、数据也不够,项目一个月就搁浅了。

我的建议是:能用成熟API解决的,就不要自己训练模型。RAG(检索增强生成)、提示词工程、工作流编排可以解决绝大多数业务需求的80%,而且能快速上线验证。只有当你明确知道API基座模型在特定垂直领域表现不稳定,且你有足够的高质量数据时,才去考虑微调这条路。

一个务实的从零开始技术栈(基于我的实际验证)是这样的:

环节推荐选择理由
开发语言Python生态最全,AI相关库基本都有Python接口
环境管理uv 或 conda依赖隔离干净,避免不同项目互相污染
大模型API主流的GPT系列或Claude系列效果稳定,无需考虑GPU运维
开源模型备选Qwen系列中文效果优秀,社区生态活跃
向量数据库先用Milvus或者Chroma,量大了再换前期数据量小,不需要专业分布式引擎
RAG框架LlamaIndex或LangChain,建议先用LlamaIndex编排逻辑比LangChain更清晰,上手成本低
应用框架FastAPI写API服务非常轻量,性能足够
部署方式Docker + 云服务器一台4核16G的机器就能跑得很舒服

这套组合的核心理由是“最少依赖原则”:每个组件都经过验证,组合在一起没有明显的兼容性问题,并且每一层都可以被替换。你在看技术选型时,不要被“Kubernetes + GPU集群”这种高端方案迷惑,从零开始最重要的是快速跑通闭环,之后再按需演进。

3. AI工程落地实操:从环境搭建到第一个完整闭环

3.1 环境搭建:用uv把Python环境问题一次性解决

Python环境问题一度是我最烦躁的事情。不同项目要不同版本的Python、不同包的依赖互相冲突,用传统的pip和conda管理,简直是在做依赖考古。

直到我完全切换到uv之后,这个问题才算终结。uv是目前我认为体验最好的Python包和环境管理器,它可以用Rust的速度给你创建一个全新的虚拟环境,并且在几秒内解析出依赖树。对AI工程来说,依赖通常非常多,比如torch、transformers、langchain、milvus等,轻量秒装的感觉会让你心情好很多。

创建AI工程基础环境的实操,大概是这样:

# 安装uv(macOS/Linux) curl -LsSf https://astral.sh/uv/install.sh | sh # 创建新项目目录并初始化 mkdir ai-engineering-from-scratch && cd ai-engineering-from-scratch uv init # 创建虚拟环境并安装核心依赖 uv add python=3.11 uv add openai langchain langchain-openai python-dotenv uv add fastapi uvicorn

装完之后,你会发现project里多了一个pyproject.toml,所有依赖都记录在这个文件里,以后换机器直接用uv sync就能一键还原环境。这比requirements.txt更好用,因为依赖被锁定到具体版本,不会有“在我机器上能跑”这类问题。

3.2 准备高质量数据:RAG时代的“数据工程”怎么做

AI工程里,数据工程的占比被严重低估。不管你是做微调还是做RAG,数据的质量直接决定系统的效果上限。做RAG时,最核心的数据工作是对知识库文本进行清洗、切分、嵌入和入库。

我自己经常用一套五人团队的“穷鬼方法论”,不需要大数据团队,自己动手用Python脚本处理数据就行。首先做文档清洗,把PDF、Word、Markdown统一转成纯文本,然后按标题层级做结构拆分。这个结构拆分如果做得粗糙,后续检索质量会急剧下降。以一段几千字的文档为例,我会先按Heading(## / ###)切块,再按段落、句子切成100-300字左右的chunk,相邻chunk之间保留少量重叠(比如用text_splitter的chunk_overlap参数设置为20-50字)。

有个细节容易被忽略:切分时不要硬切句子。我拿默认按字符切分的方案试过,结果很多chunk的语义被拦腰截断,检索到的上下文信息非常破碎。后来我改用按语义切分,用split_by=“markdown_header”或split_by=“sentence”这类工具,效果好了很多。

嵌入模型的选择也会影响检索效果。如果以中文为主,我会优先考虑bge-large-zh-v1.5或者text2vec-large-chinese,这两类模型在中文语义上的表现经过社区验证都比较稳。如果是英文混合中文,用nomic-embed-text或OpenAI的text-embedding-3-small也可以。这里有一个我个人很在意的点:嵌入模型要和你后续的检索策略配套。如果用的是向量+关键词混合检索,那么嵌入模型输出维度最好固定在一个合理范围(比如1024或1536),避免维度太稀疏导致召回率不稳定。

3.3 用LlamaIndex搭一个带检索的QA系统

搭RAG系统,我强烈建议从LlamaIndex开始,因为它的核心抽象是“文档 → 索引 → 查询引擎”,整个链路非常直白。不推荐从LangChain开始的原因是LangChain的组件编排非常灵活,但灵活意味着你要自己理解各种概念,对新手来说容易迷失方向。

一个标准的LlamaIndex检索流程,大致可以写成下面的结构:

from llama_index.core import VectorStoreIndex, Settings from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.llms.openai import OpenAI from llama_index.core.node_parser import MarkdownNodeParser # 设置嵌入模型和LLM Settings.embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-large-zh-v1.5") Settings.llm = OpenAI(model="gpt-4o-mini", temperature=0.2) # 从文档目录加载知识库 documents = SimpleDirectoryReader("data").load_data() # 按Markdown结构解析节点 parser = MarkdownNodeParser() nodes = parser.get_nodes_from_documents(documents) # 构建向量索引 index = VectorStoreIndex(nodes) index.storage_context.persist(persist_dir="./storage/")

这段代码跑通后,你就有了一个可以回答的知识库引擎。但我必须提醒你:这个Demo离“能交付”还很远。最大的问题在于简单向量检索的召回质量不稳定,特别是当用户提问方式与文档原文表达差异较大时,常常检索不到相关chunk。

解决办法有两种:一种是加一层混合检索(BM25+向量),一种是在用户查询后加一层查询改写(query rewriting)。前者的实现几乎已经成为RAG应用的标准配置,把关键词语义匹配和字面匹配都跑一遍,再把两个结果做融合重排(Rerank),整体召回率能提升不少。

3.4 加一个Rerank层:把检索质量再做一次保证

做RAG的人应该都深有体会:向量检索只是初筛,真正的精度提升靠的是重排(Rerank)。原理是这样的:向量检索把Top 100的候选块捞出来,然后Rerank模型再对每个候选块和用户查询做一对一的精细相关度打分,最后只把最高分的Top 5-10送给LLM生成答案。

为什么要做这一步?因为向量检索的“语义相似”和“回答用户问题的相关性”并不完全等价。举个例:用户问“怎么修改密码?”,向量检索可能召回“密码长度要求为8位以上”,字面上语义相关,但它并不直接回答用户的操作步骤。Rerank模型就是用来纠正这种偏差的。

实操层面,我推荐两个工具:bge-reranker-v2-m3(BAAI出品,中文效果很好)或者用Cohere Rerank API(英文数据集效果很好)。用Python接入也非常简单,把检索到的候选chunk列表传给Rerank模型,让它输出重新排序后的列表,再取前N个做生成。

加了Rerank之后,会有个明显的体验变化:模型的回答质量会显得“准很多”,幻觉现象也会下降。因为输入给LLM的上下文更聚焦了,LLM“自由发挥”的空间被压缩。

3.5 构建FastAPI服务:把AI能力变成接口

当你的检索+生成链路在本地脚本里跑通之后,下一步是把它包成一个HTTP服务,这样前端、客户端才能调用。

我一般用FastAPI来做,代码非常干净:

from fastapi import FastAPI from pydantic import BaseModel app = FastAPI(title="AI Knowledge QA API") class QueryRequest(BaseModel): question: str top_k: int = 5 @app.post("/qa") async def qa_endpoint(request: QueryRequest): response = query_engine.query(request.question) return {"answer": str(response), "sources": extract_sources(response)} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)

这里有三个工程细节值得注意:

  • 超时控制:LLM调用很慢,必须设置合理的超时时间,否则接口会堆积请求。
  • 并发控制:默认的异步接口无法控制内部LLM并发量,如果需要限制并发,可以用asyncio.Semaphore或者消息队列。
  • 速率限制:如果用户请求量不稳定,建议加一个简单的令牌桶算法,避免下游模型API被调用过度。

3.6 离线评测:量化“回答得好不好”

AI工程最容易被忽视但又最必须做的是“评测”。很多人上线后靠感觉判断效果,实际上非常危险。因为没有量化指标,你根本不知道一次代码改动到底让效果变好了还是变差了。

我自己的做法是构建一个“黄金评测集”:准备50-100个典型问题和对应的标准答案,每次改动系统后都跑一遍评测集,用GPT自动打分(LLM-as-Judge),计算回答的准确率、完整率和有害性报告。

用GPT做裁判的prompt大概是这样:

请根据以下标准对AI助手的回答进行打分: 1. 回答是否正确(0-2分) 2. 回答是否完整覆盖问题(0-2分) 3. 回答是否有明显的幻觉内容(0-2分) 4. 回答是否安全无害(0-2分) 总分8分。 问题:{question} 标准答案:{reference} AI回答:{answer}

这个评测集的价值会在你后续迭代时充分体现:每次改动,都跑一遍,看分数是涨是跌。分数的波动,就是你决策的依据。迭代不再凭感觉,而是有数字指引。

4. 部署、性能优化与成本控制:工程化的分水岭

4.1 Docker化部署:让环境一致可交付

从零开始的AI工程,做到脚本能跑还不够,必须走到可部署。我在部署环节的第一步永远是写Dockerfile,因为只有容器化才能保证“在我机器上能跑”这句话不再出现。

一份最小可用的Dockerfile长这样:

FROM python:3.11-slim WORKDIR /app COPY pyproject.toml /app/ RUN pip install uv && uv sync COPY . /app/ EXPOSE 8000 CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

构建完成后,一条docker build -t ai-app . && docker run -p 8000:8000 ai-app就能把服务跑起来。不用再担心宿主机Python版本不同、依赖冲突的问题。

4.2 推理延迟和数据缓存:体验提升最直接的手段

大模型API的延迟通常在2-5秒之间,这个延迟对很多交互场景来说都不够理想。我实践下来,最有效的两个优化手段是:

  • 语义缓存(Semantic Caching):用户经常重复问类似问题,比如“退款政策是什么?”,把这类常见问题的回答缓存起来,用向量相似度匹配,相似度超过0.9就直接返回缓存结果。
  • 流式输出:改用stream=true,让LLM生成的文字像打字机一样逐步呈现,用户感知上的等待时间能缩短一半以上。

语义缓存实现很简单,用一个带向量索引的字典即可:

from cachetools import TTLCache cache = TTLCache(maxsize=100, ttl=600) def get_cached_answer(query): query_emb = embed_model.embed(query) for cached_q, cached_emb, answer in cache: if cosine_similarity(query_emb, cached_emb) > 0.9: return answer return None

4.3 成本管控:一个token一个token抠出来的钱

大模型API按token计费,对AI工程而言,成本不是伪命题。经验是:对话历史越长,成本越高,因此要对传给模型的内容做严格的前置裁剪。

  • 系统提示词:控制在200个token以内,只写“你是客服助手,回答基于以下知识库”。
  • 检索上下文:传给模型的知识片段,只保留Rerank后Top 5的chunk,总量控制在1000-1500 token。
  • 历史对话:只保留最近两轮的用户问题,不要全量塞进上下文。

成本控制方面还有一个容易被忽略的点:多个用户请求时,尽量复用系统级检索结果。比如“退货政策”这种问题,知识库内容一样,只是人不同,检索结果可以缓存,避免每次都调嵌入API。

5. 实战中常见的坑与排查技巧

5.1 我实测遇到的三大问题及排查方法

以下问题100%来自我的实操,不是网上抄来的理论,遇到的人大概率会在这里卡住。

问题一:检索不到相关内容,答非所问

现象:模型答非所问,跟知识库的内容完全不沾边。排查顺序是:

  1. 先看检索到的Top 5 chunk是什么。直接用检索组件的retrieve接口打印结果。
  2. 如果chunk里没有相关内容,说明是数据切分太粗或嵌入模型不匹配。
  3. 如果chunk里有相关内容,但模型没答出来,说明是prompt引导的问题,让模型忽略了context,把提示词改成“只用下方资料回答”。

问题二:模型产生幻觉,编造内容

现象:知识库没有的信息,模型一本正经地编。这个问题的根本原因是模型在生成时过度依赖自身参数知识,而不是检索到的上下文。解决办法有三个:

  • 把prompt里加上“如果上下文中没有相关信息,请直接回答‘不知道’”。
  • 降低temperature到0.1-0.2。
  • 在生成之后加入一层“事实校验”,用原文对比回答中的关键实体,不一致就拒绝生成。

其实有一个更彻底的办法是引入“引用溯源”:要求模型在回答时附带来源文档编号[1][2],这样用户能验证答案。这个操作能大幅降低用户对幻觉的容忍成本。

问题三:接口慢到超时

现象:用户反馈“转圈圈转了半天”。这个问题的典型瓶颈在LLM API的响应速度,跟代码性能关系不大。排查步骤:

  1. 先分清是网络慢还是检索慢:在日志里给检索和LLM调用各打一条时间戳。
  2. 如果是LLM调用占了80%以上的时间,直接上流式输出+语义缓存。
  3. 如果检索本身就超过500ms,考虑向量数据库索引是否没建好,或者chunk数量太大。

5.2 经验总结:小步快跑,用评测指挥改进方向

从零开始做AI工程,我最大的体会是“不要指望一步到位”。一个系统总是在上线之后才暴露出真问题,比如用户问法的多样性、数据更新的频率、知识库覆盖的盲区。正确的做法是构建一个极简的最小闭环,跑起来之后,每周用小步改动去迭代。

我自己的迭代节奏是这样的:

  1. 每周固定跑一次黄金评测集,记录分数。
  2. 分析失败案例,把回答错误、检索失败、幻觉案例归类。
  3. 针对最多的一类问题,采取一次对应优化(改切分、改prompt、加Rerank、补数据等)。
  4. 重跑评测集,看分数是涨是跌。这就是数据驱动的AI工程节奏。

5.3 最后的实用建议:先让系统跑起来,再做精细雕琢

如果你打算从零开始做一个AI工程,我的建议是先走通最小链路,不要追求完美。先做一个最简单的“文档上传 -> 切分 -> 向量化 -> 检索 -> LLM回答”的闭环,哪怕所有参数都不优化也没关系。

跑通之后,你会发现很多问题是之前想不到的。比如数据格式五花八门、用户的问法比你预料的更多样、模型输出偶尔抽风。这些都是正常的,工程能力就是在这个不断见招拆招的过程中积累起来的。

如果你手边有具体的项目想尝试,可以从你工作里最小的一个痛点开始,把一个问答场景做到极致。我个人体会是:真正让你成长的不是炫酷的模型技巧,而是你如何把一个模糊的想法,变成一个可评测、可部署、可迭代的AI系统。这个过程本身就是“ai-engineering-from-scratch”的全部价值所在。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询