☰
从Chatbot到Agent:LLM智能体系统设计与工程实践
2026/10/10 4:29:46 网站建设 项目流程

同样一个 LLM,有人拿它做了一个只会聊天的漂亮外壳,有人却用它搭出了能自主调研、自动写码、甚至自己给自己修 bug 的 Agent。差距不在模型大小,而在“系统”。斯坦福 CS329Z 这门课,讲的就是 Agentic Systems——智能体系统——从概念到工程的完整框架。这篇笔记是我对第一讲导论的学习复盘,也是把课程观点和我自己项目经验揉在一起后的浓缩版,目标读者是正在做 LLM 应用开发、想从 Chatbot 迈向下一个阶段的工程师朋友。

需要先说清楚一件事:CS329Z 不是“提示词进阶教程”。它把 LLM 当成一个被放进复杂环境里的“行动体”,讨论怎么让它调用工具、拆分任务、记住关键信息、从错误中恢复,以及最后怎么评估和上线。第一讲本身内容量不大,但它像一张地图,把整门课的家底都铺开了。看完第一讲,你真正能带走的是一个思维转换:从“我写一段好 prompt 让它回答得好”到“我设计一个系统,让它在没人盯着的情况下也能把事情办成”。

1. CS329Z 这门课到底在讲什么

1.1 第一讲里最基础的一个转向:从“生成器”到“行动体”

第一讲抛出的核心命题我理解下来是这样的:传统 LLM 应用的本质是“单次生成”。你给我输入,我给你输出,一段文字结束,调用就结束了。但真实任务几乎都不是一次性文本生成——比如“帮我调研这三个竞品的定价策略,生成一份对比表”,这个任务需要搜索、打开页面、提取数据、比对口径、整理结构,最后才形成报告。任何一个环节失败,都必须有下一步决策:换个站点搜、换个关键词、或者先问用户优先级。

这就是 Agent 和 Chatbot 的本质差异。课程把 LLM 重新定位成“处于环境中的行动体”,它不再只是吐出 token,而是在一个目标约束下连续地观察环境、做出动作、承担后果。这个定位一换,所有工程问题都变了:你要考虑工具怎么暴露、状态怎么保存、权限怎么控制、失败怎么恢复。CS329Z 第一讲就是在给你换这个脑子。

1.2 为什么 Agent 在最近两年才真正开始爆发

Agent 这个概念其实很老,2016 年前后就有游戏智能体、机器人控制这类方向。但那时候做一个能自主决策的 Agent,需要自己训练策略网络、自己调奖励函数、自己准备海量样本,成本高得离谱,普通团队根本玩不动。LLM 出现之后,门槛一下被削平了:你不需要训练决策模型,你只需要给一个预训练模型提供“推理提示 + 工具清单 + 输出格式”,决策由模型本身来做。

所以课程里反复出现一个词:脚手架(scaffolding)。大多数智能体能力不是模型天赋出来的,而是外面套了一层壳——任务分解策略、自我纠错流程、工具调用规范、记忆管理机制。这层壳是工程问题,不是模型问题。这也是 CS329Z 存在的理由:它不教你怎么训模型,教你给模型盖这层壳。

1.3 课程整体框架与第一讲的位置

从公开的课程目录来看,主线大体是这样的:先讲 Agent 基础与典型应用场景,然后深入工具调用和函数接口,接着是规划与推理、记忆管理、多智能体协作,再往后是评估、对齐,最后落到生产级可靠性。第一讲就是一张地图,告诉你后面每一节课解决的是整张图里的哪一块。

我学完第一讲之后的最大感受是:这不是“教你写 prompt”的课,而是“教你像设计分布式系统一样设计 Agent”。如果你要做的是一个 production 级智能体而不是演示 Demo,这门课的方向非常对口。哪怕只是看第一讲,你也能立刻意识到自己之前做的 Agent 到底缺了哪几块:没有状态管理、没有评估闭环、没有退化预案。

2. 智能体的骨架:控制循环、工具调用与记忆管理

2.1 把控制循环画在纸上:Think → Act → Observe

