
许多朋友第一次接触AI工程第一反应是“我会写Prompt是不是也算AI工程师”。说实话两年前我也这么想。当时靠一套精心设计的提示词把小项目跑得不错直到要给几十个真实用户稳定提供服务才发现提示词只是最外层的东西背后还站着数据、评估、部署、监控一大串工程问题。今天想聊的“ai-engineering-from-scratch”就是我从“会写Prompt”到“能把AI系统做成产品”过程中的完整复盘。这篇内容适合三类人看一是脑子里有个AI点子但不知道从哪里落手的人二是已经调通了一堆ChatGPT式接口但始终觉得项目“站不稳”的人三是准备在公司里引入AI能力却被各种工具链绕晕的团队。我会尽量不说废话把从零起步需要面对的模型选型、数据准备、Prompt工程、检索增强、Agent落地、本地部署和项目协作这些事一件件拆开讲明白。1. 从零起步的第一步先想清楚AI工程到底在做什么我在很多社区里看到新人把AI工程理解为“调用大模型接口写个聊天框”。这其实只看到了最表面的那层。AI工程的核心不是模型本身而是把模型的不确定性纳入到一套确定性系统里。换句话说你需要让模型在大部分情况下输出正确结果在出错时能被发现在被滥用时能被拦住在性能下降时能被感知到。1.1 Demo和产品的差别在哪里一个Demo通常长这样启动一个服务输入问题模型返回一段漂亮回答。看起来效果不错但距离“产品”还差得远。产品意味着有人会在不同设备、不同网络、不同情绪状态下使用你的系统他们会输入你完全没设计过的内容会连续追问会试图让模型输出不该输出的东西会在高峰期把流量打满。这些问题的解决思路和模型本身关系不大。你要做的是抽象出一层“输入处理-系统推理-输出校验-兜底降级”的架构。我刚入行时以为AI工程的重心在算法后来才发现真正消耗时间和精力的地方在于数据清洗、接口协议设计、错误码规范、日志字段设计、成本计算和回归测试。模型能力当然重要但它只是整个链路中的一个环节不是全部。1.2 一个合格AI工程系统应有的分层我习惯把AI系统拆分成五个层次从底向上分别是基础设施层算力、存储、模型服务、数据层语料的采集、清洗、切分、向量化、推理层上下文组装、Prompt模板、模型调用、参数控制、业务逻辑层工具调用、状态流转、权限校验、交互层前端体验、流式输出、反馈收集。这五个层不是每个项目都需要做得很重但至少你要意识到它们的存在。早期我自己做项目时只关心推理层结果就是模型一旦换版本业务表现就飘忽不定因为底层数据和交互层没有做配套的适配。后来老老实实把每一层都补上系统才真正“稳”下来。1.3 从零起步要建立的第一个习惯记录一切AI工程和传统软件工程最大的不同是模型的行为具有概率性。你今天输入同样的Prompt可能得到略有差异的结果。如果不对请求、响应、Token消耗、耗时进行记录出了问题你连复现都做不到。所以从第一个项目开始你就要给自己定死一条规矩所有进出大模型的请求必须落日志。哪怕是本地调试也要把输入输出完整保存下来。这条习惯会在后续排查问题时帮你节省大量时间。后面我会专门讲监控与可观测这里先埋个种子。2. 搭一套能跑通全流程的最小技术栈很多初学者会陷入工具选择的泥潭。今天看到有人推LangChain明天看到有人用LlamaIndex后天又觉得Dify好。你先别急着挑框架把一套“最小可用技术栈”跑通再谈是否引入更多组件。这个最小技术栈是我个人反复迭代后留下的组合。2.1 最小技术栈推荐与选择理由我把这套组合列出来并说明每个组件解决的问题组件 | 选择 | 理由 目标框架 | Python FastAPI | 生态最全FastAPI自带OpenAPI文档调试和联调方便。 模型访问层 | OpenAI兼容接口SDK或HTTP调用 | 无论接云端大模型还是本地部署的Ollama/vLLM接口协议统一切换成本低。 向量存储 | Chroma本地起步/ Milvus生产 | 前期数据量小时Chroma够用后面换Milvus的迁移成本也低。 编排层 | 尽量不用框架用原生Python代码 | 自己写流程控制避免被框架封装的“黑魔法”坑到。 配置管理 | Pydantic .env | 各类API Key、模型参数统一管理避免硬编码。这套组合看起来“朴素”但每一层都是必要的。特别是编排层我建议新手从一开始就自己写控制逻辑而不是直接用LangChain的Chain或Agent。因为框架帮你隐藏了太多细节报错时你很难知道问题出在Prompt还是Tool还是Retriever。自己用代码写一段简单的“调用模型→解析结果→执行工具→再调用模型”循环总共不过几十行却能把每一步都看透。2.2 跑通一个最小RAG服务的步骤我这里说的RAG是“检索增强生成”通俗讲就是先把你的私有资料切成一段段文本灌进一个向量数据库里等用户提问时先到库里搜出相关的片段再把这些片段和用户问题一起交给大模型让模型“看着素材回答”。跑通最小服务可以按下面几步来准备一份《产品FAQ》或“老员工离职交接文档”用langchain_text.splitter或直接按段落分隔把文档切成300-500字的文本块给每一块加上来源编号。用Embedding模型把文本块向量化。优先选支持中文效果好的模型比如bge-m3或者云端的text-embedding-v3。本地起步时用BAAI/bge-base-zh-v1.5也可以。把向量和原文写进Chroma的collection。写一个retrieve(query, k4)函数计算用户问题的向量和库里的向量相似度返回TopK片段。用Prompt模板拼出“背景材料用户问题”调用大模型接口生成回答。用FastAPI包装成/chat接口接口内部返回回答内容和引用的文档来源。这六步就是我反复强调的“最小可运行闭环”。它不复杂但它让你第一次完整看见数据从哪里来检索如何生效模型如何引用材料。2.3 为什么我砍掉了大部分“流行编排框架”不否认LangChain里有一些好用的封装比如文档加载器、输出解析器。但问题在于很多新人一旦使用框架就会天然地向框架的抽象低头而不是向自己的业务低头。框架希望你“按照Agent、Chain、Tool的方式组织代码”你的业务却可能只需要三个集中的函数调用。我的经验是先在纯代码里把业务逻辑跑通感到重复劳动太多时再针对性地从框架中抽取你需要的工具类。这样既保留了灵活度又不会负担过度设计。很多人学AI工程学到怀疑人生大概率不是因为模型太难而是因为被一堆无意义的抽象绕晕了。2.4 这个阶段最容易翻车的三个地方第一Token数估算错误。很多人忽略了向量化调用本身也要花钱、花时间结果功能做完才发现成本超预算。第二把“相似度检索”当成万能方案。它只解决“查得到”不解决“查得准”后面还有重排序等一堆事。第三接口超时没处理。大模型生成长文可能需要几十秒如果前端一次性等待用户早就流失了。正确做法是用SDK的streamTrue做流式输出边生成边给前端推字。3. 从“调用接口”到“拥有业务手感”模型选型与Prompt工程怎么落地技术栈跑通之后你会发现真正影响业务体验的是两件事用哪个模型以及怎么把Prompt写到“用户随便问都能稳定输出”的程度。这节我聊聊模型选型和Prompt工程彼此咬合的关系。3.1 模型选型API、开源服务、本地部署怎么权衡模型选型没有绝对标准但有个简单的决策框架。把候选方案分成三类云端商业化API如DeepSeek、通义、Kimi、智谱等开箱即用推理质量高不用管运维但涉及隐私和成本控制。开源模型本地部署如Qwen系列、DeepSeek系列、GLM系列数据不出内网长线成本可控但需要GPU和工程能力效果也比云端大模型差一些。开源模型的开源API服务如通过Ollama在局域网起一个兼容接口适合开发调试和Demo性能和并发都不建议直接上生产。我自己的选择规律是如果业务对数据敏感度不高、用户量大用云端API快速上线把精力放在业务逻辑上如果业务涉及客户隐私或必须内网运行就退回到本地部署但要做好效果打折的心理准备。不要一开始就迷信本地部署先想清楚你到底是“需要隐私”还是“觉得本地更高级”。3.2 Prompt工程的核心不是模板是“结构化”现在网上流传很多所谓“万能Prompt模板”实际上都是提示词套路。真正工程化的Prompt本质上是在定义一个“输入输出的约束协议”。我常用的一套组织方式包含四个部分角色与任务边界告诉模型它是什么、能做什么、不能做什么。背景与限制条件提供上下文、格式要求、字数限制、列举禁止事项。输出结构定义指定JSON格式或Markdown结构让下游程序好解析。示例Few-shot给两三个“输入→正确输出”示例减少歧义。比如一个客服问答场景的Prompt我会这样写你是一个电商售后客服助手。 你只能基于下面提供的“售后政策”片段回答禁止编造规则。 回答时先判断用户诉求属于“退货/换货/退款/物流”中的哪一类。 输出格式为JSON包含字段 - type: 诉求类型 - reply: 对用户的完整回复不超过120字 - policy_basis: 引用的政策原文片段编号 以下是政策片段 {context} 用户问题 {question}这种写法的好处是模型输出可以直接被程序读取不用事后用正则去猜。很多新人忽略了这一点让模型自由发挥结果出来的文本一会儿是列表一会儿是散文解析代码写得比Prompt还长。3.3 参数调优temperature、top_p到底怎么设置在业务场景里我基本遵循“创意生成类任务把temperature调高0.7-0.9检索问答/代码生成类任务调低0-0.3”的经验。很多人以为temperature是“随机性旋钮”其实它是控制模型输出概率分布平滑度的参数数值越高回答越发散。top_p则是“候选词截断”策略。如果两个参数都设置了一般建议只重点调整一个避免相互干扰。我通常只动temperature把top_p设为默认值。另外务必设置max_tokens它会直接影响延迟和成本。一次让我记忆犹新的线上事故就是因为没限制输出长度模型在一个回答里不停重复最后Token耗尽返回了半句话。3.4 Prompt版本的婴儿期改一版断一版只要你开始认真维护一个AI项目你就会意识到Prompt本身也是一份代码需要版本管理。我的做法是把所有Prompt放进一个prompts/目录每个Prompt带版本号比如customer_service_v3.py。改Prompt之前先复制一份旧版再在新版上调整而不是原地覆盖。为什么要这样因为Prompt的微小变化可能让部分场景变好同时让另一部分场景变坏。没有版本记录你就没法回滚也没法知道“上周用户反馈变差”是不是因为谁偷偷改了一句提示词。在我看来Prompt工程最大的坑不是不会写而是“写了不认账”。4. RAG与知识库让AI学会你不知道的事情不管大模型本身多强大它都不了解你公司的业务细节。RAG是目前把私有知识“灌输”给大模型最务实的一条路。这一节我把RAG从原理到工程落地的关键点拆开讲。4.1 检索增强生成的本质是“把答案带进上下文”大模型回答问题完全依赖它见过的训练数据。训练数据里没有你公司半个月前刚定的新政策它就只能胡编。RAG的思路很朴素既然模型要靠上下文来答题那我们就从知识库里把相关文档检索出来塞进上下文让模型“带着参考答案作答”。这里有个容易被忽视的提醒RAG不是做语义搜索而是做“信息定位”。你最终的目标是让模型看到最相关的几段话而不是给它塞一大堆含糊相关的材料。检索到的材料质量直接决定生成质量。4.2 文档切分策略切得好检索成功一半我见过不少团队在RAG上花费大量时间调模型却对最基础的文本切分草率处理。他们用固定长度3000字符无脑切结果一段代码横跨两刀一个完整的事件描述被拆得七零八落。切分要遵循“语义完整性优先”的原则。我常用的切分策略是“滑动窗口 标题感知”先按Markdown标题、章节号、自然段把文档拆成块。如果一个块超过512个token再按句号、换行拆成更小的子块。给每个子块保留父级标题路径作为metadata例如/产品手册/售后政策/退货条件。相邻块之间重叠20到50个字避免检索时丢失上下文衔接。这个策略听起来简单实际效果远比固定长度切分可靠。你可以用spacy或nltk做句子切分也可以直接用正则匹配中文句号。总之让“一个块尽可能是一个完整的意思”是切分的最高原则。4.3 Embedding模型的选择与向量库的日常保养Embedding模型决定了你能把“语义相近”的文本在向量空间里放多近。中文场景下我实测过几个模型bge-base-zh-v1.5在常规FAQ场景表现不错bge-m3在长文档和混合语言上更稳如果接云端OpenAI的text-embedding-3-small在英文上很强但中文一般国内厂商的text-embedding-v3对中文支持更好。向量库也需要日常保养。每隔一段时间你的知识库会新增、修改、删除文档。如果只增量写入但从不处理过期数据检索结果就会被旧文档干扰。我习惯给每个向量记录doc_id和updated_at每次更新时先按doc_id删除旧向量再写入新的。这件事花不了多少时间但能避免很多诡异的“错案”。4.4 检索质量优化从TopK到混合检索与重排序只用向量相似度跑TopK对很多场景已经够用但还会遇到两个典型问题一是关键词精确匹配的场景如产品型号“A51-B2”向量检索可能找不到二是检索出的TopK里顺序不够合理最重要的材料被排在了后面。解决办法是混合检索加重排序。混合检索就是把向量检索和BM25关键词检索的结果取并集再用一个轻量的reranker模型重新打分。重排序模型可以是一个专门训练的Cross-Encoder比如bge-reranker-base。流程上首先各取Top50候选再由重排序模型选出最后的Top5。这一步对检索精度的提升有时候比你换更大的模型还明显。4.5 一个RAG上线的真实案例我之前在做一个内部的“老带新辅助系统”时把公司过去两年所有的项目复盘文档灌进知识库。一开始用固定1024字符切块向量检索按TopK5召回效果只能说勉强。后来加了标题感知切分和BM25混合又上了重排序最后把模型的回答从“看着有点相关”变成“能直接引用原文档里的关键结论”。上线后测试准确率提高了将近20个百分点。说到底RAG的工程深度很多时候比模型选择更值得投入。5. Agent不是魔法把意图拆解成确定性流程这两年“AI Agent”被炒得很热很多新人误以为Agent就是“给模型一个目标它自己就能搞定一切”。我在实际落地的经验是Agent里的模型只是“决策器”真正决定系统稳定性的是外部定义好的工具、状态机和边界条件。5.1 从一个极简Agent的循环说起一个Agent的本质可以简化成一段循环系统拿到用户指令后先让大模型分析意图、决定调用哪个工具、生成工具参数然后程序去执行工具把执行结果返回给模型模型再根据结果判断任务是否完成没完成就继续调用下一步工具。这个循环在代码上非常简单但工程化的难点在于模型可能选错工具、填错参数工具执行可能抛异常循环可能无限跑下去。所以你必须给这个循环加上硬性护栏——最大轮数限制、工具白名单、参数JSON Schema校验、每一步的完整日志。这些护栏不是限制Agent的智能而是让它在失控时有制动器。5.2 Function Calling是你最值得信任的入口现在主流的云端模型都支持Function Calling也就是让模型输出的结果结构化地指向某个函数调用而不是自由文本。这比让模型“想象着使用工具”可靠得多。以OpenAI兼容接口为例你需要在请求里声明一个tools列表描述每个函数的名称、功能、参数模式然后当模型认为需要调用工具时会在返回的tool_calls字段里带上结构化调用请求。我在自己的项目里把Function Calling视为唯一可信的Agent入口。所有业务动作都封装成工具函数每个工具函数都有严格的输入校验和错误提示。例如一个“创建工单”的工具如果用户提供的信息不全工具会返回一个明确提示模型收到提示后可以继续追问用户。这种你来我往的过程远比模型自己编一个“创建成功”要踏实。5.3 Agent工程里最容易失控的三个环节第一工具权限过宽。我给Agent接数据库查询工具时一开始直接把SQL执行封装成了函数结果模型在推理过程中生成了一条“DELETE FROM”语句。虽然当时只是内部测试但这个教训让我立刻意识到所有工具必须经过白名单校验SQL场景只允许执行SELECT文件操作只允许操作指定目录。第二循环不终止。不加最大轮数限制的Agent会在一场对话里反复调用工具消耗大量Token和用户耐心。我在所有Agent循环里强制limit5超过就停止并把当前进展返回给用户而不是让它一直撞墙。第三工具结果太长。如果工具返回一坨上千行的结果模型大概率会迷失在细节里。所以设计工具时要尽量让返回值“结构化、短小、摘要化”比如数据库查询先返回前20行再提供翻页能力。模型不会因为“信息少”而变蠢反而会因为“信息精”而更稳。5.4 用状态机代替“自由意志”Agent工程化的成熟路径我最后想强调的是越是重要的业务越不应该让模型每隔几步就自由决策。比如一个客服Agent大可不必完全由模型决定下一步做什么。你可以把它拆成一个状态机初始状态用户意图识别然后根据意图进入查退换货政策、查物流信息、转人工等状态。每个状态下只允许模型做小范围决策比如从几个槽位中提取关键信息。这个做法的好处是系统的行为是可预期的。审计时你能从日志里清楚地看到某个用户走到了哪个状态、哪个状态触发了人工兜底。相比之下“自由Agent”的表现虽然偶尔惊艳但更多时候会让你查日志查到怀疑人生。我的原则是把风险留在设计里而不是把自由留给模型。6. 本地部署AI的真实成本与选型不吹不黑前面提过本地部署是很多团队绕不开的选项。但这件事远远不止“下载个模型跑起来”这么简单。我把最近一年折腾本地大模型的经历浓缩成经验讲一讲你可能会踩的坑。6.1 先问自己到底为什么需要本地部署我见过有人因为“不想把数据交给第三方”选择了本地部署结果部署完后模型效果比云端差一大截整个团队都开始怀疑项目方向。我的建议是本地部署的适用场景至少满足下面一个条件客户或监管有明确的数据本地化要求原始数据不能出内网调用量极大云端API长期来看成本高到不可接受所在网络环境下访问云端API不稳定需要内网低延迟服务你们有专职的AI基础设施团队能扛住模型迭代和GPU运维。如果只是“觉得本地部署很酷”我劝你尽早打消这个念头。本地部署的隐性成本包括显卡采购、机房带宽、模型更新、版本兼容、并发压测每一项都够喝一壶。6.2 从Ollama到vLLM不同阶段的部署工具选择新手本地起步我推荐先用Ollama因为它把模型下载、量化、启动一条龙做了一句话就能跑起来。比如装好Ollama后执行ollama pull qwen2.5:7b-instruct ollama run qwen2.5:7b-instruct就可以在本地里聊起来了。它还提供一个/v1/chat/completions的兼容接口直接让FastAPI替换掉云端API的base_url就能接上切换成本很低。等你要做并发比较高的生产服务时Ollama就不太够看了。这个时候我会转向vLLM。vLLM的PagedAttention和连续批处理能显著提高吞吐我自己在部署一个7B模型时用vLLM把单卡并发从寥寥几个请求拉到了能扛住几十路并发。代价是配置复杂一些需要写启动脚本、管理模型仓库、处理前缀缓存等。总之Ollama负责“用起来”vLLM负责“跑得稳”和“扛得住”。6.3 模型量化用一点精度换大量显存本地部署最头疼的是显存不够。一个7B参数量的模型以半精度存储大约需要14GB显存普通消费级显卡很容易爆。这时候就要对模型做量化也就是把原本用16位浮点数存储的权重压缩到8位或4位从而把显存占用降低一半甚至更多。实测中4bit量化在7B模型上生成的文本流畅度依然不错只是偶尔会丢失一些精确细节。我的建议是起步阶段直接用Ollama里的q4_K_M量化版先跑通业务再决定要不要上高精度。很多任务场景中量化带来的损失远小于Prompt写不好带来的损失。别为了追求“无损”而让项目卡在硬件上。6.4 本地部署最容易被低估的环节是“推理质量验收”本地模型和云端大模型的效果差距是客观存在的。你拿一个7B模型去复现GPT-4级别的复杂推理大概率会得到失望的结果。所以本地部署之前一定要准备一组代表真实业务的测试用例先跑一遍基线记录准确率部署完再跑一遍对比差异。如果关键业务指标下降过多就需要重新思考是不是该用更强的开源模型还是应该妥协为云端API。以我自己的经验本地部署一个14B的模型配合重排序RAG在垂直知识问答场景勉强能达到可用水平但涉及长链条代码生成、开放式创意写作还是云端大模型更靠谱。这不是说本地不行而是你要搞清楚“业务能不能接受这样的质量”。7. AI工程中最容易踩的五个坑从评估到幻觉再到监控所有AI项目最后拼的不是谁的模型更先进而是谁更能把问题用工程手段按在可控范围内。这一章我把自己日常工作中最容易踩的五个坑复盘一遍每一个都是真金白银换来的。7.1 只看样例输出不建回归测试集我早期做项目时每次调完Prompt都拿两三个经典问题测一遍觉得“效果不错”就上线。后来才发现某个Prompt改动让一个刁钻用户问题从“正常回答”变成了“输出一大段免责声明”。原因就是我没有一套覆盖边界情况的测试集。现在我的做法是维护一个golden_questions.json里面放100条带标准答案或评价标准的历史问题每次改动Prompt、换模型或调参数都要把这100条重新跑一遍对比输出质量。这比任何“感觉”都要可靠。刚开始时测试集的构建很痛苦但积累起来之后它会让你的迭代胆子变大很多。7.2 幻觉问题治本靠约束治标靠引用幻觉也就是模型一本正经地胡说八道。想完全消除不太现实但工程上可以把它压低到可接受范围。第一层约束是Prompt明确告诉模型“没有依据就回答不知道”第二层约束是系统逻辑比如RAG场景下只把检索到的片段交给模型并强制要求回答引用片段编号第三层约束是输出校验在代码里判断回答中的引用编号是否真的存在。实际效果非常明显。我上线的知识库问答系统在加了“引用编号必须存在”的校验后胡说八道的情况基本绝迹。因为一旦模型引用了不存在的编号程序会直接让它重新生成或者转人工。工程手段带来的可靠性比模型本身的多轮进化更立竿见影。7.3 上下文窗口是“看起来大”不是“真的能塞”现在很多模型说自己支持128K上下文但真实处理时会遇到两个问题一是长上下文的注意力会分散模型对中间位置的细节记忆明显变差二是Token量增大首字延迟和成本都上升。所以不要因为模型支持长上下文就把整本手册一次性塞进去这既不经济也不一定有效。我在处理长文档时依然倾向让RAG先把内容切成小块再检索而不是全量塞给模型。只有在需要跨章节综合归纳时才考虑把整段关键材料放进上下文。记住一句话上下文是给模型“参考”的不是给模型“硬背”的。你只要确保关键事实出现在上下文的头部或尾部模型通常能答得更准。7.4 监控和可观测不是生产环境才要做开发阶段就得做我们项目上线第一个月有一次用户反馈“回答变慢、且偶尔空白”。我查了半天最后发现是底层模型服务在下午时段触发了限流而代码里的重试逻辑又没做好。如果当时有完整的监控我可能几分钟就定位了。自那之后我给自己定下可观测性三件套请求日志完整记录请求体、响应体、模型名、Prompt id、Token数、耗时、状态码。指标统计按小时聚合平均耗时、错误率、Token消耗、成本预测。业务回放把用户输入和系统输出保存成离线数据用于后续复盘和测试集扩充。这三点听起来不像“AI工程”更像是普通后端工程的标配但在AI项目里尤为关键因为模型的输出不稳定你更需要足够的“案件现场”来推断问题。没有日志AI项目调试就像在黑灯瞎火里找掉在地上的针。7.5 模型升级改动只是改个版本号代价却没上限今天把问答模型从V1切到V2可能只改配置里的一个版本号但这个切换会让整个链路里的Prompt、解析逻辑、工具调用结果都产生微妙变化。我踩过一次坑升级Embedding模型后向量空间的分布变了导致旧的知识库向量检索结果全乱套。当时所有测试用例都过了唯独线上真实用户的查询方式没覆盖到结果检索精度暴跌。从那以后我再也不做“突然的全量切换”。正确的做法是新旧模型并行跑一段时间按流量比例灰度观察核心指标后再切全量。同时知识库向量也要跟着Embedding模型的版本一起迁移不能只换模型不重建索引。这种谨慎是AI工程里最值得投入的部分。8. 从个人项目到小组协作AI工程的交付形态当你把一个AI系统做到了自己满意接下来要考虑的就是怎么让别人也能维护它。这一章是我跟团队磨合出来的协作方式也许不完全适用于所有公司但提供一个可参考的框架。8.1 一个可维护的AI项目目录怎么组织我不喜欢把所有文件堆在main.py里。AI项目的目录最好能让新加入的工程师一眼就明白“数据在哪、Prompt在哪、测试在哪”。我常用的结构是project/ ├─ app/ │ ├─ main.py # FastAPI入口 │ ├─ routers/ # /chat /search接口路由 │ ├─ services/ # 业务逻辑RAG、Agent循环 │ ├─ llm/ # 模型封装云端/本地统一接口 │ └─ prompt_templates/ # 所有Prompt文本统一管理 ├─ data/ │ ├─ raw/ # 原始文档 │ └─ processed/ # 切分后的chunk、向量索引 ├─ tests/ │ ├─ golden_questions.json │ └─ test_retriever.py ├─ configs/ │ ├─ dev.yaml │ └─ prod.yaml └─ requirements.txt这个结构的好处是把模型相关代码、业务逻辑和配置分离。换模型或调Prompt时不需要动业务代码改业务规则时也不会误伤模型层。很多初学者喜欢把所有逻辑写在一个文件里前期跑得爽后期改得惨我深有体会。8.2 用测试定义系统行为而不仅仅是单元测试AI项目的测试有两个层次。第一层是常规的单元测试检查工具函数、解析逻辑、接口协议是否符合预期第二层是模型效果测试检查模型对测试集的输出质量。这两者缺一不可。模型效果测试不能像单元测试那样用二分断言“对或错”我习惯采用两种方式一是“确定性断言”比如JSON输出结构必须合法、引用编号必须存在二是“打分制”让评估模型或者人工给回答从1到5打分设定最低达标线。比如我要求知识库问答的召回准确率≥90%回答相关度平均分≥4.2不达标就不允许上线。方式听起来繁琐但一定要做。因为AI系统处在持续迭代状态没有测试网兜住你根本不敢动任何一行Prompt。8.3 文档与Prompt的版本管理让协作不吵架Prompt是团队的公共资产。为了防止成员各自改Prompt导致行为漂移我们把Prompt的修改规范定为每次改动必须更新版本号并在注释里写明修改原因和影响范围。prompt_templates下的文件不叫customer_service.py而是叫customer_service_v3.py并且每个版本都保留一份完整代码不做覆盖。模型配置也一样统一记录在configs里包含model_version、temperature、top_p、max_tokens。上生产前必须提交一条配置变更记录写明“从哪个版本切换到哪个版本”。这一步看似多余但当你和团队连续迭代三周后就会明白“没有版本记录的Prompt等于没有发生过”。8.4 从单人项目到产线落地我的五个建议最后给出五个建议都是基于我自己的惨痛教训希望你少走弯路先做“最笨”的确定性实现再上AI能力。能写规则解决的逻辑不交给模型让模型只做它擅长的“语义理解”和“内容生成”。Token成本和GPU成本要提前建成本监控别等月底账单吓一跳。每次改动只动一个变量。不要在同一次迭代里既改Prompt又换Embedding还调参数否则你根本不知道哪个变量导致效果变化。把你的Prompt当成代码来审查。不要让任何人“随手改一句话不改版本号”就直接上线。别迷信“Agent全自动”。现在的大模型仍然需要人在关键节点兜底把人工审核环节设计成系统的一部分产品才敢真正交给用户。我个人在实际操作中还有个体会AI工程的“从零”不是指从零学机器学习理论而是从零建立一套“快速试错稳定交付”的工程观念。你可以不懂Transformer里的所有细节但你必须懂“模型输入输入什么、输出怎么被校验、错误怎么被兜底”。这些工程上的基本功才是支撑你在这个领域长期走下去的地基。希望这篇复盘能帮你把“从零”的第一步走得稳一点。最后再分享一个小技巧把每一次失败的案例都记进你的测试集AI工程的成长本质上是“让系统记住它曾经犯过的错”。