Skip to content

1 LangChain 提示词模版

提⽰词模板有助于将⽤⼾输⼊和参数转换为语⾔模型的指令。这可以⽤于指导模型的响应,帮助其理 解上下⽂并⽣成相关且连贯的基于语⾔的输出。

提⽰词模板的输⼊是⼀个字典,其中每个键表⽰要填充的提⽰词模板中的变量。

有两种类型的提⽰词模板:

1.1 字符串提示词模板

这些提⽰词模板⽤于格式化单个字符串,通常⽤于更简单的输⼊。

例如,构造和使⽤ PromptTemplate 的⼀种常⻅⽅式如下:

python
from langchain_core.prompts import PromptTemplate

# 提示词模版
prompt_template = PromptTemplate.from_template("帮我⽣成⼀个简短的,关于{topic}的报幕词。")

resp = prompt_template.invoke({"topic": "相声"})
print(resp)

1.2 聊天提示词模板

这些提示词模板用于格式化消息列表。这些”模板"本身由一系列模板组成。 例如,构建和使用 ChatPromptTemplate 的一种常见方式如下:

python
from langchain_core.prompts import ChatPromptTemplate


# {topic} 变量占位符
prompt_template = ChatPromptTemplate.from_messages([
    ("system", "你是一个幽默的电视台主持人!"),
    ("user", "帮我生成一个简短的,关于{topic}的报幕词。"),

])

res = prompt_template.invoke({"topic": "相声"})
print(res)

在上述示例中,当调用此 ChatPromptTemplate 时,将构造两个消息。第一个是系统消息,没有变量需要格式化。第二个是 HumanMessage,将由用户传入的 topic 变量进行格式化。

1.3 消息占位符

此提⽰词模板负责在特定位置添加消息列表。在上⾯的 ChatPromptTemplate 中,我们看到如何格式化两个消息,每个消息都是⼀个字符串。但是如果我们希望用户传⼊⼀个消息列表(历史消息),并将其插⼊到特定位置呢?这就是需要使用MessagesPlaceholder。

python
from langchain_core.messages import HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt_template = ChatPromptTemplate.from_messages([
    ("system", "你是一个幽默的电视台主持人!"),
    MessagesPlaceholder('msgs') # 里面名称随便填
])

res = prompt_template.invoke({"msgs": [HumanMessage(content='你好,主持人!')]})
print(res)

这将⽣成⼀个包含两个消息的列表,第⼀个是系统消息,第⼆个是我们传⼊的 HumanMessage。后面的消息就是我和AI⼤模型对话过程中的历史消息。这对于将消息列表插⼊到特定位置⾮常有⽤。

python
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt_template = ChatPromptTemplate.from_messages([
    ('system', '你是⼀个智能助⼿,尽可能的调⽤⼯具回答⽤⼾的问题'),
    MessagesPlaceholder(variable_name='chat_history', optional=True),
    ('human', '{input}'),
    MessagesPlaceholder(variable_name='agent_scratchpad', optional=True),
])

1.3 提示词模版 + LCEL

In-context-learning (ICL)作为一种新的自然语言外理范式逐渐崭露头角。ICL的该心思想是:通过提供少量示例作为上下文,让大模型直接从中学习并做出预测。这一方法不仅省去了传统监督学习中繁琐的训练过程,还为大型的应用开辟了新的可能性。

python
from langchain_core.prompts import PromptTemplate

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model='qwen3-8b',
    temperature=0.8,
    api_key='xxx',
    base_url='http://localhost:6006/v1',

    # qwen3特有的参数: enable_thinking 表示是否开启深度思考
    extra_body={'chat_template_kwargs': {'enable_thinking': True}}
)

# 提示词模版
prompt_template = PromptTemplate.from_template("帮我⽣成⼀个简短的,关于{topic}的报幕词。")

chain = prompt_template | llm
res = chain.invoke({"topic": "相声"})
print(res)

1.4 提示词模版嵌套-FewShotPromptTemplate + 示例

