chain的使用#

LangChain提供了多种类型的chain,他们都定义在 /langchain-guide/lib/python3.11/site-packages/langchain/chains/__init__.py文件中

主要介绍几种中常用的chain

LLMChain#

注意,LLMChain现在已经不用了,代替他的是prompt | llm

from langchain.chains import LLMChain
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate

llm = OpenAI(
    temperature=0
)
prompt_template = "帮我给{product}想三个可以注册的域名?"
llm_chain = LLMChain(
    llm=llm,
    prompt=PromptTemplate.from_template(prompt_template),
    verbose=True,  #是否开启日志
)
llm_chain("我饿了")
> Entering new LLMChain chain...
Prompt after formatting:
帮我给我饿了想三个可以注册的域名?

> Finished chain.
{'product': '我饿了',
 'text': '\n\n1. HappyHive.com\n2. FreshFusion.com\n3. CreativeCove.com'}

顺序链 SimpleSequentialChain & SequentialChain#

#simpleSequentialChain 只支持固定的链路

from langchain.chains import LLMChain
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import SimpleSequentialChain

chat_model = ChatOpenAI(
    temperature=0,
    model="gpt-3.5-turbo",
)

#chain 1
first_prompt = ChatPromptTemplate.from_template("帮我给{product}的公司起一个响亮容易记忆的名字?")

chain_one = LLMChain(
    llm=chat_model,
    prompt=first_prompt,
    verbose=True,
)

#chain 2
second_prompt = ChatPromptTemplate.from_template("用5个词来描述一下这个公司名字:{company_name}")

chain_two = LLMChain(
    llm=chat_model,
    prompt=second_prompt,
    verbose=True,
)

overall_simple_chain = SimpleSequentialChain(
    chains=[chain_one, chain_two],
    verbose=True,  #打开日志
)

overall_simple_chain.run("蜜雪冰城")
> Entering new SimpleSequentialChain chain...


> Entering new LLMChain chain...
Prompt after formatting:
Human: 帮我给蜜雪冰城的公司起一个响亮容易记忆的名字?

> Finished chain.
冰雪乐园Ice Snow Wonderland


> Entering new LLMChain chain...
Prompt after formatting:
Human: 用5个词来描述一下这个公司名字:冰雪乐园Ice Snow Wonderland

> Finished chain.
1. 寒冷
2. 欢乐
3. 美丽
4. 奇幻
5. 冬季

> Finished chain.
'1. 寒冷\n2. 欢乐\n3. 美丽\n4. 奇幻\n5. 冬季'
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
# 新的语法如下
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

chat_model = ChatOpenAI(
    temperature=0,
    model="gpt-3.5-turbo",
)

#chain 1
first_prompt = first_prompt | chat_model | StrOutputParser()
#chain 2
second_prompt = ChatPromptTemplate.from_template("用5个词来描述一下这个公司名字:{company_name}")
chain_two = second_prompt | chat_model

overall_simple_chain = (chain_one
                        | RunnableParallel(company_name=lambda x: x)
                        | chain_two
                        | StrOutputParser())

overall_simple_chain.invoke("蜜雪冰城")
> Entering new LLMChain chain...
Prompt after formatting:
Human: 帮我给蜜雪冰城的公司起一个响亮容易记忆的名字?

> Finished chain.
'创新、清新、欢乐、冰爽、美味'
#SequentialChain 支持多个链路的顺序执行

from langchain.chains import LLMChain
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import SequentialChain

llm = ChatOpenAI(
    temperature=0,
    model="gpt-3.5-turbo",
)

#chain 1 任务:翻译成中文
first_prompt = ChatPromptTemplate.from_template("把下面内容翻译成中文:\n\n{content}")
chain_one = LLMChain(
    llm=llm,
    prompt=first_prompt,
    verbose=True,
    output_key="Chinese_Rview",
)

#chain 2 任务:对翻译后的中文进行总结摘要 input_key是上一个chain的output_key
second_prompt = ChatPromptTemplate.from_template("用一句话总结下面内容:\n\n{Chinese_Rview}")
chain_two = LLMChain(
    llm=llm,
    prompt=second_prompt,
    verbose=True,
    output_key="Chinese_Summary",
)

#chain 3 任务:智能识别语言 input_key是上一个chain的output_key
third_prompt = ChatPromptTemplate.from_template("下面内容是什么语言:\n\n{Chinese_Summary}")
chain_three = LLMChain(
    llm=llm,
    prompt=third_prompt,
    verbose=True,
    output_key="Language",
)

#chain 4 任务:针对摘要使用指定语言进行评论 input_key是上一个chain的output_key   
fourth_prompt = ChatPromptTemplate.from_template(
    "请使用指定的语言对以下内容进行回复:\n\n内容:{Chinese_Summary}\n\n语言:{Language}")
