从“调接口”到“真正做工程”,这一路我踩过的坑都在这个开源项目里
如果你看过不少AI项目代码,大概率有过这种感受:网上教程里三行代码调用大模型接口,感觉AI工程也就那么回事。可一到自己动手,要处理文档解析、上下文管理、模型输出不稳定、接口限流、部署时显存不够……全套流程走下来,才知道“会调接口”和“能上生产的AI工程”之间隔着一整条河。我最近把从零搭建AI工程的全过程整理成了一个开源项目,叫“ai-engineering-from-scratch”,核心就是把一个完整AI应用从无到有落地所涉及的所有环节——模型选型、提示词工程、检索增强、Agent设计、评估部署——按可复现的顺序串起来。这篇文章不聊PPT,就讲我在这个项目里实际做的那些选择、踩过的那些坑,以及每一步为什么非这么做不可。适合刚入门想往工程方向走的开发者,也适合已经在做业务AI化、想补一补系统性知识的人。
1. 先搞懂“AI工程”到底在拼什么
1.1 从“调接口”到“工程化”的认知升级
很多人以为AI工程就是“API调得多、模型用得好”,实则以我做了几个落地项目之后的感受,真正的AI工程更像是在不确定性里搭一套确定性系统。
模型回答本身是概率性的,你今天问它“你好”,它回得挺好,明天同样的问题,它可能换了种说法,甚至偶尔会胡说。工程化要做的事,就是把这些概率输出包裹进一套结构化流程里,用提示词规范行为,用检索约束事实,用Agent拆解任务,用评估兜住质量底限。这个概念想通了,后面所有设计才有方向。
我见过不少团队卡在“模型不听话”上:让模型输出JSON,它偶尔给你解释一段;让模型从长文档提取信息,它把原文抄了一大半。这不是模型不行,是工程化没跟上。从零开始做AI工程,第一步是接纳这三个现实:模型会犯错、延迟会波动、上下文有上限。基于这些现实设计系统,而不是用“换个更强的模型”去掩盖问题,才是工程化的起点。
1.2 开源项目“ai-engineering-from-scratch”的路线图拆解
这个项目名里的“from scratch”强调的是不依赖现成低代码平台,自己把每个模块搭一遍。我给它设计的主线是:先跑通最小链路,再逐层添加复杂度。
完整路线分四段。第一段是基础链路:选定一个开源模型或商用API,写出一个能跑通“提问-回答”的最小程序;第二段是增强能力:把提示词工程、RAG检索、结构化输出这些模块逐个加入,让模型行为变得可预期;第三段是Agent化:让模型不只是回答问题,还能拆分任务、调用工具、执行动作;第四段是工程兜底:加入评估、监控、部署和性能优化,让系统能稳定在线上跑。
每一段我都会配套一个实战主题,比如“用RAG做企业知识库问答”“用Agent做自动化信息整理”“用评估集压测模型稳定性”。这样做的好处是每阶段都有可验证的里程碑,不至于学了一堆概念最终却拼不出一个能用的东西。如果你跟着做下来,最终会得到一个分层清晰的AI应用骨架,替换业务场景后就能变成自己的产品。
2. 从零搭建AI工程的技术底座:模型、提示词、RAG
2.1 模型选型与API调用:先跑通一条端到端链路
动手第一步,选模型。这里没有“最好”,只有“最合适”。我的建议是,除非业务对数据隐私极其敏感,否则初期直接用商用大模型API,比如OpenAI、Anthropic或国产的DeepSeek、通义千问都行,先把链路跑通,别在自部署上浪费半天。如果确实要本地部署,后面第4章会专门讲。
选模型时重点看三个指标:上下文长度、工具调用能力、输出格式稳定性。上下文长度决定你单次能喂多少资料,工具调用能力决定能否走Agent路线,输出格式稳定性决定你后处理要花多少力气。我最初用的是一个参数量较小的开源模型,想着省成本,结果它经常把JSON输出在前面加一段“好的,下面是我生成的结果”,后处理脚本不堪重负,最后还是换了能力更强的模型,数据处理成本反而降了一半。
API调用这块,别急着上复杂框架,先用最朴素的HTTP请求调用一次,亲手看系统提示词、用户消息、工具定义这三部分是怎么组装的。等理解了协议,再根据需要引入OpenAI SDK或LangChain这类上层封装。我项目里的示例代码就用OpenAI兼容接口做了一个最简单的循环:组装消息、调用模型、拿到回复。这一步虽然基础,却是后续所有复杂系统的地基。
2.2 提示词工程(Prompt Engineering)的三个关键细节
很多人觉得写提示词就是“把问题说清楚”,实际做完这个项目我发现,专业提示词设计要考虑的细节远比想象多。这里有三个我踩出经验的关键点。
第一,系统提示词不要只写“你是一个助手”,要写清角色、目标、约束和输出格式。比如做知识库问答,系统提示词至少要有这几层:你是企业知识库助手;你的任务是根据给定资料回答问题;如果资料中没有答案,必须明确说明“资料中未查询到”;回答用简体中文,分点列出引用依据。这四层缺一不可。我见过无数例子,只写“你是助手”,结果模型自由发挥到姥姥家。
第二,给模型“安全网”和“退路”。模型在有明确规则时会更守规矩。比如你要求模型从文档提取关键词,它可以输出空数组,但绝不能瞎编一个。在提示词里显式留出“当无结果时输出空值”的选项,能大幅减少幻觉。我自己做信息抽取时,加上这句之后无效输出比例从18%降到了3%以下。
第三,少用抽象形容词,多用具体示例。提示词里说“回答要专业”,模型不知道什么叫专业,但你在用户消息里给出一个小例子,说明期望的回答结构,模型马上能模仿得像模像样。Few-shot示例是性价比最高的调优手段。我甚至会专门为复杂任务维护一个“示例库”,把测试中表现最好的几条输入输出对放进去,作为提示词的固定组件。
2.3 检索增强生成(RAG)实战:让模型回答你的业务数据
RAG是目前把私有知识接入大模型最主流的方式,架构不复杂,但细节里的坑一个接一个。
基础流程是:把文档切成小块,做向量化,存入向量数据库;用户提问时,把问题向量化,检索出最相关的几个文本块,连同问题一起塞进提示词。听起来简单,可切分方式、检索策略直接决定回答质量。我最初图省事,按照固定长度(比如每500字)切文档,结果很多段落被拦腰截断,语义破碎,检索出来的内容前言不搭后语。后来改用“结构化切分”:优先按Markdown标题、段落等自然边界切,实在不行再按字数兜底,检索命中率明显提升。
另一个容易翻车的点,是“检索到相关不等于回答正确”。模型会把检索到的内容当真理,哪怕片段本身有误导信息。所以我在提示词里明确加了“仅根据以下资料回答,不要推测”的约束,并且要求模型在回答末尾标注引用来源序号。这样即便答案不完美,用户也能追溯到原始文档,工程上叫“可溯源”,这对做企业知识库几乎是硬指标。
向量数据库我试过Chroma和Qdrant,最终在项目里选的是Qdrant,因为它在过滤元数据(比如限定某个文档范围检索)时更灵活。检索策略上,除了纯向量相似度,我还会额外加一层BM25关键词召回,再把两路结果合并重排。这种“混合检索”在专业术语繁多的场景下特别有用——向量模型对生僻词理解弱,但关键词匹配能精准捞回来。
3. 迈向AI Agent:从“对话”到“做事”
3.1 Agent架构拆解:规划、工具、执行、反思
如果说RAG让模型“知道得更多”,Agent就是让模型“做得更多”。一个完整的Agent需要具备四大能力:规划、工具使用、执行、反思。
规划,是模型理解用户目标后,决定分几步完成;工具使用,是模型在需要时调用外部函数,比如搜索、查数据库、发通知;执行,是实际运行这些工具并拿到结果;反思,是根据结果判断是否已经完成任务,要不要调整计划重新来一次。
听起来很玄,但底层逻辑就是“把一个大任务拆成几步循环”。我用日常备课做个类比:你准备一节课,首先拆解目标(讲透一个知识点),然后搜集资料(调用工具),资料不够再补充检索(反思并修正),直到能形成教学方案。Agent本质就是把这个思维过程程序化。
设计Agent时最怕的是让模型“自由发挥”太多。我建议一开始把所有工具定义写得极其严格,每个工具注明功能、参数、返回格式。并且给Agent设计一个固定循环:思考-行动-观察-再思考,最多迭代N次,超过次数就停止。这个“最大迭代次数”就是安全闸门,缺了它,Agent可能陷入死循环烧掉大量Token。
3.2 用代码实现一个最小可用Agent(附关键代码)
项目里我实现了一个最简Agent,不依赖LangChain这类重量级框架,只用原生函数就能看透核心机制。这里贴一段核心循环的简化版,用伪代码说明思路:
def run_agent(user_goal, tools, max_steps=5): messages = [{"role": "system", "content": SYSTEM_PROMPT}] messages.append({"role": "user", "content": user_goal}) for step in range(max_steps): response = call_llm(messages, tools=tools) # 如果模型决定调用工具 if response.get("tool_calls"): messages.append(response) # 保存模型回复 for call in response["tool_calls"]: result = execute_tool(call["name"], call["arguments"]) messages.append({ "role": "tool", "tool_call_id": call["id"], "content": result }) else: # 没有工具调用,视为最终回复 return response["content"] return "已达最大步数,停止迭代"这段代码的核心是“把模型的每次回复以及工具返回结果都能放回上下文”,这样模型才能推理下一步。实际项目中,execute_tool背后可能是调用一个天气API、查询数据库,或者执行一段Python脚本。为了让模型能正确调用,每个工具定义需要写成JSON Schema,告诉模型工具叫什么、需要哪些参数。我踩过的坑就在这:工具定义示例写得太少,模型调用时参数名对不上,后来我把每个参数都加了“示例值”,调用准确率立刻提上来了。
代码封装好后,你自然会面临两个工程问题:怎么并发跑多个Agent任务?怎么让Agent在任务中间失败后自动重试?我现在的做法是用消息队列把任务提交给Worker,每个Worker跑一次run_agent,结果写入数据库。重试逻辑则放在调用方,检测到超时或返回错误就重新入队,最多重试两次。这套实现大概二百行,但已经足够支撑一个自动化处理上百个文档的并发任务。
3.3 多Agent协作与工作流编排的工程化思路
单Agent解决独立任务已经很好用了,但真实业务里很多需求要多个角色配合。比如做一个“需求分析Agent”,可能需要“调研Agent”先去搜资料,再有“撰写Agent”整理成文档,最后“评审Agent”挑毛病。这就涉及多Agent协作和工作流编排。
我的实践建议是不要把多个Agent塞进一个循环里让他们自由对话——那样成本高、不可控且极难调试。更稳的做法是“工作流+子Agent”:外部用代码定义好每一步(第一步调用调研Agent,第二步调用撰写Agent),每一步之间通过结构化的JSON传递结果。这就像工厂流水线,每个工位固定干一件事,产品按顺序流转。
在这个项目里,我用的是一个很轻的编排方式:写一个pipeline函数,接收任务描述,依次调用不同的Agent模块,每个Agent只是单独的函数,内部再用之前run_agent的逻辑。关键接口保持一致:都接收字符串任务,返回结构化结果。这样随时可以把某个子Agent替换成普通函数,方便单元测试。多Agent协作的核心不是“让模型自己商量”,而是“让工程代码掌控节奏,让模型专注每一步的执行”。
4. 部署、评估与运维:AI工程化的真正分水岭
4.1 模型部署与推理优化:GPU资源怎么花在刀刃上
前面的一切在本地跑通只是起点,一旦要给别人用,部署优化就成了头等难题。如果选的是API服务,你只需要关注延迟和费用均衡,偶尔切换到更便宜的模型即可。但若要私有化部署开源模型,这章就是我整理的经验库。
首先切勿一上来就上最大参数量模型。7B和13B之间的效果差距,在多数业务场景里远比部署成本差距小得多。先跑通效果,分析瓶颈,再考虑升级模型。部署时我推荐用vLLM或SGLang这类推理框架,相比原生Transformers代码,同样的硬件吞吐量能提升数倍。核心原理是连续批处理、PagedAttention这些技术,它们让GPU显存被更高效利用。一次实测里,用vLLM部署7B模型,吞吐量从每秒5次请求跳到了30次,差别非常直观。
显存不够时,还有两个成熟方案:量化(把模型权重压缩到4bit或8bit)和切片。4bit量化后的7B模型,显存占用能降到6GB左右,普通消费级显卡都能跑。代价是生成质量轻微下降,但作为内部工具完全能接受。我的建议是优先尝试AWQ或GPTQ量化,这俩在效果和速度上最大平衡。
部署之后必须监控两个核心指标:首Token延迟(用户发出请求到看到第一个字的时间)和Token吞吐量(每秒生成的字数)。这两个指标决定了用户体验,也决定了成本。我写过一个极简监控脚本,每分钟采集一次推理服务的性能和GPU显存占用,超过阈值就告警。别小看这一步,没有监控的AI服务就跟没有仪表盘的车一样,开着心惊胆战。
4.2 评估体系:没有评测指标,AI工程就是盲人摸象
做AI工程最担心的不是模型不够聪明,而是“不知道现在好不好”。很多人调了几个小时提示词,感觉有改善但说不清改善在哪。所以我在项目里专门写了评估模块。
评估的关键是先做“评测集”。挑出100条具有代表性的业务问题,为每条写好标准答案或答案要点。然后定义指标:比如准确率、完整率、格式合规率、不必要的召回率(模型是否输出了页面没有的信息)。每次改动提示词、更新模型或者调整检索策略,都把评测集跑一遍,用脚本计算指标对比。
这个过程会逼着你把“我觉得好像变好了”变成“准确率从71%提升到79%”。我在开发RAG知识库时,就靠评测集发现了一个意外问题:增加检索召回数量从3到5,虽然召回完整性变高了,但错误信息也变多了,准确率反而下滑。这个结论如果靠人肉判断,得看几十条回答才能偶然发现,评测集五分钟就暴露了。
评测集本身也要定期更新。线上用户真实问题里会不断出现新表达,可以每周抽一定比例真实请求,人工标注后加进评测集。这属于数据飞轮,做得越久,系统越好把控。
4.3 可观测性与上线后的持续迭代
模型上线只是开始,真正的工程化在运维中才见真章。我踩过最典型的坑就是:线上用户提出了一个知识库没有覆盖的问题,模型胡编了一个答案,用户投诉后才追查原因。这背后缺的是日志系统。
做AI应用,至少要记录四层日志:每一轮请求的原始输入输出、模型生成用了多少Token、检索出的文档ID和相关性分数、整个请求链路耗时。这些日志不仅要存,还要能方便回溯。比如用户说“答案不对”,你能立刻查到他当时的问题、检索到的资料片段、模型输出的原文,问题定位效率翻倍。
除了日志,还要关注成本。每个请求的Token占用直接就是费用。上线后我发现有相当比例的请求把大量上下文传给了模型,但真正有用的就一小段。优化方式是把历史对话做压缩:只保留最近两轮完整对话,更早的用摘要替代。这么调整后单次成本降了近30%,回答质量基本没受影响。
持续迭代方面,我给你一个具体的节奏:每周收敛一个指标。要么提高评测集准确率,要么降低单位请求成本,要么减少极端失败案例。以周为周期,每次只改一个变量,不要同时换模型又改提示词,否则出了问题根本不知道是谁引发的。用这种方式跑了三个月后,我对系统的掌控力远超以前“随机调参”的状态。
我个人做完“ai-engineering-from-scratch”,一个很深的体会是:AI工程领域最稀缺的不是模型知识,而是工程素养。用评测集说话,用日志定位问题,用架构控制不确定性——这些能力在任何技术栈里都成立。如果你准备从零开始做自己的AI应用,别迷恋“换个更强模型”的捷径,先把RAG、Agent、评估这三板斧练扎实。之后你会发现,真正难的不是让模型“听懂话”,而是让系统“靠得住”。