传统软件开发有一条被广泛接受的公理:软件的生命周期包括需求、设计、开发、测试、部署、运维。每个阶段有明确的方法论、工具和最佳实践。你写一个Web服务,不会写完代码直接扔到生产环境——你会写测试、做代码审查、配置CI/CD、监控运行状态。
但Agent开发呢?
2024年的大部分Agent项目,生命周期是这样的:写Prompt → 手动聊几轮 → 感觉不错 → 部署 → 等用户投诉。测试靠感觉,部署靠手动,监控靠运气。
这不是因为开发者懒惰,而是因为Agent的生命周期管理在工程上确实很难。传统软件的"正确性"是确定的(输入A应该输出B),Agent的"正确性"是概率性的(输入A,大多数时候应该输出B,但有时输出C也说得过去)。这给生命周期的每个阶段都带来了新的挑战。
本节将Agent的生命周期分为四个阶段——构建、测试、部署、监控——逐一讨论每个阶段的核心活动和特殊挑战。理解这个生命周期,你就理解了Harness各模块在时间维度上是如何组织起来的。
构建阶段的目标是:创建一个能满足需求的Agent原型。你定义Agent的角色和能力边界,编写系统提示词,选择和实现工具,搭建核心循环。
第一:定义Agent的职责边界。
这是构建阶段最容易被跳过的一步。一个Agent不能做所有事。你需要明确:
这些决策直接写入系统提示词。写得不清楚,Agent在边界场景中就会做出不可预测的行为。
第二:选择模型。
不同的模型有不同的能力特性。你需要考虑:
注意:构建阶段选择的模型不是最终答案。在测试阶段,你可能会对比多个模型的表现。构建阶段的重点是先跑通,而非选最优。
第三:编写系统提示词。
系统提示词是Agent的"宪法"——它定义了Agent的身份、行为准则、工作流程和边界。一个好的系统提示词至少包含以下部分:
第四:实现工具。
根据Agent的职责,实现它需要的工具。每个工具需要:
构建阶段的工具实现不需要完美,但Schema必须认真写——它直接影响LLM的工具选择质量。
陷阱一:过早优化。 在原型还没跑通之前就纠结于"工具的超时应该设为多少秒"这类细节。正确的顺序是:先跑通,再度量,再优化。
陷阱二:职责膨胀。 用户在构建过程中不断提出"能不能也做这个",Agent的职责范围不断扩张,最终变成一个什么都做但什么都做不好的庞然大物。保持职责聚焦。
陷阱三:忽视边界测试。 构建阶段只测试"正常路径"(用户输入标准格式,一切顺利),从不测试"异常路径"(用户输入模糊、工具返回异常、超时)。等到上线后,用户会用你从未想过的方式使用Agent。
测试阶段的目标是:在部署之前,尽可能系统地发现和修复Agent的问题。 这是Agent生命周期中最关键的阶段,也是最被低估的阶段。
第一层:单元测试——测试工具和组件。
工具函数的测试相对直接:给定输入,检查输出是否正确。这与传统软件的单元测试类似。
def test_get_weather():
result = get_weather("北京")
assert "北京" in result
def test_calculate():
result = calculate("(3+5)*2")
assert "16" in result
但Agent的单元测试不止于此。你还需要测试工具Schema的质量:LLM是否能正确理解每个工具的描述和参数?这需要用一个测试LLM来验证:给LLM一个用户输入,检查它是否选择了正确的工具和参数。
第二层:端到端测试——测试完整的Agent行为。
这是Agent测试的核心。你构建一个评估数据集,包含一组输入和对应的期望行为,然后让Agent在数据集上运行,度量各项指标。
评估数据集的设计是第7章的主题。这里先建立一个基本认知:
一个好的评估数据集应该覆盖:
第三层:对抗测试——寻找意外行为。
对抗测试的目标是故意让Agent失败。你扮演一个"恶意用户"或"意外用户",尝试诱导Agent做出不当行为:
对抗测试不是为了让Agent变得完美——它不可能完美——而是为了了解Agent的失败模式和边界,从而在部署前采取防护措施。
测试阶段的产出
评估数据集(初始版本)
Agent在评估集上的得分报告
已知的失败模式和边界
修复后的系统提示词和工具(可能经过多次迭代)
测试阶段的常见陷阱
陷阱一:用"感觉"代替"度量"。 "我觉得Agent表现不错"不是一个可验证的结论。你需要数字:任务完成率、工具调用准确率、平均循环次数。
陷阱二:测试集与真实使用脱节。 评估数据集中的问题都是开发者自己编的,可能与真实用户的实际使用方式有很大差异。评估集需要持续更新,加入真实使用中遇到的问题。
陷阱三:忽视回归测试。 你修了一个bug,但可能引入了三个新bug。每次修改后,都需要在评估集上完整跑一遍,确认整体表现没有退化。
部署阶段的目标是:将经过测试的Agent投入生产环境,供真实用户使用。 这个阶段的核心挑战是:Agent在开发环境中表现良好,但在生产环境中可能面对完全不同的条件。
第一:部署形态。
Agent可以以多种形态部署:
不同形态对Harness的要求不同。API服务需要关注并发和可用性,消息机器人需要关注会话管理,后台任务需要关注失败恢复。
第二:隔离与沙箱。
生产环境中的Agent必须运行在受控的隔离环境中。工具的执行不应该直接影响宿主系统。如果Agent需要调用一个"删除记录"的工具,这个工具应该有独立的权限控制——不是Agent说删除就删除。
常见的隔离策略:
第三:版本管理。
部署的每一个Agent都应该有明确的版本标识。这个版本包含了:
当Agent在生产中出现问题时,你需要知道是哪套配置出了问题,以及如何回滚到之前的版本。
第四:灰度发布。
不要一次性把所有流量切到新版本。先让新版本处理小部分请求(比如5%),观察表现,再逐步放量。灰度发布是Agent部署中最重要的实践——因为Agent的行为在真实流量下是不可完全预测的,小范围验证能避免大范围的灾难。
部署阶段的产出
部署阶段的常见陷阱
陷阱一:开发与生产环境的差异。 开发环境中用的模型、工具、数据与生产环境不同,导致Agent行为差异。尽量保持环境一致,或者至少在评估时考虑环境差异。
陷阱二:忽视冷启动问题。 Agent在刚启动时可能需要加载工具定义、连接外部服务、初始化记忆系统。如果冷启动时间过长,用户会感知到明显的延迟。
陷阱三:一次性全量部署。 在测试集上表现良好的Agent,在真实流量下可能遇到完全不同的输入分布。灰度发布是Agent部署的底线,不是可选项。
监控阶段的目标是:在Agent运行过程中持续跟踪其表现,及时发现退化、异常和风险。 这是Agent生命周期中最长的一个阶段——从部署到退役,Agent都处于监控之中。
第一:性能监控。
第二:质量监控。
第三:安全监控。
第四:漂移监控。
生产环境中的每一次Agent运行,都不可能进行完整的质量评估(太昂贵)。实际的监控做法是采样:从生产流量中抽取一部分(比如5%),对这些样本进行自动化评估。
采样评估可以回答:
第9章会详细讨论可观测性的实现。这里先建立认知:监控不是简单的"记录日志",而是一套持续运行的评估机制。
监控发现异常后,需要告警。告警的阈值设计是一门艺术:
建议的告警阈值设定:
陷阱一:只看技术指标,不看用户反馈。 延迟和吞吐很重要,但最终评判Agent价值的是用户。如果用户不喜欢Agent的回答方式,即使所有技术指标都很好,这个Agent也是失败的。
陷阱二:告警设置后就不管了。 告警规则需要持续调优。第一次设置的阈值往往是拍脑袋,需要根据实际运行情况调整。
陷阱三:监控数据不用于改进。 监控收集了大量数据,但如果这些数据不回流到构建和测试阶段,监控就是纯粹的浪费。监控的最终目的是改进,而不是记录。
四个阶段不是一条直线,而是一个循环:
构建 → 测试 → 部署 → 监控
↑ │
└────── 改进 ←───────┘
监控阶段发现的问题,成为下一轮构建和测试的输入。评估集中加入新的失败案例,系统提示词和工具被修订,新版本经过测试后再次部署,然后继续监控。
这个闭环每转一圈,Agent的质量就提升一点。没有这个闭环,Agent开发就是一次性行为——部署之后就听天由命。有了这个闭环,Agent开发才成为真正意义上的"工程"。
现在回头看Harness的各模块,你会发现它们在生命周期中各有其位:
Harness不是某一个阶段使用的工具,而是贯穿整个生命周期的基础设施。 理解了生命周期,你就理解了为什么Harness需要包含这些模块——因为Agent在每个阶段都需要特定的支撑能力。
Agent的生命周期包括构建、测试、部署、监控四个阶段。每个阶段有各自的核心活动和特殊挑战:
生命周期不是线性的,而是一个持续迭代的闭环。监控阶段的数据必须回流到构建和测试阶段,Agent的质量才能持续提升。
在下一节中,我们将用一个核心术语表来总结第2章涉及的所有关键概念,为进入第3章的实际构建做好准备。
评论专区
评论加载中...登录后即可发表评论