python
from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate

from langchain_demo.my_llm import llm

# ICL:In Context Learning
# 问题: 巴伦·特朗普的父亲是谁?


# 步骤一: 提供示例
examples = [
    {
        "question": "穆罕默德·阿里和艾伦·图灵谁活得更久?",
        "answer": """
是否需要后续问题: 是。
后续问题: 穆默德·阿里去世时多大?
中间答案:穆罕默德·阿里去世时74岁。
后续问题: 艾伦·图灵去世时多大?
中间答案: 艾伦·图灵去世时41岁。
所以最终答案是: 穆罕默德·阿里
        """
    },
    {
        "question": "乔治·华盛顿的外祖父是谁?",
        "answer": """
是否需要后续问题: 是。
后续问题: 乔治·华盛顿的母亲是谁?
中间答案: 乔治·华盛顿的母亲是玛丽·鲍尔·华盛顿。
后续问题: 玛丽·鲍尔·华盛顿的父亲是谁?
中间答案: 玛丽·鲍尔·华盛顿的父亲是约瑟夫·鲍尔。
所以最终答案是: 约瑟夫·鲍尔
"""
    },
    {
        "question": "《大白鲨》和《007:大战皇家赌场》的导演是否来自同一个国家?",
        "answer": """
是否需要后续问题: 是。
后续问题: 《大白鲨》的导演是谁?
中间答案: 《大白鲨》的导演是史蒂文·斯皮尔伯格。
后续问题: 史蒂文·斯皮尔伯格来自哪里?
中间答案: 美国。
后续问题: 《007:大战皇家赌场》的导演是谁?
中间答案: 《007:大战皇家赌场》的导演是马丁·坎贝尔。
后续问题: 马丁·坎贝尔来自哪里?
中间答案: 新西兰。
所以最终答案是: 否
"""
    },
]

# 提示词基础模版
base_template = PromptTemplate.from_template("问题:{question}\n{answer}")

# 步骤二:创建 FewShotPromptTemplate 实例
final_template = FewShotPromptTemplate(
    examples=examples,  # 传入示例列表
    example_prompt=base_template,  # 指定单个示例的提示模板
    suffix="问题: {input}",  # 最后追加的问题模板
    input_variables=["input"],  # 指定输入变量
)

chain = final_template | llm
res = chain.invoke({"input": "巴伦·特朗普的父亲是谁?"})
print(res)

1.5 提示词模版嵌套-FewShotChatMessagePromptTemplate + 示例

python
from langchain_core.messages import HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder, FewShotChatMessagePromptTemplate

from langchain_demo.my_llm import llm

# ICL
# 2 🦜 9 的结果是多少

examples = [
    {'input': '2 🦜 2', 'output': '4'},
    {'input': '2 🦜 3', 'output': '5'},
]

# 单个用户输入和AI回复的模板
base_template = ChatPromptTemplate.from_messages([
    ("human", "{input}"),
    ("ai", "{output}"),
])

# 包含实例的提示词模板
few_shot_prompt = FewShotChatMessagePromptTemplate(
    examples=examples,
    example_prompt=base_template
)

final_template = ChatPromptTemplate.from_messages([
    ("system", "你是智能机器人AI助手!"),
    few_shot_prompt,
    MessagesPlaceholder('msgs')  # 里面名称随便填
])

chain = final_template | llm
res = chain.invoke({"msgs": [HumanMessage(content='2 🦜 9 的结果是多少')]})
print(res)

1.6 2、输出解析器和结构化输出

输出解析器:负责获取模型的输出并将其转换为更适合下游任务的格式。 在使用大型语言模型生成结构化数据或规范化聊天模型和大型语言模型的输出时非常有用。

大型语言模型能够生成任意文本。这使得模型能够适当地响应广泛的 输入范围,但对于某些用例,限制大型语言模型的输出 为特定格式或结构是有用的。这被称为结构化输出

