跳到主要内容

MLflow LangChain 模块

信息

langchain 模块目前正在积极开发中,并被标记为实验性功能。公共 API 可能会发生变化,并且随着模块的演进可能会添加新功能。

欢迎来到将 LangChain 与 MLflow 集成的开发者指南。本指南是了解和利用 LangChain 与 MLflow 组合能力以开发高级语言模型应用的综合资源。

LangChain 是一个多功能框架,旨在构建由语言模型驱动的应用程序。它在创建利用语言模型进行推理和生成响应的上下文感知应用程序方面表现出色,从而能够开发复杂的 NLP 应用。

LangGraph 是由 Langchain 的创建者提供的互补的基于代理的框架,支持创建有状态代理和多代理 GenAI 应用程序。LangGraph 利用 LangChain 来与 GenAI 代理组件接口。

为什么要在 LangChain 中使用 MLflow?

除了使用 MLflow 管理和部署机器学习模型的优势之外,将 LangChain 与 MLflow 集成还提供了与在更广泛的 MLflow 生态系统中使​​用 LangChain 相关的许多优势。

实验跟踪

LangChain 在实验各种代理、工具和检索器方面的灵活性,与 MLflow 跟踪配对时变得更加强大。这种组合可以实现快速实验和迭代。您可以轻松比较运行,从而更容易地改进模型并加速从开发到生产部署的历程。

依赖管理

有信心地部署您的 LangChain 应用程序,利用 MLflow 自动管理和记录代码和环境依赖项的能力。您还可以明确声明外部资源依赖项,例如 LangChain 应用程序查询的 LLM 服务终端或向量搜索索引。这些依赖项作为模型元数据被 MLflow 跟踪,以便下游服务系统可以确保从您的已部署 LangChain 应用程序到这些依赖资源的身份验证正常工作。

这些功能确保了开发和生产环境之间的一致性,从而减少了部署风险,同时减少了手动干预。

MLflow 评估

MLflow 评估在 MLflow 内部提供了评估语言模型的原生功能。使用此功能,您可以轻松地对 LangChain 应用程序推理结果的结果利用自动化评估算法。此功能有助于有效评估 LangChain 应用程序的推理结果,确保稳健的性能分析。

可观测性

MLflow 跟踪是 MLflow 的一项新功能,它允许您跟踪数据如何在 LangChain 链/代理/等的中流动。此功能提供了数据流的可视化表示,使您更容易理解 LangChain 应用程序的行为并识别潜在的瓶颈或问题。凭借其强大的自动跟踪功能,您无需更改任何代码即可仪器化您的 LangChain 应用程序,只需运行一次 mlflow.langchain.autolog() 命令。

自动记录

自动记录是一个强大的一站式解决方案,只需一行代码 mlflow.langchain.autolog() 即可实现上述所有优势。通过启用自动记录,您可以自动记录 LangChain 应用程序的所有组件,包括链、代理和检索器,只需最少的精力。此功能简化了跟踪和管理 LangChain 应用程序的过程,使您可以专注于开发和改进模型。有关如何使用此功能的更多信息,请参阅MLflow LangChain 自动记录文档

MLflow LangChain 集成中支持的元素

警告

当记录依赖于来自合作伙伴包(如 langchain-openai)的 LangChain 组件的链或代理时,存在已知的反序列化问题。如果您使用基于传统序列化的记录方法记录此类模型,某些组件可能会从相应的 langchain-community 包而不是合作伙伴包库中加载,这在执行代码时可能导致意外行为或导入错误。为避免此问题,我们强烈建议使用从代码记录模型的方法来记录此类模型。此方法允许您绕过模型序列化并稳健地保存模型定义。

信息

记录包含 ChatOpenAIAzureChatOpenAI 的链/代理需要 MLflow>=2.12.0LangChain>=0.0.307

链、代理和检索器概述

硬编码在代码中的操作或步骤序列。LangChain 中的链将各种组件(如提示、模型和输出解析器)组合在一起,以创建处理步骤的流程。

