langchain 当将回调函数传递给列表或回调管理器时,它们被调用的次数不同,

pvabu6sv  于 2个月前  发布在  其他
关注(0)|答案(7)|浏览(42)

检查其他资源

  • 为这个问题添加了一个非常描述性的标题。
  • 使用集成搜索在LangChain文档中进行了搜索。
  • 使用GitHub搜索查找类似的问题,但没有找到。
  • 我确信这是LangChain中的一个bug,而不是我的代码。
  • 通过更新到LangChain的最新稳定版本(或特定集成包)无法解决此bug。

示例代码

设置:

from typing import Any, Dict, List, Optional
from langchain.chat_models import ChatOpenA
from langchain_core.callbacks.base import BaseCallbackHandler, BaseCallbackManager
from langchain_core.output_parsers import StrOutputParser
from langchain.prompts import PromptTemplate

prompt = PromptTemplate(
    input_variables=["question"],
    template="Answer this question: {question}",
)
model = prompt | ChatOpenAI(temperature=0) | StrOutputParser()

from typing import Any, Dict, List, Optional
from langchain_core.callbacks.base import (
    AsyncCallbackHandler,
    BaseCallbackHandler,
    BaseCallbackManager,
)

class CustomCallbackHandler(BaseCallbackHandler):
    def on_chain_start(self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any) -> None:
        print("chain_start")

    def on_chain_end(self, outputs: Dict[str, Any], **kwargs: Any) -> None:
        print("chain_end")

通过回调列表调用 => 每条链事件打印三次。

model.invoke("Hi", config={"callbacks": [CustomCallbackHandler()]})

# > Output:
# chain_start
# chain_start
# chain_end
# chain_start
# chain_end
# chain_end
# 'Hello! How can I assist you today?'

通过回调管理器调用 => 仅打印一次链事件

model.invoke("Hi", config={"callbacks": BaseCallbackManager([CustomCallbackHandler()])})

# > Output:
# chain_start
# chain_end
# 'Hello! How can I assist you today?'

错误信息和堆栈跟踪(如有)

NA

描述

当将回调传递给可运行对象的 .invoke 方法时,有两种方法可以这样做:

  1. 作为列表传递: model.invoke("Hi", config={"callbacks": [CustomCallbackHandler()]})
  2. 作为回调管理器传递: model.invoke("Hi", config={"callbacks": BaseCallbackManager([CustomCallbackHandler()])})
    然而,两者的行为是不同的。前者触发处理程序的次数比后者多。

系统信息

系统信息

操作系统:Linux
操作系统版本: #70 ~20.04.1-Ubuntu SMP Fri Jun 14 15:42:13 UTC 2024
Python版本:3.11.0rc1(主版本,8月12日2022,10:02:14) [GCC 11.2.0]

软件包信息

langchain_core: 0.2.23
langchain: 0.2.10
langchain_community: 0.0.38
langsmith: 0.1.93
langchain_openai: 0.1.17
langchain_text_splitters: 0.2.2

没有安装的软件包(不一定是个问题)

以下软件包未找到:
langgraph
langserve

voj3qocg

voj3qocg1#

我明白差异的原因
分支用于处理程序列表,这里的处理程序和可继承的处理程序都设置为处理程序列表。
分支用于回调管理器,这里的可继承的处理程序设置为回调管理器的可继承处理程序,这没什么意义。
步骤调用当步骤(提示、llm等)被调用时,只有可继承的处理程序传递给它们。
话虽如此,我不知道如何正确修复它

nkkqxpd9

nkkqxpd92#

实际上,这里可能没有什么需要修复的。guide 在这里接收一个处理器列表,并在每次调用步骤(提示、llm 等)时输出 "chain start"。

zujrkrfu

zujrkrfu3#

感谢你的调查,@wulifu2hao。
是的,处理程序列表可以正常工作,但我不明白为什么回调管理器分支是这样实现的。逻辑完全忽略了传递给 _configure 函数的 inheritable_callbacks 参数,这似乎不正确,因为那时它已经不再是“可继承”的了。L2149应该合并 inheritable_callbackscallback_manager.inheritable_callbacks。或者有其他特定原因没有这样做吗?

ffvjumwh

ffvjumwh4#

我不确定我是否理解得正确...
我的理解是,CallbackManager的构造函数接收参数inheritable_callbacks,这似乎意味着"在构造这个新的回调管理器时要继承的回调管理器或回调列表"。
从这个意义上说,第2148行和第2149行似乎是正确的:在构造新的回调管理器时,它会复制handlers以及inheritable_handlers

bhmjp9jg

bhmjp9jg5#

对不起,似乎我误解了一点。所以现在 _configure 正在做的事情是:

  • 通过 inheritable_callbacks 传递的处理程序列表 => 继承
  • 通过 inheritable_callbacks 传递的 callback_manager.inheritable_handlers => 继承
  • 通过 inheritable_callbacks 传递的 callback_manager.handlers => 不继承

我觉得最让我困惑的是第三种情况。guide 提到通过 callbacks kwargs 传递的回调将传播到所有嵌套对象。它没有解释回调管理器 handlersinheritable_handlers 字段之间的区别。
但在将其归咎于文档问题之前,我很好奇 BaseCallbackManager 是否不是为用户传递他们的回调而设计的?换句话说,它只是用于在内部传递回调,用户应该只在他们的代码中传递回调列表吗?
如果是这样,我同意我们不需要任何修复。我只是使用了 BaseCallbackManager 遵循一些互联网示例,但这可能不是预期的使用方式。

xtupzzrd

xtupzzrd6#

我怀疑BaseCallbackManager仅供内部使用,因为RunnableConfig中的回调被定义为处理器列表和BaseCallbackManager的联合体,因此用户将其用作RunnableConfig的回调应该是合理的。
也许文档中缺少对这些字段含义的明确解释?

fquxozlt

fquxozlt7#

有道理。那么在这里的行动是为the callback guide中的行为的添加一个备注。我可以在几天内进行更新。听起来怎么样?@wulifu2hao

相关问题