AI 助手最危险的不是报错,而是"看起来成功":我给工作流加了四道保险
AI 助手真正让人头疼的时刻,往往不是页面上弹出一个红色错误,而是它安静地告诉你:已经完成。
文件确实生成了,但里面少了一半内容;消息确实发出去了,但收件人不对;表格确实更新了,但同一条记录出现了两次;文章确实提交了,可平台保存的正文是空的。
这些都不是传统意义上的"失败"。请求可能返回了 200,工具可能返回了 success: true,模型也可能给出一段看起来非常完整的总结。但从用户结果来看,事情并没有真正完成。
我后来给自己的 AI 工作流加了一个简单原则:
任何动作都不能只凭"调用成功"判定完成,必须经过结果验证。
再往前走一步,如果验证失败,还要有清楚的回退路径:重试、换工具、查状态、保留现场,或者停下来请人确认。
这套方法不依赖某个具体模型,也不限定某个 Agent 框架。只要工作流会读文件、写数据、调用网页或发送消息,就值得加上这几道保险。
一、为什么"成功"会骗人
一个完整的自动化动作,至少包含三层结果:
text
请求是否发出
↓
服务是否接受
↓
用户要的结果是否真的产生
很多工具只告诉你前两层。
例如,调用"创建文档"接口后返回了一个文档 ID,只能说明服务端接受了创建请求。它并不能证明正文已经完整写入,更不能证明标题、代码块和链接都正确。
同样,调用模型后拿到一段文字,只能说明模型生成了输出。它不能证明输出满足任务要求,更不能证明模型替你执行了文件写入、网页操作或消息发送。
我现在会把"动作成功"拆成四个问题:
- 请求有没有发出去?
- 服务端有没有接受?
- 结果是否完整?
- 结果是否符合用户目标?
前三个可以由程序检查,第四个有时需要人工确认。
二、第一道保险:给结果定义"完成标准"
没有完成标准,就没有真正的验证。
"生成一篇文章"这个要求太模糊,程序无法判断什么叫完成。换成可检查的标准就清楚多了:
- 标题不能为空;
- 正文达到最低长度;
- 一级标题数量不低于某个值;
- 代码围栏必须成对;
- 关键章节必须存在;
- 链接不能被截断;
- 正文不能只是错误提示或登录页面。
一个文件任务可以这样定义:
python
from pathlib import Path
def verify_article(path: str) -> tuple[bool, list[str]]:
file = Path(path)
issues = []
if not file.exists():
issues.append("文件不存在")
return False, issues
content = file.read_text(encoding="utf-8").strip()
if len(content) < 2000:
issues.append("正文长度不足")
if not content.startswith("# "):
issues.append("缺少一级标题")
if content.count("`" * 3) % 2 != 0:
issues.append("代码围栏没有成对出现")
return not issues, issues
这段代码并不智能,却比一句"请确认文章已经生成"可靠得多。
验证规则不用一次写得很复杂。先覆盖最容易出错的地方,再根据真实问题逐步补充。重点是把"我觉得应该完成了"变成"这些条件都满足了"。
三、第二道保险:把读取结果当成不可信输入
AI 工作流经常要读取网页、文档或接口返回值。这里有一个容易踩的坑:读取成功,不代表读取到的是目标内容。
网页可能返回验证码页面,接口可能返回错误对象,文档可能只加载了前半部分,登录过期后也可能得到一个状态码正常的跳转页。
所以我会同时检查状态和内容:
python
def verify_page(status_code: int, text: str) -> tuple[bool, str]:
if status_code != 200:
return False, f"HTTP 状态异常: {status_code}"
body = text.strip()
if len(body) < 200:
return False, "正文过短"
blocked = ("人机验证", "登录后继续", "请求频繁")
for marker in blocked:
if marker in body:
return False, f"疑似拦截页面: {marker}"
return True, "ok"
检查内容时,不能只看长度。一个几万字的错误页面仍然是错误页面。更实用的方式是组合几种信号:
- 状态码;
- 内容长度;
- 页面标题;
- 目标关键词;
- 错误关键词;
- 数据结构是否能正常解析。
对于 JSON 响应,还要区分"能解析"和"业务成功"。
python
def verify_response(data: dict) -> tuple[bool, str]:
if not isinstance(data, dict):
return False, "返回值不是对象"
if data.get("err_no") not in (None, 0):
return False, data.get("err_msg", "业务错误")
if not data.get("data"):
return False, "缺少业务数据"
return True, "ok"
AI 助手越能操作外部世界,越不能把"有返回值"当成"返回值可信"。
四、第三道保险:写操作必须防重复
读操作失败,最多是没有拿到结果;写操作失败,可能留下重复结果。
这是我在自动化流程里最重视的一类问题。
假设创建记录的请求已经在服务端执行成功,但客户端因为网络超时没有收到响应。此时直接重试,就可能出现两条完全相同的记录:
text
客户端发起创建
↓
服务端创建成功
↓
响应返回途中超时
↓
客户端误以为失败
↓
再次创建
↓
重复记录
因此写操作不能只有"失败重试",还需要三步保护:
1. 执行前查重
根据标题、主题、内容摘要或业务编号,先查有没有相同对象。
2. 使用幂等标识
同一个动作生成固定的请求标识。即使客户端重复提交,服务端也能识别这是同一次操作。
3. 执行后回查
如果响应丢失,先查询最终状态,再决定是否补偿,不要直接重新创建。
可以把这个过程抽象成:
python
def safe_create(find_existing, create, key):
existing = find_existing(key)
if existing:
return existing, "already_exists"
result = create(key)
if result is not None:
return result, "created"
# 创建结果不确定时,先回查,不直接重试
existing = find_existing(key)
if existing:
return existing, "confirmed_after_timeout"
return None, "needs_review"
这个逻辑看起来比"失败后再试一次"麻烦,但外部系统最怕的就是重复创建。多花一次查询的成本,通常比后面清理重复数据划算。
五、第四道保险:让每次回退都有边界
回退不是无限重试。
如果一个任务失败后一直自动重跑,系统可能陷入三个循环:
- 同一个错误重复请求,浪费调用额度;
- 写操作重复提交,制造脏数据;
- 模型不断改写内容,却离用户目标越来越远。
我会给回退动作设置三个边界。
次数边界
同一路径最多重试一到两次。超过次数就切换路径或停止。
成本边界
优先使用低成本回退:重新读取、缩小任务、检查登录态,然后才考虑切换浏览器或更重的模型。
风险边界
读操作可以自动重试;写操作需要先查状态;发布、发送、删除等外部动作,最好停在人工确认点。
一个简单的回退决策可以是:
text
读取失败 → 短暂重试
仍然失败 → 换读取方式
内容疑似不完整 → 保留现场并重新校验
写入结果不确定 → 查询状态
外部发布前 → 人工确认
真正稳定的系统,不是拥有最多备用方案,而是知道什么时候应该停止自动化。
六、人工确认不是流程失败
很多人搭 Agent 时,会把人工确认看成自动化不够彻底。我的看法正好相反:在高风险动作前保留确认点,是流程设计成熟的表现。
可以把任务分成三类:
低风险:可以自动完成
- 读取文件;
- 搜索资料;
- 生成草稿;
- 做格式检查;
- 输出分析报告。
可逆:自动完成,但保留版本
- 修改本地草稿;
- 生成新的适配版本;
- 更新工作区内的文档;
- 整理目录和日志。
外部影响:默认需要确认
- 发布文章;
- 发送消息;
- 更新共享表格;
- 删除数据;
- 修改公网配置。
人工确认时,不需要让用户重新阅读所有过程,只要展示真正影响结果的内容:标题、对象、变更摘要、最终版本和风险提示。
自动化负责把选择成本降下来,用户负责在关键节点做最后判断。
七、日志要记录"为什么",不只是记录"发生了什么"
很多自动化日志只写:
text
任务完成
任务失败
重试成功
这种日志对排查帮助不大。更有价值的是记录决策依据:
text
任务:创建文章草稿
默认路径:请求超时
回退动作:查询标题是否已存在
查询结果:发现同标题草稿
最终判断:首次创建已成功,不再重复提交
状态:待人工确认
我通常只保留四类信息:
- 任务标识;
- 当前链路;
- 验证结果;
- 最终状态。
如果触发回退,再多记一条:为什么回退。
这样下次遇到同类问题时,不需要重新猜测系统到底做过什么。
八、从一个最小验证器开始
如果你准备给自己的 AI 工作流加回退机制,不建议一开始就设计复杂的 Agent 编排系统。
先挑一个最容易出问题的动作,给它补上验证器:
- 明确成功标准;
- 检查结果是否完整;
- 区分读取和写入;
- 给失败设置重试上限;
- 结果不确定时先查状态;
- 高风险动作前保留确认点;
- 把回退原因写进日志。
这七步跑顺之后,再考虑模型切换、工具降级和多路径编排。
AI 助手的价值,不是让所有事情都自动发生,而是让事情在自动化之后依然可控。
默认链路可以负责速度,可回退链路负责稳定;验证器负责判断结果,人工确认负责守住边界。
当这几层东西放在一起,AI 助手才不会因为一次超时、一次空响应或一次误解,就把一个小问题变成公开事故。
它可能仍然会出错,但至少每次出错,都能知道错在哪里、下一步做什么,以及什么时候应该停下来问人。
#人工智能 #AI工作流 #自动化 #Agent #程序员