生产级 Agent 工作流上线清单
上线前先定义边界
过去两年,我见过太多团队把 Agent 从 demo 推到生产环境后才发现——模型能跑通不代表系统能用。一个在 notebook 里表现流畅的 Agent,到了真实用户手里可能因为一次工具调用失败就陷入死循环,或者在没有任何告警的情况下默默产出错误结果。
生产级 Agent 工作流的核心在于让任务边界、工具权限和失败处理都足够清楚,而非让模型更自由。上线前要确认系统能解释每一次关键动作——它为什么选了这个工具、传了什么参数、拿到了什么结果、为什么认为任务完成。如果团队无法复盘一次失败任务,就不应该让 Agent 执行高风险动作。
这篇文章整理了一份上线检查清单,涵盖目标定义、工具权限、状态管理、评测、可观测性、人工兜底和分阶段发布。清单不长,但每一项都对应着我踩过的坑或者别人分享过的生产事故。
为什么需要系统化的上线标准
LLM Agent 和传统服务的区别在于:它的行为是非确定性的。传统微服务在相同输入下产出相同输出,你可以用端到端测试覆盖主要路径。但 Agent 的每一步推理、工具选择和参数构造都是模型实时生成的,同一个任务跑两次可能走出完全不同的执行路径。
JetBrains 在 2026 年 5 月的技术博客里说得很直接:「LLM evaluation determines if the AI agent can work, while AI agent observability determines if it is working.」评测解决的是「能不能跑」的问题,可观测性解决的是「跑得好不好」的问题,两者缺一不可。
MLflow 在同年同月的文章里进一步强调:「Evaluation is not something you do before launch and then forget.」评测是贯穿整个生命周期的持续活动,而非一次性的上线门禁。Agent 上线后的评测密度应该比上线前更高,因为真实用户的输入分布永远比测试集宽。
Arthur AI 的上线清单把这个问题拆成了六个层面:全面遥测埋点、Prompt 外置管理、自动化生产评测、离线回归验证、拦截过滤器、企业合规与问责。每个层面都有具体的技术要求,不是写一段 system prompt 就能跳过的。
Azalio 则从业务视角提出了 10 条发布标准,第一条就是「定义价值指标」——在写代码之前就要回答这个 Agent 要改变什么业务指标、怎么衡量成功。如果答不出来,后面的技术工作做得再漂亮也是在空转。
上线流程全景
这条流程不是一次性的。每次扩大权限(L)都要回到监控与复盘(I),指标不达标就回滚并重新调整工具权限(B)。上线不是一个时间点,是一个持续循环。
上线检查清单
以下清单按模块组织,每项标注了检查类型和重要程度。建议作为发布门禁使用——有任何一项不通过就不应该上线。
目标与边界
| # | 检查项 | 检查类型 | 重要程度 |
|---|---|---|---|
| 1 | 任务目标是否有明确的完成标准,能用代码或规则判定 | 文档 + 代码 | 必须 |
| 2 | 是否定义了 Agent 不应该做的事情(负面边界) | 文档 | 必须 |
| 3 | 是否与业务方确认了价值指标和衡量方式 | 文档 + 会议 | 必须 |
工具与权限
| # | 检查项 | 检查类型 | 重要程度 |
|---|---|---|---|
| 4 | 每个工具是否有完整的 JSON Schema,包含参数说明和示例 | 代码 | 必须 |
| 5 | 工具是否区分读操作和写操作,写操作是否有独立权限控制 | 代码 | 必须 |
| 6 | 是否按最小权限原则分配工具访问范围 | 代码 + 配置 | 必须 |
| 7 | 高风险动作(删除、转账、发布)是否需要人工确认 | 代码 | 必须 |
状态与恢复
| # | 检查项 | 检查类型 | 重要程度 |
|---|---|---|---|
| 8 | 执行状态是否能持久化保存 | 代码 | 必须 |
| 9 | 中断后是否能从上次状态恢复,而不是从头开始 | 代码 + 测试 | 必须 |
| 10 | 是否支持状态回放,用于调试和复盘 | 代码 | 推荐 |
评测与验证
| # | 检查项 | 检查类型 | 重要程度 |
|---|---|---|---|
| 11 | 是否有覆盖主路径的自动化评测 | 代码 | 必须 |
| 12 | 是否有覆盖边界路径的评测(空结果、超时、权限不足) | 代码 | 必须 |
| 13 | 评测结果是否使用二元判定(通过/不通过),而非模糊评分 | 代码 | 推荐 |
| 14 | 是否有回归评测,每次 Prompt 或模型变更后自动运行 | CI | 必须 |
可观测性
| # | 检查项 | 检查类型 | 重要程度 |
|---|---|---|---|
| 15 | 每次 LLM 调用是否记录了 Prompt、补全内容、Token 数和费用 | 代码 | 必须 |
| 16 | 每次工具调用是否记录了参数、返回值和执行时间 | 代码 | 必须 |
| 17 | Trace 是否包含完整的推理链路(计划 → 上下文 → 工具 → 结果 → 下一步计划) | 代码 | 必须 |
| 18 | 是否有基于 Trace 的告警规则(失败率、延迟、成本超阈值) | 配置 | 必须 |
失败处理
| # | 检查项 | 检查类型 | 重要程度 |
|---|---|---|---|
| 19 | 工具调用失败时是否有重试机制,重试次数是否有上限 | 代码 | 必须 |
| 20 | 不可逆操作失败时是否有补偿或回滚方案 | 代码 | 必须 |
| 21 | Agent 是否能在连续失败后主动放弃并通知人工介入 | 代码 | 必须 |
人工兜底
| # | 检查项 | 检查类型 | 重要程度 |
|---|---|---|---|
| 22 | 用户是否能随时取消 Agent 正在执行的任务 | 代码 | 必须 |
| 23 | 是否有「人工接管」入口,接管后 Agent 是否停止自主操作 | 代码 | 必须 |
| 24 | 人工接管的操作是否会被记录,用于后续改进 Agent | 代码 | 推荐 |
发布策略
| # | 检查项 | 检查类型 | 重要程度 |
|---|---|---|---|
| 25 | 是否先内部使用,再灰度给少量用户 | 流程 | 必须 |
| 26 | 早期是否限制在只读或草稿模式 | 配置 | 推荐 |
| 27 | 每次扩大权限时,是否同步扩大了评测和监控范围 | 流程 | 必须 |
关键设计决策的代码对比
工具权限:粗粒度 vs 细粒度
粗粒度权限把所有写操作放在同一个权限桶里,一旦出现权限问题就是整类操作全部不可用或全部开放。细粒度权限按业务对象拆分,出问题时可以精确关闭单个操作而不影响其他功能。
// 粗粒度——所有写操作共享一个权限
interface AgentTools {
read: (query: string) => Promise<unknown>
write: (action: string, payload: unknown) => Promise<unknown>
}
// 权限控制只能区分读和写
if (permission === 'write') {
await tools.write('update_address', { orderId, address })
await tools.write('refund', { orderId, amount }) // 同一权限
}// 细粒度——按业务对象独立授权
interface AgentTools {
order: {
query: (id: string) => Promise<Order>
updateAddress: (id: string, addr: Address) => Promise<void>
}
refund: {
create: (id: string, amount: number) => Promise<Refund>
// 超过阈值需要人工确认
createWithApproval: (id: string, amount: number) => Promise<Refund>
}
}
// 每个操作独立鉴权
const refundTool = amount > THRESHOLD
? tools.refund.createWithApproval
: tools.refund.create失败处理:静默吞错 vs 结构化重试
静默吞错是 Agent 上线初期最常见的隐患。工具返回错误时,模型可能把它理解为「这个工具不可用」然后换一种方式重试,甚至直接跳过这个步骤。结构化重试让每次失败都有明确的分类和处理路径。
# 静默吞错——模型可能误读错误原因
try:
result = await call_tool("query_order", order_id="12345")
except Exception:
# 异常被吞掉,模型不知道发生了什么
result = {"status": "unknown"}# 结构化重试——每次失败有分类和处理策略
class ToolFailure(Exception):
def __init__(self, tool: str, error_type: str, retryable: bool):
self.tool = tool
self.error_type = error_type # "timeout" | "permission" | "not_found" | "server_error"
self.retryable = retryable
async def call_tool_with_retry(tool_name, params, max_retries=3):
for attempt in range(max_retries):
try:
return await call_tool(tool_name, params)
except ToolFailure as e:
trace.record(tool_name, attempt, e.error_type)
if not e.retryable:
raise # 权限错误不重试,直接上报
if attempt == max_retries - 1:
await escalate_to_human(tool_name, params, e)
raise
await backoff(attempt)可观测性:非结构化日志 vs 结构化 Trace
非结构化日志只能告诉你「Agent 运行了一次」,结构化 Trace 能还原完整的决策链路。两者的差别在排查问题时尤其明显——前者靠猜,后者靠证据。
# 非结构化日志——排查问题时基本靠猜
logger.info(f"Agent started for user {user_id}")
logger.info(f"Called tool: {tool_name}")
logger.info(f"Agent finished, result: {result}")
# 中间发生了什么?不知道# 结构化 Trace——每一步可追溯
trace = Trace(task_id=task_id, user_id=user_id)
with trace.span("plan") as span:
span.set("input", user_message)
plan = await agent.plan(user_message)
span.set("output", plan.steps)
for step in plan.steps:
with trace.span("tool_call") as span:
span.set("tool", step.tool_name)
span.set("params", step.params)
result = await call_tool(step.tool_name, step.params)
span.set("result", result)
span.set("latency_ms", elapsed)
trace.flush() # 写入结构化存储,支持查询和回放评测设计:模糊评分 vs 二元判定
模糊评分(比如 1-5 分)在回归评测中很难设定阈值——从 4.2 掉到 3.8 到底是正常波动还是质量下降?二元判定(通过/不通过)让每次回归都有明确信号。
# 模糊评分——阈值难以设定,波动难以解读
def evaluate_response(response: str) -> float:
score = 0.0
if "correct_format" in response:
score += 0.3
if "has_relevant_content" in response:
score += 0.4
if "no_obvious_errors" in response:
score += 0.3
return score # 3.7 算通过吗?没人知道
# 回归阈值模糊,团队经常争论
assert average_score >= 3.5 # 这个 3.5 是怎么来的?# 二元判定——每条评测有明确的通过条件
def evaluate_response(response: str, expected: dict) -> EvalResult:
checks = [
("format_valid", validate_json_schema(response, expected.schema)),
("contains_required_fields", all(f in response for f in expected.fields)),
("no_hallucinated_ids", verify_ids(response, expected.known_ids)),
("within_token_budget", count_tokens(response) <= expected.max_tokens),
]
passed = all(result for _, result in checks)
return EvalResult(passed=passed, checks=checks)
# 回归门禁清晰:任何一条不通过就阻断发布
assert all(result.passed for result in eval_results)评测和可观测性的具体指标
把评测和可观测性放在一起说,因为它们共享同一套指标体系,只是采集时机不同。评测关注的是「这批样本的整体表现」,可观测性关注的是「每一次运行的实时状态」。
| 指标类别 | 具体指标 | 采集时机 | 告警阈值建议 |
|---|---|---|---|
| 任务完成率 | 成功完成 / 总任务数 | 每次任务结束 | 低于 85% 告警 |
| 工具调用正确率 | 正确调用 / 总调用数 | 每次工具调用 | 低于 90% 告警 |
| 步骤推理一致性 | 相同输入下推理路径一致的比例 | 回归评测 | 低于 70% 需要调查 |
| 单次任务成本 | Token 消耗 × 单价 | 每次任务结束 | 超过均值 3 倍告警 |
| 端到端延迟 | 从用户输入到最终输出 | 每次任务结束 | P95 超过 SLA 告警 |
| 人工接管率 | 人工接管 / 总任务数 | 每次接管事件 | 超过 10% 需要调查 |
| 幻觉率 | 包含不可验证声明的输出比例 | 采样评测 | 超过 5% 阻断发布 |
| 忠实度 | 输出与检索文档一致的比例 | 每次 RAG 调用 | 低于 80% 告警 |
JetBrains 的文章特别提到了一个容易被忽略的点:「Small inefficiencies compound dramatically over time.」一个每次多消耗 500 Token 的冗余工具调用,在日均一万次任务的环境下,一个月下来就是一笔不小的额外开支。成本和延迟不是优化问题,是上线前就要设定的硬约束。
分阶段发布的实操建议
分阶段发布不是一句「先灰度再全量」就能概括的。每次权限变更都对应着不同的风险和不同的监控重点。
| 阶段 | 权限范围 | 用户范围 | 监控重点 | 持续时间建议 |
|---|---|---|---|---|
| 阶段一 | 只读(查询、分析) | 内部团队 | 工具调用成功率、结果准确性 | 1-2 周 |
| 阶段二 | 受限写(草稿模式) | 内部 + 少量外部用户 | 写操作错误率、用户反馈 | 2-4 周 |
| 阶段三 | 完整写操作 | 灰度用户群 | 端到端成功率、成本、人工接管率 | 4-8 周 |
| 阶段四 | 全量发布 | 所有用户 | 全量指标看板、回归评测 | 持续 |
每个阶段之间要确认当前阶段的所有监控指标都在可接受范围内,而非简单的「时间到了就放开」。Arthur AI 把这个策略叫做「progressive autonomy」——渐进式自主权。Agent 的权限增长曲线应该和团队对它行为的理解深度同步。
Azalio 的文章还提到了一个值得注意的实践:shadow deployment。在重大变更(模型升级、Prompt 重写、工具新增)时,先在 5% 的流量上跑新版本,对比新旧版本的指标差异,确认没有回归后再全量切换。这种做法在传统 ML 系统里很常见,但在 Agent 工作流里经常被忽略——可能是因为 Agent 的行为变化比传统模型更难预测。
复盘机制
上线后定期查看三类任务:失败任务、人工接管任务和用户取消任务。这三类任务对应着 Agent 能力的三个不同维度的不足。
失败任务说明 Agent 在某些场景下能力不够,需要补充工具或改进 Prompt。人工接管任务说明 Agent 能跑但跑得不好,用户不信任它的输出,需要改进推理质量或增加解释性。用户取消任务说明 Agent 的任务理解可能偏离了用户意图,需要改进输入解析或增加确认环节。
复盘的输出不应该是「下次注意」,而应该是具体的评测用例和监控规则。每一个失败样本都应该变成回归评测里的一条,每一个人工接管场景都应该触发一条告警规则的检查。
MLflow 的说法很到位:「Evaluation does not end after deployment; rather, it is intensified.」上线不是评测的终点,是评测密度增加的起点。
检查清单总结
把上面所有检查项按优先级压缩成一份快速参考。上线前逐条过一遍,任何一项不通过就不应该发布。
目标与边界
[ ] 任务目标有明确的完成标准
[ ] 定义了 Agent 不应该做的事情
[ ] 业务方确认了价值指标
工具与权限
[ ] 每个工具有完整的 JSON Schema
[ ] 读写操作独立授权
[ ] 遵循最小权限原则
[ ] 高风险动作需人工确认
状态管理
[ ] 执行状态可持久化
[ ] 中断后可恢复
[ ] 支持状态回放(推荐)
评测
[ ] 主路径自动化评测
[ ] 边界路径评测(空结果、超时、权限不足)
[ ] 二元判定替代模糊评分(推荐)
[ ] 回归评测接入 CI
可观测性
[ ] LLM 调用记录 Prompt、补全、Token、费用
[ ] 工具调用记录参数、返回值、延迟
[ ] Trace 包含完整推理链路
[ ] 配置了告警规则
失败处理
[ ] 可重试错误有重试机制,有上限
[ ] 不可逆操作有补偿方案
[ ] 连续失败后主动放弃并通知人工
人工兜底
[ ] 用户可随时取消任务
[ ] 有人工接管入口
[ ] 接管操作被记录用于改进
发布策略
[ ] 先内部再灰度
[ ] 早期限制为只读或草稿模式
[ ] 权限扩大时同步扩大监控参考资料
- Your Checklist to Launch a Production-Ready AI Agent — Arthur AI, 2026
- 10 Essential Release Criteria for Launching AI Agents — Azalio, 2026
- Building Production-Ready AI Agents in 2026 — MLflow, 2026
- LLM Evaluation and AI Observability for Agent Monitoring — JetBrains, 2026
- How to Deploy AI Agents to Production: A 7-Point Checklist — MindStudio, 2026
- AI Agent Observability, Tracing & Evaluation with Langfuse — Langfuse, 2026
- Evaluation-Driven Development and Operations of LLM Agents — arXiv, 2025
- Human Judgment in the Agent improvement loop — LangChain, 2026