技术思考问题18:AI的超时和回答不准怎么作系统设计和处理?

AI 接入业务前,先定义失败怎么表现

AI 接进售后系统,第一个要回答的不是答对率,而是答错时用户看到什么。

text 复制代码
[读者] 正在把大模型接入已有业务流程的工程师
[痛点] 超时、拒答、低置信度全被压成一句"服务繁忙"
[现在读] 因为线上已经出现无止境等待和错误操作
[读完] 能给每条失败路径定义状态、预算、出口与验证指标
text 复制代码
[旧方案] 接口封装 + 固定重试三次 + 统一报错文案
    |
    v
[新需求] AI 参与退款、工单这类有真实资金与责任后果的流程
    |
    v
[冲突] 模型的不确定性撞上业务的确定性,重试把后台故障放大成前台等待
    |
    v
[后果] 用户等很久只看到报错,低置信度硬答扩大损失,人工接手时上下文全丢

我是老李,做了几年交易与售后中台,习惯把线上事故当成下一版设计的输入,而不是当成运气问题。

去年底,业务方希望把大模型接进已有的售后链路:退换货政策问答、订单物流查询、以及在满足条件时发起退款。前两件事是信息服务,第三件会真的动到钱,也会真的产生责任。

我最初的想法很朴素:包一层 SDK,加三次重试,失败就弹一句统一提示。直到有位用户在页面上转了半分钟圈,最后只看到"服务繁忙,请稍后再试",我意识到我们其实还没回答一个更靠前的问题。

模型答不上来的时候,用户到底该看到什么?

是把所有失败收敛成一句统一报错,还是让每种失败都有自己的状态、话术和出口?

如果两个月后流量翻倍、模型服务整体抖动,这套只会重试的封装还能撑住吗?

01、故事

这套售后中台跑了五年。用户提问先过规则引擎,命中关键词走固定话术,没命中就进人工队列。规则引擎的世界观很干净:要么命中,要么不命中,不命中就转人工。

任务是:让 AI 在自己的能力边界内生成答复,在明确条件满足时调用退款工具,并且保证不管模型表现如何,用户始终有下一步可走。

需求上线后我才发现,真正难的不是让模型答对,而是定义它失败时的产品形态。模型会超时,会拒答,会给出一个看起来很像答案的低置信度结论,工具会失败,授权凭据会过期。而我们的第一版实现只有一种失败形状:弹一句"服务繁忙"。

规则引擎时代,失败只有一种含义:条件不匹配。模型时代,失败至少有五种含义,而它们对用户的意义完全不同:超时是"再等一下",拒答是"这件事我不该答",低置信度是"我给不出可负责的结论",工具失败是"动作没做成",授权失败是"现在不该继续"。把这五种混成一种,用户就只能靠猜。

一问接模型

一错全报错

三问未答完

事故已上桌

02、问题

旧方案在第一个小事故里就露出了结构缺陷。模型服务开始抖动,单次调用超时,客户端按固定次数重试;三次重试串行叠加,等待时间变成次数乘以超时上限。用户端没有任何进度信息,只有转圈;等来的是一句没有下一步的报错。

业务影响分三层。第一层是体验:用户不知道系统在做什么、还要等多久、能不能换一条路。第二层是成本:用户重新发起咨询、重复描述问题,人工还要从头问一遍。第三层是风险:模型在低置信度下仍然给出肯定语气,如果它刚好接了工具,就会产生需要人工冲正的操作。

技术表现集中在五件事上:没有任务级时间预算,重试次数与单次超时是乘法关系;没有熔断,上游整体故障时重试流量还在持续加压;没有状态区分,日志里只有成功和失败两态;模型返回的置信度字段被代码丢弃;转人工时只传一个会话号,问题和已执行动作都不在工单里。

可验证的完成标准我定了五条:每个失败分支都有明确状态和对应话术;单次用户请求的等待有硬上限;上游连续失败时系统自动停止自动处理而不是继续重试;转人工时问题原文、已执行动作和当前状态完整可见;P95 等待时长、误成功率、人工转接成功率、二次投诉率四项指标可观测。最后一条尤其重要,因为没有指标就没有边界,只有感觉。

重试非良药

超时是乘法

状态若不分

体验必塌方

03、原理

这一篇只需要两个模型:反演思维和安全边际。

