AI 助手最危险的不是报错,而是“看起来成功”:我给工作流加了四道保险

AI 助手最危险的不是报错,而是"看起来成功":我给工作流加了四道保险

AI 助手真正让人头疼的时刻,往往不是页面上弹出一个红色错误,而是它安静地告诉你:已经完成。

文件确实生成了,但里面少了一半内容;消息确实发出去了,但收件人不对;表格确实更新了,但同一条记录出现了两次;文章确实提交了,可平台保存的正文是空的。

这些都不是传统意义上的"失败"。请求可能返回了 200,工具可能返回了 success: true,模型也可能给出一段看起来非常完整的总结。但从用户结果来看,事情并没有真正完成。

我后来给自己的 AI 工作流加了一个简单原则:

任何动作都不能只凭"调用成功"判定完成,必须经过结果验证。

再往前走一步,如果验证失败,还要有清楚的回退路径:重试、换工具、查状态、保留现场,或者停下来请人确认。

这套方法不依赖某个具体模型,也不限定某个 Agent 框架。只要工作流会读文件、写数据、调用网页或发送消息,就值得加上这几道保险。

一、为什么"成功"会骗人

一个完整的自动化动作,至少包含三层结果:

text 复制代码
请求是否发出
    ↓
服务是否接受
    ↓
用户要的结果是否真的产生

很多工具只告诉你前两层。

例如,调用"创建文档"接口后返回了一个文档 ID,只能说明服务端接受了创建请求。它并不能证明正文已经完整写入,更不能证明标题、代码块和链接都正确。

同样,调用模型后拿到一段文字,只能说明模型生成了输出。它不能证明输出满足任务要求,更不能证明模型替你执行了文件写入、网页操作或消息发送。

我现在会把"动作成功"拆成四个问题:

  1. 请求有没有发出去?
  2. 服务端有没有接受?
  3. 结果是否完整?
  4. 结果是否符合用户目标?

前三个可以由程序检查,第四个有时需要人工确认。

二、第一道保险:给结果定义"完成标准"

没有完成标准,就没有真正的验证。

"生成一篇文章"这个要求太模糊,程序无法判断什么叫完成。换成可检查的标准就清楚多了:

  • 标题不能为空;
  • 正文达到最低长度;
  • 一级标题数量不低于某个值;
  • 代码围栏必须成对;
  • 关键章节必须存在;
  • 链接不能被截断;
  • 正文不能只是错误提示或登录页面。

一个文件任务可以这样定义:

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 编排系统。

先挑一个最容易出问题的动作,给它补上验证器:

  1. 明确成功标准;
  2. 检查结果是否完整;
  3. 区分读取和写入;
  4. 给失败设置重试上限;
  5. 结果不确定时先查状态;
  6. 高风险动作前保留确认点;
  7. 把回退原因写进日志。

这七步跑顺之后,再考虑模型切换、工具降级和多路径编排。

AI 助手的价值,不是让所有事情都自动发生,而是让事情在自动化之后依然可控。

默认链路可以负责速度,可回退链路负责稳定;验证器负责判断结果,人工确认负责守住边界。

当这几层东西放在一起,AI 助手才不会因为一次超时、一次空响应或一次误解,就把一个小问题变成公开事故。

它可能仍然会出错,但至少每次出错,都能知道错在哪里、下一步做什么,以及什么时候应该停下来问人。

#人工智能 #AI工作流 #自动化 #Agent #程序员

相关推荐
秦先生在广东1 小时前
用 AI Agents 搭建自动化 Niche 简报,实现每月 $500 被动收入——拆解与验证
人工智能
Fnetlink11 小时前
FNET 云网安 260819
网络·人工智能·安全·网络安全
zzzzzz3101 小时前
一篇文章发五个平台:我用 TRAE Work 搭了条内容分发流水线,2 小时变 20 分钟
人工智能·markdown
xushichang123_1 小时前
如何通过云平台与架构优化,解决 Agentic AI 应用 Token 消耗过高问题?
人工智能
用户8356290780511 小时前
如何使用 Python 将 PowerPoint 转换为 PDF 文档
后端·python
菜冻鱼1 小时前
Python-pytorch-高级技巧
开发语言·人工智能·pytorch·python·深度学习·神经网络·聚类
lpfasd1231 小时前
python webview打包版卡死、开发版正常
开发语言·python
用户8356290780512 小时前
如何使用 Python 为 PowerPoint 幻灯片添加切换效果
后端·python
菜冻鱼2 小时前
Python-pytorch-模型保存与加载
开发语言·人工智能·pytorch·python·深度学习·机器学习