智能体开发与评估闭环:LlamaAgents+Promptfoo+GPT-5.4打造文档分类与邮件生成流水线 前阵子一位做客服系统的朋友问我手上攒了一批历史工单想搞一个智能体会自动把每张单据分类再按类别起草回复邮件的流程有没有一套完整、能落地的方案。我给他的建议很简单——别自己拼一套临时脚本直接用LlamaAgents Builder负责智能体搭建和编排用Promptfoo做全流程评估底模统一走GPT-5.4。这套组合拳的好处在于从文档分类数据到邮件撰写从提示词设计到质量指标整个链路是可复现、可回归、可量化的而不是靠肉眼抽查效果。这篇文章就是我把整个开发与评估过程完整走一遍的记录适合正在做Agent应用、但不知道如何把开发和评估串起来的开发者也适合想给团队搭一套标准化Agent交付流程的朋友。看完你就能照着搭出一个自己的文档分类与邮件生成流水线并且能明确说出我这个版本比上一个版本好在哪里。1. 为什么是构建器 评估器 模型三件套而不是一个框架搞定一切先澄清一个常见误区很多人以为做AI智能体就是选一个Agent框架把工具接上然后就能交差。但真正进入线上环境后你会发现开发一个智能体其实只占了整个工作量的三成剩下七成是在验证它、测试它、迭代它。LlamaAgents Builder、Promptfoo、GPT-5.4这三个东西分别对应搭建能力、验证能力、推理能力它们不是一个框架的三个模块而是三个互相独立、又能通过标准接口组合的环节。1.1 这三者各解决什么问题LlamaAgents Builder的价值在于把Agent的开发从写死状态机变成声明式编排。你不需要手写一堆循环调模型的胶水代码通过配置就能定义Agent的姓名、工具、输出结构、执行顺序。它对普通开发者的意义类似于Git相对于手动复制文件夹——不是不能手动做而是有了约定和框架之后出错和返工的概率大幅下降。Promptfoo解决的是我怎么知道新版本真的更好了这个难题。它是一个专门针对LLM应用的开源评估框架可以批量跑测试用例、定义断言、对比不同模型和不同提示词的效果并且能接入CI做回归测试。它和LlamaAgents Builder是天然互补的Builder负责把Agent造出来Promptfoo负责把Agent考一遍。GPT-5.4在这里的角色就是底模。整个流程里所有分类判断、邮件草稿生成都由它完成。我选择它作为统一的模型后端是因为在文档分类这类需要结构化输出的任务上它输出JSON格式的稳定程度明显更好而且在邮件这种长文本生成场景下不太会偏离语气约束。当然实际项目中你也可以在Promptfoo里同时配置多个模型做AB对比这件事后面会专门讲。1.2 一个完整Agent项目的真实生命周期从项目的角度拆解真正完整的工作流长这样定义场景与数据域比如把工单分为账单咨询、技术支持、合作意向、投诉四类在LlamaAgents Builder里创建Agent挂上工具、设定输出协议准备一份有代表性的评估数据集用Promptfoo写配置文件跑第一轮评估根据评估结果回头调整提示词或Builder配置再跑一轮多轮迭代直到指标达标把Promptfoo配置接入CI做持续回归上线后持续收集badcase补充进测试集注意第5步到第6步实际上会循环很多次。如果你跳过了第3步和第4步直接进入上线看效果那你会陷入一种地狱模式每天靠人工点开日志看几条结果既说不清整体质量也说不清每次修改到底提升了什么。所以这篇文章把开发和评估并列放在标题里不是并列关系而是迭代闭环关系。1.3 为什么选文档分类数据 邮件撰写当切入点文档分类是典型的结构化输出任务特别适合拿来验证Agent的执行协议能力邮件撰写则是典型的非结构化生成任务适合验证Agent的风格遵循能力。把两者串起来就成了一个非常经典的两阶段Agent流水线先分类、再生成。这个结构在企业场景里非常常见——客服工单处理、合同初审、需求分诊基本都是先判断再响应的逻辑。学会这一套后面迁移到任何类似场景都不需要从零开始。2. 用LlamaAgents Builder搭出第一个文档分类智能体LlamaAgents Builder有两种上手方式一种是在它的可视化界面里拖拽配置另一种是直接用Python SDK写声明式配置。我个人强烈建议直接选第二种原因很简单可视化界面方便演示但版本管理、代码审查、团队协作都不方便写式配置才能进Git。注意这里的Builder更像一个强大的构建器模式——它把Agent的各个部分抽象成可配置的模块而不是让你从无到有地写实现。2.1 先想清楚分类协议再动键盘动手之前必须把输入什么、输出什么定死。很多人在这一步偷懒导致后面评估时根本没法自动化断言。我是这样定义的输入一条工单的原始文本至少包含问题描述可选附带渠道来源输出一个JSON对象包含category、confidence、reason三个字段类别体系billing账单咨询、tech_support技术支持、cooperation合作意向、complaint投诉这里特别要说一个细节业务类别体系必须是你自己定死的不能交给模型自由发挥。如果模型发现某条内容不像这四个类别之一它可以输出低置信度并标记category为unknown但绝不能自己发明一个refund之类的类别出来。这个边界在系统提示词里要写清楚在输出协议里也要用约束语法限制住。2.2 用Builder声明式定义一个分类Agent下面是构建文档分类智能体的核心配置我用的是LlamaAgents的Python SDK写法from llama_agents import LlamaAgentsBuilder, AgentConfig builder LlamaAgentsBuilder() builder.add_agent( AgentConfig( namedoc_classifier, description对输入的文档内容进行类别判定输出JSON格式的类别标签, system_prompt你是一个企业内部工单分类器。 规则 1. 只允许输出以下类别之一billing, tech_support, cooperation, complaint 2. 如果内容明显不属于任何一个类别输出 unknownconfidence 必须低于 0.5 3. 输出必须是合法JSON不允许输出任何额外文字 4. confidence 表示你对分类判断的确定程度范围0到1 5. reason 用一句话概括你的分类依据供后续人工复核使用, tools[], output_schema{ type: object, properties: { category: { type: string, enum: [billing, tech_support, cooperation, complaint, unknown] }, confidence: {type: number}, reason: {type: string} }, required: [category, confidence, reason] } ) ) app builder.build()看到没output_schema这部分是关键。它告诉底层模型你必须按这个结构输出在实践里这比在提示词里写一百遍请输出JSON都管用。除了Schema约束system_prompt里的规则3不允许输出任何额外文字也很重要——如果你不写这句模型经常会在JSON前面加一句好的我来分析一下这个问题这对于给人看的场景无所谓但对于自动化管道来说就是灾难。2.3 跑通分类链路从一次调用到完整管道定义完Agent之后实际调用逻辑很简单result app.run(客户反馈扣款金额和上月账单对不上实际多扣了18元要求退回。) print(result) # 期望输出结构示例 # { # category: billing, # confidence: 0.95, # reason: 用户提到扣款金额与账单不一致属于账单咨询范畴 # }但这里我想强调管道思维上面的app.run虽然一次就返回结果了但在真实业务里文档分类Agent往往是管道中的一个节点。前一级可能是从邮件附件、钉钉消息、历史Excel中解析出文本后一级可能是把分类结果写入数据库再触发邮件撰写Agent。LlamaAgents Builder的好处在于它把这些节点也抽象成了可编排的组件。你可以先不急着接数据库和后端先把本地的输入输出跑通再逐步替换成真实数据源。2.4 边界问题没见过的类别和模棱两可的文本我实测下来文档分类Agent最容易翻车的是两类输入一是内容完全不在这四个类别里二是同时包含多个类别信息。比如一条工单同时抱怨账单扣错和系统登录不了模型经常会纠结。我的处理办法是在系统提示词里增加一条如果内容同时命中多个类别选择语气更强烈、或者和钱相关的优先级更高的类别对于前一种冲突明确允许输出unknown并让置信度低于0.5供人工队列兜底在评估阶段专门准备一批这样的棘手样本这一点非常重要下一节重点讲顺带说一句如果你的文档数量大、类别体系复杂比如几十类建议别一次塞给模型让它直接判断而是把类别体系拆成分层判断先粗分类再细分类。这个技巧放到后面邮件场景同样适用。3. Promptfoo介入把分类质量变成可以被追问的数字Builder把Agent造出来了但看起来能用和确实能用之间隔着一道鸿沟。要跨过这道鸿沟我推荐直接把Promptfoo接进来。它做的事就三个批量跑测试、验证输出、出报告。简单说它就是LLM应用的自动化测试框架持续集成工具。3.1 评估数据集从哪里来别自己拍脑袋编测试用例很多人第一次用Promptfoo会随手写几条测试样例。我建议直接打消这个念头。正确做法是从真实数据里抽样从历史工单里随机抽100条作为主测试集额外手工构造20条边界样本多条类别混淆的、错字和口语化的、超长的、只有一两句话的再从历史里挑出10条之前人工标注为疑难的样本把这130条样本整理成统一的JSON格式字段包含document和expectedCategory。注意一点expectedCategory不应该只写最终类别如果某条工单本身就有争议可以写成数组表示可接受的多标签结果但Promptfoo断言里要能支持这个逻辑。为什么要强调从真实数据抽因为AI应用的评估最怕幸存者偏差。你用自己写的干净样例测结果全绿一上线收到真实噪音数据立刻崩溃。我自己经历过一次测试集里全是标准书面语线上日常全是口语缩写分类准确率从96%直接掉到61%。所以从第一天起评估数据就必须和线上真实分布贴近。3.2 用promptfooconfig.yaml把Agent接进评估系统Promptfoo通过一个YAML配置文件描述测试任务。贴一个我当时实际用的配置做了脱敏简化prompts: - file: prompts/classify.txt providers: - id: openai:gpt-5.4 config: temperature: 0.2 response_format: type: json_object defaultTest: options: # 从输入变量里取文本稳定传给模型的字段 vars: document: {{document}} tests: - vars: document: 客户反馈扣款金额和上月账单对不上实际多扣了18元要求退回。 assert: - type: equals value: billing - type: is-json - type: llm-rubric value: 针对账单扣款问题的工单分类必须为billing不能因为用户语气强硬就归为complaint - vars: document: 我的账号登录不上一直提示密码错误麻烦尽快处理。 assert: - type: equals value: tech_support # 这里放一条边界样本 - vars: document: 你们到底怎么回事扣错了钱还让我自己提交工单太离谱了 assert: - type: equals value: complaint - type: llm-rubric value: 用户表达强烈不满且指控平台责任应归类为投诉complaint而不能只看扣款字眼就归为billing配置里几个值得细说的点response_format强制JSON输出配合Builder里的output_schema双保险temperature设成0.2因为分类任务是确定性任务不要让它自由发挥断言里的equals比contains严格得多equals要求值和期望完全一致contains只要包含关键字就行。分类任务必须用equalsllm-rubric类型是让另一个LLM判断输出是否满足自然语言规则它是处理微妙语义的好工具跑评估的命令也一并给出来npx promptfoo eval -c promptfooconfig.yaml --output report.json npx promptfoo vieweval执行测试并输出报告view会在浏览器里打开一个可视化面板可以按用例逐个看输入、输出、断言结果。实测下来第一次跑到分类准确率大约在85%左右主要丢分点就是1.2节说的多类别混合和口语化噪音文本。3.3 评估报告怎么看准确率只是及格线Promptfoo的默认报告会给你一个通过率但只看通过率远远不够。我把每次报告里额外记录的三类指标列出来它们对后续迭代影响最大指标计算方式我设定的参考阈值类别准确率分类正确的用例数 / 总用例数≥ 95%格式合法率输出能被JSON解析的用例数 / 总用例数100%高置信错误率模型给出高置信度但分类错误的用例数 / 总用例数≤ 2%高置信错误率是我个人非常看重的一个指标。它的意义在于低置信度错误可以通过人工兜底拦截高置信度错误则是系统自信地犯错最危险。如果这个指标超过2%说明你的提示词和类别体系存在系统性误导必须回到2.2节的Agent配置里去修。3.4 用Promptfoo做AB实验别凭感觉换模型或换Prompt一个特别常见的操作是朋友说换个模型效果更好或者你改了句话感觉NB了但没有验证就上线了。我的原则是任何一次修改都要能在Promptfoo里跑出对比报告。Promptfoo允许你在同一个配置文件里定义多个provider和多个prompt组合跑完之后它会把结果列成矩阵直接对比旧提示词旧模型、新提示词旧模型、新提示词新模型的性能。比如想比较GPT-5.4和某个开源模型在providers里追加一个配置然后跑一遍promptfoo eval报告里就能看到同一批测试用例在不同模型下的通过率差异。这个方法成本极低却能避免团队里我觉得式的争吵。4. 第二站邮件撰写智能体的搭建与提示词工程细节文档分类Agent跑通且评估通过之后接下来做邮件撰写智能体。这一步的重点不再是分类正确而是在正确分类的约束下生成一封语气合适、信息准确、结构完整的邮件草稿。4.1 先定数据流协议分类结果不能只是给人看的两个Agent的衔接最容易出问题的就是数据流设计。很多人会把分类Agent的结果直接拼进邮件提示词里比如用户是billing类请回复。这样做不是不行但丢失了很多信息。我推荐的协议是把分类结果的三个字段都传下去category决定邮件整段的语气和主题confidence决定邮件的坚定程度低置信度时语气更谨慎、更需要引导用户补充信息reason给邮件撰写Agent提供一个为什么这么分类的上下文避免它误解原文这个设计有一个额外好处当分类Agent出错时邮件Agent其实有机会纠偏。比如分类结果是complaint但reason里写着用户主要是询问扣款明细那么邮件Agent可以察觉到矛盾主动生成更中性的开场白。这是在真实业务里非常有价值的一层容错。4.2 创建邮件撰写Agent并和分类Agent连接在LlamaAgents Builder里把第二个Agent加进来同时建立两个Agent之间的上下游关系mail_agent AgentConfig( namemail_writer, description根据文档分类结果与原始内容撰写邮件回复草稿, system_prompt你是一名企业客服邮件撰写助手。 流程 1. 你会收到原始用户消息和分类Agent给出的分类结果 2. 根据分类结果选择语气 - billing清晰说明金额核算方式不要擅自承诺退款 - tech_support以排查步骤为主先让用户提供必要信息 - cooperation保持专业礼貌引导商务沟通 - complaint先表达重视和歉意再说明处理流程 - unknown以询问更多细节为主不做出任何承诺 3. 邮件必须包含三部分称呼、正文、落款 4. 正文不超过150字使用简洁中文 5. 如果原始消息包含金额、订单号等关键信息必须在邮件中复述一遍 ) builder.connect(doc_classifier, mail_agent, transfer_fields[category, confidence, reason])connect这一步是关键它定义了分类Agent的输出字段如何传递给邮件Agent。如果后续想改成三阶段流程比如中间加一个人工审核节点只需要在connect链里再插入一个组件即可这就是用Builder做编排的核心收益。4.3 邮件模板与动态生成如何平衡实测三种写法邮件撰写场景里最大的坑是模板化太重显得死板自由化太强容易跑偏。我实测过三种做法直接给结论写法优点缺点适用场景纯动态生成只给规则让模型自由发挥语气自然、灵活容易遗漏必要信息偶尔失控不重要的场景纯模板每个类别一套固定文案替换变量稳定、可控、合规千篇一律对复杂情况不友好合规要求极高动态生成 结构约束当前推荐兼顾自然与稳定需要多花时间调试提示词大多数业务场景我最终采用的是第三种。具体做法是系统提示词里强约束邮件结构但不约束具体句子同时在提示词末尾塞入一段必要信息清单由模型自己从原文里提取金额、单号等关键信息。这样既保证了不同类别的语气差异又不会漏掉关键信息。4.4 兜底规则不是所有输入都适合直接生成邮件邮件写给人看出错了比分类错了更严重。所以我会在邮件Agent前加一道闸门如果分类置信度低于0.4邮件Agent的输出必须带上需要您补充更多信息的开场白如果原文包含明显的辱骂或人身攻击内容模型检测到后应生成转人工处理的短邮件如果原文本检测不到任何业务关键信息例如只有你好邮件Agent应回复引导而不是硬凑内容这些规则可以用一段独立的审核Prompt实现也可以在邮件Agent的系统提示词里写死。我的建议是作为独立审核节点先用一个规则模型判断触发条件再决定走哪条分支。这样邮件Agent保持纯净后续也方便在审核节点里加敏感词过滤、合规检查等能力。5. 融合验收分类质量是如何连带影响邮件生成的现在两个Agent都搭好了Pipeline也跑通了接下来是很多人会忽略的一步端到端验收。你要证明的是整个输入工单 - 输出邮件草稿的流水线比单独的分类正确率 邮件生成质量两个指标更可靠。因为分类一旦出错后面的邮件写再好也无济于事。5.1 给整条流水线设计端到端断言我在Promptfoo里为邮件Agent新增了一组测试输入是原始工单文本期望输出则关注三个层面邮件是否包含关键业务信息、语气是否匹配正确的分类预期、是否包含了不该出现的承诺。tests: - vars: document: 客户反馈扣款金额和上月账单对不上实际多扣了18元要求退回。 assert: - type: llm-rubric value: 邮件中必须提到18元或扣款金额的具体信息并且将问题定性为账单核实不得直接承诺退款 - type: contains value: 尊敬的用户 - type: llm-rubric value: 邮件语气应该中立、友善不能因为用户是投诉类信息就变得过于卑微或过度道歉注意这里我故意没有断言分类结果因为端到端检查里真正关心的不是Agent内部把文本归为哪一类而是最终邮件有没有回应正确的问题。如果分类错了但邮件仍然正确回应了用户这在业务上其实是成功的只有分类错了且邮件也跟着错才是必须捕获的badcase。5.2 一个典型回归案例分类误导直接导致邮件语气崩坏我在融合测试阶段抓到过一个很有代表性的badcase。输入是一段很长很详细的账单询问工单分类Agent正确输出了billing但置信度只有0.52比较低。按照我的兜底规则置信度低于0.4才触发询问更多信息所以它没触发邮件Agent又严格按照billing必须谈金额核对的语气生成了邮件。结果用户真正想表达的其实是账单错误投诉客服态度差邮件完全没有回应情绪。人工一看就觉得不对劲但自动化检查里分类和格式都全通过。这个案例给我的教训是兜底阈值要绑定真实业务风险不能拍脑袋定。后来我把低置信度触发值从0.4提到0.6并且增加了若文本同时出现情绪词邮件语气自动降一级的规则这类问题大幅减少。这也是为什么要强调端到端评估而不是只看单点指标。5.3 每次修改都跑一遍回归把Promptfoo接入工作流我现在的习惯是每次改提示词、改输出协议、换模型版本都会跑一遍完整的Promptfoo回归并且把通过率变化记录在旁边的注释里。更正式的项目会让CI在每次Pull Request时自动执行promptfoo eval如果分类准确率或邮件合规率低于基线构建直接失败。这套做法成本很低但收益极大。它把我觉得改好了变成数据证明改好了也让后来接手的人不用翻聊天记录就能知道每个Prompt版本的真实表现。5.4 成本与延迟估算全流程跑一次到底值不值最后估算一下这整套流程的消耗。我以自己的测试集规模130条分类用例 80条邮件用例实测GPT-5.4接口按输入输出token计费单条文档分类平均消耗约500 token单条邮件生成平均消耗约900 token全流程跑一轮评估大约消耗 130×500 80×900 13.7万token按当前价格粗算一次完整回归测试的成本在个位数人民币左右对比人工审查每条邮件的时间成本这点token成本完全可以忽略。真正要控制成本的地方是频繁迭代——如果一天改10次每次都全量回归累计起来也不少。我建议开发阶段用小规模冒烟集比如30条确认改动方向没问题后再跑全量回归。6. 实际踩过的坑和效率技巧6.1 结构化输出解析失败的三种原因与对策即使配置了response_format和output_schema我仍然遇到过非零星的解析失败。总结下来就三类原因模型在某些边界case里输出里出现了Markdown代码块标记比如把JSON包在json里中文引号、全角逗号把JSON搞得不合法极端情况下模型拒绝输出JSON输出了一段道歉文字对策分三层首先在系统提示词里加不允许使用Markdown代码块标记其次在接收端做一次清洗把首尾的代码块标记剥掉再交给解析器最后一定要在Promptfoo的断言里加上type: is-json让这类问题立刻暴露而不是等到生产环境。如果模型频繁输出不合法JSON优先怀疑你的输出协议设计有问题而不是怀疑模型能力。6.2 断言别只写关键字匹配用rubric处理语义正确我见过太多人在Promptfoo里写contains: billing这种断言。它的问题是即使分类正确邮件正文里完全没有billing这个词断言照样失败反过来如果模型在邮件里说请不要回复billing断言反而通过。所以我的经验是结构化字段用equals自然语言质量用llm-rubric安全合规用自定义JavaScript断言。三种断言各管一摊不要图省事全部用contains。6.3 测试集里不要混入你的示例prompt有个魔鬼细节很多人会把开发时用来调试的那几条示例也加进测试集。看起来没什么但这些示例通常是你精心构造的、最能体现Prompt能力的样例把它们放进测试集会让通过率虚高。正确的做法是让测试集只包含模型没见过的真实或模拟数据如果你发现自己总能在测试集里拿到满分大概率是测试集泄露了提示词信息。6.4 可视化Builder和代码同步的版本管理如果你团队里有人习惯用LlamaAgents Builder的可视化界面编辑配置一定要约定好导出的配置文件必须提交到Git任何人改动都要同步。我们遇到过最尴尬的事有人在线编辑器里调了参数效果很好但忘了导出结果本地的代码版本完全没包含那个改动白忙活半天。现在我们的约定是可视化编辑器只用来预览和快速实验一旦确定参数必须落到代码里再跑一遍Promptfoo验证。还有一个关于Prompt迭代的小技巧Prompt的版本号不是v1、v2、v3这样的数字而应该和它的行为挂钩。比如我每次修改提示词都会在本地的Promptfoo报告里记录这一版比上一版在高置信错误率上降低了1.2%这些记录最终会成为你写技术总结、向上汇报、以及向新同事解释系统设计时的第一手素材。我在实际做这个项目时最深的体会是真正让一套Agent系统稳定可用的不是某个华丽的提示词技巧也不是哪个更强的模型而是一条能快速发现哪里坏了的评估链路。LlamaAgents Builder负责让构建变得高效GPT-5.4负责让效果达到可用线Promptfoo负责让每个改动都可验证。三者缺一不可。如果你手头也有分类生成这类两阶段Agent要做建议你今天就从搭建评估测试集开始哪怕Agent本身还没写评估先行后面每一步你都会走得更踏实。