Skip to content

框架实战递进练习 ​

这些练习默认你已经完成 裸 API 手写 Agent、LangGraph 和 Agent SDK 的最小示例。每题都从上一题的代码继续改,不要另起一个完全不同的天气或聊天 demo。

练习的目标是让你亲手做出取舍。代码可以很短,但每次改动都要记录:改了哪个边界、运行现象有什么变化、出现问题时你先查哪里。

练习一:给裸 API Agent 加知识检索 ​

起点 ​

从 Raw API 版本开始。保留已有的模型调用循环和一个只读工具,把天气工具替换为本地 search_knowledge。知识库可以先用列表或 JSON 文件模拟,返回标题、片段、来源和更新时间。

要改哪段 ​

  1. 修改工具 schema,让 query 成为必填字符串,并限制返回条数。
  2. 修改工具执行函数,只返回模型回答所需的字段,不要把整个文档文件塞进消息。
  3. 在 system prompt 中写明:没有检索证据时要说明资料不足,不能编造公司制度。
  4. 在日志中增加检索耗时、命中文档 ID 和返回片段数量。

预期现象 ​

询问“VPN 怎么申请”时,模型会先调用检索工具,再根据片段回答并带出来源。询问“讲个笑话”时,不应因为工具描述太宽泛而盲目检索。

排查提示 ​

  • 工具始终不被调用:先检查 tools 是否真正传入模型,以及 description 是否说明了适用场景。
  • 模型回答没有使用片段:打印回传的 role: tool 消息,确认 JSON 可解析且没有超出上下文。
  • 所有问题都触发检索:收窄工具描述,并增加一个“不需要知识库”的反例测试。

思考方向 ​

为什么“没有证据时拒答”应该同时写在提示词和代码日志里?如果检索结果带有恶意指令,下一步你会在哪一层做过滤?

练习二:把同一分支搬进 LangGraph ​

起点 ​

使用练习一的两个工具:search_knowledge 和 get_ticket。先在 Raw API 中确认两种问题都能跑,再打开 LangGraph 版本。

要改哪段 ​

  1. 在 state 中增加一个表示请求类型的字段,例如 intent,并规定只有路由节点写它。
  2. 新增一个路由节点,根据用户问题把流程送往知识检索或工单查询。
  3. 为“无法判断”设置明确出口:要求用户补充信息,不能让图随机选择工具。
  4. 让两个分支最后汇合到同一个回答节点,避免复制两份生成逻辑。

预期现象 ​

“VPN 怎么申请”与“INC-1042 到哪一步”会走不同节点,但最终由同一个回答节点组织结果。模糊问题会走澄清出口,图不会无限绕圈。

排查提示 ​

  • 节点拿不到用户问题:检查 state 初始化时是否把原始消息放进 messages。
  • 图直接结束:打印条件边返回值,并核对映射表中的节点名称。
  • 两个分支的结果互相覆盖:检查 state 字段的单一写入者,必要时把证据拆成不同字段。

思考方向 ​

路由由模型分类还是由规则分类更合适?如果分类模型本身失败,默认走哪个出口才不会误调用有副作用工具?

练习三:加入可控的超时与重试 ​

起点 ​

继续使用 LangGraph 版本,让 get_ticket("INC-9999") 模拟超时,让 search_knowledge("unknown") 模拟空结果。

要改哪段 ​

  1. 在工具层给异常统一分类,至少区分超时、参数错误、权限错误和资料为空。
  2. 在 state 中增加重试计数,明确最大值,不要用“只要失败就重试”。
  3. 增加错误路由:超时可重试一次,权限错误转人工或结束,空结果回到澄清节点。
  4. 为每次重试记录原因、间隔和最终去向。

预期现象 ​

超时任务最多重试一次后结束或改走备用路径;参数错误不会重复调用;资料为空会要求用户换一个关键词。运行轨迹里能看出失败节点和重试次数。

排查提示 ​

  • 图不断循环:检查重试计数是否写回 state,以及条件边是否真的读取了最新值。
  • 重试导致重复创建工单:确认副作用工具尚未接入自动重试路径,并为工具增加幂等键设计。
  • 错误信息泄露内部堆栈:在回传模型前做错误消息裁剪,完整堆栈只写受控日志。

思考方向 ​

哪些错误适合交给模型“换个参数再试”,哪些错误必须由程序直接终止?如果备用路径需要另一个模型,预算和超时如何传递?

练习四:在副作用工具前加入人工确认 ​

起点 ​

从 LangGraph 版本复制出一个“创建工单”分支。用户提出“帮我创建 VPN 权限申请工单”时,先生成草稿,不要立即执行 create_ticket。

要改哪段 ​

  1. 新增草稿节点,产出标题、描述、目标资源和风险提示。
  2. 在真正的工具节点前增加暂停点或人工确认节点,保存稳定的任务 ID。
  3. 审批恢复时重新校验操作者、草稿版本和参数摘要,确认一致后才调用工具。
  4. 为批准、拒绝、过期和重复批准分别设计结束状态。

预期现象 ​

首次运行会停在“等待确认”,不会出现工单编号。批准后只创建一次并返回编号;拒绝或过期会给出清晰原因,模型不能绕过暂停点直接调用工具。

排查提示 ​

  • 重启后找不到待审批任务:检查 checkpoint 或持久化存储是否使用稳定任务 ID。
  • 重复批准创建两张工单:检查幂等键和已处理状态是否在执行前后都被记录。
  • 用户修改草稿后仍执行旧参数:比较审批时的版本号或参数哈希,不一致就要求重新确认。

思考方向 ​

人工确认是 UI 交互、工作流状态还是模型对话的一部分?为什么不能只在 prompt 中写“执行前请询问用户”?

练习五:把最小流程迁移到 Agent SDK 并做选择 ​

起点 ​

选择你正在使用的官方 Agent SDK。用它重写练习一的“知识检索 + 最终回答”路径,保留同样的工具 schema、固定问题和 mock 返回值。

要改哪段 ​

  1. 把 Raw API 的 system prompt 和工具列表映射到 SDK 的 Agent 定义。
  2. 把手写循环替换为 SDK runner,打开事件或 tracing 输出。
  3. 在工具函数内部保留参数、权限和结果裁剪,不要因为 SDK 自动注册工具就删除校验。
  4. 用同一组十条问题对比两版的成功率、调用次数、延迟、token 和失败轨迹。

预期现象 ​

SDK 版通常少了消息拼接和循环样板,但工具边界和业务错误处理仍然存在。某些默认行为(例如重试、session 保存或事件粒度)可能与 Raw API 不同,必须记录实际版本和配置。

排查提示 ​

  • SDK 找不到工具:检查注册对象、函数签名和异步/同步模式是否符合当前版本文档。
  • 结果无法和 Raw API 对齐:先锁定模型、提示词、工具返回值和温度,再比较框架行为。
  • tracing 看不到敏感字段脱敏:检查 SDK 的采样和导出配置,必要时在进入 SDK 前先裁剪输入。

思考方向 ​

你的项目真正缺的是哪一部分:少写循环、统一 tracing、handoff,还是可暂停的复杂流程?如果半年后要支持跨模型供应商,当前 SDK 的绑定会带来什么迁移成本?

练习提交前的自检 ​

完成五题后,回到 同一个任务,三种 Agent 写法 的对照表,补齐每一格,并写下最终选择的依据。至少保留一条成功轨迹、一条工具失败轨迹和一条审批拒绝轨迹。

不要用“代码更少”“框架更流行”作为唯一结论。能否定位失败、控制副作用、恢复中断和解释成本,才是这组练习要验证的能力。

持续学习,持续实践。