回调(Callbacks)
注意:关于与第三方工具的内置回调集成,请前往 集成 (opens in a new tab)。
LangChain 提供了一个回调系统,允许你挂钩到 LLM 应用的各个阶段。这对于日志记录、监控、流式输出和其他任务都很有用。
你可以通过整个 API 中可用的 callbacks 参数来订阅这些事件。该参数是处理程序对象的列表,这些对象预期实现下文更详细描述的一个或多个方法。
回调处理程序
CallbackHandler 是实现 CallbackHandler 接口的对象,该接口为每个可订阅的事件都提供了一个方法。当事件被触发时,CallbackManager 会在每个处理程序上调用相应的方法。
class BaseCallbackHandler:
"""Base callback handler that can be used to handle callbacks from langchain."""
def on_llm_start(
self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any
) -> Any:
"""Run when LLM starts running."""
def on_chat_model_start(
self, serialized: Dict[str, Any], messages: List[List[BaseMessage]], **kwargs: Any
) -> Any:
"""Run when Chat Model starts running."""
def on_llm_new_token(self, token: str, **kwargs: Any) -> Any:
"""Run on new LLM token. Only available when streaming is enabled."""
def on_llm_end(self, response: LLMResult, **kwargs: Any) -> Any:
"""Run when LLM ends running."""
def on_llm_error(
self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any
) -> Any:
"""Run when LLM errors."""
def on_chain_start(
self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any
) -> Any:
"""Run when chain starts running."""
def on_chain_end(self, outputs: Dict[str, Any], **kwargs: Any) -> Any:
"""Run when chain ends running."""
def on_chain_error(
self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any
) -> Any:
"""Run when chain errors."""
def on_tool_start(
self, serialized: Dict[str, Any], input_str: str, **kwargs: Any
) -> Any:
"""Run when tool starts running."""
def on_tool_end(self, output: Any, **kwargs: Any) -> Any:
"""Run when tool ends running."""
def on_tool_error(
self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any
) -> Any:
"""Run when tool errors."""
def on_text(self, text: str, **kwargs: Any) -> Any:
"""Run on arbitrary text."""
def on_agent_action(self, action: AgentAction, **kwargs: Any) -> Any:
"""Run on agent action."""
def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> Any:
"""Run on agent end."""入门
LangChain 提供了几个内置处理程序供你入门。它们位于 langchain_core/callbacks 模块中。最基本的处理程序是 StdOutCallbackHandler,它只是把所有事件记录到 stdout。
注意:当对象上的 verbose 标志设置为 true 时,即使没有显式传入,StdOutCallbackHandler 也会被调用。
from langchain_core.callbacks import StdOutCallbackHandler
from langchain.chains import LLMChain
from langchain_openai import OpenAI
from langchain_core.prompts import PromptTemplate
handler = StdOutCallbackHandler()
llm = OpenAI()
prompt = PromptTemplate.from_template("1 + {number} = ")
# 构造函数回调:首先,让我们在初始化链时显式设置 StdOutCallbackHandler
chain = LLMChain(llm=llm, prompt=prompt, callbacks=[handler])
chain.invoke({"number":2})
# 使用 verbose 标志:然后,让我们使用 `verbose` 标志来达到相同结果
chain = LLMChain(llm=llm, prompt=prompt, verbose=True)
chain.invoke({"number":2})
# 请求回调:最后,让我们使用请求 `callbacks` 来达到相同结果
chain = LLMChain(llm=llm, prompt=prompt)
chain.invoke({"number":2}, {"callbacks":[handler]})
> Entering new LLMChain chain...
Prompt after formatting:
1 + 2 =
> Finished chain.
> Entering new LLMChain chain...
Prompt after formatting:
1 + 2 =
> Finished chain.
> Entering new LLMChain chain...
Prompt after formatting:
1 + 2 =
> Finished chain.在哪里传入回调
整个 API 中的大多数对象(链、模型、工具、代理等)都可以在两个不同的地方使用 callbacks:
- 构造函数回调:在构造函数中定义,例如
LLMChain(callbacks=[handler], tags=['a-tag'])。在这种情况下,回调将用于在该对象上进行的所有调用,并且只作用于该对象。例如,如果你向LLMChain构造函数传入一个处理程序,它不会被子链所挂接的模型使用。 - 请求回调:在用于发出请求的 'invoke' 方法中定义。在这种情况下,回调只用于该特定请求以及它包含的所有子请求(例如,对 LLMChain 的调用会触发对模型的调用,后者使用传入
invoke()方法的同一个处理程序)。在invoke()方法中,回调通过 config 参数传入。 使用 'invoke' 方法的示例(注意:batch、ainvoke和abatch方法也可以使用相同的方式):
handler = StdOutCallbackHandler()
llm = OpenAI()
prompt = PromptTemplate.from_template("1 + {number} = ")
config = {
'callbacks' : [handler]
}
chain = prompt | chain
chain.invoke({"number":2}, config=config)注意: chain = prompt | chain 等价于 chain = LLMChain(llm=llm, prompt=prompt)(更多细节请查看 LangChain 表达式语言(LCEL)文档)
verbose 参数在 API 中的大多数对象(链、模型、工具、代理等)上都可以作为构造函数参数使用,例如 LLMChain(verbose=True),它等价于向该对象及所有子对象的 callbacks 参数传入一个 ConsoleCallbackHandler。这对于调试很有用,因为它会把所有事件记录到控制台。
什么时候该用哪种方式?
- 构造函数回调最适合日志记录、监控等场景,这些场景_并非针对单个请求_,而是针对整个链。例如,如果你想记录对某个
LLMChain发出的所有请求,你会向构造函数传入一个处理程序。 - 请求回调最适合流式输出等场景,你希望把单个请求的输出流式传输到特定的 websocket 连接,或其他类似场景。例如,如果你想将单个请求的输出流式传输到 websocket,你会向
invoke()方法传入一个处理程序。