下图展示了通过 API 调用直接与 SaaS LLM 接口的示例,其中不包含对话历史记录的上下文(上半部分)。下半部分显示了将相同的查询提交到 LangChain 链,该链结合了对话历史状态,使得整个对话历史都包含在每个后续输入中。以这种方式保留对话上下文是创建“聊天机器人”的关键。

The importance of stateful storage of conversation history for chat applications

MLflow LangChain 模块入门 - 教程和指南

入门教程

在这个入门教程中,您将了解 LangChain 最基本的组件以及如何利用与 MLflow 的集成来存储、检索和使用链。

高级教程

在这些教程中,您可以了解 LangChain 与 MLflow 的更复杂用法。强烈建议在探索这些更高级的用例之前阅读入门教程。

从代码记录模型

从 MLflow 2.12.2 开始,MLflow 引入了直接从代码定义记录 LangChain 模型的功能。

该功能在管理 LangChain 模型方面具有若干优势

  1. 避免序列化复杂性:文件句柄、套接字、外部连接、动态引用、lambda 函数和系统资源是不可挑选的。某些 LangChain 组件不支持原生序列化,例如 RunnableLambda

  2. 无需 Pickling:在与序列化对象时使用的 Python 版本不同的 Python 版本中加载 pickle 或 cloudpickle 文件不能保证兼容性。

  3. 可读性:序列化的对象通常不易被人类阅读。从代码记录模型允许您通过代码审查模型定义。

有关此功能的更多信息,请参阅从代码记录模型功能文档

要使用此功能,您将利用 mlflow.models.set_model() API 来定义您希望记录为 MLflow 模型的链。在定义链的代码中设置好此项后,在记录模型时,您需要指定定义链的文件的路径

以下示例演示了如何使用此方法记录一个简单的链

  1. 在一个单独的 Python 文件中定义链

    提示

    如果您使用 Jupyter Notebook,您可以使用 %%writefile 魔术命令将代码单元直接写入文件,而无需离开笔记本手动创建它。

    python
    # %%writefile chain.py

    import os
    from operator import itemgetter

    from langchain_core.output_parsers import StrOutputParser
    from langchain_core.prompts import PromptTemplate
    from langchain_core.runnables import RunnableLambda
    from langchain_openai import OpenAI

    import mlflow

    mlflow.set_experiment("Homework Helper")

    mlflow.langchain.autolog()

    prompt = PromptTemplate(
    template="You are a helpful tutor that evaluates my homework assignments and provides suggestions on areas for me to study further."
    " Here is the question: {question} and my answer which I got wrong: {answer}",
    input_variables=["question", "answer"],
    )


    def get_question(input):
    default = "What is your name?"
    if isinstance(input_data[0], dict):
    return input_data[0].get("content").get("question", default)
    return default


    def get_answer(input):
    default = "My name is Bobo"
    if isinstance(input_data[0], dict):
    return input_data[0].get("content").get("answer", default)
    return default


    model = OpenAI(temperature=0.95)

    chain = (
    {
    "question": itemgetter("messages") | RunnableLambda(get_question),
    "answer": itemgetter("messages") | RunnableLambda(get_answer),
    }
    | prompt
    | model
    | StrOutputParser()
    )

    mlflow.models.set_model(chain)
  2. 然后,从主笔记本中,通过提供定义链的文件的路径来记录模型

    python
    from pprint import pprint

    import mlflow

    chain_path = "chain.py"

    with mlflow.start_run():
    info = mlflow.langchain.log_model(lc_model=chain_path, name="chain")
  3. chain.py 中定义的模型现已记录到 MLflow。您可以加载模型并运行推理

    python
    # Load the model and run inference
    homework_chain = mlflow.langchain.load_model(model_uri=info.model_uri)

    exam_question = {
    "messages": [
    {
    "role": "user",
    "content": {
    "question": "What is the primary function of control rods in a nuclear reactor?",
    "answer": "To stir the primary coolant so that the neutrons are mixed well.",
    },
    },
    ]
    }

    response = homework_chain.invoke(exam_question)

    pprint(response)

    您可以在 MLflow UI 中看到模型作为代码被记录

    Logging a LangChain model from a code script file