例如,如果输出要存储在关系数据库中,如果模型生成遵循定义的模式或格式的输出,将会容易得多。 最常见的输出格式将是JSON,尽管其他格式如YAML也可能很有用。

1.6.1 StrOutputParser

python
chain = final_template | llm | StrOutputParser()

1.6.2 .with structured output()

为了方便,一些LangChain聊天模型支持 .with_structured_output()方法。该方法只需要一个模式作为输入,并返回一个字典或pydantic对象。 通常,这个方法仅在支持下面描述的更高级方法的模型上存在, 并将在内部使用其中一种。它负责导入合适的输出解析器并 将模式格式化为模型所需的正确格式。

需求生成一个笑话的段子:三个属性

python
import json
from typing import Optional
from langchain_core.prompts import PromptTemplate
from pydantic import BaseModel, Field
from langchain_demo.my_llm import llm


# 使用pydantic定义一个类
class Joke(BaseModel):
    """笑话(搞笑段子)的结构类(数据模型类)"""
    setup: str = Field(description='笑话的开头部分') # 笑话的铺垫部分
    punchline: str = Field(description='笑话的包袱/笑点')  # 笑话的爆笑部分
    rating: Optional[int] = Field(description="笑话的有趣程度评分,范围1到10")  # 可选的笑话评分字段


prompt_template = PromptTemplate.from_template("帮我⽣成⼀个关于{topic}的笑话。")
runnable = llm.with_structured_output(Joke)

chain = prompt_template | runnable
res = chain.invoke({"topic": "猫"})
print(res)

# 输出JSON格式
json_str = json.dumps(res.__dict__)
print(json_str)

1.6.3 SimpleJsonOutputParser

一些模型,例如 Mistral、OpenAl, Together AI和 Olama,支持一种称为 JSON 模式 的功能,通常通过配置启用。启用时,JSON 模式将限制模型的输出始终为某种有效的 JSON。

需求:1大模型回答 2要输出一个新问题 最终输出JSON格式

python
from langchain_core.output_parsers import  SimpleJsonOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_demo.my_llm import llm

# 创建聊天提示模板,要求模型以特定格式回答问题
prompt = ChatPromptTemplate.from_template(
    "尽你所能回答用户的问题。"  # 基本指令
    '你必须始终输出一个也含"answer"和"followup_question"键的JSON对象。其中"answer"代表: 对用户问题的回答;"followup_question"代表:用户可能提出的后续问题'  # 输出格式要求
    "{question}"  # 用户问题古位符
)

chain = prompt | llm | SimpleJsonOutputParser()
res = chain.invoke({"question": "细胞的动力源是什么?"})
print(res)

1.6 提示词模版 + 工具调用

对于支持此功能的模型,工具调用 可以非常方便地生成结构化输出。它消除了 关于如何最好地提示模式的猜测,而是采用内置模型功能。

它的工作原理是首先将所需的模式直接或通过 LangChain 工具 绑定到 聊天模型,使用 .bind tools()方法。然后模型将生成一个包含 与所需形状匹配的 args 的tool cals 字段的 AIMessaqe。工具调用是一种通常一致的方法,可以让模型生成结构化输出,并且是默认技术 用于.with_structuredoutput()方法,当模型支持时。

python
from pydantic import BaseModel, Field
from langchain_demo.my_llm import llm

class ResponseFormatter(BaseModel):
    """始终使用此工具来结构化你的用户响应"""  # 文档字符串说明这个类用于格式化响应

    answer: str = Field(description="对用户问题的回答")  # 回答内容字段
    followup_question: str = Field(description="用户可能提出的后续问题")  # 后续提出的问题


runnable = llm.bind_tools([ResponseFormatter])

res = runnable.invoke("细胞的动力源是什么?")
print(res)
print(res.tool_calls[-1]['args'])
res.pretty_print()

bind_tools 可以使用多个模版,大模型会根据上下文语义自动去选取最合适的模版进行使用

Released under the MIT License.