引子:一次线上事故让我重新审视Agent架构
前阵子帮一个团队review他们的AI Agent系统,上线两周内出了三次事故:一次模型输出了完全不相关的代码建议、一次Agent在多轮对话中丢失了用户核心诉求导致重复执行、还有一次直接因为异常未捕获导致整个服务挂了。
排查下来,四个技术问题浮出水面。写下来给同行参考。
一、OOD泛化:模型在"没见过"的输入面前就是瞎子
先从最底层的问题说起。
所有基于LLM的AI Agent都受困于同一个技术命题:分布外泛化(OOD Generalization)。
训练数据覆盖的是"已知模式",但真实业务场景里,输入分布随时可能偏移。一旦遇到OOD样本,模型的置信度校准(Confidence Calibration)完全失效------它可能以99%的置信度输出一个完全错误的结果。
python
# 错误的做法:直接信任模型输出
def agent_process(user_input):
result = llm.generate(user_input)
return result # 如果输入是OOD,这里返回的可能是灾难
# 正确的做法:加置信度过滤
def safe_agent_process(user_input, threshold=0.8):
result = llm.generate(user_input)
confidence = llm.get_confidence(user_input, result)
if confidence < threshold:
return fallback_response("当前输入超出处理范围,已转人工")
# 二次校验:让另一个模型做交叉验证
verification = verifier.verify(user_input, result)
if verification.score < 0.7:
return fallback_response("输出质量未达标,重新处理中")
return result
踩坑总结:永远不要完全信任模型对自己输出的置信度评估。加一层独立校验器做交叉验证,是性价比最高的兜底方案。
二、多轮对话的状态管理:Agent做着做着就"失忆"了
这是在实际项目里最难搞的问题。
Agent在与用户的多轮交互中,需要持续维护会话状态------当前执行到哪一步、用户的核心诉求是什么、哪些约束条件需要保持。但现实是:
- 上下文窗口溢出:Token超限后,最早的上下文信息被"挤出去"
- 意图漂移:用户中途可能换话题,Agent容易跟着"跑偏"
- 幻觉累积:推理链越长,每一步的误差被放大,最终方向全歪
python
# 状态管理的简化方案
class AgentState:
def __init__(self, max_history=10):
self.core_intent = None # 用户核心诉求,不会被窗口溢出冲掉
self.execution_history = []
self.constraints = set()
self.max_history = max_history
def update(self, user_input, agent_output):
# 核心意图只允许主动更新,不会被自动覆盖
if not self.core_intent:
self.core_intent = extract_intent(user_input)
self.execution_history.append({
"input": user_input,
"output": agent_output,
"timestamp": now()
})
# 控制历史长度
if len(self.execution_history) > self.max_history:
# 不是直接丢弃,而是做上下文摘要压缩
summary = summarize_context(self.execution_history[:-self.max_history//2])
self.execution_history = [summary] + self.execution_history[-self.max_history//2:]
def is_drifted(self, current_input):
"""检测用户意图是否发生显著漂移"""
current_intent = extract_intent(current_input)
similarity = cosine_similarity(embed(self.core_intent), embed(current_intent))
return similarity < 0.6 # 低于阈值认为意图已漂移
踩坑总结:核心意图必须单独维护,不能放在prompt里让模型自己"记住"。一旦意图漂移检测触发,主动向用户确认"你刚才说的是不是这个意思",比闷头继续跑完有用得多。
三、LLM当决策层:让"相关性引擎"做因果判断
这里有一个非常容易被忽视的技术问题。
LLM本质上是一个相关性引擎(Correlation Engine) ------它在海量文本中学会了"A后面通常跟着B"的模式,但技术上不具备因果推理能力。而企业的核心决策,恰恰需要的是因果判断(Causal Reasoning)。
让LLM做决策层,等于把业务风险押注在一个基于统计模式匹配的模型上。
python
# 分层架构:Agent只做建议层,人类保留决策层
class LayeredAgent:
def __init__(self):
self.llm = LLM()
self.decision_layer = DecisionLayer() # 人类决策接口
def handle_request(self, request):
# 第一步:Agent做分析建议
analysis = self.llm.analyze(request)
# 第二步:风险等级评估
risk_level = self.assess_risk(request, analysis)
if risk_level == "LOW":
# 低风险:自动执行+审计日志
result = self.execute(analysis)
self.log(request, analysis, result, "auto")
return result
elif risk_level == "MEDIUM":
# 中风险:建议+等待确认
return {
"status": "PENDING_CONFIRMATION",
"analysis": analysis,
"suggestions": analysis["actions"]
}
else: # HIGH
# 高风险:直接升级到决策层
return self.decision_layer.escalate(analysis)
def assess_risk(self, request, analysis):
# 基于规则的硬编码风险评估
rules = [
("涉及金额>阈值", "HIGH"),
("涉及用户隐私数据", "HIGH"),
("涉及对外承诺", "MEDIUM"),
("纯内部查询", "LOW"),
]
return max((risk for condition, risk in rules
if condition_matches(condition, request)),
key=risk_level_sort)
踩坑总结:Agent只能建议和执行,不能决策。关键决策节点必须保留人类确认机制------这不是信任问题,是架构设计问题。
四、Agent工程的异常处理:90%的团队都没做好
这是我review过的项目里最常见的问题。
python
# 典型的"裸奔"Agent
def agent_run(task):
plan = llm.plan(task)
for step in plan:
result = tool_call(step) # 一旦挂了,整条链崩溃
return result
看起来简单,但上线后问题层出不穷:第三方API超时、模型返回格式异常、某个步骤的结果不是预期类型......每一步都有可能崩。
python
# 带完整异常处理的版本
def agent_run_safe(task, max_retries=3):
try:
# 限制推理深度
plan = llm.plan(task, max_steps=10)
results = []
for step_idx, step in enumerate(plan[:10]):
try:
# 每个步骤独立try-catch
result = tool_call_with_retry(step, max_retries,
timeout=30)
results.append(result)
except ToolCallTimeout:
# 超时:跳过+记录,不影响后续步骤
log_warning(f"步骤{step_idx}超时,已跳过:{step}")
results.append({"status": "SKIPPED", "reason": "timeout"})
continue
except ToolCallError as e:
# 工具调用失败:尝试降级
degraded = degrade_call(step)
if degraded:
results.append(degraded)
continue
# 降级也失败,终止整条链
return {
"status": "FAILED",
"completed_steps": results,
"failed_step": step_idx,
"fallback": True
}
return {"status": "SUCCESS", "results": results}
except Exception as e:
# 最外层兜底:转人工
return escalate_to_human(task, str(e))
踩坑总结:每个步骤独立try-catch,不要一个try包整条链。超时可跳过、调不通可降级、所有路子都走不通再转人工------不要让用户在错误面前干等。
五、正确的Agent架构长什么样
综合以上踩坑经验,一个能上线的Agent架构至少应该有三层:
diff
+---------------------------+
| 人类决策层 | 做判断、担责任、处理异常
+---------------------------+
| Agent工程化层 | 路由、状态管理、异常兜底
| - 意图追踪模块 |
| - 风险分级模块 |
| - 异常处理模块 |
| - 人工升级模块 |
+---------------------------+
| 大模型能力层 | 推理、生成、分析
+---------------------------+
把Agent设计成一个"需要人类监护的实习生"------能干活,但需要指导、需要审核、需要兜底。不要把它设计成全自动的"黑箱处理器"。
给开发者的五条行动建议
- 检查你的Agent有没有HITL------关键决策节点是否保留了人工确认机制?
- 做一次OOD压力测试------用真实业务数据里最"奇怪"的输入去测
- 加三个监控指标:置信度异常率、转人工率、推理链平均步数
- 写清楚Agent的边界:prompt里不光写"你能做什么",更要写"你不能做什么"
- 每个步骤都有Plan B:超时怎么办、返回格式不对怎么办、API挂了怎么办------全部代码级兜底
下周会写一篇关于Agent状态管理的最佳实践,包括上下文摘要压缩和意图漂移检测的具体实现,欢迎关注交流。