第一讲会反复出现一个基本运行循环。无论你用 LangGraph、AutoGen、CrewAI 还是纯手写,Agent 的内核其实是同一个模式:

  • Think:模型根据当前状态和目标做推理或计划
  • Act:调用一个工具或执行一个具体动作
  • Observe:观察动作返回的结果
  • 回到 Think,决定下一步

这个过程通常会不断重复,直到任务完成、步数耗尽、或者触发停止条件。建议把循环画在纸上再写代码。做第一个 Agent 时,我直接对着循环图把每个节点拆成一个函数:plan(state)、act(state)、observe(state),调试的时候就能精确定位是“模型的计划错了”还是“工具的执行错了”还是“我解析结果错了”。相比之下,把逻辑塞进一个巨大 prompt 里,出了问题你会完全无从下手。

2.2 工具调用的成败,往往藏在“描述”里

工具调用是智能体跟世界交互的接口。很多人以为把函数列出来模型就会乖乖用,实际根本不是这样。我总结过一条规律:一个工具的 description 写得越像“给人看的使用手册”,被正确调用的概率就越高。什么叫给人看的使用手册?至少要包含三件事:这个工具是干什么的、在什么场景下使用、常见的坑和报错是什么。

举一个函数声明的例子:

tools = [ { "type": "function", "function": { "name": "search_products", "description": ( "按关键词搜索商品列表。" "当用户想查找某个商品时使用。" "示例:'找一下200元以内的蓝牙耳机'应传入 price_max=200。" "若结果为空,建议提示用户更换关键词或放宽价格区间。" ), "parameters": { "type": "object", "properties": { "keyword": {"type": "string", "description": "商品关键词"}, "price_max": {"type": "number", "description": "最高价格,可选"}, }, "required": ["keyword"], }, }, } ]

第一讲虽然不细抠 API 格式,但一定会强调一个原则:工具是智能体“可控行动的边界”。模型只可能调用你暴露出来的工具,也只可能按你写的描述去理解工具的作用。你给的工具边界有多大,模型的行动边界就有多大。这是个安全话题,也是可靠性话题。工具描述写不好,后面所有环节都会跟着出错。

2.3 记忆不是越长越好,而是分层管理

第一讲里关于记忆的内容,印象最深的观点是:上下文窗口不是记忆,它只是工作台。你可以把窗口想象成一张桌子,桌子再大,堆满东西之后你反而找不到需要的工具。真正的长期记忆应该放到外部:

  • 用向量库或结构化存储保存历史事实与用户偏好
  • 定期对老对话做摘要压缩
  • 明确设计“什么信息写入记忆、什么信息只留在当前对话”

这样做的原因很简单。Agent 任务一长,把所有原始信息都塞进上下文,模型注意力会被稀释,回复质量反而下降。把已经处理过的信息归档到外部,模型才能保持焦点。实际项目里,我通常会在每轮循环结束时,让 Agent 判断一下“当前这轮有没有值得长期保存的信息”,命中就写入外部存储,而不是每轮无条件往里堆。

3. 构建可靠 Agent 的工程防线:容错、评估与可观测性

第一讲导论严格来说没有专门讲工程可靠性,但整个课程都在为这个问题做铺垫。现在圈子里聊得最多的“LLM 智能体自主容错控制”和“构建可靠 AI 系统的工程实践”,其实就是这个方向。这是智能体从 Demo 到生产最难跨过的一道坎,值得用一整节说透。

3.1 失败是默认状态:单点错误会滚成累积错误

先算一笔简单的账。假设智能体每一步执行的成功率是 95%,看起来不低,但一个需要 5 步的任务,整体成功率是 0.95^5,约等于 77%;10 步任务直接掉到 60% 左右。也就是说,只要 Agent 需要多步行动,失败就不是“偶发事件”,而是默认状态。

第一讲给你的正是这种系统思维:单独看模型每次回答都像模像样,但串成一个长任务之后,任何一步偏一点,最终结果可能面目全非。所以生产级 Agent 必须把“每一步都可能失败”当前提来设计,而不是当异常来容忍。谁先把心态从“让它别出错”调成“出错之后怎么办”,谁就能在工程化上领先一步。

3.2 我实战中真正用上的容错手段