反演思维的做法是先不问"怎么让 AI 答对",而是问"如果这次接入注定失败,它会以哪几种方式失败"。把灾难路径先写出来:用户无止境等待、系统给出错误操作、失败静默无感知、人工接管时上下文丢失。每一条灾难路径倒推一个前置防御:等待上限、停止自动执行、显式状态、上下文留存。防御是在失败被命名之后才存在的。

安全边际的做法是承认模型不确定性无法被消灭,只能被预算。为它预留时间余量(任务级超时预算)、资源余量(上游容量与并发上限)、以及可回退方案(人工接管与自动操作回滚)。安全边际不是保守,是让系统在估计错误时仍有退路。

第一个反直觉判断:模型的失败不是异常,而是分布的一部分。 如果你把它当异常处理,用 try/except 加一句统一报错,那么异常的语义就丢了,你永远不知道自己损失了什么。把它当正常分支建模,失败才有名字、等级和出口。

第二个反直觉判断:重试不是可靠性手段,在依赖过载时它是放大器。 Azure 架构中心的 Circuit Breaker 模式文档明确指出,面对可能瞬时恢复的故障,重试有价值;但当依赖整体过载时,持续重试会加剧故障。断路器让失败快速返回,给下游留出恢复时间,其状态分为 Closed、Open 与 Half-Open,Half-Open 时只放行试探性请求来确认依赖是否恢复。这段描述直接对应我们事故里的行为:我们以为在提高成功率,实际在给已经抖动的上游继续加压。

第三个反直觉判断:置信度阈值不是准确率指标,而是路由信号。 它的作用不是把模型调准,而是回答"这个问题该由谁负责"。0.31 的回答不该被丢弃,也不该被当成结论,它应该被送进人工复核队列。

本篇涉及的另一个官方来源是 Meta 官方站点上的模型发布页(话题中给出的 about.fb.com 新闻链接)。该链接的具体模型能力、接口形态与限制条件,需按当前官方文档核验;本篇架构不基于任何未核验的模型能力假设。

先画灾难图

再设防线桩

余量留三分

未知不慌张

04、架构

text 复制代码
[输入] 用户售后请求(会话 + 订单上下文)
    |
    v
[模块] 会话编排器(意图识别 + 任务状态机 + 预算管理)
    |
    v
[数据/状态] 任务状态(预算余量、尝试次数、熔断状态、置信度、工单)
    |
    v
[处理] 模型调用 / 工具调用(退款等)/ 状态路由与熔断判定
    |
    v
[输出] 成功答复 / 显式降级提示 / 人工工单(上下文无损)

架构的关键点在于:模型调用不再是主流程,而是被状态机编排的一个步骤。编排器持有三样东西:时间预算、重试额度、熔断状态。模型返回后不是直接透传,而是先判定状态,再由状态决定输出通道。

边界要说清楚:这套架构不保证模型一定答对,也不保证工具一定成功。它保证的是失败可定义、可退出、可接管。如果你的场景没有真实后果(纯低风险 FAQ),可以裁剪掉工单与熔断,只保留状态与超时。

收益是等待有硬上限、失败可解释、上游故障不会被重试放大、人工接管不丢上下文。代价是引入一个需要维护的状态机、一套工单接口,以及对模型返回结构的约束------置信度、拒答信号这类字段必须稳定可得;如果模型不返回这些字段,需要由编排层生成替代信号(例如规则命中、检索得分、答案与语义槽位的一致性),具体可用字段需按当前官方文档核验。

适用条件是:AI 参与有资金、责任或合规后果的流程,且系统里已经存在人工处理通道。没有人工通道时,先建通道,再接模型。

输入进编排

状态定进退

预算分秒算

出口留人工

05、实战一次

先把最小版本跑起来。以下环境与版本是写作时的示例组合:Python 3.11、FastAPI 0.115.x、httpx 0.27.x、uvicorn 0.32.x,安装最新稳定版即可,具体版本约束需按当前官方文档核验。

bash 复制代码
pip install fastapi uvicorn httpx
mkdir ai-failure-demo && cd ai-failure-demo

先写一个本地模型桩,用来稳定复现三类分支:超时、拒答、低置信度回答。生产环境里这是真实的模型服务,本地桩只是为了把故障变成可控实验。

python 复制代码
# mock_model.py
import asyncio
import random
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class GenIn(BaseModel):
    q: str