警告

从代码记录模型时,请确保您的代码不包含任何敏感信息,例如 API 密钥、密码或其他机密数据。代码将以纯文本形式存储在 MLflow 模型构件中,任何有权访问该构件的人都可以查看该代码。

详细文档

要了解有关 MLflow LangChain 模块详细信息的更多信息,请阅读下面的详细指南。

常见问题

我无法加载我的链!

  • 允许危险的反序列化:LangChain 中的 Pickle 选择加入逻辑将阻止通过 MLflow 加载组件。您可能会看到如下错误

    text
    ValueError: This code relies on the pickle module. You will need to set allow_dangerous_deserialization=True if you want to opt-in to
    allow deserialization of data using pickle. Data can be compromised by a malicious actor if not handled properly to include a malicious
    payload that when deserialized with pickle can execute arbitrary code on your machine.

    LangChain 中强制用户选择加入 pickle 反序列化的更改可能会导致加载使用 MLflow 记录的链、向量存储、检索器和代理时出现一些问题。由于该选项没有按组件暴露来设置加载函数上的此参数,因此您需要在记录模型时直接在定义的加载函数中设置此选项。未设置此值的 LangChain 组件将无问题保存,但如果未设置,加载时将引发 ValueError

    要解决此问题,只需重新记录您的模型,并在定义的加载函数中指定选项 allow_dangerous_deserialization=True。有关在记录 FAISS 向量存储实例时指定此选项的示例,请参阅LangChain 检索器教程

我无法使用 MLflow 保存我的链、代理或检索器。

提示

如果您在将 LangChain 组件与 MLflow 一起记录或保存时遇到问题,请参阅从代码记录模型功能文档,以确定是否从脚本文件记录模型可以提供更简单、更稳健的记录解决方案!

  • Cloudpickle 的序列化挑战:根据对象的复杂性,使用 cloudpickle 进行序列化可能会遇到限制。

    某些对象,特别是那些具有复杂内部状态或依赖于外部系统资源的对象,本身不是可挑选的。出现此限制的原因是序列化本质上要求将对象转换为字节流,这对于与系统状态紧密耦合或具有外部 I/O 操作的对象来说可能很复杂。请尝试将 PyDantic 升级到 2.x 版本以解决此问题。

  • 验证原生序列化支持:如果使用 MLflow 保存或记录失败,请确保 langchain 对象(链、代理或检索器)可以使用 langchain API 原生序列化。

    由于其复杂的结构,并非所有 langchain 组件都易于序列化。如果原生序列化不受支持,并且 MLflow 不支持保存模型,您可以向 LangChain 存储库提交问题或在LangChain 讨论板上寻求指导。

  • 跟上 MLflow 中的新功能:MLflow 可能不会立即支持最新的 LangChain 功能。

    如果 MLflow 不支持新功能,请考虑在 MLflow GitHub issues 页面提交功能请求。鉴于处于积极开发中的库(如LangChain 的发布速度)的快速变化,即使是现有功能的破坏性变更、API 重构和基本功能支持也可能导致集成问题。如果您希望看到 LangChain 中支持的链、代理、检索器或任何未来结构,请告诉我们!

我在保存模型时遇到 AttributeError

  • 处理 LangChain 和 MLflow 中的依赖安装:LangChain 和 MLflow 不会自动安装所有依赖项。

    特定代理、检索器或工具可能需要的其他包需要在保存或记录模型时明确定义。如果您的模型依赖于这些不包含在标准 LangChain 包中的外部组件库(特别是对于工具),这些依赖项并不总能作为模型的一部分自动记录(有关如何包含它们的指南见下文)。

  • 声明额外依赖项:在保存和记录时使用 extra_pip_requirements 参数。

    当保存或记录包含核心 langchain 安装中不包含的外部依赖项的模型时,您将需要这些额外的依赖项。模型模块提供两个选项来声明这些依赖项:extra_pip_requirementspip_requirements。虽然指定 pip_requirements 是完全有效的,但我们建议使用 extra_pip_requirements,因为它不依赖于定义推断 LangChain 模型所需的所有核心依赖包(其他核心依赖项将自动推断)。

