
1. AI工程从零开始到底在做哪件事很多朋友看到ai-engineering-from-scratch这个项目名第一反应是又要从张量开始写神经网络。这是最大的误会。过去两年我经手过不少大模型落地项目真正考验人的从来不是怎么训练模型而是怎么把一个有概率输出的黑盒模型变成一条稳定、可控、能迭代的业务链路。这篇文章面向的读者很明确想用大模型做产品但不知道怎么动手的开发者被老板要求一周内跑通AI Agent的工程师以及在RAG、模型部署、Prompt调优里转了很久还是觉得工程化没谱的同学。我会按我自己搭建项目的顺序从整体设计讲到目录结构再到第一次调用、Agent编排、部署监控和问题排查把一个最小可用的AI工程从0到1完整拆开。不发散到模型训练也不聊那些只有大厂才用得上的分布式系统就聊个人和中小团队能直接落地的部分。好先说设计思路。1.1 先分清AI研究、AI应用和AI工程我在很多项目评审会上发现大家嘴上说的AI工程其实是三件完全不同的事。AI研究是探索算法边界比如设计新的模型结构、提出新的训练目标。这东西需要有深厚的理论基础普通业务团队基本碰不到。AI应用是定义产品交互比如用户上传一段需求我们自动拆分任务并发给对应Agent。这更接近产品经理和业务架构师的工作。AI工程则是把AI应用变成可运行的软件系统怎么选模型、怎么写Prompt、怎么接数据、怎么让调用不超时、怎么记录日志、怎么评估效果、怎么控制成本。这三个词一直被混用导致我现在带项目第一件事就是拉齐认知我们不做研究不做PPT我们要交付的是一个能被持续维护的系统。所以如果你准备把ai-engineering-from-scratch当作一个学习路径我建议你直接把重心放在AI工程上。训练自己的小模型不是第一优先级而是先掌握基于成熟模型做应用的工程能力。现代大模型的API已经足够强个人团队完全可以站在上面搭自己的产品。真正拉开差距的地方在于工程体系是否完整。1.2 从零开始的核心技术栈和知识地图一个完整的AI工程项目从需求到上线至少要经过下面这几层。我自己习惯把它画成一张表每往下一层抽象程度都不一样。层次要解决的问题常用手段业务层用户到底要什么边界在哪需求分析、场景拆解、评估指标定义交互层模型怎么说人话、怎么不跑偏Prompt Engineering、Few-shot、系统提示词编排层单次调用不够用怎么办Agent循环、工具调用、多Agent协作数据层模型不知道你的私有知识怎么办RAG、向量检索、重排序、数据清洗服务层模型部署在哪怎么扛流量API网关、私有化部署、容器编排观测层出问题能不能快速定位日志、链路追踪、Token消耗统计、评估集这套知识地图基本就是一个AI工程从零起步的全部地盘。你不需要一开始全部精通但必须知道每一层大概有哪些坑。比如很多人第一个Demo跑通之后就高高兴兴上线结果Prompt里一个小改变线上效果直接崩掉就是因为没有评估集又比如Agent循环没有设置最大步数模型在工具调用里绕圈子一次对话烧掉几块钱就是因为编排层没有加约束。我的建议是先按这个地图把最小闭环跑通——调用模型加上Prompt接一个工具记录日志然后评估。后面的所有方案都会围绕这条主链路展开。2. 搭一个可运行的AI工程骨架目录、配置和第一次调用理论说多了容易飘还是直接动手。这一节我完整给出一个最小项目结构同时解释每个目录为什么存在。可以说目录设计是AI工程里最容易被忽视、但后续最影响迭代速度的部分。2.1 项目目录到底怎么设计网上很多AI项目的Demo就是单个Python文件所有Prompt写在字符串里密钥直接写在代码里工具函数堆在一起。一个人玩没问题一旦要加人、加需求马上变成泥潭。我推荐从第一天就按下面的结构来哪怕项目还很小my-ai-app/ ├── app/ │ ├── main.py # 入口CLI或API服务 │ ├── agents/ # Agent角色与执行逻辑 │ ├── tools/ # 模型可以调用的外部工具 │ ├── prompts/ # 所有的提示词按版本管理 │ └── services/ # 模型调用、日志、评估的封装 ├── config/ │ ├── config.yaml # 环境无关的基础配置 │ └── .env.example # 密钥模板真实密钥不进仓库 ├── data/ │ ├── raw/ # 原始数据 │ └── processed/ # 清洗后的数据 ├── tests/ │ ├── test_prompts.py │ └── test_tools.py └── pyproject.toml为什么要这样分核心原因是把经常变的东西和不经常变的东西分开。Prompt几乎天天改如果它和业务逻辑耦合在一起每改一句话都要动代码、重新部署效率极低。配置文件也一样模型服务商的地址、密钥、超时时间这些东西不该写在代码里。我自己踩过的坑是早期图省事把Prompt放在代码文件里后来要同时测三个Prompt版本只能复制整个文件最后改到怀疑人生。还有一点tests目录一定要从第一天就留出来。AI工程的测试不是传统的单测而是给一组固定输入看输出是否符合预期这个后面在评估那一节展开。先把目录留出来后面补起来会舒服很多。2.2 第一次模型调用Prompt Engineering的最小实践目录搭好了接下来要做的事情特别简单调用一次模型但这次调用要兼顾稳定性、可观测性和可配置性。我习惯封装一个统一的模型接口而不是在业务代码里直接调SDK。下面这段是一个最小可用的调用封装兼容OpenAI接口的大多数服务商import os import time from openai import OpenAI client OpenAI( api_keyos.getenv(LLM_API_KEY), base_urlos.getenv(LLM_BASE_URL, https://api.openai.com/v1), ) DEFAULT_SYSTEM 你是一个严谨的AI助手。不知道的信息明确说不知道不做猜测。 def call_llm(messages, temperature0.2, max_tokens1024, retry3): for attempt in range(retry): try: resp client.chat.completions.create( modelos.getenv(LLM_MODEL, gpt-4o-mini), messagesmessages, temperaturetemperature, max_tokensmax_tokens, ) return resp.choices[0].message.content except Exception as e: if attempt retry - 1: raise time.sleep(2 ** attempt) # 指数退避这段里有两个容易被忽略的工程细节。第一temperature要按场景明确设置。如果是事实问答、信息抽取温度调到0或者0.2减少随机性如果是写文案、头脑风暴可以调到0.7以上。很多新手全程默认一个温度是效果不稳定的重要原因。第二max_tokens要设置合理上限。不设置的话模型可能在长输出任务中无限生成既费钱又影响延迟。但也不要设置得过大否则和下游缓存、队列策略会打架。下面看一个Prompt Engineering的最小例子。假设我们要做一个从用户留言中提取结构化信息的功能系统提示词可以这样写你是客户工单分析助手。从用户输入中提取以下字段 - intent: 用户意图只能取值 complaint/suggestion/inquiry - urgency: 1-5的整数5表示最紧急 - summary: 一句话总结不超过50字 要求 1. 只输出JSON不要输出任何解释。 2. 如果无法提取对应字段填null。 3. 输出示例{intent: complaint, urgency: 5, summary: 充值后未到账}然后把用户留言作为user消息传入。你会发现只要在Prompt里给出明确字段、取值范围和输出示例模型基本能稳定地返回可用JSON。用代码去json.loads就省心很多。这个例子看着简单但它包含了Prompt Engineering的三板斧角色定位业务边界、任务输出约束、示例提供格式锚点。这三板斧足够覆盖绝大多数结构化输出需求。2.3 从第一次调用就要加上的可观测性很多人在这一步会跳过去觉得能跑就行。我强烈建议不要省。因为AI应用的失败模式和传统软件不一样——它很少直接崩溃更多是返回了一个看起来合理但其实是错的答案。如果没有日志你根本无从判断是Prompt的问题、模型的问题还是数据的问题。我每次调模型至少记录四样东西输入消息、输出内容、Token数、耗时。再往后加可以记录模型名、温度、成本估算。下面是一个极简的日志封装import json import time def log_llm_call(messages, response, usage, latency_ms): entry { ts: time.time(), messages: messages, response: response, total_tokens: usage.total_tokens if usage else 0, latency_ms: latency_ms, } # 写入本地JSONL或上报到日志平台 with open(logs/llm_calls.jsonl, a) as f: f.write(json.dumps(entry, ensure_asciiFalse) \n)一个小技巧total_tokens这个值大部分模型接口都会在返回的usage字段里给出。把它记下来后面做成本核算和性能分析都有据可查。我自己曾经因为没有记录耗时排查一个页面偶尔很慢的问题查了一整天最后发现是模型服务偶发超时而当时日志里压根没有这个字段只能靠猜。3. 核心环节的进阶实现选型、RAG和Agent编排最小骨架跑通之后一个工程才真正开始。接下来这一段是AI工程的核心内容模型选型与部署、RAG引入私有知识、从单次调用进化到Agent。3.1 模型选型与部署先别急着上GPU服务器模型选型是个很现实的工程问题。每次听到哪个模型最强这个问题我都想反问一句你的场景真的需要最强模型吗我一般按四个维度选型数据敏感度数据能不能出域决定你要不要私有化部署。响应延迟C端交互需要低延迟离线分析可以容忍慢。调用成本高频场景对单位token成本极其敏感。能力边界是否需要复杂推理、长上下文、多模态。把它们放到一张决策表里会很清楚场景推荐方案原因个人原型托管API零运维成本低速度快企业低敏内部工具托管API 数据脱敏省人力安全性可控高敏感数据私有化开源模型数据不出域高频低价值任务小模型 缓存成本优先复杂推理任务大模型效果优先关于部署我必须说句实在话如果只是团队内部用托管API永远是最划算的。不要为了追求私有化而私有化。你租一台GPU服务器至少要面对显存管理、并发排队、模型热更新、监控告警一堆问题而这些托管API都已经帮你处理好了。如果真到了必须私有化部署的那天我建议从这类开源模型入手7B到14B参数级别的小模型用vLLM或者Ollama就能扛住不少场景。部署时最需要注意的就是显存。简单估算一下14B模型用FP16加载光权重就需要约28GB显存加上推理时的KV Cache一张40GB的卡基本是起步配置。所以别拿笔记本跑也别用CPU硬扛那不是工程化是自虐。3.2 RAG让模型只说自己有依据的话大模型的知识截止于训练数据很多业务私有知识它根本不知道。RAG检索增强生成是目前最主流的解法本质是三步把知识库切成小块存进向量库用户提问时先检索相关片段把这些片段塞进上下文让模型基于片段回答。我画过最简洁的流程图其实就是文档切分 - 向量化 - 召回 - 重排 - 生成。不展开画图直接给核心代码骨架# 伪代码RAG主流程 def rag_query(question): # 1. 召回从向量库中取topK相关文档块 chunks vector_store.search(question, top_k5) # 2. 重排对召回结果打分取最相关的3块 reranked reranker.rerank(question, chunks)[:3] # 3. 构造上下文 context \n---\n.join([c.text for c in reranked]) # 4. 生成回答 prompt f请只基于下面的资料回答问题不要编造。\n\n资料\n{context}\n\n问题{question} return call_llm([{role: user, content: prompt}])工程上最容易出问题的不是向量化而是切分策略。很多人习惯按固定长度硬切比如每512个字符一刀结果把一句话从中间切断、把表格拆成碎片召回质量自然差。我的经验是优先按语义边界切比如Markdown标题、段落、代码块再配合少量重叠。一个没有重叠的切分在跨块信息上几乎是必坑的。还有RAG落地后必须做召回评估不能只看几个例子觉得差不多。最简单的做法是准备一批问题-相关文档块的标注数据算召回率。召回率如果低于70%生成答案再好也是空中楼阁。很多项目死在最后一步就是因为没有这个评估集。3.3 从单次调用到Agent编排的本质是约束循环如果说RAG解决的是模型不知道Agent解决的是模型不会做多步任务。所谓Agent简单理解就是模型 工具 循环。模型根据任务决定要不要调用工具然后观察工具结果再决定下一步动作直到结束。一个最基础的ReAct循环代码骨架长这样def agent_loop(task, max_steps5): messages [{role: user, content: task}] for step in range(max_steps): resp call_llm(messages, temperature0.2) # 模型返回的文本里如果包含Action标记就执行对应工具 action extract_action(resp) if action is None: return final_answer(resp) result run_tool(action.name, action.args) messages.append({role: assistant, content: resp}) messages.append({role: tool, content: result}) raise TimeoutError(Agent超过最大步数)注意这里有个关键参数max_steps。这是AI工程里必须加的护栏。没有它模型在工具调用中一旦陷入循环会无限烧钱。我的惯例是默认5步起步复杂任务最多10步步数超了就强制终止让用户手动介入。多Agent协作是更进阶的编排方式。常见套路是一个Planner拆解任务一个Worker执行子任务一个Critic做审查。听起来很美好但我必须说一句不要为了炫技上多Agent。每多一个Agent就多一层模型调用、多一种失败模式、多一份成本。我自己见过太多团队任务本来单Agent能搞定非要拆成三个角色结果消息传递出错、职责边界模糊效果反而不如一个Agent加几个工具来得稳定。3.4 AI编程与AI测试工程链路上的两个增量很多热词里都有AI编程和AI测试这两个其实也是AI工程的一部分。AI编程是用LLM写代码但它写出来的代码本质上和业务代码一样需要测试。AI测试则相反是指用AI自动生成测试用例、做异常兜底。我在项目里常见的做法是让Agent生成一段核心函数后自动追加两个测试用例然后跑一遍。这也算一种轻量的Agent实践。但要注意AI生成的单测不等于测试完成覆盖率、边界条件还是得人肉看。我觉得最值得做的不是让AI写全部测试而是让AI生成用户可能问出什么刁钻问题的用例集然后拿这些用例去测Prompt。这属于AI工程里非常关键的质量环节。4. 线上常见问题和排查技巧实录无论前面设计多完备线上总会出问题。这一节是我最想写的因为每一个问题都是我或身边团队真实踩过的。4.1 回复不稳定、幻觉多先别怪模型很多朋友一看到模型回答不靠谱第一反应是换个更强的模型。但换模型成本高、周期长而且很多时候根本不解决问题。我排查这类问题的顺序是固定的。先看输入。你是不是把用户的原始问题直接丢给模型了用户问题时常含糊不清系统提示词有没有把它约束成你是一个客服助手只回答订单相关问题如果输入复杂先做意图分类或改写。再看输出约束。需要结构化结果时有没有在Prompt里给出JSON示例有没有设置temperature为0有没有要求模型资料里没有就回答不知道这三点做好大多数幻觉都能压下去。最后才看模型。同一批Prompt不同模型效果确实不同但这往往是最后一步判断。我印象最深的一次是客服工单分类模型总是把催发货识别成退货看起来像是模型能力不足。后来排查发现是我们给模型的Few-shot示例里两个类别的样例太相似没有给出催发货特有的关键词信号。调整示例之后准确率立刻上去了。所以别急着换模型先检查你是不是给了模型足够清晰的边界。4.2 成本失控和性能瓶颈怎么调Token成本可以在项目第一天就估算。每次请求的费用大概是每次调用成本 输入token数 / 1000 × 输入单价 输出token数 / 1000 × 输出单价假设一个模型输入0.15元/千token输出0.6元/千token。一次调用输入2000 token、输出500 token单次成本就是0.3 0.3 0.6元。如果每天1万次调用一天就是6000元。这么一算很多团队就不敢乱调了。控制成本有几个实操抓手做Prompt压缩把历史对话摘要化而不是把所有聊天记录原样塞进上下文。五个会话轮次可能就超过一万token你不裁剪钱就白烧了。做语义缓存相同或相似问题直接命中缓存不重复调模型。对于FAQ类场景缓存命中率能到40%以上。分层用模型简单任务用小模型复杂任务才用大模型。我常用一个规则先让一个小模型做意图分类只有复杂推理类才转给大模型成本能降一半。异步批处理一些不追求实时响应的任务如离线批量总结可以用异步队列既降成本又降峰值压力。性能方面最大的瓶颈往往不是模型而是下游工具和网络。比如Agent里某个工具要调外部接口一次要等5秒Agent要调三次整个链路就慢到不可用。这种问题只能靠链路的可观测性去发现所以前面日志一定要记耗时。4.3 私有数据和合规边界怎么处理做AI工程数据安全是绕不开的坎。我不是法务只从工程师角度说说落地经验。先判断数据能不能出域。如果企业内部数据完全不能传到外部接口那就不要硬撑着走托管API老老实实私有化部署小模型。如果部分数据可以出域也应该先做脱敏再调用。最简单的脱敏是去掉姓名、手机号、身份证号等字段再做日志脱敏。日志是重灾区。很多团队把模型输入输出全量记录方便排查问题结果日志里全是用户真实信息。我的做法是日志里存请求ID、消息的哈希值或者只存脱敏后的内容。另有一个原则不记录模型收到的原始附件和图片只记录文件路径。这样即便日志泄露影响面也可控。还有权限调用模型的服务账号应该只拥有它必需的权限不能让它顺便读库、写文档。这个和传统后端的安全策略完全一致但到了AI应用里经常被忽略。4.4 一套亲测好用的排查速查表最后把问题现象、可能原因和优先级梳理成一张表方便大家直接对着查症状最可能的原因排查重点优先级答案经常跑偏Prompt边界不清系统提示词、Few-shot示例高偶尔返回乱码/空输出格式约束不足增加JSON示例、后处理校验高响应很慢上下文太长或外部工具慢看耗时日志、压缩上下文高成本涨得吓人上下文膨胀、无缓存算Token分布、加摘要和缓存高引入了错误知识RAG召回质量差查切分策略、召回率评估中工具调用了不该调的Agent权限过大加白名单、限制工具暴露高这张表我基本每次培训学员都会发因为大多数团队的AI工程问题都能在这里对号入座。写到这里我自己最大的感受是AI工程这个领域门槛不在AI在工程。模型能力再强没有一套稳定的调用、评估和可观测体系就是一台没有安全带的跑车。我的实践经验是从零起步时宁可慢一点也要先把日志、版本化、成本护栏这些不性感的东西打好。它们不会让你发朋友圈但会让你在三个月后不翻车。顺着这条路继续做下去下一步值得研究的是Agent模式拆解和RAG的离线评估体系这些都可以在现有骨架上慢慢长出来。