@app.post('/generate')
async def generate(inp: GenIn):
    roll = random.random()
    if roll < 0.25:
        await asyncio.sleep(60)          # 模拟超时
    if roll < 0.40:
        return {'kind': 'refusal', 'text': '抱歉,这个问题我不能提供结论', 'confidence': 0.0}
    return {'kind': 'answer', 'text': '可以为您办理退款', 'confidence': 0.31}

再写 V1,也就是我最早那版实现:固定重试、固定超时、统一报错,置信度字段直接忽略。它有两个故意留下的缺陷,后面排查会用到。

python 复制代码
# v1_chat.py
import httpx
from fastapi import FastAPI
from pydantic import BaseModel

MODEL_URL = 'http://127.0.0.1:9000/generate'
RETRY = 3
TIMEOUT = 10.0

app = FastAPI()

class ChatIn(BaseModel):
    session_id: str
    question: str

async def call_model(question: str) -> dict:
    async with httpx.AsyncClient(timeout=TIMEOUT) as client:
        resp = await client.post(MODEL_URL, json={'q': question})
        resp.raise_for_status()
        return resp.json()

@app.post('/chat')
async def chat(inp: ChatIn):
    for attempt in range(RETRY):
        try:
            data = await call_model(inp.question)
            return {'state': 'ok', 'answer': data['text']}
        except Exception:
            continue
    return {'state': 'error', 'answer': '服务繁忙,请稍后再试'}

启动两个进程:

bash 复制代码
python -m uvicorn mock_model:app --port 9000
python -m uvicorn v1_chat:app --port 8080

发起请求:

bash 复制代码
curl -s -X POST http://127.0.0.1:8080/chat \
  -H 'Content-Type: application/json' \
  -d '{\"session_id\":\"s1\",\"question\":\"我要退款\"}'

未在当前环境实测,以下为预期结果。命中正常分支时:

text 复制代码
{"state":"ok","answer":"可以为您办理退款"}

命中超时分支时(示例输出):

text 复制代码
{"state":"error","answer":"服务繁忙,请稍后再试"}

V1 跑通了,但留下三个清晰的问题:等待时间上限等于重试次数乘以单次超时;置信度 0.31 的回答被当成成功直接返回;上游整体故障时,重试流量会继续叠加。这三个问题就是下一章要排查的对象。

先让 V1 跑

再让问题现

代码不省步

结论才可靠

06、排查

第一条诊断链,现象是用户等待时间过长。工单描述用户在页面上等了很久,只拿到一句报错。

怀疑方向是模型推理太慢。检查动作是核对请求日志的时间戳(以下为示例日志,用于说明排查方法):

text 复制代码
10:00:00.112 POST /chat session=s1 attempt=1 start
10:00:10.130 POST /chat session=s1 attempt=1 timeout(10.0s)
10:00:10.132 POST /chat session=s1 attempt=2 start
10:00:20.150 POST /chat session=s1 attempt=2 timeout(10.0s)
10:00:20.152 POST /chat session=s1 attempt=3 start
10:00:30.171 POST /chat session=s1 attempt=3 timeout(10.0s)
10:00:30.172 POST /chat session=s1 resp state=error msg=服务繁忙

证据很直接:三次尝试各自吃满 10 秒,总等待约 30 秒,且全程没有任何中间状态返回给用户。根因不是模型慢,而是重试次数与单次超时上限是乘法关系,且没有任务级预算来兜底。修复方向是把总预算从调用层上提到任务层。

错误尝试: 我第一反应是把 TIMEOUT 从 10 秒调到 30 秒,理由是"模型就是慢,多给点时间就成功了"。这个尝试是错的。它把单次等待上限抬高,等于把最坏等待从 30 秒量级推到 90 秒量级;在故障窗口内,用户更久地卡在转圈里,上游也会被更长时间地占住,重试放大问题反而更严重。调超时是在改症状,不是在改结构。

第二条诊断链,现象是用户收到了肯定的退款答复,但订单状态并不满足条件。

怀疑方向是模型幻觉。检查动作是回放该会话的请求与响应体,发现模型返回中带有置信度字段,值为 0.31,而 V1 代码只读取了 text 字段。证据是字段确实存在、确实被丢弃。根因是低置信度没有被建模为一种状态,因而没有资格进入路由决策。修复方向是新增低置信度分支,把这类回答转入人工复核而不是直接输出。

第三条诊断链,现象是上游模型服务整体抖动期间,我们自己的重试流量叠加在原流量之上,恢复被拖后。