如何使用支持流式传输的 API 与 LangChain 一起使用?

  • 使用 LangChain 模型的流式传输:确保 LangChain 模型支持流式传输响应,并使用 MLflow 版本 >= 2.12.2。

    从 MLflow 2.12.2 版本开始,使用 MLflow 2.12.2(或更高版本)保存的支持流式传输响应的 LangChain 模型可以使用 predict_stream API 加载并用于流式推理。确保正确消耗返回类型,因为这些模型的返回值是 Generator 对象。要了解更多信息,请参阅predict_stream 指南

如何将使用 LangGraph 构建的代理记录到 MLflow?

LangGraph 与 MLflow 的集成旨在利用 MLflow 中的从代码记录模型功能,以拓宽和简化对代理序列化的支持。

要记录 LangGraph 代理,您可以将代理代码定义在一个脚本中,如下所示,保存到文件 langgraph.py

python
from typing import Literal

from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent

import mlflow


@tool
def get_weather(city: Literal["seattle", "sf"]):
"""Use this to get weather information."""
if city == "seattle":
return "It's probably raining. Again."
elif city == "sf":
return "It's always sunny in sf"


llm = ChatOpenAI()
tools = [get_weather]
graph = create_react_agent(llm, tools)

# specify the Agent as the model interface to be loaded when executing the script
mlflow.models.set_model(graph)

当您准备将此代理脚本定义记录到 MLflow 时,您可以在定义模型时直接引用此保存的脚本

python
import mlflow

input_example = {
"messages": [{"role": "user", "content": "what is the weather in seattle today?"}]
}

with mlflow.start_run():
model_info = mlflow.langchain.log_model(
lc_model="./langgraph.py", # specify the path to the LangGraph agent script definition
name="langgraph",
input_example=input_example,
)

当从 MLflow 加载代理时,将执行该脚本,并且定义的代理将可用于调用。

可以按如下方式加载和使用代理进行推理

python
agent = mlflow.langchain.load_model(model_info.model_uri)
query = {
"messages": [
{
"role": "user",
"content": "Should I bring an umbrella today when I go to work in San Francisco?",
}
]
}
agent.invoke(query)

如何在 PyFunc predict 中控制我的输入是否被转换为 List[langchain.schema.BaseMessage]?

默认情况下,MLflow 会将聊天请求格式的输入 {"messages": [{"role": "user", "content": "some_question"}]} 转换为 List[langchain.schema.BaseMessage],例如 [HumanMessage(content="some_question")],用于某些模型类型。要强制转换,请将环境变量 MLFLOW_CONVERT_MESSAGES_DICT_FOR_LANGCHAIN 设置为 True。要禁用此行为,请将环境变量 MLFLOW_CONVERT_MESSAGES_DICT_FOR_LANGCHAIN 设置为 False,如下所示

python
import json
import mlflow
import os
from operator import itemgetter
from langchain.schema.runnable import RunnablePassthrough

model = RunnablePassthrough.assign(
problem=lambda x: x["messages"][-1]["content"]
) | itemgetter("problem")

input_example = {
"messages": [
{
"role": "user",
"content": "Hello",
}
]
}
# this model accepts the input_example
assert model.invoke(input_example) == "Hello"

# set this environment variable to avoid input conversion
os.environ["MLFLOW_CONVERT_MESSAGES_DICT_FOR_LANGCHAIN"] = "false"
with mlflow.start_run():
model_info = mlflow.langchain.log_model(
model, name="model", input_example=input_example
)

pyfunc_model = mlflow.pyfunc.load_model(model_info.model_uri)
assert pyfunc_model.predict(input_example) == ["Hello"]