下面这些手段不是课程原话,都是我基于第一讲的思路、在真实项目里反复试出来的,按优先级排列:

  1. 重试加指数退避。面对限流、网络抖动,不能只重试一次。tenacity这类库可以直接用,或者手写一个循环:首次失败等 1 秒,第二次 2 秒,第三次 4 秒,最多 5 次。这里的关键不是“多试几次”,而是“别把限流试成熔断”。

  2. 为每个动作要“凭据”。Agent 说“我已经发送了邮件”不算数,要让它返回邮件 API 的 message_id;说“文件已生成”不算数,要让它返回文件大小或哈希值。下一步决策必须建立在可验证的凭据上,而不是模型的自我陈述。

  3. 检查点持久化。把任务状态存到数据库或本地文件,标记当前执行到第几步。一旦中途崩溃,可以从失败步骤恢复,而不是整个任务重来。我做过一个数据搬运 Agent,在第 3 步拉取第三方 API 时超时,有检查点的版本只重试了第 3 步,没有检查点的版本把所有接口又重新请求了一遍,成本和耗时直接翻了三倍。

  4. 步数与预算上限。每轮循环递增step_index,超过max_steps就强制终止,并输出“当前已完成的部分 + 剩余未完成的原因”。防止 Agent 在一个分叉里无限打转。

  5. 自动降级路径。主工具挂了,切备用工具。比如主搜索 API 限流,就切到备用的搜索接口,再不行就退化成“直接给用户几个建议关键词,让用户自己确认方向”。降级的核心原则是:宁可交出一个不完美但明确的中间结果,也不要让用户对着一个卡死的对话等半天。

  6. 人工确认闸门。对“删除数据、发送对外消息、执行支付”这类不可逆或高风险动作,必须暂停循环,把动作内容和后果展示给用户,等确认再继续。这一点在课程后面的对齐和可靠章节会被反复强调,但从第一讲开始就应该刻在脑子里。

3.3 可观测性:把 Agent 的过程变成可回放的录像

很多 Agent 项目失败后很难排查,就是因为只记录了最终结果,没记录过程。我强烈建议无论项目多小,都要把“轨迹日志”当作第一优先级。至少每个动作记录以下字段:

  • 时间戳与执行顺序
  • 模型的输入消息与输出内容
  • 被调用的工具名称、参数、原始返回
  • token 消耗和延迟
  • 任何告警或异常信息

有条件的话,把完整循环过程落成结构化数据,相当于每一步都留存了“录像”。有了这套数据,定位错误会快很多。比如用户反馈“结果不对”,你可以回放轨迹看到:第 2 步模型选错了工具,还是第 3 步工具返回了脏数据。没有轨迹,这一切只能靠猜。

3.4 评估:没有评测集,可靠性无从谈起

第一讲虽然没有展开评估,但整个课程都渗透着同一个理念:可靠工程离不开可量化的评估。我们现在开发 Agent,不是“调好一个 prompt 就行”,而是要在迭代中持续确认“改动到底是变好了还是变差了”。建议维护三类测试集:

  • 单步工具选择测试:给一个用户请求,预期调用哪个工具、传什么参数;
  • 端到端任务测试:给一个完整任务,校验最终产物是否满足要求;
  • 回归测试:把历史上失败过的 case 全部收进来,每次改系统都要重新跑一遍。

模型一更新,Agent 的行为很可能大变。没有回归测试兜底,你根本不知道一次升级是把工具调用准确率提高了,还是把某个隐蔽路径搞崩了。这就像给智能体装了一个刹车系统,平时看不出作用,关键时候能救你一命。

4. 第一讲里值得反复咀嚼的设计思想

4.1 系统提示词不是“生活指南”,而是“操作手册”

第一讲没有直接教怎么写系统提示词,但给出的智能体范例都不是“你是一个友好的助手”这种风格。真正有效的系统提示词,写的是判断标准和默认行为。举几个例子:

  • “如果搜索结果为空,主动询问用户是否放宽关键词,而不是编造结果。”
  • “任何涉及删除数据的操作,必须先执行 dry-run,并等待用户明确确认。”
  • “当用户说‘查找物流’时,先调用 get_order 获取订单号,再调用 track_package。”

