老铁们,今天我们来聊聊一个很有用的技术点:在构造函数中如何传播回调。这个话题对于那些在使用LangChain框架进行AI模型开发的朋友们来说,可能会经常碰到。说白了,这个技术点其实不难,但其中的细节还是有必要深入理解一下。
技术背景介绍
在LangChain中,很多模块允许我们直接在构造函数中传递回调。这样做的好处是,回调只对该实例及其任何嵌套的运行有效。然而,这种方式有个潜在的问题:构造函数中的回调只限定在定义它们的对象上,不会被子级对象继承。这样可能会导致一些让人捉摸不透的行为。因此,一般建议将回调作为运行时参数传递。
原理深度解析
构造函数回调的作用域只限于定义它们的对象。这意味着当你在例如ChatAnthropic
类的构造函数中定义回调时,它们不会被用在该对象的子级,比如一个更复杂的链式调用中。这可能会造成一些困惑,比如你期望在整个链的执行中看到某些事件,但实际上只看到了部分。
实战代码演示
下面是一个代码示例,展示了如何在ChatAnthropic
的构造函数中传递和使用回调:
from typing import Any, Dict, List
from langchain_anthropic import ChatAnthropic
from langchain_core.callbacks import BaseCallbackHandler
from langchain_core.messages import BaseMessage
from langchain_core.outputs import LLMResult
from langchain_core.prompts import ChatPromptTemplate
class LoggingHandler(BaseCallbackHandler):
def on_chat_model_start(
self, serialized: Dict[str, Any], messages: List[List[BaseMessage]], **kwargs
) -> None:
print("Chat model started")
def on_llm_end(self, response: LLMResult, **kwargs) -> None:
print(f"Chat model ended, response: {response}")
def on_chain_start(
self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs
) -> None:
print(f"Chain {serialized.get('name')} started")
def on_chain_end(self, outputs: Dict[str, Any], **kwargs) -> None:
print(f"Chain ended, outputs: {outputs}")
callbacks = [LoggingHandler()]
llm = ChatAnthropic(model="claude-3-sonnet-20240229", callbacks=callbacks)
prompt = ChatPromptTemplate.from_template("What is 1 + {number}?")
chain = prompt | llm
chain.invoke({"number": "2"})
你会发现,在这个例子中,我们只看到了来自聊天模型运行的事件,而没有看到提示或更广泛链式调用的事件。
优化建议分享
我先前踩过这个坑,在使用构造函数回调时发现它们的作用范围有限,后来发现更好的办法是将回调作为运行时参数传递给对象。这波操作可以说是相当丝滑,解决了很多不可预期的行为问题。同时,建议使用一些稳定的API服务以提高代码的稳定性,比如在回调处理时的网络请求。
补充说明和总结
如果你经常处理复杂的链式调用,建议考虑使用一些一站式大模型解决方案服务,比如云务AI,这样可以大大简化开发流程。
今天的技术分享就到这里,希望对大家有帮助。开发过程中遇到问题也可以在评论区交流~
—END—