1. 为什么“聪明的智能体”反而更脆弱
1.1 一个让我彻底改变认知的线上事故
去年冬天,我负责的一个自动化运维智能体在灰度环境里跑了整整两周,各项指标都漂亮得不像话——任务完成率 97%,平均响应延迟 800 毫秒,人工接管率不到 3%。团队里所有人都觉得这事成了,准备全量上线。结果全量切换的第二天凌晨,上游一个服务的响应时间从 200 毫秒抖到了 1.2 秒,就这么一个在监控大盘上几乎看不见的小波动,整个智能体链路像多米诺骨牌一样崩了:任务队列堆积、重试风暴、上下文窗口被垃圾信息塞满,最后连健康检查接口都开始超时。从第一个异常到完全不可用,前后不到 90 秒。
事后复盘,问题根本不在模型能力上。那个智能体在“正常工况”下的决策质量确实很高,但它对扰动的容忍度低得可怕。上游延迟一抖,它的规划模块就开始产生次优决策;次优决策导致更多重试;重试又进一步加剧了上游压力。这是一个典型的正反馈失控,而不是能力不足。
这件事让我意识到一个被整个行业长期忽视的问题:我们花了 90% 的精力去提升智能体的“聪明程度”,却几乎没花精力去保证它的“稳定性”。用控制论的话说,我们一直在优化开环性能,却忘了闭环系统最核心的指标是鲁棒性。
1.2 智能体可靠性困境的本质是什么
把 AI Agent 当成一个控制系统来看,很多事情就豁然开朗了。一个智能体系统至少包含这几个部分:感知(输入解析、上下文获取)、决策(规划、推理、工具选择)、执行(调用 API、操作外部系统)、反馈(结果观测、状态更新)。这不就是一个标准的闭环控制系统吗?
问题在于,当前绝大多数智能体的设计思路是“事件驱动 + 条件判断”,本质上是一种开环或弱闭环结构。它们假设外部环境是相对稳定的,一旦环境出现扰动——上游延迟、工具返回格式变化、并发量突增、上下文被污染——系统没有能力去“感知偏差并主动补偿”,只能被动地按照预设逻辑继续执行,直到彻底崩溃。
这就是我说的“脆弱的聪明”。模型本身可能很强,但整个系统缺乏对抗扰动的结构性能力。而控制论这门已经发展了近百年的学科,恰恰就是专门研究“如何在扰动下保持系统稳定”的。PID 控制、自抗扰控制(ADRC)这些听起来像是工业自动化领域的东西,其实和智能体可靠性问题有着惊人的同构性。
1.3 这篇文章适合谁看
如果你正在从 0 到 1 搭建 AI Agent,或者已经在生产环境部署了智能体但被稳定性问题折磨得睡不着觉,那这篇内容就是写给你的。我不打算讲太多控制论的数学推导,而是把 PID 和 ADRC 的核心思想“翻译”成智能体工程能直接用的设计模式。你会看到:为什么一个简单的 PID 思路就能解决智能体的重试风暴问题;为什么 ADRC 的“扩张状态观测器”概念能帮我们构建自适应的智能体调度策略;以及具体到代码层面,这些控制论思想该怎么落地。
不管你是做企业级 Java AI Agent 应用平台,还是用 Spring AI 开发自己的 Agent,或者只是想在练手小项目里验证一些想法,这套思路都能直接抄作业。
2. 从 PID 到 ADRC:控制论能给智能体带来什么
2.1 PID 的核心思想:用偏差驱动修正
PID 控制器的逻辑极其朴素:测量当前值和目标值的偏差,然后根据偏差的大小(比例项 P)、偏差的累积(积分项 I)、偏差的变化率(微分项 D)来计算一个修正量。它的伟大之处在于,不需要知道系统的精确数学模型,只要这个系统是“可控的”,PID 就能通过不断测量偏差、不断修正,把系统拉回目标附近。
把这个思路映射到智能体上,你会发现很多可靠性问题都可以用 PID 的视角重新理解。比如智能体的任务队列长度,这就是一个典型的被控量。目标值是“队列长度维持在合理水位”,实际测量值是当前队列长度,偏差就是两者之差。当偏差为正(队列积压),P 项会让系统加大处理力度(比如增加并发 worker);I 项会累积历史偏差,防止长期小偏差被忽略;D 项则能在队列长度快速上升时提前预警,避免等到积压严重了才反应。
我试过在一个任务调度智能体里引入最基础的 P 控制:当队列长度超过阈值时,动态调整并发度。实测下来,任务积压的峰值下降了 60% 以上,而且再也没出现过重试风暴。原理很简单——以前是固定并发度,队列涨到天上去了系统还在用同样的速度处理;现在队列一涨,并发度立刻跟着涨,偏差被快速消除。
2.2 为什么纯 PID 在智能体场景下不够用
PID 好用,但它有个前提假设:系统的工作点是相对固定的,扰动是围绕工作点的小幅波动。智能体系统恰恰不满足这个条件。上游服务的延迟可能从 200 毫秒突然变成 2 秒,工具返回的数据格式可能因为版本更新完全变了,用户请求的模式可能从“零星几个”变成“洪峰式涌入”。这些不是小扰动,而是系统动态特性的根本性变化。
更麻烦的是,智能体系统里存在大量“未建模动态”。你不可能为每一个工具调用、每一次模型推理、每一个外部依赖都建立精确的数学模型。PID 的积分项在这种场景下还会帮倒忙——如果系统已经因为某个外部依赖挂了而无法完成任务,积分项会不断累积偏差,导致修正量越来越大,最后产生严重的超调和振荡。
这就是为什么我们需要 ADRC。自抗扰控制的核心洞察是:与其费尽心思去建模系统内部的所有动态,不如把所有“说不清道不明”的部分统统归为“总扰动”,然后用一个扩张状态观测器(ESO)去实时估计这个总扰动,并在控制量里把它抵消掉。
2.3 ADRC 的三个核心部件及其智能体映射
ADRC 由三部分组成:跟踪微分器(TD)、扩张状态观测器(ESO)、非线性状态误差反馈(NLSEF)。听起来很学术,但映射到智能体工程里非常直观。
跟踪微分器解决的是“目标值突变”问题。在智能体场景里,目标值可能是“每秒处理 100 个任务”,但如果突然从 10 跳到 100,系统会承受巨大的冲击。TD 的作用是安排一个过渡过程,让目标值平滑地变化,给系统一个缓冲。这就像智能体在接到突发流量时,不应该立刻把并发度拉满,而是应该有一个爬坡过程。
扩张状态观测器是 ADRC 的灵魂。它把系统内部的不确定性和外部扰动合并成一个“总扰动”状态,然后通过观测器实时估计。在智能体里,这相当于一个“异常感知器”:它不关心具体是哪个工具变慢了、哪个模型响应变长了,它只关心“系统当前的实际表现和预期表现之间有多大差距”,然后把这个差距作为总扰动来补偿。
非线性状态误差反馈则是根据误差的大小和方向,动态调整控制力度。误差大时控制力度大,误差小时控制力度小,避免超调。这在智能体调度里非常实用——队列轻度积压时温和增加并发,队列严重积压时果断扩容。
2.4 一个关键认知:稳定性优先于最优性
控制论给智能体工程最大的启示,不是某个具体算法,而是一种设计哲学:在不确定环境下,稳定性优先于最优性。一个 80 分但稳定的智能体,远比一个 95 分但时不时崩溃的智能体有价值。PID 和 ADRC 的所有设计都是在为稳定性服务——它们不追求每一步都做出最优决策,而是追求系统始终运行在可控范围内。
这个认知转变非常关键。很多团队在搭建 AI Agent 时,把大量精力花在 prompt 优化、模型选型、工具链丰富度上,这些当然重要,但它们解决的是“上限”问题。而控制论解决的是“下限”问题——保证系统在最坏情况下也不会崩。对于生产环境来说,下限比上限重要得多。
3. 智能体控制系统的核心细节与实操要点
3.1 被控量选择:到底该控制什么
设计智能体控制系统,第一步是确定被控量。不是所有指标都适合做被控量,好的被控量应该满足三个条件:可实时测量、与系统稳定性强相关、可通过控制手段影响。
我梳理了几个在智能体场景下最实用的被控量:
| 被控量 | 测量方式 | 目标值设定 | 控制手段 |
|---|---|---|---|
| 任务队列长度 | 队列监控 | 动态水位线 | 并发度调整 |
| 端到端延迟 | 链路追踪 | P95 阈值 | 超时策略、降级 |
| 错误率 | 日志聚合 | 滑动窗口阈值 | 重试策略、熔断 |
| 上下文窗口占用率 | Token 计数 | 安全水位 | 摘要压缩、截断 |
| 工具调用成功率 | 调用统计 | 基线值 | 工具切换、降级 |
选被控量的经验法则是:优先选那些“一旦失控就会引发连锁反应”的指标。队列长度是第一优先级,因为它直接决定了系统是“忙”还是“崩”。延迟和错误率是第二优先级,它们反映的是系统健康度。上下文窗口占用率在长对话智能体里特别重要,我见过太多因为上下文被垃圾信息塞满导致模型输出质量断崖式下跌的案例。
注意:不要同时控制太多被控量。控制回路之间会相互干扰,三个以上的被控量就需要考虑解耦设计,否则很容易出现“按下葫芦浮起瓢”的情况。
3.2 采样频率与控制周期的确定
控制周期决定了系统对扰动的响应速度。周期太长,扰动已经造成严重后果了系统才反应过来;周期太短,控制开销本身就会成为负担。
我的经验值是:控制周期应该小于系统最小时间常数的 1/5 到 1/10。什么意思?如果智能体处理一个任务平均需要 2 秒,那么控制周期应该在 200 到 400 毫秒之间。这样在扰动发生的早期就能被检测到并补偿。
但这里有个坑:控制周期不能小于测量延迟。如果你的监控数据有 1 秒的聚合延迟,那控制周期设成 100 毫秒也没用,你看到的永远是 1 秒前的状态。这种情况下,要么降低测量延迟,要么在控制器里加入预测补偿。
实测下来,对于大多数智能体场景,500 毫秒到 1 秒的控制周期是一个比较稳妥的起点。你可以先用这个周期跑起来,观察系统的响应曲线,再根据实际情况调整。
3.3 参数整定的实操方法
PID 参数整定是门手艺活。教科书上的 Ziegler-Nichols 方法在智能体场景下往往不好用,因为智能体系统的非线性太强了。我总结了一套更适合智能体的整定流程:
第一步,先把 I 和 D 设为 0,只调 P。从很小的值开始,逐渐增大,直到系统出现轻微振荡。记录下这个临界 P 值,然后取它的 60% 作为初始 P。
第二步,加入 I 项。I 的作用是消除稳态误差。在智能体场景里,稳态误差通常表现为“队列长度总是比目标值高一点点”。I 值从 P 值的 1/10 开始,逐渐增大,直到稳态误差在可接受范围内。注意 I 值太大会导致积分饱和,在智能体里表现为“系统已经恢复了但控制量还在高位”。
第三步,加入 D 项。D 项对噪声很敏感,而智能体的监控数据往往噪声不小。D 值从 P 值的 1/20 开始,观察系统对突发扰动的响应是否变得更平滑。如果 D 项导致控制量抖动剧烈,说明噪声太大,要么加滤波器,要么放弃 D 项。
实操心得:在智能体场景下,很多情况下 PI 控制就够了,D 项反而容易引入不稳定。特别是当你的监控数据来自日志聚合而不是实时指标时,D 项基本可以不用。
3.4 ADRC 的 ESO 在智能体里的具体实现
ESO 的核心是一个状态观测器,它把系统输出和输入作为已知量,估计出系统的状态和总扰动。在智能体里,我们可以用一个简化的离散 ESO:
class AgentESO: def __init__(self, beta1=100, beta2=200, b0=1.0): self.z1 = 0.0 # 状态估计 self.z2 = 0.0 # 总扰动估计 self.beta1 = beta1 self.beta2 = beta2 self.b0 = b0 def update(self, y, u, dt): # y: 实际测量值(如队列长度) # u: 控制量(如并发度调整量) e = self.z1 - y self.z1 += dt * (self.z2 - self.beta1 * e + self.b0 * u) self.z2 += dt * (-self.beta2 * e) return self.z1, self.z2这个观测器的输出z2就是总扰动的估计。当z2突然增大,说明系统遇到了未建模的扰动——可能是上游变慢了,可能是某个工具挂了,可能是流量模式变了。控制器可以根据z2的大小和方向,主动调整控制策略。
我试过在一个多工具调用的智能体里用这个 ESO,效果非常明显。以前工具 A 变慢时,智能体只会傻傻地等,直到超时;现在 ESO 能在 2-3 个控制周期内检测到“总扰动增大”,然后主动降低对工具 A 的调用频率,把任务路由到工具 B。整个过程不需要任何硬编码的规则。
3.5 前馈补偿:比反馈更快的扰动应对
反馈控制有个天然缺陷:必须等扰动造成偏差之后才能补偿。前馈控制则可以在扰动影响系统之前就做出响应。在智能体场景里,前馈的典型应用是:当你从监控系统得知上游服务即将进行扩容或迁移时,提前调整智能体的超时阈值和重试策略。
PID 前馈的使用方式是:把可测量的扰动信号直接引入控制量,而不经过误差计算。比如:
def control_with_feedforward(queue_len, target, upstream_latency, d_upstream): # 反馈部分 feedback = Kp * (target - queue_len) # 前馈部分:上游延迟增加时,提前降低并发 feedforward = -Kff * d_upstream return feedback + feedforward前馈的关键是找到合适的 Kff。这个参数不能太大,否则会对噪声过度反应;也不能太小,否则起不到提前补偿的作用。我的经验是 Kff 取 Kp 的 0.3 到 0.5 倍比较合适。
4. 从零搭建一个带控制回路的智能体调度器
4.1 整体架构设计
我以一个任务调度智能体为例,展示完整的控制回路实现。这个智能体的职责是:接收任务请求,调用合适的工具处理,返回结果。核心挑战是:在工具响应时间波动、任务到达率波动的情况下,保持系统稳定。
架构分为四层:
感知层:采集队列长度、工具响应时间、错误率、上下文占用率等指标。采集频率 200 毫秒,聚合窗口 1 秒。
控制层:包含一个 PI 控制器(控制队列长度)和一个简化 ESO(估计总扰动)。控制周期 500 毫秒。
执行层:根据控制量调整并发度、超时阈值、重试策略、工具路由权重。
保护层:硬限幅、熔断、降级。控制量再大也不能超过系统物理上限。
4.2 核心控制回路的代码实现
import time import threading from collections import deque class AgentController: def __init__(self, target_queue=50, kp=0.8, ki=0.05, kd=0.01): self.target = target_queue self.kp, self.ki, self.kd = kp, ki, kd self.integral = 0.0 self.prev_error = 0.0 self.max_concurrency = 32 self.min_concurrency = 2 self.base_concurrency = 8 self.eso = AgentESO(beta1=80, beta2=160, b0=0.5) self.lock = threading.Lock() def compute(self, queue_len, dt): with self.lock: error = self.target - queue_len self.integral += error * dt # 积分限幅,防止饱和 self.integral = max(-200, min(200, self.integral)) derivative = (error - self.prev_error) / dt if dt > 0 else 0 self.prev_error = error # PID 输出 pid_output = (self.kp * error + self.ki * self.integral + self.kd * derivative) # ESO 扰动补偿 z1, z2 = self.eso.update(queue_len, pid_output, dt) # 用扰动估计修正控制量 compensated = pid_output - z2 * 0.3 # 计算目标并发度 target_conc = self.base_concurrency + compensated # 硬限幅 target_conc = max(self.min_concurrency, min(self.max_concurrency, target_conc)) return int(target_conc)这段代码的核心逻辑是:PID 根据队列偏差计算基础并发调整量,ESO 估计总扰动并做补偿,最后硬限幅保证安全。实测下来,这个控制器能在 3-5 个控制周期内把队列长度拉回目标值附近,而且对突发流量有很好的缓冲能力。
4.3 工具路由的自适应权重调整
除了并发度,工具路由也是重要的控制手段。当某个工具的响应时间持续偏高时,应该自动降低它的权重,把流量导向更健康的工具。
class ToolRouter: def __init__(self, tools): self.tools = tools # {name: {'weight': 1.0, 'latency': deque(maxlen=20)}} def update_weights(self): for name, info in self.tools.items(): if len(info['latency']) < 5: continue avg_lat = sum(info['latency']) / len(info['latency']) # 延迟越高,权重越低,但保留最低权重 info['weight'] = max(0.1, 1.0 / (1.0 + avg_lat / 1000)) def select_tool(self): total = sum(t['weight'] for t in self.tools.values()) r = random.random() * total cumulative = 0 for name, info in self.tools.items(): cumulative += info['weight'] if r <= cumulative: return name return list(self.tools.keys())[-1]这个路由器的好处是:不需要硬编码“工具 A 比工具 B 快”这样的规则,权重会根据实际表现自动调整。当工具 A 变慢时,它的权重自然下降,流量自动转移到工具 B。当工具 A 恢复后,权重又会慢慢回升。
4.4 上下文窗口的主动管理
长对话智能体最容易出的问题就是上下文窗口被塞满。传统的做法是“满了就截断”,但这太被动了。用控制论的思路,我们应该把上下文占用率作为一个被控量,主动管理。
class ContextManager: def __init__(self, max_tokens=8000, target_ratio=0.7): self.max_tokens = max_tokens self.target = max_tokens * target_ratio self.history = [] def add_message(self, message, token_count): self.history.append({'msg': message, 'tokens': token_count}) current = sum(h['tokens'] for h in self.history) if current > self.target: # 超过目标水位,触发摘要压缩 self.compress() def compress(self): # 保留最近 30% 的消息,其余摘要 keep_count = max(3, int(len(self.history) * 0.3)) old = self.history[:-keep_count] recent = self.history[-keep_count:] if old: summary = self.summarize(old) self.history = [{'msg': summary, 'tokens': len(summary) // 4}] + recent这个管理器的关键是target_ratio的设定。设成 0.7 意味着在窗口用到 70% 时就开始压缩,留出 30% 的缓冲空间。这个缓冲空间非常重要——它保证了即使突然来了一段长消息,系统也不会立刻溢出。
4.5 熔断与降级的控制论解读
熔断器本质上是一个“ bang-bang 控制器”:当误差超过阈值时,控制量直接拉到极限(断开);当误差回到阈值以下并持续一段时间后,控制量恢复(闭合)。这种控制方式简单粗暴但有效。
降级则是“多级控制”的思路:当一级控制量不足以消除偏差时,启用二级控制。比如,先降低并发度;如果还不够,就关闭非核心功能;再不够,就只保留最核心的链路。
我在实际项目里把熔断阈值设成“错误率 5% 持续 10 秒”,降级策略分三级:一级降级关闭日志详细采集,二级降级关闭非核心工具,三级降级只保留核心任务处理。这套机制在多次上游故障中保住了系统的核心可用性。
5. 常见问题与排查技巧实录
5.1 控制回路振荡怎么办
振荡是控制回路最常见的问题,表现为被控量在目标值附近来回摆动,始终无法稳定。在智能体场景里,振荡的典型表现是并发度忽高忽低、任务队列长度反复穿越目标值。
排查思路分三步走:
先看 P 值是不是太大了。P 值过大会导致系统对偏差过度反应,冲过头了再往回拉,形成振荡。解决方法很简单:把 P 值降到原来的 60%-70%,观察振荡是否减弱。
再看控制周期是不是太短了。如果控制周期小于系统的响应时间,控制器会在系统还没对上一次控制做出反应时就发出新的控制指令,这必然导致振荡。把控制周期拉长到系统响应时间的 1/3 到 1/5。
最后看有没有测量噪声。如果队列长度的测量值本身就在剧烈跳动,控制器会把这些噪声当成真实偏差来响应。解决方法是在测量端加滑动平均滤波,或者在控制器里降低 D 项权重。
避坑技巧:在智能体场景下,我习惯在控制器输出端加一个“变化率限制器”,限制每次控制量的变化幅度不超过前一次的 30%。这个简单的措施能消除大部分振荡。
5.2 积分饱和导致恢复缓慢
积分饱和的表现是:系统已经恢复正常了,但控制量还在高位,导致被控量反向超调。在智能体里,这表现为“队列已经清空了但并发度还降不下来”,浪费资源。
解决方法有两个:一是积分限幅,给积分项设一个上下限;二是积分分离,当误差很大时暂时关闭积分项,等误差回到一定范围内再启用。
def compute_with_anti_windup(self, queue_len, dt): error = self.target - queue_len # 误差大时关闭积分 if abs(error) > 30: self.integral = 0 else: self.integral += error * dt self.integral = max(-100, min(100, self.integral)) # ... 其余计算5.3 ESO 估计不准的排查
ESO 估计不准通常表现为:扰动补偿后系统反而更不稳定了。原因可能是beta1和beta2参数不合适,或者b0与实际系统增益不匹配。
beta1和beta2的经验值是:beta1 ≈ 2 * omega,beta2 ≈ omega^2,其中omega是观测器带宽,通常取控制带宽的 3-5 倍。如果控制周期是 500 毫秒,控制带宽大约是 2 rad/s,那么omega取 6-10,beta1取 12-20,beta2取 36-100。
b0的整定更依赖实测。我的方法是:给系统一个已知的控制量阶跃,观察被控量的响应幅度,b0大约等于“响应幅度 / 控制量幅度”。如果b0设得太大,ESO 会低估扰动;设得太小,会高估扰动。
5.4 常见问题速查表
| 现象 | 可能原因 | 排查方法 | 解决措施 |
|---|---|---|---|
| 队列持续高于目标 | P 或 I 太小 | 检查控制量是否达到限幅 | 增大 P 或 I |
| 队列在目标附近振荡 | P 太大或周期太短 | 降低 P 观察 | 降 P、拉长周期 |
| 恢复后反向超调 | 积分饱和 | 检查积分项历史 | 积分限幅、积分分离 |
| 对突发流量反应慢 | 控制周期太长 | 检查周期设置 | 缩短周期、加前馈 |
| 并发度频繁大幅变化 | 测量噪声大 | 看原始数据波动 | 加滤波、降 D |
| ESO 补偿后更不稳定 | beta 或 b0 不对 | 检查参数整定 | 重新整定参数 |
5.5 一个真实的排查案例
有一次线上智能体的队列长度一直稳定在目标值以上 20% 左右,不振荡,就是下不来。我先检查了 P 和 I,发现控制量已经打到限幅了——并发度已经拉到了最大值 32,但队列还是降不下来。
这说明问题不在控制器,而在执行层。我查了一下工具调用日志,发现有个工具的平均响应时间从 300 毫秒涨到了 2 秒,但它的权重还没有被及时调低。工具路由器的权重更新周期是 30 秒,太慢了。我把更新周期改成 5 秒,并且加了一个“响应时间超过 1 秒立即降权”的快速通道。改完之后,队列在 15 秒内就回到了目标值。
这个案例的教训是:控制回路的效果不仅取决于控制器本身,还取决于执行层的响应速度。如果执行层有瓶颈,再好的控制器也没用。
6. 从控制论视角重新理解智能体工程
6.1 稳定性是一种设计出来的属性
我越来越觉得,智能体的稳定性不是“调”出来的,而是“设计”出来的。如果你在架构设计阶段就没有考虑控制回路,后期再怎么优化 prompt、换模型、加工具,都只是在开环系统上打补丁。而如果你在设计阶段就把被控量、控制周期、反馈通道、执行机构这些控制论要素考虑进去,系统的稳定性就是内生的。
具体来说,我在搭建任何新智能体时,都会先问自己几个问题:这个系统的被控量是什么?扰动从哪里来?反馈通道有多长延迟?执行机构有哪些?控制量有没有硬限幅?这些问题回答清楚了,架构基本就稳了。
6.2 简单控制往往比复杂控制更有效
控制论里有个著名的“必要多样性定律”:只有控制器的多样性大于等于被控对象的多样性,才能实现有效控制。但这不意味着控制器越复杂越好。实际上,在智能体场景下,我见过太多因为控制器太复杂而引入新不稳定的案例。
一个 PI 控制器加上简单的限幅和滤波,能解决 80% 的稳定性问题。ESO 和前馈能解决剩下 15% 的难题。最后 5% 的极端情况,靠熔断和降级兜底。这个组合已经足够应对绝大多数生产环境了。
6.3 控制回路需要持续观测和调优
控制回路不是设好参数就一劳永逸的。业务模式在变、上游依赖在变、流量特征在变,控制参数也需要跟着变。我的做法是:每周回顾一次控制回路的性能指标,包括超调量、调节时间、稳态误差。如果发现某个指标持续恶化,就重新整定参数。
另外,我会在监控大盘上专门放一组“控制健康度”指标:控制量的变化率、ESO 扰动估计的均值、限幅触发次数。这些指标能提前预警控制回路的退化,比等到系统出问题再排查要主动得多。
6.4 给正在搭建 AI Agent 的同行几句实在话
如果你正在从 0 到 1 搭建 AI Agent,我的建议是:在写第一行业务代码之前,先把控制回路的设计想清楚。不需要很复杂,哪怕只是一个简单的队列长度 PI 控制器,也能让你的系统稳定性上一个台阶。
如果你已经在生产环境跑着智能体,但还没引入控制回路,那可以从最简单的开始:选一个最关键的指标作为被控量,加一个 P 控制器,观察一周。你会发现,很多以前认为是“模型能力问题”的故障,其实是“控制缺失问题”。
控制论这门学科已经发展了近百年,它在工业、航天、机器人领域积累的经验,对今天的智能体工程有巨大的借鉴价值。PID 和 ADRC 只是冰山一角,还有模型预测控制、鲁棒控制、自适应控制等大量工具等着我们去挖掘。把智能体当成一个控制系统来设计,而不是一个“更聪明的脚本”,这是我踩了无数坑之后最想分享的一条经验。