怀疑方向是上游容量不足。检查动作是统计同一时间窗内我们发出的请求次数与实际业务请求次数。证据是二者存在明显倍数关系:每个用户请求会放大成多次上游调用。根因是缺少熔断器,失败没有被快速终止。修复方向是在编排层加入三态断路器:连续失败达到阈值进入 Open,快速失败并降级;冷却后进入 Half-Open,只放行少量试探请求;成功后回到 Closed。

现象先落地

证据再开口

猜错不要紧

不查才是错

07、优化

V2 只针对第 06 章三条证据做修改,不做无依据的扩张。

根因一:缺少任务级时间预算。修改:在请求入口生成 deadline,逐次调用只允许使用剩余预算。原因:让重试次数与最坏等待解耦。新行为:无论重试几次,用户等待都有硬上限。

根因二:低置信度没有状态。修改:定义状态枚举,置信度低于阈值进入人工复核。原因:置信度是路由信号而不是准确率指标。新行为:不确定的结论不再直接触达用户。

根因三:缺少熔断。修改:加入 Closed、Open、Half-Open 三态断路器。原因:上游过载时,快速失败比持续重试更有价值。新行为:故障期间自动暂停自动处理并直接进入人工通道。

python 复制代码
# v2_chat.py
import time
from enum import Enum
import httpx
from fastapi import FastAPI
from pydantic import BaseModel

MODEL_URL = 'http://127.0.0.1:9000/generate'
TASK_BUDGET = 8.0          # 任务级总预算(秒)
PER_CALL_TIMEOUT = 3.0     # 单次调用上限
MAX_ATTEMPTS = 2           # 有界重试
CONFIDENCE_FLOOR = 0.6

class State(str, Enum):
    OK = 'ok'
    TIMEOUT = 'timeout'
    REFUSAL = 'refusal'
    LOW_CONFIDENCE = 'low_confidence'
    TOOL_FAILURE = 'tool_failure'
    AUTH_FAILURE = 'auth_failure'
    DEGRADED = 'degraded'

class Breaker:
    def __init__(self, threshold: int = 5, open_seconds: float = 30.0):
        self.threshold = threshold
        self.open_seconds = open_seconds
        self.failures = 0
        self.opened_at = None

    def state(self) -> str:
        if self.opened_at is None:
            return 'closed'
        if time.monotonic() - self.opened_at >= self.open_seconds:
            return 'half_open'
        return 'open'

    def on_success(self) -> None:
        self.failures = 0
        self.opened_at = None

    def on_failure(self) -> None:
        self.failures += 1
        if self.failures >= self.threshold and self.opened_at is None:
            self.opened_at = time.monotonic()

breaker = Breaker()
app = FastAPI()

class ChatIn(BaseModel):
    session_id: str
    question: str

async def call_model(question: str, timeout: float) -> dict:
    async with httpx.AsyncClient(timeout=timeout) as client:
        resp = await client.post(MODEL_URL, json={'q': question})
        resp.raise_for_status()
        return resp.json()

def create_ticket(session_id: str, question: str, state: State) -> dict:
    return {'session_id': session_id, 'question': question, 'state': state.value}

def handoff(inp: ChatIn, state: State, message: str) -> dict:
    return {
        'state': state.value,
        'message': message,
        'ticket': create_ticket(inp.session_id, inp.question, state),
        'next': ['继续等待人工', '取消本次咨询'],
    }

def route(inp: ChatIn, data: dict) -> dict:
    if data.get('kind') == 'refusal':
        return handoff(inp, State.REFUSAL, '这个问题需要人工确认后再回答您')
    if float(data.get('confidence', 0.0)) < CONFIDENCE_FLOOR:
        return handoff(inp, State.LOW_CONFIDENCE, '结论把握不足,已转人工复核')
    return {'state': State.OK.value, 'answer': data['text']}

@app.post('/chat')
async def chat(inp: ChatIn):
    deadline = time.monotonic() + TASK_BUDGET
    if breaker.state() == 'open':
        return handoff(inp, State.DEGRADED, '自动处理暂时不可用,已为您转人工')

    for attempt in range(MAX_ATTEMPTS):
        left = deadline - time.monotonic()
        if left <= 0.5:
            break
        try:
            data = await call_model(inp.question, min(PER_CALL_TIMEOUT, left))
            breaker.on_success()
            return route(inp, data)
        except (httpx.TimeoutException, httpx.HTTPError):
            breaker.on_failure()

    return handoff(inp, State.TIMEOUT, '模型暂时没有响应,已转人工,您可以先补充说明')

验证按四条口径进行,均为方案而非已发生的结果:P95 等待时长应不超过任务预算加上固定的编排放行开销;误成功率通过抽样回放带标签的会话,检查是否仍有低置信度回答被直接输出;人工转接成功率检查工单中问题原文与已执行动作是否完整;二次投诉率观察同一会话在转人工后是否再次发起同类投诉。前三项可从日志与工单数据直接计算,第四项需要与客服侧数据对齐。

根因定改法

预算锁全局

熔断断无谓

降级有去处

08、演进

text 复制代码
[同一输入]
    |
    +--[V1] 固定重试 3 次 / 统一报错 / 低置信度直接回答
    |        代价:最坏等待 = 次数 × 单次超时,故障被放大
    |
    +--[V2] 任务级预算 + 有界重试 + 三态熔断 + 状态路由 + 人工接管
    |        代价:多一层状态机与工单链路,需要模型返回可用的置信度信号
    |
[Trade-off]
得到:等待有上限、失败可解释、上游过载时不再加压、人工可无损接手
失去:统一报错那种实现上的简单性
边界:低风险 FAQ 可保留重试;高风险资金类操作必须停止自动执行并转人工

正确性上,V2 把"失败必须被命名"变成代码约束,超时、拒答、低置信度、工具失败、授权失败各有独立状态,互不污染。稳定性上,断路器把上游过载转化为本地快速失败,避免重试流量的乘法效应。

复杂度上,V2 引入了状态机、熔断器与工单依赖,代码量和联调成本都上升,这是明确的代价,不是可以忽略的细节。成本上,转人工比例会上升,人工团队需要接受这部分负载并配置排班。适用范围上,V2 更适合有资金或责任后果的流程;纯信息类问答可以只保留超时与状态,不必强行上熔断和工单。

遗留问题有三个:半数以上的不确定性最终仍然由人工消化,转人工的排队能力会成为新的瓶颈;置信度字段的语义与稳定性依赖模型侧,若模型升级导致字段含义变化,需要重新校准阈值;缺少故障演练机制,熔断阈值与冷却时间目前是经验值,需要定期用演练结果修订。

同问两条路

得失说清楚

边界画明白

遗留不掩藏

09、洞见

9.1 失败是产品状态,不是异常分支

在这套系统里,超时、拒答、低置信度、工具失败、授权失败被写进了状态枚举,而不是消失在 catch 里。这个差别不是代码风格问题:只有被命名的失败,才可能被设计话术、被测量、被接管。反直觉判断:系统可靠性的提升,大部分来自把失败定义清楚,而不是把模型调准。调准模型是概率上的改善,定义失败是结构上的兜底。

9.2 重试在过载时是放大器

固定重试在单点抖动时确实有效,这一点 Azure 断路器模式文档也承认:面向瞬时故障的重试有价值。但它同时指出,依赖整体过载时继续重试会加剧问题。我们的示例日志就是这句话的现场版:三次尝试把 10 秒的故障放大成 30 秒的等待。反直觉判断:让失败更快返回,往往比让失败更少发生更能提升用户感受到的可用性。

9.3 置信度是路由信号,不是质量指标

0.31 的回答不该被丢弃,也不该被直接输出。它应该触发一个路由决策:这个问题交给谁。把置信度当指标,你会去调阈值并期待分布变好;把置信度当路由信号,你会去建人工复核队列。前者是模型问题,后者是系统问题,而系统问题是你今天就能解决的。

9.4 人工接管是一条必须无损的路径

工单里如果只有会话号,人工就得从头问一遍,用户等于重新开始。V2 把问题原文、当前状态、已执行动作放进工单,这条路径才算成立。安全边际在这里体现为可回退性:自动操作必须能被人工确认、暂停或冲正,否则系统只有前进档,没有倒车档。

失败是状态

重试是乘法

置信是路由

接管是正路

10、系统落地

原来有的是一套稳定的规则引擎加人工队列:命中走话术,不命中转人工,失败只有一种形状。本篇新增的是一层编排:任务状态机、时间预算、有界重试、三态熔断、状态路由与无损工单接管。

现在能做的事情很具体:用户等待有硬上限;每一种失败都有对应的话术和下一步选项;上游整体故障时系统自动停止自动执行,而不是继续加压;人工接手时看到完整上下文;四项指标可以从日志与工单里算出来。

