LangChain的路由器链和回调函数

LangChain框架有不同类型的链,包括路由器链。路由器链允许从一组链中动态选择一个预定义的链作为给定输入的方法。在本博客中,我们将探讨如何使用路由器链。

我们在这篇博客中要讲解的 LangChain 第二个话题是回调函数。MultiPromptChain 和 LangChain 模型类支持回调函数,可以用来对某些事件做出反应,例如从 OpenAI 模型中接收到响应或收到用户输入。

RouterChain 示例流程

一个典型的路由器链基础工作流程将接收输入,选择特定的LLMChain并给出响应。在本博客中,我们将探讨如何实现可以由此图表示的工作流程:

ChatGPT中文站

以下操作在此执行:

  • 用户产生基于文本的输入。
  • 输入通过回调函数写入文件。
  • 路由器从五个选项中选择最合适的链:-Python程序员-诗人-维基百科专家-图形艺术家-英美法律专家
  • 大型语言模型响应。
  • 输出通过回调函数再次写入文件。

示例流程实现

我们使用Python作为简单的命令行应用程序实现了上述工作流,并生成一个包含输出结果的HTML文件。

实现上述工作流程的代码位于该 Git 存储库中:

我们使用了一个Conda环境,您可以使用以下命令进行设置:

conda create --name langchain python=3.10
conda install -c conda-forge openai
conda install -c conda-forge langchain
conda install -c https://conda.anaconda.org/conda-forge prompt_toolkit

请确保在运行脚本之前添加`OPENAI_API_KEY`环境变量和OpenAI API密钥。

该脚本可通过此命令执行:

python ./lang_chain_router_chain.py

示例执行

使用“gpt-3.5-turbo-0613”,我们使用了以下的输入,这些输入由指定的LLM链来处理:

  • 你可以在Python中实现sigmoid函数及其导数吗?- Python程序员
  • 你能在Python中实现ReLU激活函数及其导数吗?- Python程序员
  • 你能用 Sigmoid 函数的输出生成一张图像吗? - 图形艺术家
  • 哪些激活函数在深度学习中常用?- Python 程序员
  • 你能给我写一首诗,讲述在英国乡村编程的乐趣吗?- 诗人
  • 什么是英国和美国法律体系的主要区别?- 法律专家
  • 你能向我解释一下量子计算中QBit的概念吗?- 维基百科专家

以下是与模型的互动的文字记录。

实施细节

我们创建了两个脚本:

  • lang_chain_router_chain.py
  • FileCallbackHandler.py

主要脚本是lang_chain_router_chain.py,文件写入回调的实现是FileCallbackHandler.py。

主要的脚本 lang_chain_router_chain.py 执行三个步骤:

  • 定义一组LLMChain和相应提示。

def generate_destination_chains():
"""
Creates a list of LLM chains with different prompt templates.
"""
prompt_factory = PromptFactory()
destination_chains = {}
for p_info in prompt_factory.prompt_infos:
name = p_info['name']
prompt_template = p_info['prompt_template']
chain = LLMChain(
llm=cfg.llm,
prompt=PromptTemplate(template=prompt_template, input_variables=['input']))
destination_chains[name] = chain
default_chain = ConversationChain(llm=cfg.llm, output_key="text")
return prompt_factory.prompt_infos, destination_chains, default_chain

该脚本的提示信息在此部分中:

class PromptFactory():
developer_template = """You are a very smart Python programmer. \
You provide answers for algorithmic and computer problems in Python. \
You explain the code in a detailed manner. \

Here is a question:
{input}"""

poet_template = """You are a poet who replies to creative requests with poems in English. \
You provide answers which are poems in the style of Lord Byron or Shakespeare. \

Here is a question:
{input}"""

wiki_template = """You are a Wikipedia expert. \
You answer common knowledge questions based on Wikipedia knowledge. \
Your explanations are detailed and in plain English.

Here is a question:
{input}"""

image_creator_template = """You create a creator of images. \
You provide graphic representations of answers using SVG images.

Here is a question:
{input}"""

legal_expert_template = """You are a UK or US legal expert. \
You explain questions related to the UK or US legal systems in an accessible language \
with a good number of examples.

Here is a question:
{input}"""



prompt_infos = [
{
'name': 'python programmer',
'description': 'Good for questions about coding and algorithms',
'prompt_template': developer_template
},
{
'name': 'poet',
'description': 'Good for generating poems for creatinve questions',
'prompt_template': poet_template
},
{
'name': 'wikipedia expert',
'description': 'Good for answering questions about general knwoledge',
'prompt_template': wiki_template
},
{
'name': 'graphical artist',
'description': 'Good for answering questions which require an image output',
'prompt_template': image_creator_template
},
{
'name': 'legal expert',
'description': 'Good for answering questions which are related to UK or US law',
'prompt_template': legal_expert_template
}
]
  • 从目标和默认链生成路由器链。
def generate_router_chain(prompt_infos, destination_chains, default_chain):
"""
Generats the router chains from the prompt infos.
:param prompt_infos The prompt informations generated above.
:param destination_chains The LLM chains with different prompt templates
:param default_chain A default chain
"""
destinations = [f"{p['name']}: {p['description']}" for p in prompt_infos]
destinations_str = '\n'.join(destinations)
router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format(destinations=destinations_str)
router_prompt = PromptTemplate(
template=router_template,
input_variables=['input'],
output_parser=RouterOutputParser()
)
router_chain = LLMRouterChain.from_llm(cfg.llm, router_prompt)
return MultiPromptChain(
router_chain=router_chain,
destination_chains=destination_chains,
default_chain=default_chain,
verbose=True,
callbacks=[file_ballback_handler]
)
  • 遍历用户输入,允许保存输出。
while True:
question = prompt(
HTML("<b>Type <u>Your question</u></b> ('q' to exit, 's' to save to html file): ")
)
if question == 'q':
break
if question == 's':
file_ballback_handler.create_html()
continue
result = chain.run(question)
print(result)
print()

FileCallbackHandler.py重写了langchain.callbacks.base.BaseCallbackHandler。

它实现了

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

def on_text(self,text: str, color: Optional[str] = None, end: str = "", **kwargs: Any) -> None:

捕捉LLM输出和用户输入。

它还提供一种生成HTML文件的方法:

def create_html(self)

结论

LangChain 提供了便利的抽象,将用户输入路由到专门的链路上。从某种意义上讲,您可以产生具有不同“帽子”的链路,由于它们的专业化而被选择响应。

此外,LangChain还拥有强大的回调系统,允许您对链内触发的内部事件做出反应。

2023-10-20 16:58:24 AI中文站翻译自原文