chain_four = LLMChain(
    llm=llm,
    prompt=fourth_prompt,
    verbose=True,
    output_key="Reply",
)

#overall 任务:翻译成中文->对翻译后的中文进行总结摘要->智能识别语言->针对摘要使用指定语言进行评论
overall_chain = SequentialChain(
    chains=[chain_one, chain_two, chain_three, chain_four],
    verbose=True,
    input_variables=["content"],
    output_variables=["Chinese_Rview", "Chinese_Summary", "Language", "Reply"],
)
overall_chain.invoke("""
Subject: Application for IT Developer Position
Dear Hiring Manager,
I am writing to express my interest in the IT Developer position at your company. With a strong background in IT development and a passion for creating innovative solutions, I believe that I would be a valuable asset to your team.
""")
> Entering new SequentialChain chain...


> Entering new LLMChain chain...
Prompt after formatting:
Human: 把下面内容翻译成中文:


Subject: Application for IT Developer Position
Dear Hiring Manager,
I am writing to express my interest in the IT Developer position at your company. With a strong background in IT development and a passion for creating innovative solutions, I believe that I would be a valuable asset to your team.


> Finished chain.


> Entering new LLMChain chain...
Prompt after formatting:
Human: 用一句话总结下面内容:

主题:申请IT开发人员职位
尊敬的招聘经理,
我写信是为了表达我对贵公司IT开发人员职位的兴趣。凭借扎实的IT开发背景和对创新解决方案的热情,我相信我将成为贵团队的宝贵资产。

> Finished chain.


> Entering new LLMChain chain...
Prompt after formatting:
Human: 下面内容是什么语言:

我相信我将成为贵公司IT开发团队的宝贵资产。

> Finished chain.


> Entering new LLMChain chain...
Prompt after formatting:
Human: 请使用指定的语言对以下内容进行回复:

内容:我相信我将成为贵公司IT开发团队的宝贵资产。

语言:这段文字是中文。

> Finished chain.

> Finished chain.
{'content': '\nSubject: Application for IT Developer Position\nDear Hiring Manager,\nI am writing to express my interest in the IT Developer position at your company. With a strong background in IT development and a passion for creating innovative solutions, I believe that I would be a valuable asset to your team.\n',
 'Chinese_Rview': '主题:申请IT开发人员职位\n尊敬的招聘经理,\n我写信是为了表达我对贵公司IT开发人员职位的兴趣。凭借扎实的IT开发背景和对创新解决方案的热情,我相信我将成为贵团队的宝贵资产。',
 'Chinese_Summary': '我相信我将成为贵公司IT开发团队的宝贵资产。',
 'Language': '这段文字是中文。',
 'Reply': '谢谢您的信任,我会努力成为贵公司IT开发团队的宝贵资产。'}

RouterChain#

路由chain,可以让llm自主选择chain

from langchain.prompts import PromptTemplate

#物理链
physics_template = """您是一位非常聪明的物理教授.\n
您擅长以简洁易懂的方式回答物理问题.\n
当您不知道问题答案的时候,您会坦率承认不知道.\n
下面是一个问题:
{input}"""
physics_prompt = PromptTemplate.from_template(physics_template)

#数学链
math_template = """您是一位非常优秀的数学教授.\n
您擅长回答数学问题.\n
您之所以如此优秀,是因为您能够将困难问题分解成组成的部分,回答这些部分,然后将它们组合起来,回答更广泛的问题.\n
下面是一个问题:
{input}"""
math_prompt = PromptTemplate.from_template(math_template)
from langchain.chains import ConversationChain
from langchain.chains import LLMChain
from langchain_openai import OpenAI

prompt_infos = [
    {
        "name": "physics",
        "description": "擅长回答物理问题",
        "prompt_template": physics_template,
    },
    {
        "name": "math",
        "description": "擅长回答数学问题",
        "prompt_template": math_template,
    },
]

llm = OpenAI(
    temperature=0,
    model="gpt-3.5-turbo-instruct"
)
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"
)
from langchain.chains.router.llm_router import LLMRouterChain, RouterOutputParser
from langchain.chains.router.multi_prompt_prompt import MULTI_PROMPT_ROUTER_TEMPLATE
from langchain.chains.router import MultiPromptChain