还缺三样:一是排练,也就是定期做故障演练,验证熔断阈值、冷却时间和降级话术在真实压力下是否成立;二是校准,模型升级后置信度字段的语义可能变化,阈值需要重新验证;三是分级,把业务动作按风险等级分类,低风险 FAQ 可以保留重试,高风险资金操作必须停止自动执行。

下一步的演进方向是把这套状态机抽象成公共能力,让其他要接 AI 的业务线直接复用状态定义、预算模型和接管协议,而不是每条线各自再写一遍统一报错。

原有工单在

今添状态机

能答也能停

缺的是演练

11、小结

text 复制代码
Q1 → 失败按状态定义:超时 / 拒答 / 低置信度 / 工具失败 / 授权失败
Q2 → 选择任务级预算 + 有界重试 + 熔断降级,而不是无限重试与统一报错
Q3 → 能撑住:等待有上限、失败有出口、上游不被加压、人工可无损接管
状态 → V2 可交付:状态机 + 时间预算 + 三态熔断 + 工单接管 + 四项验证口径

这套东西的价值不在于让模型变聪明,而在于让系统在模型不聪明的时候依然可用。用户不需要知道模型发生了什么,他需要知道自己现在在哪一步、还能做什么。

三问皆有答

一事已闭环

交付可复验

不再赌运气

12、作业

12.1 理解题:为什么把模型失败统一收敛成一句报错,会同时损害体验与可观测性?

参考答案:体验上,用户失去了下一步信息,只能重试或放弃;可观测性上,超时、拒答、低置信度被压成同一个错误码,日志无法区分损失类型,无法针对性修复,也无法计算误成功率这类指标。失败的语义一旦丢失,后面所有优化都只能靠猜。

12.2 实战题:给 V2 补一个工具失败分支,并说明它与超时分支在用户话术上的差别。

参考答案:在 route 之后增加工具调用阶段,捕获工具异常后返回 State.TOOL_FAILURE,并保留已执行动作记录。差别在于:超时的话术是"暂时没有响应,已转人工,您可以补充说明",强调的是等待与不确定;工具失败的话术是"动作没有完成,请勿重复提交,已转人工核对",强调的是状态确定与防重复操作。二者对用户行为的要求完全不同。

12.3 排障题:线上出现"用户等待时间明显变长,但上游错误率没有明显变化"的现象,你会按什么顺序排查?

参考答案:先看单次请求的调用次数与每次耗时,确认是否存在重试叠乘;再看任务级预算是否存在,确认等待上限是否被调用层超时决定;然后看熔断器状态,确认是否长时间处于 Open 或 Half-Open 而未被观测;最后检查排队与并发限制,确认等待是否发生在进入模型调用之前。顺序原则是先证伪乘法关系,再查结构性缺失。

12.4 架构判断题:低风险 FAQ 与高风险退款,是否应该共用同一套重试与降级策略?

参考答案:不应该。低风险 FAQ 的失败代价是体验,可以保留有界重试与较宽松的降级;高风险退款的失败代价是资金与责任,必须在不确定时停止自动执行并转人工,重试只能用于幂等的查询类调用,不能用于产生副作用的操作。策略分级的依据是失败代价,不是模型能力。

理解要落地

实战要跑通

排障要证据

判断要边界

13、思考

回到最开始那个冲突:模型的不确定性和业务的确定性撞在一起时,工程上能做的不是消灭不确定性,而是把不确定性变成可以被产品消费的状态。反演思维让我们先写灾难路径,再写防御;安全边际让我们承认估计会错,于是预留时间、资源和退路。

这套判断可以迁移到任何一个要接 AI 的存量系统里。接入前先回答三个问题:失败怎么表现、什么时候降级、谁来接手。这三个问题答不出来,模型能力再强也只是把不确定性更快地送到用户面前。

真正成熟的系统不是不会失败,而是失败时用户依然有路可走,人工依然有据可查,团队依然有数可看。

先定失败相

再留安全边

终定接管人

有路即可靠

相关推荐
李福春1 天前
技术思考问题15:技术选型说不清禁区还敢选型吗?
java技术 技术管理
李福春3 天前
技术思考问题7:AI应用越多,人均产出为何不涨?
java技术 技术管理
李福春3 天前
AgentScope第11式·定式输出
java技术 技术管理