从零搭建AI工程:提示词、RAG与Agent全链路实战
我2019年第一次跑通一个简单的图像分类模型时整整熬了一个通宵。当时CUDA环境乱七八糟、数据集格式对不上、损失函数死活不收敛每一步都像是在泥坑里挣扎。但那种从零把一件事搞明白的踏实感至今记忆犹新。后来带团队做AI项目我发现一个规律真正能把AI落地到业务里的人往往不是那些收藏了一堆模型源码的人而是亲手从零搭过完整工程链路的人。这份经验比任何花哨的算法都值钱。所以这次想认真聊聊AI工程从零起步这件事。不是教你调一个现成模型的参数而是把AI落地的完整逻辑掰开揉碎——从提示词设计、智能体搭建到知识库检索、服务化部署全链路走一遍。无论你是刚接触大模型开发的产品经理、想转AI方向的后端工程师还是正在做个人项目的独立开发者这篇文章能帮你少走至少三个月的弯路。1. 内容整体设计与思路拆解1.1 from scratch到底在说什么很多朋友听到从零开始学AI工程第一反应是去啃深度学习理论、手写反向传播、从空文件训练一个大模型。我劝你打住。这条路不是不对而是性价比极低——绝大多数业务场景根本不需要你从零训练模型你需要的是把现成的模型能力变成可靠的产品功能。这个项目里的from scratch指的是从零建立一张完整的AI工程认知地图。你不需要自己造发动机但你必须知道发动机怎么装进车里、油路怎么走、仪表盘怎么设计、刹车失灵了怎么排查。换句话说你要掌握的是怎么选模型、怎么写提示词、怎么让模型调用工具、怎么接入业务数据、怎么部署成服务、怎么监控和迭代。我见过太多人把大量时间花在下载模型权重上硬盘塞满了各种开源模型却连一个能稳定回答业务问题的API服务都写不出来。这就是典型的模型收集癖本质上是用收藏的勤奋掩盖思考的懒惰。真正的工程能力是端到端交付的能力。1.2 为什么先做应用层而不是底层原理我的建议是应用层优先原理按需补齐。先通过调用成熟的大模型API跑通一个完整应用你会自然产生一堆问题——为什么这个提示词效果不稳定为什么上下文一长就出错怎么让模型输出结构化数据这些问题会像钩子一样把你拽向更深层的原理。带着问题学原理效率是漫无目的学习的十倍。反过来的路线是灾难。先花三个月学数学基础、再花三个月学PyTorch、再花三个月学Transformer结构等你好不容易准备就绪发现市面上的工具链又换了一轮。技术更新太快等你学会屠龙术龙已经进化成变形金刚了。1.3 一条可落地的技术路线图基于我的实操经验推荐如下路线第一阶段提示词工程打底1~2周。掌握System Prompt、Few-shot、Chain-of-Thought、结构化输出的写法熟悉温度、Top-p等参数对输出的影响。这是性价比最高的起点因为任何AI应用都离不开这层。第二阶段API接入与工具链上手1周。熟练使用OpenAI、DeepSeek等模型的API掌握请求封装、错误处理、异步调用。顺手把LangChain或LlamaIndex这类编排框架的基本用法学会。第三阶段RAG知识库2周。学会用向量数据库比如Chroma、Milvus做文档检索增强解决模型不知道你的私有数据的问题。第四阶段Agent智能体2~3周。理解ReAct模式、工具调用、多智能体协作做一个能自主完成任务的小系统。第五阶段工程化部署1~2周。用FastAPI封装服务用Docker容器化加一层简单的监控和日志让你的项目能被别人真正用起来。这条路线整体大约需要6~8周。走完一遍你会对AI应用开发有一个完整的体感。之后再回头补Transformer细节、微调方法、模型原理就水到渠成了。2. 核心概念拆解与实操要点2.1 Prompt EngineeringAI应用的第一行代码我一直认为提示词就是今天AI应用的第一行代码。你不需要懂Python也能写提示词但能写好提示词的人和写不好的人调出来的模型完全是两个物种。先纠正一个误区提示词不是咒语不是你把话术写得越复杂越好。它的本质是给模型建立清晰的任务边界和输出约束。我见过有人写上千字的prompt把模型的性格、背景、语气、例句全塞进去结果输出反而飘忽不定。为什么因为重点太多等于没有重点。实践中最有效的写法是结构化提示词角色设定System告诉模型你是谁——你是一名资深的数据分析师任务描述User明确要做什么——根据以下销售数据找出环比下滑最严重的三个品类输入格式给定原始材料的格式比如要分析的数据表输出约束规定输出结构——用Markdown表格输出每行包含品类名、下滑比例、可能原因示例引导Few-shot给一两个输入输出样例模型就有了模仿的锚点我自己的习惯是任何Prompt都先做小步验证。别指望一次写好先跑通一个最小用例再逐步叠加约束。每次只改一个变量观察输出变化。这跟调试代码是一个思路——你不能同时改十个参数然后看结果那样出了问题根本不知道是谁引起的。再提一个关键参数temperature。它控制输出的随机性。0到1之间取值做事实性问答比如客服、知识库问答我一般设在0.1~0.3避免模型自由发挥做创意写作、头脑风暴可以设在0.7以上。很多人忽略这个参数问为什么同样的问题两次答案不一样十有八九是温度设太高了。2.2 AI Agent让模型从回答问题变成完成任务如果说RAG解决的是模型不知道你的事那Agent解决的是模型只会说话不会干活。一个典型的Agent系统核心由三部分组成大脑LLM负责理解目标、拆解任务、决定下一步手工具模型可以调用的函数/API比如搜索、计算、发邮件、操作数据库工作记忆上下文当前执行的中间状态模型基于它做推理原理上最经典的模式叫ReAct——Reason Act。模型先思考我该做什么然后调用一个工具观察返回结果再思考结果告诉我什么下一步怎么办如此循环直到完成任务。这就像你让一个实习生去调查市场——他不会一口气给你报告而是先搜集资料、分析数据、发现问题、再看下一步每一步都用前面的结论指导后面的动作。实际开发中最常见的一个坑是模型无限循环。模型反复调用同一个工具或者陷入思考→行动→再思考的死循环就是不输出最终答案。解决办法有三个一是设置最大迭代次数比如5~8轮超过就强制终止二是给每个工具设置超时和错误降级逻辑工具失败后返回明确的错误信息让模型知道换个思路三是在Prompt里明确如果三轮内没有进展就基于已有信息给结论。还有一点要特别提醒Agent不是万能的。不要试图让Agent完成一个超出模型推理能力极限的复杂任务。我的经验是把大任务拆成小Agent相互协作多智能体协作比单Agent硬扛一个超大任务稳定得多。比如写报告这个任务可以拆成资料搜集Agent数据分析Agent报告撰写Agent各管一段中间用消息队列或结构化数据传递结果。每个Agent只做自己擅长的事出错的概率直线下降。2.3 RAG让大模型学会查你的数据库大模型的知识是训练时灌进去的它不知道你公司的产品手册、你的历史订单、你的私有文档。RAG检索增强生成的思路特别朴素模型回答前先帮它查一下资料把它需要用到的内容贴进上下文再让它回答。就像开卷考试自动帮你翻书翻到第几页再做题。完整RAG流程分为四步文档加载与拆分Load Split把PDF、Word、Markdown等文档读进来按语义切块。切块大小有讲究——太小会丢失上下文太大又超出模型token限制我经验里500~800个字符比较均衡。向量化与入库Embed Store用embedding模型把每个文本块变成向量存进向量数据库。检索Retrieve用户提问时把问题也变成向量在库里找语义最相近的Top-K个文本块。生成Generate把检索到的文本块和用户问题一起拼进提示词交给大模型生成答案。这个流程里最容易翻车的环节是检索质量。向量检索不是银弹它擅长抓语义相近但经常忽略精确匹配——你的文档里有合同编号A-2024-001用户问合同编号A2024001语义检索可能就翻车了。我的方案是搞混合检索向量召回和关键词召回并行再用重排序模型Rerank把两边结果合并排序。这条链路虽然多了一步但效果提升非常明显。另外强烈建议RAG的Prompt里明确告诉模型如果检索到的资料不够就直说不知道不要编。这是从源头杜绝幻觉的办法之一比在模型层做安全控制简单得多。2.4 常用工具链选型参考按我个人的踩坑经验给一套当前比较成熟、适合中文项目的组合环节推荐工具备选选型理由大模型DeepSeek-V3 / GPT-4o / Claude通义千问、文心一言DeepSeek性价比高中文能力强API兼容OpenAI格式编程语言Python 3.10—AI生态最全没有悬念编排框架LangChain 或裸写LlamaIndex框架帮你省时间但不要被框架绑架核心逻辑要自己懂向量数据库Chroma原型/ Milvus生产Qdrant、pgvectorChroma开发爽Milvus支撑亿级向量EmbeddingBGE系列中文友好OpenAI embeddingsBGE对中文语义理解好可本地部署服务框架FastAPIFlask原生异步性能好自动生成API文档部署Docker NginxK8sDocker足够支撑中小项目别一上来就搞集群选型要记住一个原则选你团队最熟的工具而不是网上吹得最响的工具。工具永远为业务服务不能为了技术先进给自己挖坑。3. 实操过程与核心环节实现3.1 项目目标与系统设计这一节我们动手做一个完整的小项目——本地知识问答智能体用户上传几份PDF文档系统自动建立知识库然后用户可以用自然语言提问AI基于文档内容回答并且能在回答过程中调用一个计算工具比如算同比增长率最后通过一个Web API暴露服务。麻雀虽小但把RAG、Agent、工具调用、服务化部署全串起来了。系统架构分为四层接入层FastAPI提供REST接口接收用户问题和文档上传Agent层大模型做推理决策决定是直接回答还是先检索知识库还是调用计算工具知识库层文档切块→向量化→存Chroma检索时返回相关片段基础层大模型APIDeepSeek、Embedding模型、日志监控3.2 环境准备建议用Python 3.10以上版本创建虚拟环境mkdir ai-engineering-demo cd ai-engineering-demo python3 -m venv venv source venv/bin/activate pip install fastapi uvicorn chromadb langchain-openai \ langchain-community pydantic python-dotenv注意一定要用虚拟环境否则依赖冲突会折磨你半天。另外建议把API密钥放在.env文件里别硬编码进代码。3.3 实现基础问答链路先不做RAG和Agent只做最基础的聊天框确认API连通和Prompt调优双正常from openai import OpenAI import os from dotenv import load_dotenv load_dotenv() client OpenAI( api_keyos.getenv(DEEPSEEK_API_KEY), base_urlhttps://api.deepseek.com ) def chat(question: str) - str: resp client.chat.completions.create( modeldeepseek-chat, temperature0.3, messages[ {role: system, content: 你是严谨的技术助手回答需简洁准确不知道就直说。}, {role: user, content: question} ] ) return resp.choices[0].message.content if __name__ __main__: print(chat(用一句话解释什么是RAG))这个最小链路跑通了后面所有模块都建立在此之上。我习惯先把这个写到一个llm.py里作为公共模块方便其他代码统一调用。这里有个小细节base_url要按不同模型服务商的规范配好如果用DeepSeek就是https://api.deepseek.com如果走OpenAI官方就是https://api.openai.com/v1搞错了会一直报连接错误。3.4 构建RAG知识库知识库的核心是文档切块和检索召回。我用LangChain的加载器和递归字符分割器from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_chroma import Chroma # 1. 加载PDF拆分文本块 loader PyPDFLoader(manual.pdf) docs loader.load() splitter RecursiveCharacterTextSplitter( chunk_size800, chunk_overlap120, separators[\n\n, \n, 。, , ] ) chunks splitter.split_documents(docs) # 2. 初始化embedding模型本地BGE适合中文 embeddings HuggingFaceEmbeddings( model_nameBAAI/bge-small-zh-v1.5 ) # 3. 存入向量数据库 vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./chroma_db )这里我踩过一个很深的坑一开始chunk_size设到1500想着减少切块数省token结果检索召回的内容又长又杂模型抓不住重点回答质量奇差。后来把chunk_size降到800、chunk_overlap设120效果立刻改善。chunk_size的本质是模型每次能精确消费的信息量不是越大越好。overlap的作用是防止关键信息恰好被切在边界上丢掉相当于相邻块之间的缓冲带。检索函数封装如下def retrieve(query: str, k: int 4) - list[str]: docs vectorstore.similarity_search_with_score(query, kk) return [doc.page_content for doc, score in docs]建议先单独跑几个查询检查检索返回的文本块跟问题相关性高不高。这一步如果不对后面模型回答必然歪。3.5 给模型接上手工具调用现在给模型增加工具能力。这一步是Agent的核心。我让模型能够调用calculate_growth这个函数当用户问销售额同比增长多少时模型会主动请求调用工具而不是自己瞎算。tools [{ type: function, function: { name: calculate_growth, description: 计算两个数值之间的同比增长率单位百分比, parameters: { type: object, properties: { current: {type: number, description: 本期数值}, previous: {type: number, description: 上期数值} }, required: [current, previous] } } }] def calculate_growth(current: float, previous: float) - float: return round((current - previous) / previous * 100, 2)然后把检索知识库也定义成工具这样模型就有了两个可选项查资料 or 算数。Agent主循环如下def agent_run(question: str): messages [ {role: system, content: 你是数据分析助手当用户问题涉及文档内容时必须先调用retrieve_docs工具获取资料。}, {role: user, content: question} ] for step in range(5): # 最大5轮迭代防止死循环 resp client.chat.completions.create( modeldeepseek-chat, messagesmessages, toolstools, tool_choiceauto ) msg resp.choices[0].message if msg.tool_calls: messages.append(msg) for call in msg.tool_calls: if call.function.name retrieve_docs: result retrieve(json.loads(call.function.arguments)[query]) elif call.function.name calculate_growth: args json.loads(call.function.arguments) result calculate_growth(args[current], args[previous]) messages.append({ role: tool, tool_call_id: call.id, content: json.dumps(result, ensure_asciiFalse) }) continue return msg.content return 多次尝试后仍无法完成任务建议简化问题后重试。这段代码里最关键的是循环里每一步都要把模型的完整响应含tool_calls塞回messages并且把工具返回结果以tool角色消息加回去。很多新手在这一步漏了tool_call_id的对应关系导致API直接报错。整个交互逻辑可以理解为模型说我要调用xxx工具你执行工具把结果写在纸上递回给模型看模型看完再决定下一步直到它觉得可以给最终答案。这个项目里我让模型先检索再推理。别小看这一步它把Agent和RAG串在了一起也是很多真实业务中结合私有知识做智能应用的标准范式。3.6 用FastAPI暴露服务把上面的核心逻辑包装成Web APIfrom pydantic import BaseModel class QueryRequest(BaseModel): question: str app FastAPI() app.post(/ask) def ask(req: QueryRequest): answer agent_run(req.question) return {answer: answer} app.post(/ingest) def ingest(file: UploadFile): # 保存临时文件→切块→入库→返回状态 ...这一步的意义在于让AI能力可以被任何客户端调用——网页、小程序、内部系统都能通过HTTP接口接到你的Agent上。Request模型用Pydantic做参数校验避免脏数据直接打到Agent里。3.7 Docker部署写一个Dockerfile把服务跑起来FROM python:3.10-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8000]构建镜像并运行docker build -t ai-demo . docker run -d --name ai-demo -p 8000:8000 ai-demo然后访问http://localhost:8000/docsFastAPI会自动生成交互式接口文档直接在网页上测试你的Agent。这个过程特别有成就感——当你看到自己的智能体服务在浏览器里正常回答问题时AI工程从零起步这条路基本就走通了。4. 常见问题与排查技巧实录4.1 模型输出幻觉问题现象模型一本正经地编造文档里不存在的数据还引用得像模像样。原因模型本质是续写机器它不知道你不知道它在编。如果拿到的检索片段信息不足它就会用训练时学到的常识补全而补全的内容未必真实。排查顺序先检查RAG检索返回的片段是否真的包含用户问题的答案。如果检索到的都是无关内容那问题出在检索环节先优化chunk和召回如果检索结果正确但回答跑偏那就加强Prompt约束在System Prompt里明确你只能依据提供的资料回答资料中没有的信息必须声明未知严禁猜测还可以把temperature调到0.1~0.2压一压想象力。4.2 Agent陷入无限循环现象日志里模型反复调用同一个工具停不下来或者答非所问。原因最常见的是工具返回的错误信息不够明确模型不知道失败了就换个方向于是不断重试同一条死路。其次是任务本身太开放模型每轮都发现还缺信息来回检索停不下来。排查顺序加最大循环次数是最简单的保底方案。然后检查工具返回——失败也要给结构化反馈比如未找到相关文档请尝试更换关键词。再进一步把大任务拆小降低单Agent决策压力或者用子Agent专项处理。4.3 上下文越来越长导致费用飙升现象多轮对话后Agent把全部历史记录塞进上下文每次调用都传一大坨响应变慢、费用变高。原因Agent的每一步循环都要传完整messages轮次一多消息体积就膨胀。排查顺序对历史消息做裁剪或压缩。可以只保留最近N轮完整对话更早的用摘要替代或者每条消息设置内容上限超过就截断。这个优化在真实项目中能省一大半token成本。4.4 API超时与并发问题现象用户量稍微上来接口动不动超时。原因大模型API本身响应就要好几秒同步调用把所有请求串起来了。排查顺序FastAPI接口改成async def用异步方式调用大模型API再加一层简单的缓存相同问题直接返回历史答案如果瓶颈在模型供应商的限流考虑接入多个供应商做负载均衡。还有一点容易忽视把耗时操作和快速操作拆开省得一次慢请求阻塞全局。5. 落地后的几点经验之谈项目做完之后有几条心得想特别分享。第一永远把评估放在开发的前面。我见过太多团队花两周把RAG搭起来却从没定义过回答得好不好的标准。至少要准备二三十个典型问题作为评估集每次改动后跑一遍看看回答质量是升了还是降了。没有评估所谓优化就是玄学。第二AI工程是概率工程要接受不完美。写代码时我们希望测试全过但AI应用很难做到100%准确。你要做的不是让系统永不犯错而是让错误可控、可见、可退回。比如在答案后面附上参考知识片段的链接用户能核验比如对低置信度的回答自动标注该回答可能不准确。第三技术栈可以换思维框架是通用的。今天用LangChain明天可能出来个新框架今天调DeepSeek明天可能换更好的模型。但检索→推理→行动→校验这一套循环不会变。投资认知比投资工具划算得多。最后送大家一个实用的学习技巧每学一个新概念就动手写一个最小可运行demo然后把demo拆掉重写一遍换成不同的工具或架构。第二遍才是你真正学会的开始。这个过程会比较慢但几年后回头看它比你看过的任何教程都值钱。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →