ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

斯坦福CS329Z第一讲:智能体系统从模型到工程化的关键认知

斯坦福CS329Z第一讲:智能体系统从模型到工程化的关键认知

CS329Z是斯坦福2024年新开的一门课,全名很长,但核心就三个字:智能体系统。第一讲标题是“智能体系统导论”,听起来像概念介绍,实际内容却很硬核。我完整跟完第一讲之后最大的感触是:这门课一上来就把“模型能力”和“系统能力”分得非常清楚——大部分Agent项目翻车,问题根本不在模型选得不够好,而是把整个系统设计当成了一个大号的Prompt工程任务来做。它其实是一个典型的系统工程问题,有调度、有记忆、有工具协议、有容错、有可观测性,一环扣一环。

这篇博文围绕第一讲的核心内容展开,把智能体系统的概念拆开讲清楚,同时结合我在真实项目里踩过的坑,补上一些工程取舍和排查经验。如果你正在做Agent开发,或者准备从“单次Prompt调用”转向“完整Agent系统”,这篇文章应该能帮你少走不少弯路。

1. 智能体系统到底是什么:从“模型”到“系统”的认知升级

开门见山的说,智能体系统不是“更强的模型”。第一讲反复强调一个观点:单个LLM模型本身不是Agent,哪怕它能力再强。只有当你给它接上了感知输入、行动输出、记忆回放、工具调用这些外围机制,并且让它在多步循环里不断“感知-推理-行动-观察”,它才变成了一个系统。这个区分很重要,因为它意味着开发重心的转移——从“选一个更聪明的模型”,变成“设计一个围绕模型的工程系统”。

我用一个实际场景来解释这个区别。假设你要做一个“自动修复Bug”的机器人。单模型的做法是:把报错信息粘贴给GPT-4o,让它给修复建议——这个做法一次只能处理一个孤立步骤,而且没法自动验证修复是否真的有效。完整智能体系统的做法则是:先让Agent读取仓库代码、复现Bug、提出修复方案,然后自动跑测试;测试失败,再把新的报错信息喂回模型,循环迭代直到验证通过。后面的这个闭环,才叫“系统”。

1.1 最小闭环:感知、推理、行动、观察

所有智能体系统,无论表层多复杂,底层都是同一个循环:

  1. 感知:接收环境反馈,可以是用户指令、API返回值、日志、测试结果。
  2. 推理:LLM基于当前上下文和目标,决定下一步行动。
  3. 行动:调用某个工具,或者生成一段回复。
  4. 观察:读取行动结果,再把它作为下一轮感知的输入。

这个循环和经典控制理论里的“传感-决策-执行”反馈回路是同构的。有意思的是,最近热词里经常出现“多智能体系统的协同群集运动控制”,研究者的视角其实可以直接平移到LLM Agent设计上——每个智能体都遵循局部感知-决策规则,宏观上群体涌现出协作行为。理解这个最小闭环,后面所有内容都顺了。

1.2 LLM在系统里承担什么角色:它不是大脑,而是主控器

第一讲有一个观点让我印象很深:LLM在系统里更适合扮演“不断选择接下来做什么”的调度者,而不是所有计算任务都往模型里塞。这个角色定位直接决定了系统的架构走向。

举个具体例子。解析JSON、统计数据、计算日期差这类确定性操作,不应该让LLM去“猜”,交给普通代码处理又快又稳。只有需要理解语义、判断计划、决定分支走向的时候,才值得调用LLM。这样分工的核心动机有三个:降低成本、提升速度、提高稳定性。代码执行是确定性的,同样的输入永远得到同样的输出;但LLM本质是概率采样,哪怕温度调到0,不同轮次下也可能产生细微抖动。所以一个务实的设计原则是:能用常规代码完成的,绝不让LLM代劳;LLM负责弹性判断,代码负责刚性执行。

2. 智能体系统的核心机制:规划、记忆与工具调用

“循环”只是骨架,要让智能体系统真正运转起来,还需要四个核心机制:规划、记忆、工具调用、多Agent协调。第一讲用了大部分篇幅逐一拆解,我按自己的理解重新组织一下,重点是讲清楚每个机制的实现思路和选型理由。

2.1 规划:把大目标拆成可执行步骤

规划的核心是让LLM把高层次的用户目标分解成一系列低层次动作。常见做法有三种:

  • Chain-of-Thought(思维链):在Prompt里要求“先思考再回答”,靠中间推理步骤提升复杂任务的准确率。这是最轻量的规划方式。
  • ReAct:推理和行动交替进行。模型先推理下一步做什么,然后调用工具,观察结果,再推理,直到任务完成。
  • 任务分解加子任务调度:把大问题拆成多个子任务,甚至可以给每个子任务分配一个子模型或子Agent。

实际项目中ReAct是目前最常用的模式。实现起来其实不复杂:每轮循环里,Prompt包含类似“Thought: 我需要查询数据库;Action: query_db; Action Input: SELECT ...”这样的格式,模型输出一个行动请求,系统执行动作,再把结果以“Observation”的形式追加回上下文,形成循环。这个模式之所以好用,是因为它把推理过程显式暴露出来,人能看到模型每一步在想什么、在做什么,排查问题的时候就方便多了。

2.2 记忆:别指望上下文窗口能一直撑下去

第一讲讲记忆的时候说了一句大实话:上下文窗口再大,也撑不住一个长期运行的智能体系统。这句话我深有体会。原因有两个:一是LLM的注意力机制对超长上下文的中间部分存在明显衰减,前面的关键信息容易被“遗忘”;二是Token成本随输入长度线性上涨,长期跑下来经济上根本扛不住。

所以记忆必须分层设计。我习惯把Memory分成三层:

  • 短期记忆:就是上下文窗口本身,只放当前任务必要的信息。
  • 工作记忆:对话历史摘要、中间结果缓存。主动把旧内容压缩成摘要,塞进后续调用。
  • 长期记忆:外部存储,向量数据库、普通数据库或文件系统,保存跨会话的知识。

工程实现上,向量检索并不是万能的。我踩过很多次坑之后发现,“混合检索”更稳:先用向量检索找出语义相关的片段,再用BM25这类关键词检索补充精确信息,最后按时间排序合并结果,拼进Prompt。尤其是遇到代码片段、ID、配置项这类需要精确匹配的内容时,纯向量检索经常召不回,关键词检索能兜底。

2.3 工具调用:Agent的能力边界取决于工具

LLM本身不会发HTTP请求、不会读本地文件,它必须通过工具调用机制和外部世界交互。OpenAI的Function Calling就是让模型输出结构化的JSON,指名要调用的函数和参数;开源生态里则有Gorilla、ToolLLM这类微调模型方案。

Function Calling看起来方便,但实际用起来有一个很常见的坑:模型会产生“幻觉参数”。比如从上下文里提取一个根本不存在的订单号,或者把布尔类型的参数当成字符串传进去。所以工具层前面必须加输入校验:类型检查、取值范围检查、必填参数检查。校验不通过就拦截,不要指望模型重新采样一两次能自己修正。我的经验是:宁可让系统返回“参数不合法”让Agent重试,也不要让脏数据溜进核心业务逻辑。

2.4 多智能体协同:别让“群聊”变成“群魔乱舞”

“多智能体系统的协同群集运动控制”这个词最近频繁出现在各种技术讨论里。它来自控制论视角,强调的是多个智能体如何通过局部规则达成全局协作。这个思路放在LLM Agent系统里,对应的是几种常见架构模式:

  • 单一Agent加工具:最简单,覆盖70%的场景。
  • Supervisor模式:一个主控Agent负责调度多个Worker Agent。
  • 流水线模式:Agent A的输出作为Agent B的输入。
  • 辩论模式:多个Agent对同一问题各抒己见,最后投票或汇总。

工程上的建议很明确:默认从一个Agent开始,只有当你发现单个Agent的上下文明显混乱、难以维护时,再考虑拆分。很多Agent框架都搞了花哨的“多智能体群聊”,但真实业务里,多个LLM Agent自由对话经常变成互相跑题,产出质量反而下降。多Agent的真正难点在于定义好通信协议、任务分配机制和信息共享边界,这些设计不做好,多Agent只会放大单Agent的问题。

3. 构建可靠系统的工程实践:容错、评估与可观测性

第一讲最核心的部分,其实是关于可靠性。LLM是概率模型,这意味着“出错”是常态,不是异常。可靠AI系统的核心能力不是让模型永不犯错,而是让系统在模型犯错时还能兜得住。这也是为什么“自主容错控制”这个概念在智能体工程里越来越受重视。

3.1 容错设计:承认模型会犯错,用系统兜底

容错要分三个层次来做,缺一不可。

请求级容错是最基本的:重试机制要加指数退避,避免高频重试把下游API打爆;超时处理必须设上限,防止Agent在单个请求上卡死;降级策略也要提前想好,比如主模型不可用时,是降级到小模型,还是返回明确错误给用户。

流程级容错要更聪明一点。核心思路是加验证器。以自动修Bug为例,Agent给出代码补丁后,必须自动跑一遍测试,测试通过才允许进入下一步。验证器可以是代码编译、测试用例、数据格式校验,或者任何能确定性判断结果好坏的规则。这个机制把模型的不确定性限制在可控范围内。

业务级容错是最后一道防线。高风险操作前面加人工审批闸门,或者设置“最大尝试次数”循环上限。我在实际项目里见到太多Agent在同一个错误点上疯狂重试,烧掉几千个Token还在原地打转。解决办法是维护一个最近N步的动作历史,如果出现三到五次完全重复且结果不变的情况,就强制终止当前计划,转入备用路径。

3.2 评估体系:Agent评测不等于模型评测

第一讲里有一个观点值得反复琢磨:评估智能体系统,要看“端到端任务成功率”,而不是单个Prompt的输出质量。模型评测一般看答案准确率,但系统评测要看的指标完全不同。

我建议至少跟踪以下几个指标:

指标定义参考意义
任务成功率端到端完成目标的概率系统整体可靠性的直接度量
平均执行轮数Agent完成任务需要多少轮推理-行动循环轮数过高说明规划能力差或工具描述不清晰
工具调用失败率全部工具调用中失败的比例高频失败说明工具描述或参数Schema设计有问题
错误恢复率首次执行失败后,通过重试或修正最终成功的比例衡量容错机制是否真正有效
单任务Token成本完成一次任务平均消耗的Token数业务化运营必须关注的指标

这些指标统计出来之后,要沉淀成一个“金标准评测集”。每次改动Prompt、换模型、调工具参数之前,先跑一遍金标准集做回归测试。没有评测集的Agent优化就是盲人摸象——今天这个改完感觉好了一点,下周新改动又把之前的效果弄丢了,根本无从查起。

3.3 可观测性:没有追踪就没有迭代

第一讲用了一个很形象的比喻:调试Agent系统就像追着一个疯子保姆满屋子跑。如果看不到它每一步看到了什么、为什么做那个决策,你永远没法改好它。可观测性是Agent开发里最容易被低估的工程环节。

我每次搭Agent系统,第一件事就是埋日志。需要记录的信息至少有:

  • 每次LLM调用的完整输入输出,包括System Prompt、User消息、模型原始输出。
  • 工具调用的参数和返回结果。
  • 上下文截断或摘要发生时,原始内容被删掉/压缩了哪些。
  • 每一步的Token消耗和耗时。
  • 用户最终反馈。

这些日志最后要能完整回溯一条“决策链”:用户说了什么,模型想什么,工具返回了什么,模型怎么理解这个返回结果,最后输出了什么。有了这个链路,排查问题才有据可依。我见过太多线上Agent报错、开发人员对着一行报错信息干瞪眼的场景。结构化日志早做一天,后面排查效率提升的不止十倍。

3.4 缓解幻觉:结构化约束加验证器加人工兜底

第一讲对幻觉的态度非常务实:根除不了,但可以管理。管理手段有三个层次。

