欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > 【LangChain核心组件】Callbacks机制深度剖析与实战指南

【LangChain核心组件】Callbacks机制深度剖析与实战指南

2025/4/19 11:46:45 来源:https://blog.csdn.net/qq_62223405/article/details/147285600  浏览:    关键词:【LangChain核心组件】Callbacks机制深度剖析与实战指南

目录

一、通俗解释(举个🌰)

二、具体能干啥?

三、怎么用?(一句话说透)

四、小结

五、为什么Callbacks是LangChain的灵魂组件?

六、Callbacks核心API解析

1、 基础回调处理器

2、 标准实现方案对比

七、代码示例

代码一:回调函数定义和执行方式

代码二:不使用回调

代码三:使用回调函数

八、是否使用回调的区别

1、回调机制使用方式

2、执行流程差异

3、输出效果对比

4、代码结构差异

5、最佳实践建议

附:执行效果差异示意图


在 LangChain 中,​​回调函数​​就像给 AI 程序装了一个“事件监听器”或“自动小助手”。它的作用是:​​在 AI 执行任务的各个关键节点,自动触发你设定的操作​​。比如监控进度、记录日志,甚至实时显示生成结果。


一、通俗解释(举个🌰)

想象你在看厨师做菜:

  1. ​厨师开始切菜​​ → 你记录开始时间(回调函数:on_llm_start
  2. ​每切完一片菜​​ → 你数一片数量(回调函数:on_llm_new_token
  3. ​菜切完了​​ → 你喊“上菜!”(回调函数:on_llm_end
  4. ​切到手了​​ → 你立刻递创可贴(回调函数:on_llm_error

这就是回调函数的作用:​​在 AI 做事的每个步骤里,帮你自动完成额外任务​​。


二、具体能干啥?

  1. ​实时看进度​
    比如 AI 生成文字时,每输出一个词就显示到屏幕上(像打字效果)。

  2. ​算钱省成本​
    自动统计 AI 用了多少“字数额度”(比如 OpenAI 按字数收费),帮你控制预算。

  3. ​出错了能处理​
    如果 AI 调用网络接口失败,自动发邮件通知你,而不是让程序卡死。

  4. ​存日志好复盘​
    把 AI 每次对话记录自动保存到文件,方便后期查看哪里出了问题。

  5. 监控与日志​​:回调函数用于在模型运行时捕获关键事件(如开始、结束、生成Token等),并输出调试信息。
  6. ​应用场景​​:常用于调试、性能监控、流式输出处理等

三、怎么用?(一句话说透)

写一个“监听函数”,告诉 LangChain:“当 AI ​​开始干活/干完活/干到一半/出错时​​,就执行我这个函数”。
(比如:每次 AI 生成文字,就把内容实时推送到网页聊天框里)


四、小结

回调函数就是给 AI 装“监控”和“自动化工具”,让程序更智能、更可控。不需要懂代码细节,记住它能帮你​​自动响应事件​​就行。


五、为什么Callbacks是LangChain的灵魂组件?

在大语言模型应用开发中,回调机制扮演着至关重要的角色。LangChain通过Callbacks实现了:

  1. 全链路可观测性:实时追踪LLM调用、工具执行、任务链流转

  2. 执行过程干预:动态修改提示词、调整温度参数、过滤敏感内容

  3. 性能监控:统计token消耗、记录响应延迟、分析错误率

  4. 流式处理:实现逐token输出、实时进度展示等交互体验

通过下面的架构图可以看到,Callbacks贯穿整个LangChain执行生命周期:


六、Callbacks核心API解析

1、 基础回调处理器
class BaseCallbackHandler:"""处理LLM/Chain/Tool/Agent各阶段事件的抽象基类"""def on_llm_start(self, serialized, prompts, **kwargs):"""LLM开始生成时触发"""def on_llm_new_token(self, token, **kwargs):"""流式输出时每个token的生成事件"""def on_chain_end(self, outputs, **kwargs):"""任务链完成时收集最终结果"""# 共14个关键事件处理点...
2、 标准实现方案对比
配置方式优点缺点适用场景
显式回调列表支持多处理器并行需手动管理处理器实例生产环境
verbose=True零配置快速启用只能输出到stdout快速调试
自定义Handler完全定制处理逻辑开发成本较高特殊需求

 

七、代码示例

代码一:回调函数定义和执行方式

说明:该代码主要是颜色定义和执行回调函数的一种形式,不可运行。

from typing import Any, Dict, List, Unionclass BaseCallbackHandler:"""基础回调处理器,可用于处理来自langchain的回调。"""def on_llm_start(self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any) -> Any:"""当LLM开始运行时触发。"""def on_chat_model_start(self, serialized: Dict[str, Any], messages: List[List[BaseMessage]], **kwargs: Any  # type: ignore) -> Any:"""当聊天模型开始运行时触发。"""def on_llm_new_token(self, token: str, **kwargs: Any) -> Any:"""生成新LLM token时触发。仅在启用流式传输时可用。"""def on_llm_end(self, response: LLMResult, **kwargs: Any) -> Any:  # type: ignore"""当LLM运行结束时触发。"""def on_llm_error(self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any) -> Any:"""当LLM发生错误时触发。"""def on_chain_start(self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any) -> Any:"""当任务链开始运行时触发。"""def on_chain_end(self, outputs: Dict[str, Any], **kwargs: Any) -> Any:"""当任务链运行结束时触发。"""def on_chain_error(self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any) -> Any:"""当任务链发生错误时触发。"""def on_tool_start(self, serialized: Dict[str, Any], input_str: str, **kwargs: Any) -> Any:"""当工具开始运行时触发。"""def on_tool_end(self, output: str, **kwargs: Any) -> Any:"""当工具运行结束时触发。"""def on_tool_error(self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any) -> Any:"""当工具发生错误时触发。"""def on_text(self, text: str, **kwargs: Any) -> Any:"""处理任意文本时触发。"""def on_agent_action(self, action: AgentAction, **kwargs: Any) -> Any:  # type: ignore"""当代理执行动作时触发。"""def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> Any:  # type: ignore"""当代理结束运行时触发。"""

代码二:不使用回调

说明:该代码直接通过千问大模型进行推理,没有采用回调

import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import LLMChain#一、加载配置环境
load_dotenv()#二、初始化大模型
qwen=ChatOpenAI(model="qwen-max",api_key=os.getenv("DASHSCOPE_API_KEY"),openai_api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",temperature=0.0)#三、定义提示模板
prompt=ChatPromptTemplate.from_template("1+{number}=")#四、初始化链(不使用回调)
print("不使用回调函数")
chain=LLMChain(llm=qwen,prompt=prompt,)
print("返回结果:",chain.invoke({"number":2}))

运行结果

不使用回调函数
d:\computer_soft\Microsoft VS Code\python_project\my_app\AI大模型应用开发\A3\A3.2_LangChain原理\一、LangChain技术原理\2、核心组件\5、Callbacks\test.py:22: LangChainDeprecationWarning: The class `LLMChain` was deprecated in LangChain 0.1.17 and will be removed in 1.0. Use :meth:`~RunnableSequence, e.g., `prompt | llm`` instead.
  chain=LLMChain(
返回结果: {'number': 2, 'text': '1+2=3'}


代码三:使用回调函数

说明:这段代码演示了LangChain中​​回调函数(Callbacks)​​和​​调试输出​​的核心用法,知识要点可概括如下:

两种启用回调的方式​

  • ​方式一:显式绑定回调处理器​
    通过 callbacks=[handler] 参数将 StdOutCallbackHandler 附加到链(LLMChain),运行时自动输出详细步骤日志。

chain = LLMChain(..., callbacks=[handler])  # 手动绑定回调
  • 方式二:启用 verbose 标志​
    设置 verbose=True 时,LangChain默认启用 StdOutCallbackHandler,效果等同于方式一。

chain2 = LLMChain(..., verbose=True)  # 隐式启用回调
from langchain.callbacks import StdOutCallbackHandler
from langchain.chains import LLMChain
from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate
import os
from dotenv import load_dotenv#一、初始化配置环境
load_dotenv()# 二、初始化回调处理器
handler = StdOutCallbackHandler()# 三、初始化模型
llm = ChatOpenAI(model="qwen-max",api_key=os.getenv("DASHSCOPE_API_KEY"),openai_api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",temperature=0.0
)# 四、定义提示模板)
prompt = PromptTemplate.from_template("1 + {number} = ")# 五、初始化链(使用回调)
print("\n使用回调函数的方式")
chain = LLMChain(llm=llm, prompt=prompt, callbacks=[handler])  # 关键:添加 callbacks
# 使用verbose标志:然后,让我们使用`verbose`标志来实现相同的结果
chain2 = LLMChain(llm=llm, prompt=prompt, verbose=True)#六、输出结果
print("回调方式一:\n",chain.invoke({"number":2}))
print("回调方式二:\n",chain2.invoke({"number":2}))

运行结果

> Entering new LLMChain chain...
Prompt after formatting:
1 + 2 = 
> Finished chain.
回调方式一:
 {'number': 2, 'text': '1 + 2 = 3'}


> Entering new LLMChain chain...
Prompt after formatting:
1 + 2 =

> Finished chain.
回调方式二:
 {'number': 2, 'text': '1 + 2 = 3'}


八、是否使用回调的区别

1、回调机制使用方式

以下是代码二和代码三的区别对比

对比维度不使用回调使用回调
回调配置方式先创建带回调的chain,后覆盖为无回调的chain同时展示两种回调方式:显式回调处理器 和 verbose标志
回调生效情况最终实际未使用回调(被后续无回调chain覆盖)明确对比两种回调方式的效果
代码逻辑存在逻辑矛盾:先配置回调后又覆盖逻辑清晰:分别演示不同配置方式
2、执行流程差异

# 代码一流程
1. 创建带回调的chain(但后续被覆盖)
2. 重新创建无回调的chain(最终生效)
3. 执行无回调调用

# 代码二流程
1. 创建两种配置的chain:
   - 方式一:callbacks=[handler] 
   - 方式二:verbose=True
2. 分别执行两种调用

 

3、输出效果对比
回调方式输出内容示例
无回调仅返回结果:{'number': 2, 'text': '1 + 2 = 3'}
显式回调打印LLM执行过程日志:
> Entering new LLMChain chain...
...
verbose=True与显式回调效果相同,底层使用默认的StdOutCallbackHandler
4、代码结构差异
特性不回调使用回调
代码注释简单注释分步骤详细注释(一、二、三...)
演示目的单一场景对比两种回调配置方式
错误示例包含配置覆盖错误无错误示范
5、最佳实践建议
  1. 避免配置覆盖:不要重复初始化同名chain对象

  2. 回调选择原则

    • 需要自定义处理时使用 callbacks=[...]

    • 快速调试时使用 verbose=True(内部自动使用StdOutCallbackHandler)

  3. 生产环境推荐:使用显式回调处理器,便于扩展和自定义日志处理

附:执行效果差异示意图

 代码一输出:
不使用回调函数
{'number': 2, 'text': '1 + 2 = 3'}
结果返回: {'number': 2, 'text': '1 + 2 = 3'}

代码二输出:
使用回调函数的方式

> Entering new LLMChain chain...
Prompt after formatting:
1 + 2 = 

> Finished chain.
回调方式一:
 {'number': 2, 'text': '1 + 2 = 3'}

> Entering new LLMChain chain...
Prompt after formatting:
1 + 2 = 

> Finished chain.
回调方式二:
 {'number': 2, 'text': '1 + 2 = 3'}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词