LangChain 中 LLM 的 bind_tools 原理

之前一直在写 agent,虽然知道如何使用 bind_tools,但是并不清楚底层原理。如果你也有困惑,这篇文章或许能够帮助你更好的理解 bind_tools 及其底层原理。

前言

bind_tools 是 LangChain 中 LLM 模块的核心功能之一,主要用于将外部工具与语言模型绑定,实现模型对工具的自动化调用。该机制通过结构化输入输出来协调模型与工具间的交互。

正文

如图所示,我们要知道不同的 LLM 供应商通过继承 BaseChatModel 实现自己的 LLM 接口(主要是 api 不同,也就是 post 请求,所以需要自行实现 post 请求前的数据和请求后返回的结果的代码,限于篇幅,具体细节不再展开)。

LLM 工具绑定

ChatModel(例如:ChatTongyi)没有绑定工具

当运行 ChatTongyi 实例(即调用 invoke、ainvoke、stream、astream 方法)的时候,这些方法在 BaseChatModel 中执行,具体的执行代码如:_generate、_stream 会在 ChatTongyi 中实现,这里给出 BaseChatModel 的 _generate、_stream 代码:

class BaseChatModel(BaseLanguageModel[AIMessage], ABC):
	@abstractmethod
	def _generate(
        self,
        messages: list[BaseMessage],
        stop: list[str] | None = None,
        run_manager: CallbackManagerForLLMRun | None = None,
        **kwargs: Any,
    ) -> ChatResult:
        """Generate the result.

        Args:
            messages: The messages to generate from.
            stop: Optional list of stop words to use when generating.
            run_manager: Optional callback manager to use for this call.
            **kwargs: Additional keyword arguments to pass to the model.

        Returns:
            The chat result.
        """
    
    def _stream(
        self,
        messages: list[BaseMessage],
        stop: list[str] | None = None,
        run_manager: CallbackManagerForLLMRun | None = None,
        **kwargs: Any,
    ) -> Iterator[ChatGenerationChunk]:
        """Stream the output of the model.

        Args:
            messages: The messages to generate from.
            stop: Optional list of stop words to use when generating.
            run_manager: Optional callback manager to use for this call.
            **kwargs: Additional keyword arguments to pass to the model.

        Yields:
            The chat generation chunks.
        """
        raise NotImplementedError

@abstractmethod 和 NotImplementedError 说明了继承 BaseChatModel 就必须实现这两个方法。

ChatModel(例如:ChatTongyi)绑定了工具

绑定工具需要 ChatTongyi 实例调用 bind_tools 方法,该方法在 ChatTongyi 中执行,并使用 self.bind 实现。如图所示,这里的 self.bind 来自 Runnable 类,会返回 RunnableBinding 实例。RunnableBinding 继承 RunnableBindingBase ,并且 RunnableBindingBase 继承 RunnableSerializable,因此最终绑定工具后的 ChatModel 是 RunnableBinding 实例。

LLM 工具绑定

梳理完 bind_tools 的原理之后,我们观察参数传递。

在 Runnable 的 bind 方法中,RunnableBinding 类传入 self(也就是创建好的 ChatTongyi 实例),kwargs(包含 ChatTongyi 调用 bind_tools 时传入的 tools 和 kwargs)。当我们需要运行实例(即调用 invoke、ainvoke、stream、astream 方法)的时候,会在 RunnableBindingBase 执行对应方法(RunnableBinding 继承 RunnableBindingBase 并且 RunnableBinding 没有对应方法)。如图所示的 invoke 方法会使用 bound(即 ChatTongyi 实例)进行 invoke,这里其实就回到了上文所说的 ChatModel(例如:ChatTongyi)没有绑定工具 的使用,只是这里传递了 tools 参数!。最终这里的参数会被解析并以 post 请求发送。

总结

因此,对于 LLM 的 bind_tools 方法,底层逻辑就是返回 RunnableBinding 实例,并在执行的时候将 tools 以 kwargs 的形式传递给 ChatModel 的执行函数。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