
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系统通常由六个环节组成缺一不可问题定义层你要解决什么业务问题这个问题的输入和输出是什么边界在哪里数据工程层数据从哪里来怎么清洗怎么切分训练集/验证集/测试集如果做RAG应用知识库的切分和处理是核心。模型基座层用大模型API还是开源模型自部署选哪个规模和版本需不需要微调推理服务层模型怎么部署用什么框架做推理加速如何处理上下文窗口和并发请求评测观测层怎么定义“回答得好”用离线评测集还是在线用户反馈怎么追踪模型输出的质量和成本迭代闭环层根据评测结果反向调整数据、提示词、检索策略或模型形成飞轮。这六个环节有一个很深的逻辑关系前面的环节出错后面的环节无法弥补。我遇到过数据标签有明显错误还强行微调的案例结果模型训练完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工程基础环境的实操大概是这样# 安装uvmacOS/Linux curl -LsSf https://astral.sh/uv/install.sh | sh # 创建新项目目录并初始化 mkdir ai-engineering-from-scratch cd ai-engineering-from-scratch uv init # 创建虚拟环境并安装核心依赖 uv add python3.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_nameBAAI/bge-large-zh-v1.5) Settings.llm OpenAI(modelgpt-4o-mini, temperature0.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-m3BAAI出品中文效果很好或者用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(titleAI 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, host0.0.0.0, port8000)这里有三个工程细节值得注意超时控制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就直接返回缓存结果。流式输出改用streamtrue让LLM生成的文字像打字机一样逐步呈现用户感知上的等待时间能缩短一半以上。语义缓存实现很简单用一个带向量索引的字典即可from cachetools import TTLCache cache TTLCache(maxsize100, ttl600) 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 None4.3 成本管控一个token一个token抠出来的钱大模型API按token计费对AI工程而言成本不是伪命题。经验是对话历史越长成本越高因此要对传给模型的内容做严格的前置裁剪。系统提示词控制在200个token以内只写“你是客服助手回答基于以下知识库”。检索上下文传给模型的知识片段只保留Rerank后Top 5的chunk总量控制在1000-1500 token。历史对话只保留最近两轮的用户问题不要全量塞进上下文。成本控制方面还有一个容易被忽略的点多个用户请求时尽量复用系统级检索结果。比如“退货政策”这种问题知识库内容一样只是人不同检索结果可以缓存避免每次都调嵌入API。5. 实战中常见的坑与排查技巧5.1 我实测遇到的三大问题及排查方法以下问题100%来自我的实操不是网上抄来的理论遇到的人大概率会在这里卡住。问题一检索不到相关内容答非所问现象模型答非所问跟知识库的内容完全不沾边。排查顺序是先看检索到的Top 5 chunk是什么。直接用检索组件的retrieve接口打印结果。如果chunk里没有相关内容说明是数据切分太粗或嵌入模型不匹配。如果chunk里有相关内容但模型没答出来说明是prompt引导的问题让模型忽略了context把提示词改成“只用下方资料回答”。问题二模型产生幻觉编造内容现象知识库没有的信息模型一本正经地编。这个问题的根本原因是模型在生成时过度依赖自身参数知识而不是检索到的上下文。解决办法有三个把prompt里加上“如果上下文中没有相关信息请直接回答‘不知道’”。降低temperature到0.1-0.2。在生成之后加入一层“事实校验”用原文对比回答中的关键实体不一致就拒绝生成。其实有一个更彻底的办法是引入“引用溯源”要求模型在回答时附带来源文档编号[1][2]这样用户能验证答案。这个操作能大幅降低用户对幻觉的容忍成本。问题三接口慢到超时现象用户反馈“转圈圈转了半天”。这个问题的典型瓶颈在LLM API的响应速度跟代码性能关系不大。排查步骤先分清是网络慢还是检索慢在日志里给检索和LLM调用各打一条时间戳。如果是LLM调用占了80%以上的时间直接上流式输出语义缓存。如果检索本身就超过500ms考虑向量数据库索引是否没建好或者chunk数量太大。5.2 经验总结小步快跑用评测指挥改进方向从零开始做AI工程我最大的体会是“不要指望一步到位”。一个系统总是在上线之后才暴露出真问题比如用户问法的多样性、数据更新的频率、知识库覆盖的盲区。正确的做法是构建一个极简的最小闭环跑起来之后每周用小步改动去迭代。我自己的迭代节奏是这样的每周固定跑一次黄金评测集记录分数。分析失败案例把回答错误、检索失败、幻觉案例归类。针对最多的一类问题采取一次对应优化改切分、改prompt、加Rerank、补数据等。重跑评测集看分数是涨是跌。这就是数据驱动的AI工程节奏。5.3 最后的实用建议先让系统跑起来再做精细雕琢如果你打算从零开始做一个AI工程我的建议是先走通最小链路不要追求完美。先做一个最简单的“文档上传 - 切分 - 向量化 - 检索 - LLM回答”的闭环哪怕所有参数都不优化也没关系。跑通之后你会发现很多问题是之前想不到的。比如数据格式五花八门、用户的问法比你预料的更多样、模型输出偶尔抽风。这些都是正常的工程能力就是在这个不断见招拆招的过程中积累起来的。如果你手边有具体的项目想尝试可以从你工作里最小的一个痛点开始把一个问答场景做到极致。我个人体会是真正让你成长的不是炫酷的模型技巧而是你如何把一个模糊的想法变成一个可评测、可部署、可迭代的AI系统。这个过程本身就是“ai-engineering-from-scratch”的全部价值所在。