ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AI工程从零到一:提示词、Agent、工作流与模型部署实战路线

AI工程从零到一:提示词、Agent、工作流与模型部署实战路线 如果让我说过去一年最花时间、也最值得复盘的一件技术事那一定是维护一个叫ai-engineering-from-scratch的个人项目。它不是课程也不是某个框架的源码解读而是一条从零开始建立 AI 工程能力的实操路径。我把它理解成四件事把提示词工程、Agent 设计、工作流编排、模型部署和测试评估串起来做成一套能照着跑、能复现、能上线的最小闭环。刚开始动手的时候我以为“会调大模型 API”就等于会 AI 工程了。结果第一次认真做一个带记忆的多轮问答机器人就被打脸上下文一长就乱、工具调用经常回传错误参数、模型偶尔一本正经地胡编。这些问题不是靠换个更强的模型就能解决而是要靠工程手段去约束和兜底。这篇内容会把我在ai-engineering-from-scratch里沉淀的路线、模板和排障方法全部翻出来。适合正在规划 AI 工程学习路径的开发者也适合团队里刚接手 AI 业务、想把 Demo 变成可交付系统的同学。大家按自己的基础取用能少踩几个坑就少踩几个。1. 为什么需要一份“AI工程从零到一”的项目清单1.1 先搞清楚AI工程到底是什么先说结论AI 工程不是一个名词而是一组能力的组合。它至少包含提示词设计、Agent 架构、工作流编排、模型部署、测试评估、可观测性和成本控制。很多人把它和“调用模型接口”混为一谈这是最大的误区。会调 API 只能说明你拿到了一个模型的能力入口但真实业务场景需要你回答一系列工程问题用户输入变化很大时怎么保证输出稳定Agent 多轮调用工具时怎么避免失控模型延迟高时要不要做缓存这些问题才是 AI 工程的核心。我更喜欢用一个比喻来解释模型是发动机AI 工程是整车。发动机马力再大没有传动系统、刹车、仪表盘和车身结构都上不了路。你写的那段openai.chat.completions.create只是点火真正的工程都藏在方向盘和底盘里。这个项目之所以叫from scratch就是暗示不要从框架文档开始学而是从第一性原理去推演整个系统。先理解模型输入输出的边界再理解如何设计交互流程最后才谈得上调度、部署和监控。顺序错了后面的坑一个都躲不掉。1.2 从零开始的路线图提示词 → 工作流 → Agent → 部署我给这个项目定的路线图非常直白先练提示词再做工作流再上 Agent最后搞部署和评估。为什么是这个顺序因为每一步都是下一步的地基。提示词是你和模型之间的“接口协议”。如果你连稳定输出 JSON 都做不到后面所有依赖结构化数据的 Agent 和工作流都会摇摇欲坠。工作流是把多个模型调用、规则判断、人工审批串起来的管线它不需要模型有复杂的推理能力但要求你有清晰的流程设计能力。Agent 则是在工作流之上引入“自主决策”——模型决定下一步该调什么工具、什么时候停下来。这一步看着炫酷实际上是最容易出乱子的地方。所以这条路线解决了一个很现实的问题你不必一上来就搞多智能体系统而是每走一步都能做验收。提示词写得好不好看能不能稳定输出合法 JSON工作流跑得顺不顺看任务失败率降没降Agent 可不可控看有没有超时和死循环。每层都有独立验收标准学起来才不会像无头苍蝇。我在项目里把每个阶段都留了可以直接运行的示例代码读者不需要理解全部细节也能跑通。但强烈建议按顺序看因为后边的代码会复用前边定义的提示词模板和工具函数。跳着看经常会出现“这变量哪来的”的困惑。2. 核心细节提示词工程与结构化输出2.1 提示词不是“说话”而是接口设计很多新手把提示词当成跟模型聊天这是一个需要立刻纠正的思维。生产环境里的提示词本质上是一份“接口契约”。系统提示词负责定义角色和行为边界用户消息是运行时动态注入的参数输出格式则是返回值结构。三者各司其职跟传统后端接口的request、response、handler非常像。我常用的提示词结构分四块身份与目标、输入上下文、处理步骤、输出格式。身份与目标告诉模型“你是谁、你要做什么”输入上下文用来放需要参考的资料处理步骤控制推理过程避免模型跳步输出格式则划定返回边界。这四块每块都要写清楚少一块都会出问题。举个例子如果你只需要模型做摘要不要在提示词里写“请帮我总结一下这段话”而是写清楚摘要长度、必须包含的字段、禁止出现的主观判断以及输出的 JSON 结构。这样模型的行为才可预期下游程序才敢直接解析。提示词的每句话最后都会变成系统行为的一部分。写得含糊系统就含糊。2.2 让模型输出稳定少样本、格式约束与校验“输出不稳定”是 AI 工程上线后最常被投诉的问题。同一批输入两次调用返回的结构可能不一样。我的解决办法是三层保险硬约束、少样本、外部校验。第一层硬约束是在模型 API 参数里直接指定输出格式。比如要求 JSON 输出就把response_format设为json_object要求特定字段就给一个 JSON Schema 或 TypeScript interface 样例。模型虽然不能 100% 遵守但大部分时候会按格式走。第二层是放 2-3 个少样本示例覆盖正常情况和边界情况。第三层是程序外部校验用pydantic或jsonschema对模型输出做校验非法就重试或标记失败。为什么外部校验这么重要因为模型输出本质上是概率采样再强的约束也可能出现字段缺失、枚举值非法、JSON 截断。这些情况只能靠程序兜底不能指望模型自觉。我在项目里写了一个safe_parse()函数先尝试json.loads()失败就提取代码块再解析再失败就返回 None 并记录日志。这个函数帮我挡掉了很多线上事故。2.3 一个可直接套用的提示词模板下面这份模板是我在项目里所有任务型对话中反复使用的你可以直接复制到自己的代码里改字段。# 身份 你是一个负责{任务名}的AI助手。你的用户是{目标用户}。 # 任务目标 在阅读用户输入后完成以下步骤 1. 提取关键信息{需要提取的字段} 2. 基于上下文判断{判断逻辑} 3. 给出结果不要解释推理过程。 # 输入上下文 {在这里插入需要参考的上下文或知识库片段} # 输出要求 严格输出以下 JSON 结构不要输出任何其他文字 { result: success | fail, summary: 不超过20字的中文摘要, data: { ... } } # 少样本示例 输入{示例输入1} 输出{对应的合法JSON} 输入{示例输入2} 输出{对应的合法JSON}这个模板最重要的地方在“不要解释推理过程”和“严格输出 JSON”这两句。如果没有这两句模型经常会额外输出一段“好的根据您的需求我来分析一下……”的前缀导致解析器报错。加了之后输出干净很多。提示如果你把模型输出接给下游系统一定不要直接信任任何字段。先在本地用 schema 校验再做业务逻辑。你可以把这理解为从前端接口拿到数据后不能用脏数据做计算一样的道理。3. Agent 不是玩具从单轮到多轮的工具调用体系3.1 拆解 Agent 的四层结构AI Agent 的热度一直很高但很多人实现的所谓 Agent 只是“for 循环里调模型”没有任何工程约束。一个可用的 Agent 至少需要四层结构感知层、决策层、工具层、记忆层。感知层负责接收用户输入和外部环境变化比如消息、文件、传感器数据决策层由模型承担根据当前信息和可用工具决定下一步动作工具层是Agent能够调用的函数集合比如搜索、查数据库、发邮件记忆层负责保存短期对话上下文和长期用户偏好。拆成四层之后你会发现真正难的不是让模型“思考”而是让工具层和记忆层稳定工作。工具参数是模型生成的调错一个字段就会报错记忆里的信息如果过期会让整个决策失去依据。我在项目里把工具函数都手动包了一层参数校验任何缺少必需字段的调用都会直接拒绝并返回错误描述而不是让模型自己去猜。3.2 从零实现一个最小 Agent伪代码我写过一个大约 100 行的最小 Agent代码放在项目examples/minimal_agent里。核心逻辑是一个循环让模型看当前状态决定调用哪个工具执行工具再把结果放回上下文直到模型判断任务完成。# 简化版单轮工具调用 def run_agent(task, tools): messages [ {role: system, content: AGENT_SYSTEM_PROMPT}, {role: user, content: task}, ] for step in range(MAX_STEPS): response call_model(messages) action parse_action(response) if action[type] final: return action[answer] if action[type] tool: result execute_tool(action[tool_name], action[args]) messages.append({role: assistant, content: response}) messages.append({role: tool, content: json.dumps(result, ensure_asciiFalse)}) raise TimeoutError(Agent exceeded max steps)这段代码看起来简单但有几个细节决定了它能不能跑稳。MAX_STEPS必须有否则模型可能无限循环execute_tool必须能抛异常并返回错误信息这样模型才知道自己错了messages要不断把工具结果追加回上下文帮助模型做下一步判断。真正的 Agent 比这复杂但基本骨架就是这样。3.3 工具调用的坑参数校验、超时、权限我在这部分踩过的坑比任何其他模块都多。第一个坑是模型生成工具参数时经常会“自以为是”。比如我定义一个get_weather(city: str)模型可能传一个{city: 北京, unit: celsius}参数多了本地 schema 直接报错。解决办法是在工具函数入口用**kwargs配合白名单过滤不要直接透传给底层 API。第二个坑是工具超时。如果 Agent 调查询接口接口本身可能耗时 5 秒以上。模型等待期间如果用户已经失去耐心整个会话就崩了。我一般会给工具调用设置独立超时比如 3 秒内必须返回结果超时就返回“查询超时请尝试其他方式”。这样模型能感知到异常自行调整策略。第三个坑是权限。Agent 能调用工具意味着它也可以操作敏感系统。我始终遵循最小权限原则每个工具只暴露必要的能力且关键操作要二次确认。没有权限管控的 Agent 就是一把谁都能开的车迟早出事。4. AI工作流把零散调用编排成可维护的流水线4.1 任务拆解与状态管理有了提示词和 Agent 的基础下一步是把它们放进工作流。工作流解决的核心问题是AI 任务不是单点调用而是一条链。以“客户工单自动处理”为例它要经过意图识别、信息抽取、结果生成、人工复核、回写系统五个阶段。每个阶段都可能成功、失败或需要人工介入。我在项目里用状态机来管理工作流。每个任务的当前状态保存在数据库里流转条件对应每个节点的执行结果。这样最大的好处是任务在执行到一半时进程崩溃了重启后可以从状态记录继续跑而不是从头再来。数据不会丢流程可控审计也方便。有人会问为什么不直接用现成的编排框架这就回到了from scratch的初衷先手写一个最小状态管理模块才能真正理解框架帮你解决了什么问题。等流程复杂到难以维护时再考虑引入成熟的 workflow 系统那时候你知道自己需要的是持久化、重试还是并行执行。否则被框架的抽象搞晕出了问题根本无从下手。4.2 失败重试与人工兜底AI 工作流里最容易犯的错误是模型调用失败一次就直接让整个任务失败。真实系统需要分级处理。对于暂时性错误比如网络抖动、限流可以做指数退避重试最多三次。对于确定性失败比如输入文本非法重试一百次也没意义应该直接进入人工处理队列。还要做一个所有 AI 工程师都应该有的设计人工兜底节点。无论模型有多强总有它把握不准的场景。我在工单流程里设计了一个needs_review状态当模型置信度低于阈值时不自动回复而是把中间结果推送给人工审核员。这个设计让系统的信誉和安全度都高了很多因为用户知道背后还有人在把关。在处理这种流程问题时我们需要把“模型出错”当作默认事实来设计系统。这不是对模型的不信任而是工程常态。就像写分布式系统时会假设网络不可靠一样写 AI 系统时要假设模型输出可能不准确、不稳定。有了这个假设重试、兜底、回滚机制才会真正被重视。4.3 日志与可观测性对AI项目更重要普通后端开发强调日志AI 项目更强调“全链路追踪”。原因很直接模型输出是概率性的同一个 prompt 可能产生不同结果。没有日志你根本没法复盘为什么某个用户看到了错误答案。我要求所有 AI 调用都必须记录四大类信息时间戳、模型名称和版本、完整 prompt包括 system 和 user、模型原始输出。Prompt 里如果包含业务敏感信息我会做脱敏后再存储。每追加一轮工具调用还要记录对应的工具名称、入参和出参这样才可能还原 Agent 的决策链路。这个习惯帮我解决过一个大事故。某天用户反馈机器人突然开始重复同一句话我靠日志发现是记忆模块把一条过期系统消息拼接进了 prompt导致模型在循环里打转。如果没有日志这种问题只能靠猜。现在我把这些日志指标做成了简单的看板用 token 消耗和工具调用次数去定位异常行为比看传统监控指标有效得多。5. 模型部署与上线从Notebook到真实服务5.1 模型选型API 调用还是开源模型本地部署把模型从 Notebook 搬到生产环境第一个决定就是选 API 还是本地部署。我整理了一个对比表方便大家按自己的场景直接选维度API 调用本地/私有化部署初始成本按量付费无固定硬件投入需要 GPU 服务器成本高数据安全数据需发送至服务商受条款约束数据不出内网私密性好技术门槛低几行代码就能接入需要处理推理引擎、显存、并发优化可定制性依赖服务商能力可以微调、量化、定制模型运维复杂度低不用管扩缩容高需要监控 GPU、处理故障我的经验是原型验证阶段用 API 最划算因为团队还在快速迭代API 可以随用随换。一旦确定了核心场景且数据隐私或成本控制要求高再评估本地部署。现在开源模型的能力已经很强搭配 vLLM、TensorRT-LLM 这类推理引擎单卡也能服务不少并发请求。另外就算选择 API也不要绑定一家服务商。我在项目里封装了一层模型网关统一了 chat、embedding、tool call 的调用接口具体模型可以配置切换。这样后续换模型或做 A/B 对比只需要改配置不用改业务代码。从 zero 开始小步迭代比一步到位靠谱得多。5.2 部署时最容易被忽视的三件事第一个容易忽略的是输入输出长度限制。很多模型对上下文长度有硬性上限超过就会直接报错。如果输入是用户上传的长文档必须提前做截断、摘要或分块。我在部署文档里建议所有输入都先统计 token 数量接近上限时触发压缩策略。第二件是并发与速率限制。API 服务商会限制每分钟请求数本地部署也受显存和推理速度限制。不加限流保护和队列缓冲高峰期一定会有请求失败。我习惯在服务前面加一层简单的信号量或 Redis 计数器控制最大并发数配合淘宝式退避重试效果还不错。第三件是优雅关闭。服务更新时如果直接杀掉进程正在执行的推理请求会被打断模型状态会丢失。正确做法是收到停止信号后先停止接收新请求等存量请求跑完再退出。这个细节做不好用户会时不时遇到“500错误”。我建议上线前先在压力测试环境模拟 10 倍日常流量观察延迟曲线和错误率。很多问题只有高并发下才显现比如某个共享状态被多个协程写坏或者某块缓存失效导致雪崩。这些是传统后端经验但在 AI 服务里同样关键。5.3 性能压测与成本估算性能压测和成本估算是上线前最难回避的环节。我给出的经验公式很简单先测单次请求的 P50、P95 延迟然后算单卡/单实例最大 QPS。比如一个开源模型单批并发 4 时单次请求耗时 1.5 秒那么单实例 QPS 大约 2-3。需要支持 100 QPS大概就要 30-50 个实例具体取决于批处理策略。成本上除了硬件还要考虑 token 消耗。我用一个脚本统计每天所有模型调用的输入、输出 token 总量乘以单价就能得到当日成本。很多项目死在“模型太聪明”每次请求都把超长知识库塞进 prompt结果 token 费用比 GPU 都贵。优化方法不外乎检索只取相关片段、压缩历史、用更小的模型做分类。提示给 AI 项目设置预算上限和告警很重要。我见过太多次账单吓人的情况。最简单的做法是在模型网关里加 token 配额按用户或按功能分别限额一旦超限就自动拒绝。6. 评估与测试如何让AI项目真正可交付6.1 测试维度准确率、召回率、稳定性、安全性AI 项目的测试不能只看“能不能回答”要看四个维度任务准确率、关键信息召回率、输出稳定性、安全性。准确率和召回率是传统指标稳定性则要看同一输入多次调用输出语义是否一致。安全性要测 prompt 注入、越狱输入、有害内容等。我遇到过最典型的情况是模型在测试集上准确率 98%一上线就被用户反馈垃圾。排查后才发现测试集里的输入都是标准问法而用户真实输入夹杂着脏话、错别字、长句、口语化表达。所以测试集必须包含真实样本包括一些“刁难”输入。我现在每个项目都会人工收集 200-500 条用户真实输入再让标注员给出预期结果用这份数据做回归测试。6.2 构建回归测试集回归测试集是 AI 系统持续交付的护身符。每次改 prompt、换模型、调参数都要跑一遍回归集防止发生“修了一个问题引出三个问题”的情况。我的回归集分三类标准样本、边界样本、对抗样本。标准样本用于验证核心能力是否达标边界样本包括超长输入、空输入、特殊字符、多语言混排等对抗样本则包含 prompt 注入、恶意指令、偏见诱导等。跑回归时我用一个简单的脚本统计每次通过率并记录每个失败样本的输出变化。这个过程非常枯燥但不做后面就得在凌晨紧急回滚二选一。6.3 AI工程里的安全与合规底线最后一块容易被人忽略的是安全与合规。无论做哪类 AI 应用都应该遵守服务协议、数据隐私法规不碰敏感内容不给用户生成违规信息。这不是套话是工程的一部分。在技术层面我至少会做三件事。一是在输入端加内容安全过滤识别明显违规的请求二是在输出端做敏感词校验防止模型生成不安全内容三是对涉及个人身份的数据做脱敏处理日志里不落明文。一次数据泄露可能毁掉团队多年积累的信任再怎么重视都不为过。任何时候都不要觉得“模型能力强就可以不管输出边界”。正因为它能力强才需要更多控制逻辑把行为限制在合理范围内。这也是ai-engineering-from-scratch项目里单独留了一章讲安全的原因。7. 常见问题与排查实录7.1 上下文窗口被塞满怎么办多轮对话和 Agent 场景里上下文窗口满了是最常见的问题。模型只会保留最近一段内容更早的信息会被截断导致“失忆”。我常用的处理策略有三级裁剪、摘要、检索增强。裁剪是指只保留最近 N 轮对话最古老的消息直接丢弃摘要是把整段历史用模型缩写成一段话当作“记忆摘要”放在上下文开头检索增强是把历史消息向量化需要时用相似度召回相关片段而不是全量塞进 prompt。三者可以组合使用。我最推荐的方式是每轮结束生成一个简短摘要对话足够长时只保留摘要加最近几轮原文。7.2 Agent陷入死循环Agent 死循环的典型表现模型反复调用同一个工具结果不变然后继续调用。第一次我看到这个现象时血压都高了。后来排查发现是 prompt 里没有明确告诉模型“工具结果不变时要换一种方式”。单纯靠模型自己意识不靠谱。工程层面我加了三个保险。一是最大轮数限制默认 10 轮超过就强制终止并返回部分结果二是重复动作检测如果连续两轮调用同一工具且入参完全一致就打断并提示模型换策略三是预算控制限制单次任务的 token 消耗上限超预算直接熔断。有了这三个保险Agent 至少不会把系统资源耗尽。7.3 响应太慢先别急着换显卡模型响应慢第一反应不该是“换更大的显卡”而是检查是不是串行调用太多。Agent 场景里如果有 5 个工具需要调用而代码是同步逐个调用总耗时就是 5 次调用的叠加。完全可以并行调用的工具我会用并发编程方式同时发出请求再把结果合并速度快好几倍。另外能用流式输出尽量用流式。让用户看到第一个 token 的时间被大幅缩短体验会好非常多。接口层把streamTrue打开前端逐字展示用户很难区分这是不是真的“实时思考”。但注意流式传输时日志采集和质量校验也要跟着改不能照搬原有非流式逻辑。7.4 模型“幻觉”泛滥时的三个止损动作幻觉问题没法根除只能止损。我做了三件事。第一要求模型只在给定上下文中找答案回答时附上引用来源没有来源就明确说“不知道”。第二用规则引擎对关键实体做校验比如数字、日期、人名必须能在原文里找到对应才放行。第三高风险场景强制人工复核不再让模型直接输出。这三点不是银弹但能把幻觉造成的危害降到可接受范围。真实业务里用户不会因为你说“不知道”而生气但会因为一本正经的错误答案而投诉。让模型学会“承认不知道”本身就是一条高效的安全策略。8. 最后聊两句我的实践体会把ai-engineering-from-scratch从零写到今天我最大的体会是AI 工程没有捷径但有稳定套路。把提示词当作接口、把 Agent 当作状态机、把工作流当作可观测的系统这些思维方式的转变比任何框架都管用。最后再分享一个小技巧。每次遇到一个新问题我会先写一个最小可复现案例比如单独跑一次模型调用把 prompt、输出、预期结果完整记录下来再去做修改。这样能大幅减少变量干扰很多看似玄学的问题最后都变成了“某段历史消息影响了模型判断”“某个工具参数没做校验”这类确定性 bug。保持这种排查习惯你会在一次次失败里真正建立起属于自己的 AI 工程能力。
返回列表