普通视图

发现新文章,点击刷新页面。
昨天 — 2026年2月11日首页

🔥从"打补丁"到"换思路":一次企业级 AI Agent 的架构拐点

作者 Sailing
2026年2月11日 17:36

在做企业级 AI Agent 时,我踩过一个非常典型的坑。

一开始我以为只是个“小逻辑问题”。后来我发现,那是一次架构认知的分水岭

这篇文章,讲的不是“消息补全”。讲的是一个更重要的问题:

当规则开始打补丁时,你是不是已经选错了工具?

问题很简单:AI 听不懂 “...这个呢”

我们在做一个企业内部智能运维助手 LUI Agent。能力很清晰:

  • 查询域名状态
  • 查询 Pod 数
  • 搜索内部文档
  • ......

在实现多轮对话时,出现了一个极其常见的问题:

用户:查询域名 bbb.com 的状态
AI:该域名 QPS 为 120,P99 为 45ms...

用户:yyy.com 这个呢
AI:???

第二句话——

“yyy.com 这个呢”

从人类视角看,毫无歧义。
但从工具调用视角看,这是一个不完整的句子

下游网关服务根本不知道用户要干什么。

所以我们需要一个能力:

在调用工具前,把“不完整的问题”补全为完整问题。

第一反应:规则一定能搞定(踩坑之路)

作为一个开发者,我的第一反应非常自然:这不就是模式匹配吗?

于是写了第一版规则:

private isIncompleteMessage(message: string): boolean {
  const trimmed = message.trim();

  if (trimmed.length < 8) return true;
  if (/呢[??]?$/.test(trimmed)) return true;
  if (/吗[??]?$/.test(trimmed)) return true;
  if (/^(这个|那个|这|那)/.test(trimmed)) return true;

  return false;
}

看起来很优雅:

  • 短消息?拦截。
  • 追问句式?拦截。
  • 指代开头?拦截。

覆盖三大类问题。我当时甚至觉得设计得挺漂亮。

然后,规则开始失控

测试几轮后,问题很快暴露:

Case 1

yyy.com这个呢

长度 19,不符合 < 8

规则顺序导致被判定为“完整问题”。

我开始加补丁。

Case 2

b.com也查一下

好,加一个“也 + 动词”规则。

Case 3

yyy.com呢

好,再扩展域名 + 呢。

Case 4

这个应用有几个pod

以“这个”开头,但其实是完整问题。误判。

Case 5

这个功能很好用

被误判为“不完整问题”。假阳性。


那一刻我突然意识到:

我已经开始写“例外规则”了。

而当你开始写例外规则的时候,你已经失去了规则系统的简洁性。

规则不再是“设计”,它开始变成“修修补补”。(越来越不好维护!)

真正的问题:这不是字符串问题

我突然意识到一个更本质的问题:我在用规则解决一个语义问题。

  1. “这个呢” 不是句法问题,是指代问题。
  2. 不是字符串匹配问题,是上下文理解问题。

这本质上是一个语义理解任务。而我在用规则解决语义,这就像用 if/else 写一个自然语言理解系统,注定会崩。

相反,正是 LLM 天生擅长的领域。

意图识别

换思路:让 LLM 做意图补全

我加了一层“消息预处理”。在真正调用 agent 工具前,让 LLM 判断:

  • 当前问题是否完整?
  • 是否是追问?
  • 是否需要结合历史补全?

核心逻辑:

/**
 * 预处理消息:使用 LLM 判断并补全不完整的问题
 */
private async preprocessMessage(
  message: string, 
  history: BaseMessage[], 
  agentId: string, 
  requestId?: string
): Promise<string> {
  // 没有历史对话,无需补全
  if (history.length === 0) {
    return message;
  }
  
  const llm = getLLM();
  
  // 取最近的对话历史
  const recentHistory = history.slice(-6).map(msg => {
    const role = msg instanceof HumanMessage ? '用户' : '助手';
    return `${role}: ${String(msg.content).substring(0, 200)}`;
  }).join('\n');
  
  const prompt = `你是一个意图分析助手。判断用户当前输入是否需要根据对话历史补全。

## 对话历史
${recentHistory}

## 用户当前输入
${message}

## 任务
1. 判断当前输入是否是一个完整、独立的问题
2. 如果是完整问题,直接返回原文
3. 如果是追问、指代、省略句式(如"这个呢"、"xxx也查一下"、"状态如何"),结合历史补全为完整问题

## 输出
只返回最终的问题(补全后或原文),不要任何解释。`;

  const response = await llm.invoke(prompt);
  const completed = typeof response.content === 'string' 
    ? response.content.trim() 
    : message;
  
  // 记录是否进行了补全
  if (completed !== message) {
    this.logger.info('消息已补全', { original: message, completed });
  }
  
  return completed || message;
}

