在自然语言处理中,处理复杂的推理问题需要考虑多步推理、条件判断以及上下文信息。本文将展示如何使用 LangChain 创建一个带有复杂逻辑的 FewShotPromptTemplate
,并结合语义相似性示例选择器来选择最相关的示例以生成更加智能的响应。
1. 导入必要的库
首先,我们导入 LangChain 的核心库 PromptTemplate
和 FewShotPromptTemplate
,以及用于示例选择的相关库。
from langchain_core.prompts import PromptTemplate
from langchain_core.prompts import FewShotPromptTemplate
from langchain_chroma import Chroma
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
from langchain_community.embeddings import HuggingFaceEmbeddings
from config import acge_text_embedding
2. 创建基本的提示模板
PromptTemplate
是 LangChain 中的一个基本组件,用于定义提示的格式。在这里,我们创建了一个简单的模板,其中包括问题和答案的占位符。
example_prompt = PromptTemplate.from_template("Question: {question}\n{answer}")
3. 定义复杂逻辑的示例数据
examples = [
{
"question": "温格高是2023年环法冠军吗?",
"answer": """
需要后续问题来回答吗: 是的。
后续问题: 温格高曾经获得过环法冠军吗?
中间答案: 是的,温格高曾获得2022年和2023年环法冠军。
后续问题: 温格高在2023年赢得的是什么比赛?
中间答案: 温格高在2023年赢得了环法比赛。
所以最终答案是: 是的
""",
},
{
"question": "温格高在哪一年首次赢得环法冠军,并且他的主要竞争对手是谁?",
"answer": """
需要后续问题来回答吗: 是的。
后续问题: 温格高第一次赢得环法冠军是在哪一年?
中间答案: 温格高在2022年第一次赢得环法冠军。
后续问题: 在2022年的比赛中,谁是温格高的主要竞争对手?
中间答案: 温格高的主要竞争对手是塔德伊·波加查(Tadej Pogačar)。
所以最终答案是: 2022年,主要竞争对手是塔德伊·波加查
""",
},
{
"question": "温格高是哪个国家的车手,他曾经参加过奥运会吗?",
"answer": """
需要后续问题来回答吗: 是的。
后续问题: 温格高的国籍是什么?
中间答案: 温格高是丹麦的车手。
后续问题: 温格高是否曾代表丹麦参加过奥运会?
中间答案: 不,温格高没有参加过奥运会。
所以最终答案是: 温格高是丹麦车手,但没有参加过奥运会。
""",
},
{
"question": "温格高和塔德伊·波加查在环法比赛中的历史交锋情况如何?",
"answer": """
需要后续问题来回答吗: 是的。
后续问题: 温格高和塔德伊·波加查在环法比赛中有过几次直接对决?
中间答案: 他们在2021年、2022年和2023年环法比赛中有过直接对决。
后续问题: 在这些对决中,谁赢得了更多的冠军?
中间答案: 温格高在2022年和2023年赢得了冠军,而塔德伊·波加查在2021年赢得了冠军。
所以最终答案是: 温格高和塔德伊·波加查有过三次对决,其中温格高赢得了两次。
""",
},
{
"question": "温格高在2023年环法赛中是否赢得了所有山地赛段的胜利?",
"answer": """
需要后续问题来回答吗: 是的。
后续问题: 温格高在2023年环法赛中是否表现出色?
中间答案: 是的,温格高在多个山地赛段中表现出色。
后续问题: 温格高是否赢得了所有山地赛段的胜利?
中间答案: 不,温格高赢得了大部分山地赛段,但不是全部。
所以最终答案是: 温格高在2023年表现出色,但并没有赢得所有山地赛段的胜利。
""",
},
]
4. 生成包含复杂逻辑示例的提示词
我们使用 FewShotPromptTemplate
来创建一个包含复杂逻辑示例的提示词。这个模板将根据我们提供的示例和用户输入的问题生成最终的提示
prompt = FewShotPromptTemplate(
examples=examples,
example_prompt=example_prompt,
suffix="Question: {input}",
input_variables=["input"],
)
print(prompt.invoke({"input": "温格高是哪个国家的车手?"}).to_string())
输出结果:
Question: 温格高是哪个国家的车手?
需要后续问题来回答吗: 是的。
后续问题: 温格高的国籍是什么?
中间答案: 温格高是丹麦的车手。
所以最终答案是: 丹麦
5. 结合语义相似性选择器选择相关示例
为了让模型根据输入问题选择最相关的示例,我们可以使用 SemanticSimilarityExampleSelector
。该选择器基于语义相似性选择最适合的示例。
example_selector = SemanticSimilarityExampleSelector.from_examples(
examples,
HuggingFaceEmbeddings(model_name=acge_text_embedding),
Chroma,
k=1,
)
6. 测试示例选择器
我们可以测试一下示例选择器,看看它能否为给定的问题找到最相关的示例。
question = "温格高和塔德伊·波加查在环法比赛中的历史交锋情况如何?"
selected_examples = example_selector.select_examples({"question": question})
print(f"与输入最相似的示例: {question}")
for example in selected_examples:
print("\n")
for k, v in example.items():
print(f"{k}: {v}")
输出结果:
与输入最相似的示例: 温格高和塔德伊·波加查在环法比赛中的历史交锋情况如何?
answer:
需要后续问题来回答吗: 是的。
后续问题: 温格高和塔德伊·波加查在环法比赛中有过几次直接对决?
中间答案: 他们在2021年、2022年和2023年环法比赛中有过直接对决。
后续问题: 在这些对决中,谁赢得了更多的冠军?
中间答案: 温格高在2022年和2023年赢得了冠军,而塔德伊·波加查在2021年赢得了冠军。
所以最终答案是: 温格高和塔德伊·波加查有过三次对决,其中温格高赢得了两次。
question: 温格高和塔德伊·波加查在环法比赛中的历史交锋情况如何?
7. 创建带有示例选择器的提示模板
最后,我们将示例选择器与 FewShotPromptTemplate
结合起来,生成一个动态的提示模板,可以根据输入自动选择最相关的示例。
prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=example_prompt,
suffix="Question: {input}",
input_variables=["input"],
)
print(prompt.invoke({"input": "温格高在2023年环法赛中是否赢得了所有山地赛段的胜利?"}).to_string())
输出结果:
Question: 温格高在2023年环法赛中是否赢得了所有山地赛段的胜利?
需要后续问题来回答吗: 是的。
后续问题: 温格高在2023年环法赛中是否表现出色?
中间答案: 是的,温格高在多个山地赛段中表现出色。
后续问题: 温格高是否赢得了所有山地赛段的胜利?
中间答案: 不,温格高赢得了大部分山地赛段,但不是全部。
所以最终答案是: 温格高在2023年表现出色,但并没有赢得所有山地赛段的胜利。
通过这个博客,了解如何使用 LangChain 来创建和使用带有复杂逻辑的 FewShotPromptTemplate
,并结合语义相似性示例选择器来处理自然语言问题。这种方法可以显著增强模型对复杂问题的理解能力,尤其是在提供多步推理和条件判断的情况下。