尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

从Prompt工程到系统化评测:构建生产级Agent的工程实践

从Prompt工程到系统化评测:构建生产级Agent的工程实践 1. 从“炼丹”到“工程”Agent评测的范式转移最近和几个做AI应用的朋友聊天发现一个挺有意思的现象。大家聊起Agent智能体开发话题总是迅速滑向“Prompt工程”——怎么设计系统提示词、怎么用思维链Chain-of-Thought、怎么让模型更好地调用工具。仿佛Agent的好坏全系于Prompt这一根弦上。这让我想起几年前做传统软件测试如果有人说“我们软件质量全靠测试用例写得好”你肯定会觉得哪里不对。测试用例是方法是工具但它背后需要一套完整的质量体系、评测标准和工程实践来支撑。“不是靠Prompt”这个标题恰恰点破了当前Agent领域一个普遍的认知偏差。我们花了太多精力在“前端”的交互设计上却忽视了“后端”的工程化评测。一个能说会道的Agent未必是一个可靠、高效、可维护的智能体。真正的挑战在于当你的Agent不再是一个简单的聊天机器人而是一个需要自主理解目标、规划步骤、调用工具、处理异常并完成复杂任务的“数字员工”时你如何系统地评估它的能力、稳定性和业务价值我最近深度参与了一个大规模Agent重构与评测项目核心代码库经历了超过31万行的重构。这不是一次简单的代码优化而是一次从评测理念到工程实践的彻底革新。整个过程让我深刻体会到脱离系统化评测的Agent开发就像在黑暗中造车你可能造出了一辆外形炫酷的跑车但根本不知道它的发动机是否可靠、刹车是否灵敏、能否安全抵达目的地。今天我就结合这次实战抛开那些玄乎的Prompt技巧聊聊Agent评测里那些实实在在的“工程活”。2. 重构的起点为什么31万行代码必须推倒重来项目初期我们有一个已经运行了半年多的Agent系统接入了多个大模型能够处理数十种任务类型从简单的信息查询到需要多步工具调用的流程自动化。表面上看它运行得“不错”能回答大部分问题。但当我们试图将它部署到对稳定性和准确性要求极高的生产环境时问题接踵而至。2.1 “不错”背后的混乱旧系统的四大顽疾第一评测手段极度匮乏且主观。当时的“评测”基本等于人工抽查。产品经理或工程师随机输入几个问题看看回答“像不像那么回事”。没有量化指标没有回归测试A工程师觉得好的回答B工程师可能认为不及格。这种主观性导致迭代方向模糊今天优化Prompt让任务A成功率提升明天可能无意中让任务B彻底失效。第二代码结构耦合严重无法隔离评测。Agent的核心逻辑、工具调用、状态管理、Prompt模板全部搅在一起。你想单独测试“在给定正确工具参数的情况下Agent能否正确调用工具”对不起你必须启动整个应用模拟完整对话。这种高耦合度使得编写低成本、高并发的单元测试或集成测试几乎不可能。第三缺乏可复现的评测环境。大模型的输出具有随机性即使温度设为0也可能因服务端变化而产生差异外部工具API可能不稳定网络会有延迟。我们的旧系统没有对这些变量进行控制和隔离导致每次测试结果波动巨大无法判断性能变化是源于我们的代码改进还是外部因素的噪音。第四没有基准Benchmark和持续集成CI。我们不知道系统的“基线”性能是多少因此任何改动都无法评估是进步还是退步。代码提交后没有自动化的测试流水线来保障核心能力不被破坏。这四大问题让我们的Agent项目陷入了瓶颈。每次发布新版本都提心吊胆所谓的“优化”更像是一种赌博。于是我们下定决心启动了一次以“可评测性”为核心目标的重构。31万行的改动首要目的不是增加新功能而是为这个复杂的智能系统建造一个精密、可靠的“质检中心”。2.2 重构的核心原则关注点分离与接口标准化重构不是蛮干。我们确立了几个核心原则将Agent“原子化”把庞大的Agent拆解成独立的、可测试的组件。例如意图识别模块、规划器模块、工具执行模块、状态管理模块、响应生成模块。定义清晰的接口每个模块之间通过明确定义的API函数接口或消息协议进行通信。这允许我们在测试时轻松地用模拟对象Mock替换真实模块。状态外部化将Agent的对话历史、执行状态等从内存中剥离存入结构化的存储如数据库。这使得我们可以随时保存和加载某个特定的测试状态实现测试的完全复现。配置驱动将Prompt模板、模型参数、工具配置等全部抽取为外部配置。评测时我们可以固定所有配置只改变需要测试的变量。举个例子旧代码中工具调用可能是这样的高度简化伪代码def handle_user_query(query, conversation_history): # 1. 拼接Prompt内含历史、查询和可用工具描述 prompt build_prompt(historyconversation_history, queryquery, toolsget_all_tools()) # 2. 调用大模型 response call_llm(prompt) # 3. 解析响应可能包含工具调用指令 if “action” in response: tool_name parse_tool_name(response) tool_args parse_tool_args(response) # 4. 直接执行工具 result execute_tool(tool_name, tool_args) # 5. 再次拼接Prompt将结果反馈给模型...这段代码里Prompt构建、模型调用、工具查找与执行全部耦合。重构后我们将其拆解# 模块1规划器 (Planner) class Planner: def plan(self, state: AgentState) - Plan: # 返回一个包含下一步行动如调用工具X的计划对象 pass # 模块2工具执行器 (ToolExecutor) class ToolExecutor: def execute(self, tool_call: ToolCall) - ToolResult: # 纯执行不关心上下文 pass # 模块3状态管理器 (StateManager) class StateManager: def update(self, old_state: AgentState, action: Action, result: ActionResult) - AgentState: pass # 主流程变得清晰且可测试 def agent_step(state: AgentState): plan planner.plan(state) # 可单独测试Planner if plan.action “call_tool”: result tool_executor.execute(plan.tool_call) # 可单独测试Executor new_state state_manager.update(state, plan.action, result) # 可单独测试StateManager return new_state通过这样的重构评测就可以针对每个模块精准进行。我们可以给Planner注入不同的状态测试其规划是否合理可以给Executor一个模拟工具测试其调用逻辑是否正确而无需连接真实的、可能不稳定外部API。3. 构建Agent评测体系从单元到场景的立体化评估重构只是打下了地基真正的评测体系需要在这地基上建造起来。我们的评测体系是一个金字塔结构从底层的单元测试到中间层的集成与组件测试再到顶端的端到端E2E场景测试。3.1 单元测试验证“齿轮”的精度单元测试针对最小的代码单元函数、类方法。在Agent上下文中这包括工具函数测试清洗输入参数的函数、解析模型输出的函数、计算相似度的函数等。这些测试不依赖模型是确定性的。模块接口测试确保每个模块如Planner, Executor的输入输出符合接口规范。例如即使Planner内部逻辑复杂我们也可以测试当输入状态包含目标“查询天气”和位置“北京”时它输出的Plan对象中action字段是否等于“call_tool”tool_call.name是否等于“get_weather”。注意单元测试要避免测试“大模型本身的能力”。例如不要测试“给定一个关于天气的提问Planner能否生成正确的工具调用指令”因为这依赖于模型的推理能力是不确定且昂贵的。我们应该测试的是给定一个明确的、结构化的“意图表示”这是上游模块的输出Planner的逻辑能否正确工作。这意味着我们需要在测试中“模拟”Mock上游的意图识别模块给它提供我们预设的、确定的输入。3.2 集成与组件测试检查“传动装置”的协同这一层测试模块之间的交互。我们使用大量的模拟Mock和桩Stub来替代外部依赖。模拟大模型LLM Mock这是最关键的一步。我们构建了一个LLM Mock服务它可以被配置为针对特定的输入Prompt返回我们预先定义好的、确定的输出。例如当测试“规划-执行”流程时我们配置Mock当收到包含“帮我订一张明天从上海到北京的机票”的Prompt时永远返回一个结构化的JSON{“action”: “call_tool”, “tool”: “book_flight”, “args”: {…}}。这样我们就隔离了模型的不确定性专注于测试我们自己的业务逻辑是否正确处理了这个结构化的决策。模拟外部工具Tool Mock同样我们模拟所有外部API。模拟的航班查询工具永远返回固定的航班列表模拟的支付工具永远返回“支付成功”。这保证了测试的稳定性和速度且能轻松模拟各种边界和异常情况如网络超时、API返回错误码。测试覆盖的关键路径完整任务流从用户输入到多轮工具调用到最终答案生成。全程使用Mock验证状态流转是否正确。错误处理与重试模拟工具调用失败验证Agent是否按预设策略如重试、切换工具、向用户求助进行处理。上下文管理测试Agent在多轮对话中是否正确地记住和引用了历史信息。我们为这些集成测试建立了数百个测试用例每个用例都是一个独立的、可配置的“剧本”Scenario定义了初始状态、一系列模拟的交互和最终的期望状态。3.3 端到端E2E场景测试在“真实路况”下试车单元和集成测试保证了内部逻辑的坚固但Agent最终要面对真实世界。E2E测试就是在尽可能真实的环境下对完整系统进行测试。这里我们无法完全Mock但要有控制地引入真实组件。使用稳定的模型版本在E2E测试中我们会连接一个真实的大模型API如GPT-4但固定其版本和参数如temperature0, top_p1。我们定期例如每天对一批核心场景进行E2E测试记录成功率、延迟等指标形成趋势图。这能帮助我们察觉因模型服务方更新带来的隐性变化。沙盒环境对于外部工具我们搭建了沙盒Sandbox环境。例如一个“发送邮件”的工具我们配置它只发往一个内部的测试邮箱一个“操作数据库”的工具我们给它一个完全隔离的测试数据库。这样既能测试真实的集成又不会产生副作用。评测指标量化E2E测试的输出不再是简单的“通过/失败”而是一系列量化指标指标说明测量方法任务完成率在N个测试场景中完全达成预设目标的比例。人工或规则判定最终输出是否满足需求。步骤效率完成一个任务所需的平均对话轮数或工具调用次数。记录轨迹并分析越少越好。工具调用准确率在需要调用工具的场景中正确调用工具且参数无误的比例。对比实际调用与预期调用。幻觉率模型生成与提供工具/知识无关的错误信息的比例。针对知识性任务进行判定。平均响应时间从用户提问到收到最终回答的平均耗时。性能监控。我们为每个指标设定了基线Baseline和警戒线。任何代码提交如果导致关键指标如任务完成率显著下降例如超过5%都会在CI/CD流水线中触发失败警报。4. 评测基础设施让31万行代码的回归测试在10分钟内完成拥有成百上千个测试用例后另一个工程挑战出现了如何快速、可靠、低成本地运行它们尤其是当测试需要调用哪怕是Mock的LLM接口时传统的测试运行方式可能慢得无法接受。4.1 测试执行引擎的定制化开发我们没有直接使用标准的 pytest 套件来运行所有测试因为我们需要更精细的控制和并行化。我们开发了一个轻量级的测试执行引擎它的核心设计是描述式测试用例每个测试用例不再是一段Python函数代码而是一个YAML或JSON文件描述测试场景。# 一个测试用例示例 id: test_weather_inquiry description: “测试简单天气查询任务” initial_state: user_query: “北京今天天气怎么样” available_tools: [“get_weather”] mock_configurations: llm_mock: # 当收到包含“北京”“天气”的Prompt时返回以下结构化动作 when_prompt_contains: [“北京”, “天气”] return_action: “call_tool” return_tool: “get_weather” return_args: {“city”: “北京”} tool_mock: “get_weather”: return: {“city”: “北京”, “condition”: “晴”, “temperature”: “22°C”} expectations: - agent_final_response_should_contain: [“晴”, “22°C”] - tool_called: “get_weather” - tool_called_with_args: {“city”: “北京”}这种描述式的方式让非工程师如产品经理、标注人员也能参与贡献测试场景极大丰富了测试集。并行执行与缓存执行引擎可以并行运行数百个独立测试用例。更重要的是它对LLM Mock的调用结果进行了缓存。因为Mock的响应是确定的输入Prompt相同输出必然相同所以首次运行后结果就被缓存。后续运行相同测试时直接读取缓存避免了不必要的模拟网络开销使测试套件的运行时间从小时级缩短到分钟级。动态测试集管理引擎支持按标签如unit,integration,e2e,critical筛选测试用例。在CI流水线中每次代码提交会快速运行所有单元测试和关键集成测试约1-2分钟。每晚的定时任务则运行完整的测试集包括耗时的E2E测试并生成详细的评测报告。4.2 持续集成/持续部署CI/CD流水线的深度集成评测不是独立的活动它必须融入开发流程。我们将评测体系深度集成到了GitLab CI/CD流水线中提交前检查Pre-commit Hook开发者提交代码前自动运行代码风格检查和快速的单元测试。合并请求Merge Request门禁当发起一个合并请求时CI流水线自动执行运行所有单元测试和集成测试。运行受影响模块相关的组件测试。如果改动涉及核心Agent逻辑还会从核心场景测试集中抽样运行一部分E2E测试。只有所有测试通过且关键业务指标通过测试场景计算得出未下降代码才被允许合并。这从根本上防止了破坏性改动进入主分支。每日健康报告每日凌晨流水线执行全量测试包括连接真实模型和沙盒工具的E2E测试生成一份包含所有量化指标趋势的报告发送给团队。任何指标的异常波动都会高亮显示。这套基础设施的建立使得我们面对31万行重构代码时心里有底。每次改动都有成千上万个“数字质检员”在帮我们验证系统的稳定性。5. 超越正确性评测Agent的“智能”与“体验”通过上述工程化手段我们基本解决了Agent的“可靠性”和“稳定性”评测问题。但一个“不犯错”的Agent未必是一个“好用”的Agent。这就进入了更主观、但也更关键的领域如何评测Agent的“智能程度”和“用户体验”5.1 基于LLM-as-a-Judge的自动化评估对于任务完成质量、回答的有用性、连贯性等难以用规则衡量的方面我们引入了“LLM-as-a-Judge”模式。具体做法是对于一个测试场景我们不仅定义“正确”的结果还定义更详细的评估标准Evaluation Rubric。例如对于一个旅行规划Agent标准可能包括“行程合理性”、“信息完整性”、“符合用户预算偏好”、“格式清晰度”。在自动化测试中当Agent运行完毕后我们会将用户原始问题、Agent的实际回答、以及评估标准一同提交给另一个大模型我们通常使用比被测Agent更强的模型如GPT-4让它扮演裁判根据标准对回答进行打分例如1-5分并提供简短的评语。我们将这些分数和评语记录到数据库中进行长期追踪。实操心得LLM-as-a-Judge的稳定性是关键。我们采取了以下措施(1) 使用固定的、强大的模型作为裁判(2) 设计清晰、无歧义的评估标准和提示词(3) 对同一回答让裁判模型评估多次取平均分以减少随机性(4) 定期抽取样本进行人工复核校准裁判模型的评分标准。虽然这仍然有主观成分但相比完全人工评估其规模化和一致性是数量级的提升。5.2 人工评估与众包获取真实用户反馈自动化评测无法完全替代人的感受。我们建立了定期的人工评估机制内部专家评估每周产品、研发、测试的同事会组成评估小组随机抽取一批最新的用户真实对话脱敏后或测试用例输出从“任务完成度”、“回答质量”、“交互自然度”等多个维度进行打分和讨论。这能发现自动化测试无法捕捉的细微问题比如语气生硬、逻辑跳跃等。众包评估对于更通用的能力我们会将一批任务和Agent的响应发布到专业的众包平台如Amazon Mechanical Turk让真实用户按照我们的评估指南进行评分。这为我们提供了来自更广泛人群的、相对客观的用户体验数据。5.3 可视化与可解释性让评测结果“看得见”评测的最终目的是指导改进。如果只有一堆数字和图表工程师很难定位问题。因此我们开发了配套的可视化调试工具。轨迹查看器Trace Viewer对于任何一个测试用例无论是通过的还是失败的我们都可以打开一个Web界面清晰地看到Agent执行的完整“思考轨迹”它接收到的用户输入、内部的状态变化、每一步的规划决策、调用了什么工具及参数、工具返回的结果、以及最终生成的回答。这就像给Agent装了一个“黑匣子”任何故障都可以回溯。对比分析工具支持将同一个测试用例在不同代码版本例如重构前和重构后下的执行轨迹并排对比高亮显示差异。这让我们能直观地看到优化到底带来了哪些行为上的改变。6. 重构与评测带来的实际收益与未来挑战历时数月的重构与评测体系建设带来的改变是深刻的。6.1 可量化的收益缺陷逃逸率降低上线后由用户反馈的严重问题数量下降了70%以上。大部分逻辑错误在合并请求阶段就被拦截。迭代速度加快因为有了可靠的测试护栏开发者敢于进行更激进的重构和优化功能迭代的平均周期缩短了约30%。性能基线清晰我们首次能够明确地说出“我们的Agent在涵盖10大类、200个核心场景的测试集上任务完成率为92.5%平均响应时间为2.3秒”。这为产品规划和客户承诺提供了坚实依据。团队协作改善评测体系成为了产品、研发、测试团队的共同语言。产品需求可以更容易地转化为可测试的场景测试结果也能直观地反馈给产品作为改进依据。6.2 持续的挑战与下一步当然挑战依然存在评测集的完备性如何设计一套真正能全面反映Agent复杂能力的评测集仍然是一个开放问题。我们正在探索结合自动化生成利用LLM生成边缘测试用例和众包收集的方式不断扩充和更新我们的“考题库”。长上下文与长期记忆的评测对于需要处理超长对话历史或具有长期记忆能力的Agent如何设计有效的评测场景是一个难点。多模态与具身Agent当Agent的感知和行动从纯文本扩展到图像、声音乃至物理世界时评测的复杂度和成本将呈指数级上升。这是我们未来需要重点探索的方向。回过头看“不是靠Prompt”并非否定Prompt的重要性。恰恰相反一套强大的评测体系能让我们更科学、更高效地优化Prompt。它把原本玄学的“调参”和“炼丹”变成了一个可观测、可度量、可复现的工程过程。31万行重构的代价不小但它为我们换来的是一个更稳健、更透明、进化速度更快的Agent系统。对于任何志在构建生产级AI应用而非仅仅做出一个演示Demo的团队来说在Agent评测上的工程投入迟早会成为那条区分“玩具”与“工具”的关键分水岭。
返回列表