🎯 课程主题
理解 Hook(钩子)函数的概念、特点及分类,为自定义中间件奠定理论基础。
📝 核心知识点
1. Hook 函数的概念
- 概念说明:在特定流程的特定时机,由框架 / 系统 / 主程序自动调用的扩展函数。主流程预留了一些"插槽",允许开发者在这些位置挂上自己的函数。
- 关键细节:
- 类比:生产车间的主流程(核心工序)中预留空档,用于参数校验、日志记录、质量检测等辅助行为——这些就是钩子函数的位置。
- 定义来源:无论是官方内置中间件、自定义中间件、还是基于装饰器定义的中间件,本质上都是通过实现一个或多个 Hook 来生效。
2. Hook 函数的两大特点
- 不是你主动调用的:不需要在业务代码中手动调用,只需定义好函数,到相应时机时框架自动触发。
- 依附于更大的执行流程:Hook 不能独立存在,必须依托于主流程(Agent 执行流程),在诸如请求开始前、模型调用前、任务结束后等特定节点执行。
3. Hook 函数的作用
- 概念说明:在不改变主流程源码的前提下,插入自定义逻辑。
- 关键细节:用于日志记录、安全检查、数据预处理、监控埋点、参数校验等横切关注点(Cross-Cutting Concerns)。
4. Agent 中的 6 个 Hook
- 概念说明:LangChain Agent(基于 LangGraph 构建)共暴露 6 个 Hook 点。
| Hook 名称 | 类型 | 触发时机 |
|---|---|---|
before_agent | Node-style | Agent 整体执行前 |
before_model | Node-style | 模型调用前(每次 LLM 请求前) |
after_model | Node-style | 模型调用后(每次 LLM 响应后) |
after_agent | Node-style | Agent 整体执行结束后 |
wrap_model_call | Wrap-style | 包裹模型调用(前后均可介入) |
wrap_tool_call | Wrap-style | 包裹工具调用(前后均可介入) |
- 关键细节:前 4 个以
wrap开头的是包装风格钩子,其余 4 个是节点风格钩子。
5. Node-style Hooks vs Wrap-style Hooks
- 概念说明:
- Node-style(节点风格):在流程的特定节点处运行(如 Agent 执行前 / 模型执行后),像"检查点"一样。
- Wrap-style(包装风格):在模型或工具调用的前后运行,像"包裹层"一样包裹住调用本身。
- 关键细节:
- Node-style:
before_agent、before_model、after_model、after_agent - Wrap-style:
wrap_model_call、wrap_tool_call
- Node-style:
🏗️ 架构与工作流
LangChain Agent 执行流程(LangGraph 构建)
┌── before_agent ──────────────────────────────────┐
│ │
│ ┌── wrap_model_call ────────────────────────┐ │
│ │ ┌── before_model ────┐ │ │
│ │ │ ★ LLM 调用 ★ │ │ │
│ │ └── after_model ─────┘ │ │
│ └───────────────────────────────────────────┘ │
│ │
│ ┌── wrap_tool_call ─────────────────────────┐ │
│ │ │ ★ 工具调用 ★ │ │ │
│ └───────────────────────────────────────────┘ │
│ │
└── after_agent ───────────────────────────────────┘
Node-style: before_agent / before_model / after_model / after_agent
Wrap-style: wrap_model_call / wrap_tool_call
💻 代码实战
本节课以理论讲解为主,无代码实战。
⚠️ 常见问题与避坑指南
无
💡 个人总结与延伸
Hook 函数是 LangChain 中间件体系的基石,理解其分类(Node-style vs Wrap-style)和触发时机,是自定义中间件的前提。6 个 Hook 覆盖了 Agent 执行流程的关键节点:Agent 级别(before/after_agent)、模型级别(before/after_model + wrap_model_call)、工具级别(wrap_tool_call)。选择合适的 Hook 取决于你想在哪个阶段插入逻辑——是全局层面还是单次模型/工具调用层面。