LangChain Chains新手教程:6大模块轻松上手
在LangChain框架中,Chains究竟承担何种职能?可以明确地说,Chains如同积木结构的骨架——缺少它,各个模块各自为战,无法互联。一旦引入Chain,Model IO、Retrieval、Memory等组件便能迅速集成,驱动出一套完整的LLM应用。
在深入探讨Chains之前,先简要梳理LangChain的六大模块,这有助于后续理解。
Model IO作为应用的核心,管控输入、模型与输出。Retrieval与向量数据库深度绑定,专用于检索与问题相关的文档。Memory负责为对话模型持久化历史记录,避免长对话丢失上下文。Chains即本文焦点,串联前三个模块。Agents可依据用户输入识别意图,自动调用工具,提升应用智能化水平。Callbacks提供回调机制,用于链路追踪与日志记录,方便调试与监控。
聚焦Chains,其调用方式通过接口直接执行。为清晰说明,我们将Chain分为三类,从基础到复杂逐一剖析。
第一类:LLMChains —— 最基础的链
这是所有Chain的起点,但功能已足够强大。LLMChain将数据、提示模板与大模型直接串联。来看一个实例:
from langchain import PromptTemplate, OpenAI, LLMChain
prompt_template = "What is a good name for a company that makes {product}?"
llm = OpenAI(temperature=0)
chain = LLMChain(
llm=llm,
prompt=PromptTemplate.from_template(prompt_template)
)
print(chain("colorful socks"))
# 输出结果'Socktastic!'
流程非常直观:首先编写Prompt模板,接着初始化大模型,最后通过Chain运行。Chain内部自动格式化Prompt,并将其传递给LLM生成响应。
第二类:Sequential Chains —— 链式接力
单个Chain有时不足以应对复杂场景,需要多个Chain接力完成。Sequential Chain为此设计,提供两种模式:单输入/输出与多输入/输出。
1. 单个输入输出
设想编写一部剧本的概要,再根据概要生成评论。借助Sequential Chains可轻松实现。先创建第一条Chain:
# This is an LLMChain to write a synopsis given a title of a play.
from langchain import PromptTemplate, OpenAI, LLMChain
llm = OpenAI(temperature=.7)
template = """You are a playwright. Given the title of play, it is your job to write a synopsis for that title.
Title: {title}
Playwright: This is a synopsis for the above play:"""
prompt_template = PromptTemplate(input_variables=["title"], template=template)
synopsis_chain = LLMChain(llm=llm, prompt=prompt_template)
再创建第二条Chain,接收概要输出评论:
# This is an LLMChain to write a review of a play given a synopsis.
from langchain import PromptTemplate, OpenAI, LLMChain
llm = OpenAI(temperature=.7)
template = """You are a play critic from the New York Times. Given the synopsis of play, it is your job to write a review for that play.
Play Synopsis:
{synopsis}
Review from a New York Times play critic of the above play:"""
prompt_template = PromptTemplate(input_variables=["synopsis"], template=template)
review_chain = LLMChain(llm=llm, prompt=prompt_template)
最后用SimpleSequentialChain将两个链条串联:
from langchain.chains import SimpleSequentialChain
overall_chain = SimpleSequentialChain(chains=[synopsis_chain, review_chain], verbose=True)
print(review = overall_chain.run("Tragedy at sunset on the beach"))
可见,单输入输出的顺序链极为简便,直接将两个Chain作为参数传给SimpleSequentialChain即可,无需复杂声明。
2. 多个输入输出
当需要同时处理多个输入与输出时,场景更具挑战性。关键在于准确设定输入变量与输出变量的名称,确保Chain正确识别。来看一个Demo:
from langchain import PromptTemplate, OpenAI, LLMChain
llm = OpenAI(temperature=.7)
template = """You are a playwright. Given the title of play and the era it is set in, it is your job to write a synopsis for that title.
Title: {title}
Era: {era}
Playwright: This is a synopsis for the above play:"""
prompt_template = PromptTemplate(input_variables=["title", 'era'], template=template)
synopsis_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="synopsis")
#第一条chain
from langchain import PromptTemplate, OpenAI, LLMChain
llm = OpenAI(temperature=.7)
template = """You are a play critic from the New York Times. Given the synopsis of play, it is your job to write a review for that play.
Play Synopsis:
{synopsis}
Review from a New York Times play critic of the above play:"""
prompt_template = PromptTemplate(input_variables=["synopsis"], template=template)
review_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="review")
#第二条chain
from langchain.chains import SequentialChain
overall_chain = SequentialChain(
chains=[synopsis_chain, review_chain],
input_variables=["era", "title"],
# Here we return multiple variables
output_variables=["synopsis", "review"],
verbose=True)
#第三条chain
overall_chain({"title": "Tragedy at sunset on the beach", "era": "Victorian England"})
每个Chain定义时需指定output_key与input_variables,顺序务必一致。最终运行Chain时只需传入第一个Chain所需的变量。
第三类:RouterChains —— 智能路由
最后探讨一个非常实用的场景。假设你有三类Chain,分别对应物理、数学学科的问题解答。用户输入随机,第一次可能是数学题,第二次可能是历史问题。你希望系统自动判断输入类别,并将其路由到对应的子链处理。RouterChain恰好提供这一能力——它先决策传给哪个子链,再将输入传递过去。同时需设置一个默认Chain,用于兜底不属于任何类别的输入。
先定义物理和数学的Prompt模板:
physics_template = """You are a very smart physics professor.
You are great at answering questions about physics in a concise and easy to understand manner.
When you don't know the answer to a question you admit that you don't know.
Here is a question:
{input}"""
math_template = """You are a very good mathematician. You are great at answering math questions.
You are so good because you are able to break down hard problems into their component parts,
answer the component parts, and then put them together to answer the broader question.
Here is a question:
{input}"""
然后声明这两个Prompt的基本信息:
prompt_infos = [
{
"name": "physics",
"description": "Good for answering questions about physics",
"prompt_template": physics_template
},
{
"name": "math",
"description": "Good for answering math questions",
"prompt_template": math_template
}
]
接着把每个prompt对应的Chain准备好,并放一个默认Chain:
from langchain import ConversationChain, LLMChain, PromptTemplate, OpenAI
llm = OpenAI()
destination_chains = {}
for p_info in prompt_infos:
name = p_info["name"]
prompt_template = p_info["prompt_template"]
prompt = PromptTemplate(template=prompt_template, input_variables=["input"])
chain = LLMChain(llm=llm, prompt=prompt)
destination_chains[name] = chain
default_chain = ConversationChain(llm=llm, output_key="text")
最后把它们组合进RouterChain里:
from langchain.chains.router.llm_router import LLMRouterChain, RouterOutputParser
from langchain.chains.router.multi_prompt_prompt import MULTI_PROMPT_ROUTER_TEMPLATE
# Create a list of destinations
destinations = [f"{p['name']}: {p['description']}" for p in prompt_infos]
destinations_str = "n".join(destinations)
# Create a router template
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(llm, router_prompt)
chain = MultiPromptChain(
router_chain=router_chain,
destination_chains=destination_chains,
default_chain=default_chain,
verbose=True,
)
print(chain.run('什么是黑体辐射'))
当输入“什么是黑体辐射”时,RouterChain根据input内容自动选择最匹配的Prompt(此处为物理),然后路由到对应子链处理。若输入既非物理也非数学的问题,默认Chain将接管。这种智能路由机制使应用极具灵活性。
从最基础的LLMChain到接力的Sequential Chains,再到智能的RouterChains,Chains模块确实是将LangChain各组件紧密聚合的强力胶。掌握它,后续进阶操作自然水到渠成。