ARTICLE DETAIL

资讯详情

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

AI工程实践:从Prompt设计到质量护栏的完整指南

AI工程实践:从Prompt设计到质量护栏的完整指南 1. 先想清楚AI 工程的核心是交付确定性1.1 为什么大多数 AI 项目死在问题没定义清楚先说一个我反复看到的场景团队拿到大模型 API 后第一反应就是来写个 prompt。Demo 阶段效果惊艳什么问题都能答得有模有样可一旦部署到生产环境马上出事——格式不稳定、偶尔胡说八道、上下文一长就丢信息、成本还压不住。很多初学者以为AI 工程就是把各种大模型 API 拼在一起做得多了才发现真正的 AI 工程是在一堆不确定性的模型行为之上用工程手段构建出一个确定、可维护、可评估的系统。它要交付的不是一个聪明的模型而是一个稳定的服务。所以从零开始学 AI 工程第一步不是选框架、不是调库而是把问题定义清楚。你要非常具体地回答三件事系统输入是什么用户原话、文件、结构化数据输出是什么自然语言回答、标准化 JSON、分类标签以及哪些错误是不可接受的答错可以容忍还是完全不能容忍。这三件事没想透后面所有工程决策都是空中楼阁。我经常举一个例子工单自动分类。模型确实可以把一段用户描述识别成退费投诉咨询等类别但生产系统要求的是每一次请求都返回一个合法分类、每条记录都可追溯、新类别出现时不需要重训模型。这种100% 必须有结果、结果必须可审计的要求单靠一个大模型调用是做不到的必须在外面包一层规则兜底和校验逻辑。1.2 需求拆解四步法把业务目标翻译成 AI 任务我自己的惯性做法是拿到需求后先走一遍拆解流程不急着写代码。整理下来大概是四步很朴素但非常管用第一步定义输入输出边界。输入是可枚举结构还是自由文本输出必须是枚举值、JSON 对象还是允许开放式生成边界定义得越窄工程实现越简单。第二步判断任务类型。判别式任务分类、抽取、匹配和生成式任务总结、创作、问答在评估、调优、容错上的思路完全不同。第三步明确失败容忍度。面向 C 端娱乐场景答错了可以一笑而过面向客服、医疗、金融场景答错了要出大事。容忍度直接决定你需要投入多少资源做验证和护栏。第四步列出约束条件。延迟要求、单次调用成本上限、数据隐私要求、是否需要本地化部署这些都会反过来影响模型选型和链路设计。我见过一个项目第一版直接选用超大杯模型结果每次请求 3 秒以上、成本高得惊人。后来我自己做需求拆解才发现这个场景的绝大多数请求只需要小杯模型就能完成超大杯只用来处理那少部分长尾疑难问题。这就是典型的问题没拆透导致设计过度。你还可以把大模型理解为一位能力很强但需要明确指令的新实习生他能在你交代清楚边界和验收标准时干得很好如果你只丢一句帮我处理一下用户消息他大概率会跑偏。需求拆解本质上是在给这位实习生写岗位说明书。2. Prompt 工程真正的接口设计而非写咒语2.1 一次请求也是一个小系统很多人把 Prompt 工程看作怎么把话说得更漂亮这是大误区。Prompt 本质上是用自然语言写就的接口契约你定义一个调用界面约定输入数据的格式、输出数据的结构和失败时的行为。写 prompt 跟设计函数签名是一个道理。我建议在最开始就把一次模型调用当成一个小系统来搭建而不是简单地把用户问题塞进模板就发出去。这个系统至少要包含四个环节输入清洗截断、去噪、转义、Prompt 组装填充模板、拼接上下文、输出解析提取内容、容错转义、异常处理超时、格式非法、空输出。这四步缺了任何一步线上都能给你表演一次现场翻车。看一段我之前常用的最小骨架Python 伪代码但逻辑可以直接用import json from openai import OpenAI client OpenAI(timeout30, max_retries2) def parse_json_response(text: str): # 模型经常会在 JSON 前后多输出一些解释文字先做一次清洗 start text.find({) end text.rfind(}) 1 if start -1 or end 0: raise ValueError(no valid json block) return json.loads(text[start:end]) def classify_ticket(user_text: str) - dict: user_text user_text.strip()[:2000] # 控制输入长度 prompt build_prompt(user_text) resp client.chat.completions.create( modelyour-model, # 换成真实模型名 messages[{role: user, content: prompt}], temperature0.2, ) raw resp.choices[0].message.content try: return parse_json_response(raw) except ValueError: return {category: other, confidence: 0.0}这段代码的意义不在代码本身而在它体现的工程思维假定模型会犯错假定输出会不合规然后在代码层面做约束。你永远不会直接把大模型的原始返回丢给下游就像你不会把用户输入直接拼进 SQL 一样。2.2 可复用 Prompt 模板的五层结构一段在生产环境撑得住的 Prompt通常有五个层次我强烈建议你把它固化成模板而不是每次手写角色与系统指令告诉模型你是谁、你遵循什么原则比如你是客服流程助手只依据给定资料回答。任务指令用动词开头说清楚要做什么比如从用户消息中抽取字段并分类。输入数据区用明确的定界符包住用户内容避免模型分不清哪句是指令、哪句是待处理数据。输出格式约束给出 JSON 结构或字段列表必要时给一个示例输出。少样本示例放 2 到 3 个典型或边界样例让模型理解你想要的具体样子。举个例子客服工单识别模板可以长这样系统指令 你是一个工单定级助手。你的任务是从用户描述中提取关键信息并分类只输出 JSON。 输入数据 用户描述 {user_text} /用户描述 输出要求 严格按照以下 JSON 结构输出不要输出任何解释文字 {category: 退款|投诉|咨询|其他, priority: 高|中|低, summary: 不超过30字的摘要} 示例 用户描述 我收到了昨天买的商品但里面有破损我要退货退款。 /用户描述 输出 {category: 退款, priority: 中, summary: 商品破损用户要求退货退款} /输出这层结构最容易被忽视的是少样本示例的选择。很多人的误区在于示例选得太标准全是教科书般的情况实际上真正帮助模型的是边界示例——比如一个用户既抱怨了物流又想要退货你给出一个如何判断主诉求的示例远胜过十个普通示例。2.3 最常见的失效模式和预警信号我自己踩过太多 prompt 的坑了挑几个最典型的说一下。第一个坑是Prompt 越长越细越好。事实是加了过多约束之后模型会开始选择性失明把指令当背景噪音反而忽略掉你后面明确的要求。我遇到过为提升准确率连续加了几十条规则结果分类准确率不升反降。后来把 Prompt 精简到只保留角色、关键约束、示例效果立刻回升。规则多不等于效果好关键是信息密度和位置。第二个坑是依赖模型自我修正。常见做法是让模型先答一遍再让它自检一遍以为这样的结果更可靠。实测下来并非如此模型倾向于认为自己的第一次回答是有道理的自检环节经常只是换一种句式复述原答案。要让模型发现自己的问题你必须喂给它一个外部参照比如正确示例、检索到的资料而不是单纯让它再想想。第三个坑是对 temperature 的理解偏差。temperature 控制的是输出采样的随机性不是聪明程度。在分类、抽取这类判别式任务里我通常把 temperature 调到 0 到 0.2在文案创作类任务里再调高到 0.7 以上。很多人一套参数打天下结果在判别任务上天天看到同一个输入被分到不同的类别还以为模型抽风了。一旦你发现以下信号大概率是 Prompt 设计出了问题相同输入时输出结果剧烈波动、模型反复输出冗余解释、边缘情况被系统性归入某一类、输出 JSON 经常解析失败。这些信号都提示你要从模板结构上找原因而不是盲目增加提示词。3. 从单点到流水线工作流与多 Agent 编排3.1 工作流 vs Agent先有流程再有智能当你搞定单次调用下一个问题就是多个步骤怎么串起来在业界讨论中这个问题通常被拆成两种实现路径Workflow工作流和 Agent。工作流的特点是流程由代码预先定义每一步做什么、在哪一步调用模型、在哪一步拼接结果都由开发者控制。模型只是在若干节点上被执行的角色。Agent 则相反模型拥有更大的自主权它自己决定下一步调用什么工具、什么时候结束。听起来 Agent 更高级但工程上它带来的是不可控和调试困难。我的选型原则很简单流程可穷尽就用 Workflow任务分支多到无法穷尽才考虑 Agent。举一个实际例子做一份竞品分析报告步骤是固定的——搜索、提炼、组织大纲、逐段撰写、汇总。这样的流程完全可预判用 Workflow 可以把每一步的中间结果都保留下来方便审查出了错也知道是哪个环节的锅。相反如果任务本身是开放式的比如帮用户规划一次旅行用户可能问出意想不到的问题、需要临时查询大量外部信息这时才更适合引入 Agent 的自主行动能力。这里我放一个对比表格方便大家在不同阶段做取舍维度WorkflowAgent决策权代码决定流程模型决定步骤可控性高出错可定位低行为难预测调试难度较低每步都有日志较高需要回溯决策链适用场景流程固定、可枚举开放式任务、分支极多成本控制容易步骤确定较难可能循环执行上线速度快慢需要大量 token 消耗测试另外一个现在比较常见的混合做法是外层用 Workflow 控制主流程只在其中某个必须灵活处理的节点上使用 Agent。先把 90% 的路径固定死再给 10% 的复杂分支引入自主性。这样既保证了系统的稳定也保留了模型灵活处理的能力。3.2 结构化中间结果不要让大模型替你拼字符串刚开始写多步流程时我犯过一个很典型的错误让模型逐步生成整段文本再把上一段文本作为下一段的输入。比如写报告流程第一步生成提纲文本第二步把提纲原文塞进下一个 Prompt 生成正文。这种方式在简单 demo 里跑得通一旦报告步骤变多文本之间会开始互相污染——模型会执着于复述前置步骤里的措辞而不是执行当前步骤的任务。后来我把中间结果改成结构化数据通常就是 JSON。第一步让模型输出一组小节标题和关键词数组第二步按数组逐个生成小节内容第三步再把所有小节拼进最终报告。这样做有三个好处中间结果可独立校验任意步骤失败时可以单独重试不用整条链重跑可以在步骤之间做缓存重复问题不会反复消耗 token。用 JSON 作为中间结果还有一个额外的价值它是人和模型、模型和代码之间通用的转接口。我见过团队一开始用自然语言字符串传中间结果后期想加一个人工审核节点时发现没法定位该修改哪个片段如果从一开始就用结构化对象每个字段在哪个环节产生、在哪被消费一查就清楚。3.3 多 Agent 协作的常见误区从热词来看多 AI 协作是当下很火的方向但我对刚上手的人有个劝告不要一开始就搭一个规划者 执行者 审查者的多角色多 Agent 框架。听上去很美好实际跑起来你会发现三个头疼的问题。第一个是角色越多循环越多。规划者让执行者做事执行者把结果给审查者审查者说要改再绕回执行者。如果没有步数上限和终止条件一次任务可能烧掉数千次调用。我现在做任何多 Agent 系统第一件事就是强制设置最大迭代次数比如 5 步以内必须收敛超时直接降级到默认结果。第二个是工具权限给得太随意。很多框架支持 Agent 自行调用工具这确实方便但风险极大。一次错误的工具调用可能引发雪崩式的连锁反应。我实际项目中会做一个工具白名单Agent 只能调用被允许的三到五个工具且每个工具调用前要经过一层参数校验。第三个误区是追求完全自主。实际上生产环境里完全自主的 Agent 反而最难用。我推荐的做法是在关键节点插入人工审批环节。比如 Agent 规划完步骤后先暂停展示给操作者确认或者生成初稿后有人工一键确认才进入发布流程。这不是给 Agent 拖后腿而是在模型自由度与业务保障之间找平衡点。所以我对多 AI 协作的理解是大多数实际落地场景并不是几个 Agent 在一个沙盒里自由聊天而是多个模型在代码编排下各司其职——一个做草案一个做对抗式评估一个做语言润色它们之间有明确的消息格式和通信边界。这更像是多模型流水线而不是AI 聊天室。4. AI 工程的护栏评估、追踪与质量门禁4.1 评估集不要凭感觉判断效果很多开发者在调 Prompt 时靠的是我觉得好像变好了。这是一个极其危险的习惯。模型输出是概率性的你这次看到的结果好不代表它在 100 次请求里依然好。没有量化评估就无法区分是模板变化带来了提升还是恰好抽到了运气好的样本。所以我做 AI 工程的第一件事永远是构建评估集Golden Set收集 50 到 200 条有代表性的真实输入标注好期望输出。评估集通常覆盖几个维度典型样本、边界样本、长尾噪音样本、空值/异常样本。不需要一口气做几千条50 条高质量样本起步完全够用它能让你在每一次变更后得到一个可对比的分数。评估维度不是越复杂越好。我第一版往往只看四类指标核心任务准确率、输出格式合法率、拒答/超时率、成本平均每次调用 token 数。其中输出格式合法率常常被忽视但对工程系统来说它是比准确率更底层的指标——格式不合法代码层面根本消费不了结果。我这里有一个建议把评估集固化成一个独立文件比如golden_set.jsonl并把评估脚本纳入每次迭代的标准流程。任何 Prompt 变更都先跑一遍评估集记录分数再决定是否提交。这个习惯会让你少走很多弯路。4.2 可观测性没有日志就没有改进模型推理过程就是个黑盒如果不刻意留日志出问题时你只能抓瞎。我自己做项目的铁律是从第一行代码开始就埋日志不要等上线后再补。一条完整的调用日志至少包含以下字段我先给一个字段表字段说明request_id全链路唯一 ID用来串起前后步骤prompt_versionPrompt 模板版本号方便定位效果来源input_sample原始输入或截断后的输入output模型原始输出parsed_result解析后的结构化结果latency_ms调用耗时token_count输入/输出 token 数error_type超时、解析失败、空输出等错误类别cost本次调用估算成本有了这些日志你能做三件特别有价值的事第一复盘时回放失败请求找出模型出错的具体模式第二对比不同 Prompt 版本的线上表现不只是线下评估集分数第三算清楚成本找出哪一个环节在烧钱。另外我建议单独捕获解析失败的原始输出。模型输出的 JSON 偶尔会因为一个多余注释或一个未转义字符导致解析失败如果只记解析失败这个错误类型不去保留原始文本你永远不知道模型具体是怎样偏离格式的。保留原始输出是排查一切问题的前提。4.3 质量门禁与回退策略这才是Harness Engineering的现实版最近热词里反复出现 harness engineering拆开来看harness 有套上挽具、加以控制的意思。放在 AI 工程语境里它其实就是护栏工程在拥有强大模型能力的同时建造一套约束体系让能力在可控的边界内释放。一个基本的护栏体系分三层。第一层是前置过滤在调用模型之前用规则和传统分类器拦截明显不合规的输入比如太短的无效消息、包含特定违禁词的输入、明显不在服务范围的请求。第二层是输出校验模型结果必须先经过结构校验和内容规则检查才能进入下游。第三层是兜底策略当模型输出不合法、超时、或者置信度过低时系统要有明确的回退路径比如返回通用话术、转人工、回滚到上一版结果。我举一个实际运行过的场景意图分类服务的置信度阈值设为 0.6低于这个值就默认走转人工分支。这个策略看起来简单但在线上避免了大量模型自信地给出错误结果的事故。很多人不敢做这类兜底总觉得转人工体验不好但实际情况恰恰相反——一个颤抖的可能不对的答案比坦诚的需要人工帮助更伤害用户体验。质量门禁的核心理念是不是所有模型输出都值得交给用户。你要做到的是凡是可能出错的输出在到达用户之前都被拦截或降级。这是 harness engineering 最朴素也最有效的实现。5. 从零搭建一个真实项目选题、样本、迭代与上线5.1 一个最小可用的项目骨架到这里理论讲得差不多了。我拿客服工单分类这个非常经典的任务做个完整的从零搭建演示这个任务足够简单又能覆盖 AI 工程的所有核心环节。项目目录我不想搞很复杂几个文件就够project/ ├── prompt_template.py # Prompt 模板 ├── model_client.py # 模型调用与解析 ├── golden_set.jsonl # 评估集 ├── evaluate.py # 评估脚本 ├── api_server.py # 对外服务入口 └── logs/ # 运行日志第一步先写golden_set.jsonl放 30 条真实工单字段包括input_text、expected_category、expected_priority。第二步写prompt_template.py使用我在 2.2 节里提到的五层模板结构。第三步写model_client.py封装超时、重试、JSON 解析。第四步写evaluate.py跑一遍评估集统计准确率、格式合法率。最后写api_server.py用一个 Web 框架把服务暴露出来并接入前置过滤和兜底逻辑。我特别想强调的是评估先行这一步。很多人是先写 API 再补评估集结果上线以后不知道哪个改动让效果变好还是变坏。先有评估集哪怕只有 30 条你就有了一个从零开始就存在的基准线后续所有迭代都在这个基准线上做增量比较。5.2 迭代节奏一次只改一个变量模型类项目最让人抓狂的问题是不好定位到底是哪里变了导致效果波动。我现在的做法非常严格一次迭代只改一个变量。这里的一个变量指一个明确的修改点比如把少样本示例从 1 个增加到 3 个、把 temperature 从 0.2 调到 0.1、把 JSON 输出结构里增加 summary 字段。改完之后用同一份评估集跑一遍记录分数再决定是保留还是回滚。绝对不会同时改 prompt 和模型参数否则效果波动时你根本说不清是哪个产生了影响。我还会做一份简单的实验记录表版本变更内容准确率格式合法率平均耗时结论v1初版模板82%95%850ms基线v2增加 2 个边界示例88%97%890ms保留v3减少系统指令字数86%96%840ms回滚v4temperature 降至 0.190%99%870ms保留这张表看起来简单但它解决的问题非常大它让你的项目有了记忆。三个月后回看你仍然能解释为什么模板长成现在这样哪些参数是被前人的踩坑经验锚定的哪些是后来实验验证出来的。很多 AI 项目烂尾就是因为没有这种记忆代码全成了考古现场。5.3 上线后的常见翻车点项目上线之后才真正进入 AI 工程最残酷的环节。我挑四个高频翻车点都见过不只一次。第一个是生产环境和开发环境的数据不一致。开发阶段样本可能是人工挑选的干净文本而生产环境里用户消息可能夹杂大量表情符号、错别字、链接、无关文字。这些噪音会在不知不觉中改变模型行为。对策是尽早把线上真实样本回流到评估集定期重跑分数。第二个是模型升级引发行为漂移。大模型服务商经常更新底层模型版本同一个 Prompt 在不同时间可能产生不同输出。我建议为每次调用显式固定模型版本号并在服务商有新版模型时主动做一次回归测试而不是被动等待线上出问题。第三个是成本失控。没有缓存和限流的 AI 服务很容易在流量突增时产生巨额账单。我的建议是对重复性问题做结果缓存对同一用户设置频率限制对低价值请求跳过模型直接给模板话术。第四个是失败日志不完整导致问题复现困难。很多团队在关键时刻才发现日志里没存原始输入只能等下一次故障重演。所以哪怕上线前时间再紧我也坚持把日志字段先定义完整即上一节那张表格里的字段早就不是可选项而是必填项。最后分享一个我个人的小技巧在 AI 链路前面加一层传统规则或轻量分类器把大量简单请求直接用规则处理把复杂请求才交给模型。比如工单分类中包含发票的消息大概率是发票类问题包含退款的往往与退款相关。这种规则先筛 模型兜底的混合架构能在保持效果的同时显著降低成本也能有效降低模型被简单问题打爆的风险。踩过几次坑之后我现在对AI 工程有了一种更平实的体感它不是什么高深魔法而是把用模型解决业务问题的整个过程搞得足够枯燥、足够可预测。真正的复杂度永远不在模型内部而在模型周围的那层系统——定义、评估、护栏、日志、兜底。你把这一圈做扎实了模型才真正变成你系统里可靠的那个齿轮。
返回列表