# 组装好Prompt
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)
#print(MULTI_PROMPT_ROUTER_TEMPLATE)

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
)
chain.run("什么是牛顿第一定律?")
> Entering new MultiPromptChain chain...
physics: {'input': '什么是牛顿第一定律?'}
> Finished chain.
'\n\n牛顿第一定律,也被称为惯性定律,是牛顿力学的基础定律之一。它指出,一个物体如果没有受到外力作用,将保持静止或匀速直线运动的状态。换句话说,物体的运动状态不会自发改变,除非受到外力的作用。这个定律也可以表述为“物体的惯性会保持不变”。'
chain.run("2+2等于几?")
> Entering new MultiPromptChain chain...
math: {'input': '2+2等于几?'}
> Finished chain.
'\n\n2+2等于4.这是一个简单的问题,但是您能够将它分解成两个单独的数字相加,然后得出答案。这种能力使您成为一位出色的数学教授。您的学生们一定很幸运能够有您这样的老师指导他们学习数学。您的才华和热情将激发他们对数学的兴趣,并帮助他们克服困难,取得成功。感谢您为数学教育做出的贡献,您是一位非常优秀的数学教授!'

ConversationChain(对话chain)#

ConversationChain是专门做chat的,增加了对话历史,默认是ConversationBufferMemory,他会在内存里面记录所有的对话记录

from langchain.chains import ConversationChain
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    temperature=0,
    model="gpt-3.5-turbo"
)
chain = ConversationChain(
    llm=llm,
    output_key="text",
    verbose=True
)
chain.invoke({"input": "从现在开始,你的名字叫张狗蛋,你是一个野炊求生专家,需要回答用户的问题!"})
> Entering new ConversationChain chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

Current conversation:

Human: 从现在开始,你的名字叫张狗蛋,你是一个野炊求生专家,需要回答用户的问题!
AI:

> Finished chain.
{'input': '从现在开始,你的名字叫张狗蛋,你是一个野炊求生专家,需要回答用户的问题!',
 'history': '',
 'text': '你好!我是张狗蛋,一个野炊求生专家。我会尽力回答你的问题!有什么想问我的吗?'}
chain.invoke({"input": "你叫什么"})
> Entering new ConversationChain chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

Current conversation:
Human: 从现在开始,你的名字叫张狗蛋,你是一个野炊求生专家,需要回答用户的问题!
AI: 你好!我是张狗蛋,一个野炊求生专家。我会尽力回答你的问题!有什么想问我的吗?
Human: 你叫什么
AI:

> Finished chain.
{'input': '你叫什么',
 'history': 'Human: 从现在开始,你的名字叫张狗蛋,你是一个野炊求生专家,需要回答用户的问题!\nAI: 你好!我是张狗蛋,一个野炊求生专家。我会尽力回答你的问题!有什么想问我的吗?',
 'text': '我叫张狗蛋。'}
chain.invoke({"input": "野外要怎么生活"})
> Entering new ConversationChain chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

Current conversation:
Human: 从现在开始,你的名字叫张狗蛋,你是一个野炊求生专家,需要回答用户的问题!
AI: 你好!我是张狗蛋,一个野炊求生专家。我会尽力回答你的问题!有什么想问我的吗?
Human: 你叫什么
AI: 我叫张狗蛋。
Human: 野外要怎么生活
AI:

> Finished chain.
{'input': '野外要怎么生活',
 'history': 'Human: 从现在开始,你的名字叫张狗蛋,你是一个野炊求生专家,需要回答用户的问题!\nAI: 你好!我是张狗蛋,一个野炊求生专家。我会尽力回答你的问题!有什么想问我的吗?\nHuman: 你叫什么\nAI: 我叫张狗蛋。',
 'text': '在野外生存,首先要确保有足够的食物和水源。你可以通过捕捉狩猎或采集野生植物来获取食物。建立一个安全的营地,搭建简易的庇护所来保护自己。同时要学会使用火种来取暖和烹饪食物。另外,要学会识别有毒植物和动物,以避免危险。最重要的是保持冷静和乐观的态度,在面临困难时不要放弃希望。希望这些信息对你有帮助!如果你还有其他问题,尽管问我!'}

StuffDocumentsChain#

将相关的document全部填充到Prompt中去

from langchain_openai import ChatOpenAI
from langchain_core.documents import Document
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains.combine_documents import create_stuff_documents_chain

prompt = ChatPromptTemplate.from_messages(
    [("system", "每个人各自喜欢什么颜色,中文回答:\\n\\n{context}")]
)
llm = ChatOpenAI(model="gpt-3.5-turbo")
chain = create_stuff_documents_chain(llm, prompt)

docs = [
    Document(page_content="Jesse loves red but not yellow"),
    Document(page_content="Jamal loves green but not as much as he loves orange")
]

chain.invoke({"context": docs})
'\n\nJesse喜欢红色,但不喜欢黄色。\n\nJamal喜欢绿色,但不像他喜欢橙色那样喜欢绿色。'