这就是把提示词从“价值观宣言”改成“操作手册”。操作手册的每一句话都应该能指导模型在某个具体岔路口做出选择。你给它写的例外情况越多,它在真实边界上的表现就越稳。这个认知会贯穿整门课。

4.2 多智能体的本质是分工,不是人多

后来课程会展开多智能体,但第一讲已经在为这个主题铺路。多智能体架构为什么有效?不是因为“多个模型一起想更聪明”,而是因为它让你能拆分职责、隔离权限、独立测试。比如 planner-executor 模式里,planner 只负责任务分解,executor 只负责执行具体调用,supervisor 负责汇总和验收。每个角色手里的工具都是最小集:executor 拿不到最终审批权,supervisor 拿不到执行细节。这本质上是一种权限分割,跟“人多力量大”完全是两码事。

设计多智能体系统时,要反复问自己一个问题:这个决策到底应该由哪个角色负责?如果谁都能写文件、谁都能发请求,那系统就退化成一堆互相竞争的工具箱。边界越清晰,系统越可靠。

4.3 越昂贵、越危险的动作,越要有闸门

还有一个思想贯穿第一讲:让 LLM 自主不等于把所有权力交给它。你可以让 Agent 自己规划路径、自己试探性执行,但涉及发送对外消息、修改生产数据、消耗大量预算的动作,都要设置人为或半自动的闸门。更直白地说,可控的自主才是最有价值的自主。

我在项目里实际采用的做法是给每个工具分配一个“自主等级”:只读类工具可以直接执行;写入类工具需要业务规则校验;不可逆类操作必须经过人工确认通道。这样既保留了 Agent 的自主性,又把风险锁在可控范围内。第一讲反复暗示的一件事就是这样:真正优秀的智能体系统设计,一定是对用户负责的系统设计。

5. 从第一讲出发:给入门者的实操路线

5.1 最小复现:先搭一个会犯错、可追踪的 Agent

听完第一讲,不要急着上复杂框架。先花三天搭一个最小闭环,选一个简单的真实任务,比如“让 Agent 从某个公开 API 拉数据,汇总成 Markdown 文件”。你需要的东西很少:一个 LLM 接口、一个工具函数、一个循环逻辑、一套轨迹日志。

我用过的手写骨架大概是这个意思:

state = {"step": 0, "messages": [system_prompt], "result": None} while state["step"] < max_steps: state["step"] += 1 response = llm_call(state["messages"], tools) log_trace(state["step"], response) if response.finish_reason == "stop": state["result"] = parse_result(response) break tool_name, tool_args = parse_tool_call(response) tool_result = execute_tool(tool_name, tool_args) state["messages"].append(tool_result)

这段代码没有用什么高级框架,但已经具备了 Agent 的三要素:循环、工具调用、状态累积。先跑通这个最小闭环,再用 LangGraph 或 AutoGen 去重构,你会发现自己对每个抽象层的理解都完全不同。

5.2 最容易踩的几个坑

  • 把精力全花在 prompt 上,不搭日志。等到出了问题,没有任何痕迹能帮你复盘。
  • 一上来就配多智能体。两个 Agent 之间消息格式没对齐,调试成本能让你崩溃。先做单 Agent,跑通再加入角色。
  • 不设步数上限。曾经有个 Agent 在“确认文件是否已存在”这个判断上循环了二十几次,最后账单比预期贵了十倍。
  • 忽略工具返回的异常信息。工具报错不是终点,而是下一轮决策的输入。把报错透传给模型,让它自己决定是换方案还是问用户。

5.3 后续学习建议

看完第一讲之后,可以有两条线继续走:一条是理论线,把规划的几种模式、记忆的具体实现、评估体系的设计逐个吃透;另一条是工程线,选一个端到端项目持续迭代。比如从一个数据整理 Agent 开始,加上评估集,再加检查点,再加人工确认闸门,你会亲眼看到系统可靠性是怎么一层层堆起来的。

我之前在实战中最大的体会是:智能体系统的难点从不在“让模型听话”,而在“让模型在没听到指令的时候也知道该怎么办”。第一讲最值钱的地方,就是让你提前看到这个问题,并且告诉你后面几周会一个个拆解它。现在回头看,能把这一步想清楚,后面的路都会顺很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询