核心 Prompt 起了很大作用:

你是一个意图分析助手。判断用户当前输入是否需要根据对话历史补全。

## 任务
1. 判断当前输入是否是一个完整、独立的问题
2. 如果是完整问题,直接返回原文
3. 如果是追问、指代、省略句式(如"这个呢"、"xxx也查一下"、"状态如何"),结合历史补全为完整问题

效果对比:规则 vs 语义

对话历史:

用户: 查询域名 xxx.com 的状态
助手: 该域名 QPS 为 120,响应时间 P99 为 45ms...

用户输入: yyy.com这个呢
LLM 补全: 查询域名 yyy.com 的状态 ✅

对话历史:

用户: 这个应用有几个pod
助手: 当前应用 yyy.com 有 3 个 Pod...

用户输入: 这个应用呢(切换了应用)
LLM 补全: 这个应用有几个pod ✅

对话历史:

用户: 查询 xxx.com 的 QPS
助手: xxx.com 的 QPS 为 50...

用户输入: yyy.com 也查一下
LLM 补全: 查询 yyy.com 的 QPS ✅

完美!LLM 能够理解语义,自动处理各种追问句式。

  • 没有新增规则。
  • 没有顺序依赖。
  • 没有边界爆炸。

它理解了语义。

但 LLM 不是银弹

LLM 问题也随之而来:

  • 延迟增加 500ms ~ 1s。
  • Token 成本增加。
  • 输出不可 100% 可控。

所以,我没有“全盘 LLM 化”。而是做了一个分层架构。

混合架构:规则前置,LLM兜底

在实际项目中,采用了"规则快速拦截 + LLM 深度分析"的混合策略:

// 意图分析流程
async analyzeIntent(message: string, history: BaseMessage[]) {
  // 1. 规则快速拦截(< 1ms)
  const quickResult = this.quickIntercept(message);
  if (quickResult.confident) {
    return quickResult;
  }
  
  // 2. LLM 深度分析(500ms - 3s)
  const llmResult = await this.llmAnalyze(message, history);
  return llmResult;
}

// 规则快速拦截
private quickIntercept(message: string) {
  // 问候语
  if (/^(你好|hi|hello|嗨)/i.test(message)) {
    return { agentId: 'general', confident: true };
  }
  // 身份询问
  if (/你是谁|你叫什么/.test(message)) {
    return { agentId: 'general', confident: true };
  }
  // 导航意图(明确的跳转词)
  if (/^(跳转|打开|进入|去)(到)?/.test(message)) {
    return { agentId: 'navigation', confident: true };
  }
  // 不确定,交给 LLM
  return { confident: false };
}

规则适合:

  • 问候语(例如:你好、你是)
  • 明确跳转(例如:打开**、跳转**)
  • 格式校验
  • 固定关键词

LLM 适合:

  • 指代
  • 追问
  • 模糊表达
  • 语义补全

规则保证速度,LLM 保证理解。这才是企业级 Agent 的现实架构。

更隐蔽的一次教训:历史丢失

后来,我还踩了一个更隐蔽的坑。

日志显示:

API historyLength: 10
MasterAgent historyLength: 6

丢了 4 条。原因:

JSON.stringify(undefined) // -> undefined

某些结构化消息没有 content 字段,被我写的代码逻辑给过滤掉了。

修复方式: 直接 stringify 化

function getMessageContent(msg) {
  if (typeof msg.content === 'string') return msg.content;

  const { role, timestamp, ...rest } = msg;
  return JSON.stringify(rest);
}

让 LLM 自己理解结构化数据

这件事让我学到一个重要认知:

不要低估 LLM 对结构化信息的理解能力。
信息别丢,比格式完美更重要。

总结

这不是一个“补全功能优化”的故事,这是一个架构边界判断问题:

  • 规则系统适合确定性边界
  • 语义系统适合模糊边界

当你发现:

  • 规则在不断打补丁
  • 误判越来越多
  • 例外规则越来越复杂

那很可能 —— 你在用规则解决语义问题

很多人做 Agent,沉迷 Prompt。但真正重要的不是 Prompt 写多长。而是学会判断:

什么时候该用规则;
什么时候该交给语义(LLM 意图识别)。

如果你也在做 Agent,你现在的系统,是规则在膨胀?还是语义在进化?

WX20230928-110017@2x.png

note: 我最近一直在做 前端转全栈前端转 AI Agent 开发方向的工作,后续我会持续分享这两方面的文章。欢迎大家随时来交流~~

❌
❌