第一层是结构化输出约束。用JSON Schema、Pydantic模型这类手段把模型的输出限制在固定格式内,把幻觉圈在格式的笼子里。第二层是验证器。格式合规之后,还要做语义审查,校验关键字段是否真实存在。比如让Agent从一段对话里抽取“订单号”,它可能编出一个格式完全正确但根本不存在的号码。这种幻觉靠JSON Schema挡不住,关键字段必须和数据库对照做存在性校验。第三层是人工兜底。凡是不能被确定性规则验证的模型决策,默认当作可疑处理,关键环节必须有人审批。

这里分享一个原则:所有由模型生成的决策,如果能被规则校验,就一定要加规则校验。没有规则能覆盖的部分,再暴露给用户确认。这个原则能挡掉大多数灾难性错误。

4. 从第一讲到落地:三个高频问题与排查思路

平时帮人看Agent项目代码,最常被问到的就是三个问题:工具调用不稳定、Agent陷入死循环、上下文爆炸。这三类问题在第一讲里各有对应章节,但实际排查时还有一些细节值得补充。

4.1 工具调用不稳定,先查Prompt再查Schema

不少人的第一反应是“换个更强的模型”,但大多数时候问题根本不在模型上。工具调用不稳定的常见原因有三个:工具描述写得含糊,模型不知道什么时候该用;参数Schema设计不合理,比如把自由文本塞进枚举类字段;系统Prompt里没有给工具的使用优先级说明。

正确的排查顺序是:先翻结构化日志,看失败调用属于“选错工具”还是“参数错误”。选错工具就去改工具描述,在描述里明确写“这个工具在什么情况下用、什么情况下别用”;参数错误就优化Schema,必要时给模型预留一个自由输入字段。改完之后跑一遍金标准集,确认改动没有引入新问题。

4.2 Agent陷入死循环,先做循环检测

死循环的症状很典型:Agent一遍遍执行同一系列操作,反复调用同一个工具,每次结果都一样,但就是不停止。触发原因通常是Prompt指令和上下文信息不完整,也可能是模型本身规划能力不够。

工程上先加循环检测机制:维护最近几轮的动作历史,出现重复动作且结果不变时,强制中断循环,转入手动规划好的Plan B。Plan B可以是重新制定计划、向用户提问澄清、或者用普通代码脚本直接完成子任务。很多框架没有内置这个机制,自己实现一个也不难——本质上就是一个字典,记录动作签名对应的执行次数,超过阈值就触发保护。

4.3 上下文爆炸,用摘要和裁剪解决

长期运行的Agent一定会遇到上下文超长的问题。场景是这样的:对话轮数越来越多,历史全部堆在Prompt里,Token成本飙升,响应时间变长,更糟的是模型开始忽略中间的关键信息。

主流解法有三种:

  • 对话历史滚动摘要:轮数或Token数超过阈值时,先用LLM把旧对话压缩成一段摘要,只保留摘要加最近内容。
  • 裁剪低价值上下文:比如原始日志很长,只保留关键报错行;网页正文太长,只抽取与任务相关的段落。
  • 外部记忆分层:把已经完成的分析结果写到长期存储,需要的时候再检索回来,而不是一直挂在上下文里。

需要提醒的是,摘要本身有成本,而且会损失细节。我更推荐的做法是切分场景而非一味摘要。复杂任务拆成多个子任务,每个子任务保持短上下文,完成一个归档一个。这样比无限扩展单次上下文要稳得多。

4.4 智能体系统的适用边界:什么时候不要用Agent

最后聊一个话糙理不糙的问题。第一讲结尾的问答环节反复强调:不是所有需求都该做成Agent。固定流程、高精度要求、低频变化的任务,用传统工作流更合适;Agent适合的是开放任务、输入不可控、流程需要动态调整的场景。

我自己有一个判断标准:如果任务流程在写代码的时候就能完整固定下来,那就没必要引入LLM做编排。Agent的价值在于处理“没法提前写死”的流程。一旦发现流程可以写死,写死永远比让模型靠猜更可靠、更便宜。这个边界意识很重要,它能帮你在Agent热潮里保持克制,把模型用在真正能发挥灵活性的地方。课程里教的是怎么把Agent做出来,但真正的工程智慧在于知道什么时候不要用Agent——这个判断力,恰恰是CS329Z第一讲端出来最有价值的东西。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进