ARTICLE DETAIL

资讯详情

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

AI工程从零到落地:Prompt、Agent、Harness与评测全链路解析

AI工程从零到落地:Prompt、Agent、Harness与评测全链路解析 很多人对“ai-engineering-from-scratch”这个项目标题的第一反应是觉得又是一套关于怎么调用大模型API、怎么堆几个Agent的教程合集。但真正动手做过一轮之后我倾向于把它理解为一条“从会用AI到能交付AI工程”的完整爬坡路径。这个项目标题想解决的问题很直接一个没有AI工程背景的人怎么从零开始建立起一套能支撑真实业务的技术栈和思维方式。如果你正在做AI应用开发、想转型AI工程方向或者只是被铺天盖地的Agent概念搞得有点焦虑这篇文章应该能给你一个相对清晰的路标。1. 先想清楚AI工程化到底是“写模型”还是“写系统”1.1 大多数人一开始就搞错了切入点我见过大量刚开始接触AI工程的人第一反应都是扑向模型本身——去学Transformer结构、去推导注意力机制、去复现训练脚本。这些内容当然有价值但如果你是奔着“用AI解决业务问题”去的这种做法往往事倍功半。在“ai-engineering-from-scratch”这个框架里AI工程的核心不是训练模型而是构建围绕模型的系统。打个比方模型像一台发动机工程化则是整车的底盘、传动、刹车、仪表盘和驾驶逻辑。没有发动机车跑不起来但只有发动机你也哪里都去不了。这个项目想给你补的恰恰是“整车组装”的能力。它包含三个层次应用层怎么把LLM大语言模型嵌入到具体业务流里完成摘要、抽取、生成、对话等任务。编排层怎么让多个AI组件协同工作怎么设计Agent的行为边界怎么处理状态流转。工程层怎么评测质量、怎么跟踪成本、怎么做回归测试、怎么上线后持续观测。如果你带着这三个层次去读代码和文档会发现很多项目的结构突然变得清晰起来。真正的AI工程永远是围绕系统建模型而不是围绕模型建系统。1.2 为什么叫“from scratch”而不是“from tutorial”项目标题里的“from scratch”值得细品。它不是说把Transformer从零手写一遍而是说从零开始建立工程判断力。你在网上能找到几十套关于Prompt的模板也能找到各种Agent框架的QuickStart但当你面对一个真实需求时最难的从来不是“调用哪个API”而是这个需求适不适合用AI解决适合用什么规模的方案输出质量怎么定义谁来验收误判成本有多高用户的异常输入怎么兜底错误信息怎么回退延迟和成本怎么平衡是换小模型、改Prompt还是加缓存这些决策没有任何QuickStart能替你回答。它们只能靠你在足够多的真实项目中踩出来。而“ai-engineering-from-scratch”路线图的核心价值就是把这些决策场景系统性地铺开给你看让你少走一些我当年绕过的弯路。2. 第一块基石提示词工程不是“写指令”是“定义接口”2.1 把Prompt当作函数签名来设计很多人对提示词工程Prompt Engineering的理解停留在“把话说清楚、把例子给足”的层面。这个理解没错但在真正的AI工程里Prompt的角色要严肃得多——它其实是你和模型之间的接口约定。就像写代码时你不会随便定义一个函数签名设计生产级Prompt时你也不能靠临场发挥。我常用的设计套路是四件套角色与目标模型以什么身份解决什么问题。输入结构待处理的数据放在哪里字段叫什么。输出契约输出格式、字段名、边界条件最好给出JSON Schema或范例。约束与兜底遇到超出范围的内容怎么说“不知道”而不是硬编。一个典型的例子把普通指令式Prompt改成结构化接口式Prompt你是一名中文医疗科普编辑。 任务基于用户提供的检查报告摘要生成一段面向普通患者的解读。 输入格式 {“检查项目”: “...”, “结果”: “...”, “参考范围”: “...”} 输出要求严格遵守 1. 输出JSON对象包含两个字段 - summary: 一段不超过150字的通俗解读避免直接给出诊断结论。 - risk_level: 取值只能是“low”、“medium”、“high”之一。 2. 若输入信息不足以判断risk_level返回“unknown”summary说明“需要更多信息”。 3. 严禁出现“疑似癌症”“不排除恶性”等容易引发恐慌的表述。 输入 {“检查项目”: “空腹血糖”, “结果”: “7.2 mmol/L”, “参考范围”: “3.9-6.1 mmol/L”}你看这其实就是在定义一个有输入、有输出、有异常分支的函数。把Prompt当成接口来设计之后后续的评测、版本管理、自动化测试才可能做起来。如果你的Prompt还是大白话聊天模式说明你还没进入工程化状态。2.2 少样本示例与“思维围栏”技巧很多人知道要放在少样本示例Few-shot里给模型看例子但给例子的方式有讲究。我在实践中有一个很深的心得示例的作用不只是告诉模型“输出长这样”更是划定一个“思维围栏”。什么意思比如我要让模型把一段口语化的用户投诉转成结构化工单负面示例和正面示例要成对出现。只给正面示例模型容易形成刻板模仿给一组“错误示范原因说明”模型能更快学到边界。举个例子不要这样转换原因丢失了用户的时效性诉求 用户原话“你们这个破网速晚上根本刷不动视频三天了还没解决气死我了。” 错误工单{“问题类型”: “网络故障”, “紧急程度”: “低”} 请这样转换原因保留时间敏感度紧急程度升级 用户原话“你们这个破网速晚上根本刷不动视频三天了还没解决气死我了。” 正确工单{“问题类型”: “网络故障”, “紧急程度”: “高”, “关键词”: [“三天”, “晚上”, “视频卡顿”]}这种“正反示例对”的做法比单纯堆十来个正面示例的稳定性和泛化性好得多。它相当于在Prompt里给模型画了一条隐形的护栏让模型知道哪些信号是必须被捕捉的。还有一个很容易被忽略的细节输出契约里要给“不知道”留位置。很多Prompt翻车不是模型能力不行而是指令里没有设计“无法回答时怎么办”的分支。模型在被迫给答案和给空结果之间大概率选择给一个看起来像答案的幻觉内容。所以设计接口时请一定加上“unknown”或者“无法判断”的合法返回值。3. 从单点调用到多步骤流程Agent与Harness Engineering的实战意义3.1 Agent的本质是“循环 工具 边界”聊完了Prompt就该进入最近被反复提及的Agent了。很多人把Agent想象得很神秘仿佛它是一个会自己思考的数字生命。但从工程视角看Agent的实现本质就是一套循环接收任务 - 调用模型决策下一步 - 执行工具 - 把结果反馈给模型 - 再次决策 - ... 直到满足终止条件关键在于这个循环里的“模型决策”不是没有边界的自由意志。它受三样东西约束系统Prompt里的角色和目标这是Agent的宪法。可用的工具清单这是Agent的双手你给什么工具它才能用什么工具绝不能让它无限接入。终止条件达到什么状态算完成任务、最多迭代多少轮、遇到什么信号必须停下来求助。我在实际项目中踩过最大的坑就是没想清楚“边界”就直接上复杂Agent结果模型在工具链里反复横跳既浪费Token又得不到结果。后来我把Agent拆成“两段式”才稳定下来第一段先做任务规划把子任务拆成清单第二段再逐项执行每项执行都走独立的Prompt。这种做法牺牲了一点端到端的流畅性但换来了可观测性和可控性。3.2 Harness Engineering给Agent戴上“笼头”现在来聊一个在中国开发社区里相对不常见、但在AI工程一线非常重要的概念——Harness Engineering。老外常说的“harness”中文直译是“马具”或“笼头”意译过来就是“控制框架”。在老牌软件测试语境里test harness指的是驱动被测组件的整套脚手架。在AI工程语境里harness engineering是指构建一套外围机制让语言模型的行为被约束、被观测、被评估。为什么需要harness因为裸调LLM的工作流是不可靠的。模型输出有随机性提示词稍有扰动结果就可能漂移。所以AI工程里的harness通常包含这些组件上下文装配器Context Assembler负责把系统指令、用户输入、检索结果、历史记录按固定顺序装配成模型输入。输出解析器与验证器Parser Validator负责把模型输出解析成结构化数据并按Schema校验。安全网关Guardrails负责拦截模型可能输出的不合规内容直接替换成预设回复。评测集Eval Set一组固定的输入-期望输出对用于每次改动后跑回归。拿CodeBuddy这类AI编程助手举例它的harness工程就体现在代码补全时自动带出相关文件作上下文对生成的代码做静态检查还要把用户的选择行为反馈到后续的排序模型里。这些功能任何一个都不是靠单条Prompt能实现的而是靠harness层层包裹的结果。**为什么说理解harness是“from scratch”路线里的分水岭**因为一旦你能画出自己应用的harness架构图你就具备了把AI当“可替换组件”来对待的工程眼光。你会开始关注“模型换掉之后我的系统还有多少能复用”而不是“我该怎么调这个模型让它听话”。3.3 手搭一个简版Harness的骨架不依赖任何重量级框架你也可以用几十行代码搭一个最小可用的harness骨架。下面是Python伪代码思路突出结构而不是完整实现from typing import TypedDict, Literal, Any import json class AgentInput(TypedDict): task: str context: dict history: list[dict] class AgentOutput(TypedDict): status: Literal[success, need_more_info, failed] result: Any reasoning: str def build_prompt(user_input: AgentInput) - str: # 固定装配顺序系统指令 - 少量示例 - 上下文 - 用户任务 - 输出契约 system load_system_prompt() examples load_few_shot_examples() contract load_output_contract() return \n\n.join([ system, examples, f上下文: {json.dumps(user_input[context], ensure_asciiFalse)}, f任务: {user_input[task]}, f输出契约: {contract} ]) def parse_and_validate(raw: str) - AgentOutput: try: data json.loads(raw) assert set([status, result, reasoning]).issubset(data) return data except Exception: return {status: failed, result: None, reasoning: 输出解析失败可能是模型返回了非JSON内容} def harness_run(user_input: AgentInput) - AgentOutput: prompt build_prompt(user_input) raw call_llm(prompt) # 你的模型调用封装 output parse_and_validate(raw) if output[status] failed: # 兜底走重试或降级路线而不是直接把错误抛给用户 return fallback_handler(user_input) return output这个骨架看起来简单但它帮你固定了三件重要的事输入永远有标准结构、输出永远有校验逻辑、失败永远有兜底路径。任何基于LLM的应用先套上这个骨架再谈功能优化稳定性会有一个显著的提升。4. 工具链怎么选从CodeBuddy这类助手到自建Pipeline4.1 用好AI编程助手的正确姿势国内开发者手里的AI辅助工具越来越多了CodeBuddy这类助手已经不只是自动补全代码而是在往“harness engineering全流程”的方向演化。我自己的经验是要用好这类工具得从“让它替我想”转变成“让它替我执行我定义好的操作”。什么叫“定义好的操作”比如我经常让CodeBuddy做这一组事按现有代码风格给新增接口补单元测试定位某个特定异常堆栈在源码里的上下文把一段冗余的SQL改写成参数化查询并保持语义一致。你会发现这些任务都有一个共同点目标明确、验收标准明确、边界明确。它们不需要AI“创造”只需要AI“执行”。在没有AI助手的时候这些工作消耗的纯机械时间最多也正是AI编程助手价值最大的地方。如果你想让AI助手在工程层面发挥更大价值建议试一下“提示词驱动的代码审查”Review以下diff你是团队里最严格的资深工程师关注点依次是 1. 并发安全是否存在竞态条件或数据不一致风险 2. 错误处理异常路径是否都被覆盖是否存在吞异常 3. 可测试性这段代码能不能轻松构造单元测试 4. 性能问题是否隐藏的O(n^2)循环或重复查询 输出格式按严重程度排序每条问题给出[文件:行号]和修复建议最后给出“可以合并/需要修改”的结论。实测下来这种受限定的审查请求比笼统的“帮我review一下代码”能产出的有效建议多得多。4.2 自建Pipeline的四个关键组件工具助手能提升单点效率但要想让AI能力真正进入你的业务系统还是得自建Pipeline。我推荐的起步组合是组件选型思路避坑要点编排框架首选轻量多不要一上来就上重型框架先自己写几十行循环理解原理后再上框架比较踏实框架不是万能的底层逻辑是循环模型服务兼顾效果与成本复杂任务用大参数模型高频低难度任务可以切小模型做模型路由而不是全部打向满配模型缓存层语义缓存用向量相似度匹配历史问答注意缓存命中率评测命中率上不去等于白做观测平台记录每次请求的Prompt、输出、耗时、Token消耗、用户反馈没有观测就没有迭代基础这里我要特别强调一下“模型路由”的价值。很多团队在成本账单出来之前都觉得一个强大模型走天下最省事。实际上真实业务里大量请求是简单抽取、格式化、关键词映射根本不需要满配模型。做一个基于输入特征的轻量路由先用分类模型判断任务难度再决定分发到哪个模型长期省下的成本非常可观。4.3 从零落地时我建议的第一条完整路线如果你是第一次搭AI工程的完整链路我的建议是不要贪多先把下面这条“最小闭环”跑通准备一个真实场景比如“FAQ问答客服助手”语料是现有的帮助文档。做检索增强而不是直接让模型硬答把文档切块、做向量化用户提问时先检索Top-K相关片段再把片段和问题一起交给模型生成回答。加上评测脚本准备50-100条黄金问答对每次调整后跑一遍算准确率和“答非所问”率。接上日志与反馈记录用户的点赞、点踩、追问转成下一次评测集的素材。这条路线麻雀虽小五脏俱全。它涵盖了一个AI工程系统最核心的四个环节输入处理、检索增强、生成、评测反馈。跑通它你对“AI工程”四个字的感知会从“玄学”变成“工程”。5. 没有评测机制你的系统就是一块漂移的浮冰5.1 评测集是AI工程的“方向盘”做AI应用最让人头疼的一件事就是感觉“时好时坏”。上周验证通过的方案这周换个用户输入就翻车。没有评测机制你就永远在“调参数”和“碰运气”之间徘徊。评测集Eval Set就是你的方向盘。它不需要一开始就追求大而全但必须有代表性。我建评测集的原则是从真实日志里选而不是自己编。先跑一版系统把用户真实提问记录下来从中筛选出高频常见问题的样本边界条件空输入、超长输入、明显恶意输入容易混淆的相近问题历史上导致过翻车的回归样本。每次改Prompt或者升级模型先把整个评测集跑一遍对比各种指标。这个过程很枯燥但它决定了你的系统是“越用越好”还是“越改越玄”。5.2 多维度的质量指标别只看单点准确率很多初学者习惯用“答对了没有”来评判AI输出质量但工程上这个标准太粗糙。我在实践里至少会看四个维度正确性核心信息是否准确有没有事实性错误。完整性用户问的三个问题是不是只回答了两个。规范性输出格式是否符合要求字段是否都在。安全性有没有违规内容、有没有价值观不可控的表述。多维度评测意味着你要在评测脚本里定义清晰的语言规则而不是依赖人工主观打分。可以用一个简单的评分Prompt让模型来给模型的输出打分LLM-as-a-Judge但要注意定期抽样做人工复核防止裁判模型本身有偏见。提示评测集不是一次建完就结束的。每发现一个新问题就把它加入评测集。这样你的系统会像滚雪球一样越来越稳定。所谓的“越用越聪明”本质上是评测集在变厚。5.3 线上观测与离线评测要双轨并行最后聊一个我从“测试开发”视角带过来的习惯离线评测负责把好质量关线上观测负责发现未知问题。离线评测跑的是固定集解决的是“这次改动有没有让旧能力退步”线上观测则是看实时日志里的失败模式负责捕捉“用户还有哪些需求是我没覆盖到的”。两件事配合起来你才能形成一个完整的迭代闭环线上日志发现问题 - 人工分析确认模式 - 构造新评测样本加入离线集 - 修改Prompt或调整流程 - 跑全量回归 - 发布上线 - 继续观测如果你现在做的AI应用还没有建立这个闭环那“从零开始”就还没有真正结束。工程化不是一个结果而是一套不断循环的机制。就我个人经验而言什么时候你开始为“评测样本太少”而焦虑而不是为“模型不够聪明”而焦虑什么时候你就算真正踏进AI工程的门槛了。
返回列表