LangChain使用之模型IO

1、Model I/O介绍

  • Model I/O 模块是与语言模型(LLMs)进行交互的 核心组件 ,在整个框架中有着很重要的地位。 所谓的Model I/O,包括输入提示(Format)、调用模型(Predict)、输出解析(Parse)。分别对应着Prompt TemplateModelOutput Parser

  • 简单来说,就是输入、处理、输出这三个步骤。

  • 针对每个环节,LangChain都提供了模板和工具,可以快捷的调用各种语言模型的接口。

2、Model I/O之调用模型1

  • LangChain作为一个“工具”,不提供任何 LLMs,而是依赖于第三方集成各种大模型。比如,将 OpenAI、Anthropic、Hugging Face 、LlaMA、阿里Qwen、ChatGLM等平台的模型无缝接入到你的 应用。

2.1 模型的不同分类方式

简单来说,就是用谁家的API以什么方式调用哪种类型的大模型

  • 角度1:按照模型功能的不同
    • 非对话模型(LLMs、Text Model)
    • 对话模型(Chat Models)(推荐)
    • 嵌入模型(Embedding Models)(暂不考虑)
  • 角度2:模型调用时,几个重要参数的书写位置的不同
    • 硬编码:写在代码文件中
    • 使用环境变量
    • 使用配置文件(推荐)
  • 角度3:具体调用的API
    • OpenAI提供的API
    • 其它大模型自家提供的API
    • LangChain的统一方式调用API(推荐)

背景小知识:OpenAI的GPT系列模型影响了大模型技术发展的开发范式和标准。所以无论是Qwen、ChatGLM等模型,它们的使用方法和函数调用逻辑基本 遵循OpenAI定义的规范,没有太大差异。这就使得大部分的开源项目能够通过一个较为通用的接口来接入和使用不同的模型。

2.2 角度1出发:按照功能不同举例

2.2.1 类型1:LLMs(非对话模型)

  • LLMs,也叫Text Model、非对话模型,是许多语言模型应用程序的支柱。主要特点如下:

    • 输入:接受文本字符串或PromptValue对象
    • 输出:总是返回文本字符串
    image-20250927144828415
  • 适用场景:仅需单次文本生成任务(如摘要生成、翻译、代码生成、单次问答)或对接不支持消息 结构的旧模型(如部分本地部署模型)( 言外之意,优先推荐ChatModel)

  • 不支持多轮对话上下文。每次调用独立处理输入,无法自动关联历史对话(需手动拼接历史文本)。

  • 局限性:无法处理角色分工或复杂对话逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
import os
import dotenv
from langchain_openai import OpenAI
dotenv.load_dotenv()
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY1")
os.environ["OPENAI_BASE_URL"] = os.getenv("OPENAI_BASE_URL")


###########核心代码############
llm = OpenAI()
str = llm.invoke("写一首关于春天的诗") # 直接输入字符串
print(str)
print(type(str))

2.2.2 类型2:Chat Models(对话模型)

  • ChatModels,也叫聊天模型、对话模型,底层使用LLMs。

  • 大语言模型调用,以 ChatModel 为主!

  • 主要特点如下:

    • 输入:接收消息列表 List[BaseMessage]PromptValue ,每条消息需指定角色(如 SystemMessage、HumanMessage、AIMessage)

    • 输出:总是返回带角色的 消息对象 ( BaseMessage 子类),通常是 AIMessage

    • 原生支持多轮对话。通过消息列表维护上下文(例如:[SystemMessage, HumanMessage,AIMessage…]),模型可基于完整对话历史生成回复。

    • 适用场景:对话系统(如客服机器人、长期交互的AI助手)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage
import os
import dotenv
dotenv.load_dotenv()
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY1")
os.environ["OPENAI_BASE_URL"] = os.getenv("OPENAI_BASE_URL")


########核心代码############
chat_model = ChatOpenAI(model="gpt-4o-mini")

messages = [
SystemMessage(content="我是人工智能助手,我叫小智"),
HumanMessage(content="你好,我是小明,很高兴认识你")
]

#输入:list[basemessage]
#输出:AIMessage
response = chat_model.invoke(messages) # 输入消息列表

print(type(response)) # <class 'langchain_core.messages.ai.AIMessage'>
print(response.content)

2.2.3 类型3:Embedding Model(嵌入模型)

  • Embedding Model:也叫文本嵌入模型,这些模型将文本作为输入并返回 ,也就是Embedding。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import os
import dotenv
from langchain_openai import OpenAIEmbeddings
dotenv.load_dotenv()
os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY1")
os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")


#############
embeddings_model = OpenAIEmbeddings(
model="text-embedding-ada-002"
)

res1 = embeddings_model.embed_query('我是文档中的数据')
print(res1)
# 打印结果:[-0.004306625574827194, 0.003083756659179926, -0.013916781172156334, ...., ]

2.3 角度2出发:参数位置不同举例

  • 这里以 的API为准,使用对话模型,进行测试。

2.3.1 模型调用的主要方法及参数

  • 相关方法及属性:

    • OpenAI(..) / ChatOpenAI(..):创建一个模型对象(非对话类/对话类)
    • model.invoke(xcxx):执行调用,将用户输入发送给模型
    • .content:提取模型返回的实际文本内容
  • 模型调用函数使用时需初始化模型,并设置必要的参数。

    • 必须设置的参数:

      • base_url :大模型 API 服务的根地址
      • api_key:用于身份验证的密钥,由大模型服务商(如 OpenAI、百度干帆)提供
      • model/model_name:指定要调用的具体大模型名称(如gpt-4-turbo、ERNIE-3.5-8K等
    • 其它参数:

      • temperature:温度,控制生成文本的“随机性”,取值范围为0~1。

        • 值越低 一输出越确定、保守(适合事实回答)
        • 值越高 一输出越多样、有创意(适合创意写作)

        通常,根据需要设置如下:

        精确模式(0.5或更低):生成的文本更加安全可靠,但可能缺乏创意和多样性。

        平衡模式(通常是0.8):生成的文本通常既有一定的多样性,又能保持较好的连贯性和准确性。

        创意模式(通常是1):生成的文本更有创意,但也更容易出现语法错误或不合逻辑的内容。

      • max_tokens:限制生成文本的最大长度,防止输出过长。

        Token是什么?
        基本单位:大模型处理文本的最小单位是token(相当于自然语言中的词或字),输出时逐个token依次生成。
        收费依据:大语言模型(LLM)通常也是以token的数量作为其计量(或收费)的依据。

        1个Token~1-1.8个汉字,1个Token~3-4个英文字母

        Token与字符转化的可视化工具:

        max_tokens设置建议:

        • 客服短回复:128-256。比如:生成一句客服回复(如“订单已发货,预计明天送达”)
        • 常规对话、多轮对话:512-1024
        • 长内容生成:1024-4096。比如:生成一篇产品说明书(包含功能、使用方法等结构

2.3.2 模型调用推荐平台:closeai

2.3.3 方式1:硬编码

  • 直接将 API Key 和模型参数写入代码,仅适用于临时测试,存在密钥泄露风险,在生产环境不推荐。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 演示对话模型
    from langchain_openai import ChatOpenAI
    # 调用非对话模型:
    # llms = OpenAI(...)

    # 调用对话模型:
    chat_model = ChatOpenAI(
    #必须要设置的3个参数
    model_name="gpt-4o-mini", #默认使用的是gpt-3.5-turbo模型
    base_url="https://api.openai-proxy.org/v1",
    api_key="xxx",

    )

    # 调用模型
    response = chat_model.invoke("什么是langchain?")

    # 查看响应的文本
    # print(response.content)
    print(response)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 演示非对话模型
    from langchain_openai import OpenAI

    # 调用非对话模型:
    llm = OpenAI(
    #必须要设置的3个参数
    #model_name="gpt-4o-mini", #默认使用的是gpt-3.5-turbo模型
    base_url="https://api.openai-proxy.org/v1",
    api_key="xxx",

    )

    # 调用模型
    response = llm.invoke("什么是langchain?")

    # 查看响应的文本
    print(response)

2.3.4 方式2:配置环境变量

  • 通过系统环境变量存储密钥,避免代码明文暴露。

    1
    export OPENAI_API_KEY= "XXX"
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    from langchain_openai import ChatOpenAI
    import os

    print(os.environ["OPENAI_BASE_URL"])
    print(os.environ["OPENAI_API_KEY"])

    # 1、获取对话模型:
    chat_model = ChatOpenAI(
    #必须要设置的3个参数
    model_name="gpt-4o-mini", #默认使用的是gpt-3.5-turbo模型
    base_url=os.environ["OPENAI_BASE_URL"],
    api_key=os.environ["OPENAI_API_KEY"],

    )

    # 2、调用模型
    response = chat_model.invoke("什么是langchain?")

    # 3、查看响应的文本
    # print(response.content)
    print(response)
  • 优点:密钥与代码分离,适合单机开发。

  • 缺点:切换终端或文件后,变量失效,需重新设置。

2.3.5 方式3:使用.env配置文件

  • 使用加载本地配置文件,支持多环境管理(开发/生产)。

    • 安装依赖:

      1
      2
      3
      pip install python-dotenv
      # 或
      conda install python-dotenv
    • 创建 .env 文件(项目根目录):

      1
      2
      OPENAI_API_KEY = 'XXX'
      OPENAI_BASE_URL = 'XXX'
  • 举例:

    • 方式一:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      from langchain_openai import ChatOpenAI
      import os
      import dotenv

      #加载配置文件
      dotenv.load_dotenv()


      # 1、获取对话模型:
      chat_model = ChatOpenAI(
      #必须要设置的3个参数
      model_name="gpt-4o-mini", #默认使用的是gpt-3.5-turbo模型
      base_url=os.getenv("OPENAI_BASE_URL"),
      api_key=os.getenv("OPENAI_API_KEY1"),

      )

      # 2、调用模型
      response = chat_model.invoke("什么是langchain?")

      # 3、查看响应的文本
      # print(response.content)
      print(response)
    • 方式二:给os内部的环境变量赋值。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      from langchain_openai import ChatOpenAI
      import os
      import dotenv

      #加载配置文件
      dotenv.load_dotenv()


      os.environ["OPENAI_BASE_URL"] = os.getenv("OPENAI_BASE_URL")
      os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY1")


      # 1、获取对话模型:
      chat_model = ChatOpenAI(
      #必须要设置的3个参数
      #model_name="gpt-4o-mini", #默认使用的是gpt-3.5-turbo模型
      #当没有显式的声明base_url和api_key的时候,默认会从环境变量中查找
      )

      # 2、调用模型
      response = chat_model.invoke("什么是langchain?")

      # 3、查看响应的文本
      # print(response.content)
      print(response)
    • 体会其它参数的使用:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      from langchain_openai import ChatOpenAI
      import os
      import dotenv

      #加载配置文件
      dotenv.load_dotenv()


      os.environ["OPENAI_BASE_URL"] = os.getenv("OPENAI_BASE_URL")
      os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY1")


      # 1、获取对话模型:
      chat_model = ChatOpenAI(
      temperature=0.7,
      max_tokens=20,
      )

      # 2、调用模型
      response = chat_model.invoke("什么是langchain?")

      # 3、查看响应的文本
      # print(response.content)
      print(response)
  • 核心优势

    • 配置文件可加入 .gitignore 避免泄露
    • 结合 LangChain 可扩展其它模型(如 DeepSeek、阿里云)
    • 生产环境推荐

2.4 角度3出发:各平台API的调用举例(了解)

2.4.1 OpenAI官方API

  • 调用非对话模型:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    from openai import OpenAI

    # 从环境变量读取API密钥(推荐安全存储)
    client = OpenAI(
    api_key="xxx", #填写自己的api-key
    base_url="https://api.openai-proxy.org/v1") #通过代码示例获取

    # 调用Completion接口
    response = client.completions.create(
    model="gpt-3.5-turbo-instruct", # 非对话模型
    prompt="请将以下英文翻译成中文:\n'Artificial intelligence will reshape the future.'",
    max_tokens=100, # 生成文本最大长度
    temperature=0.7, # 控制随机性
    )
    # 提取结果
    print(response.choices[0].text.strip())
  • 调用对话模型:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    from openai import OpenAI

    client = OpenAI(
    api_key="xxx", #填写自己的api-key
    base_url="https://api.openai-proxy.org/v1")

    completion = client.chat.completions.create(
    model="gpt-3.5-turbo", # 对话模型
    messages=[
    {"role": "system", "content": "你是一个乐于助人的智能AI小助手"},
    {"role": "user", "content": "你好,请你介绍一下你自己"}
    ],
    max_tokens=150,
    temperature=0.5
    )

    print(completion.choices[0].message)

2.4.2 百度千帆平台

2.4.3 阿里云百炼平台

  • 注册与key的获取:提前开通百炼平台账号并申请API KEY:https://bailian.console.aliyun.com/#/home。

  • 举例1:通过OpenAI SDK

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    import os
    from openai import OpenAI
    import dotenv

    #加载配置文件
    dotenv.load_dotenv()

    client = OpenAI(
    # 若没有配置环境变量,请用阿里云百炼API Key将下行替换为:api_key="sk-xxx",
    api_key=os.getenv("DASHSCOPE_API_KEY"), # 如何获取API Key:https://help.aliyun.com/zh/model-studio/developer-reference/get-api-key
    base_url=os.getenv("DASHSCOPE_BASE_URL")
    )

    completion = client.chat.completions.create(
    model="deepseek-r1", # 此处以 deepseek-r1 为例,可按需更换模型名称。
    messages=[
    {'role': 'user', 'content': '9.9和9.11谁大'}
    ]
    )

    # 通过reasoning_content字段打印思考过程
    print("思考过程:")
    print(completion.choices[0].message.reasoning_content)

    # 通过content字段打印最终答案
    print("最终答案:")
    print(completion.choices[0].message.content)
  • 举例2:通过DashScope SDK

    1
    pip install dashscope
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    import os
    import dashscope

    messages = [
    {'role': 'user', 'content': '你是谁?'}
    ]

    response = dashscope.Generation.call(
    # 若没有配置环境变量,请用阿里云百炼API Key将下行替换为:api_key="sk-xxx",
    api_key=os.getenv('DASHSCOPE_API_KEY'),
    model="deepseek-r1", # 此处以 deepseek-r1 为例,可按需更换模型名称。
    messages=messages,
    # result_format参数不可以设置为"text"。
    result_format='message'
    )

    print("=" * 20 + "思考过程" + "=" * 20)
    print(response.output.choices[0].message.reasoning_content)
    print("=" * 20 + "最终答案" + "=" * 20)
    print(response.output.choices[0].message.content)

2.4.4 智谱的GLM

  • 注册智谱模型并获取API Key:https://www.bigmodel.cn/usercenter/proj-mgmt/apikeys

  • 举例1:使用OpenAI SDK

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    from openai import OpenAI

    client = OpenAI(
    api_key="xxx",
    base_url="https://open.bigmodel.cn/api/paas/v4/"
    )

    completion = client.chat.completions.create(
    model="glm-4.5",
    messages=[
    {"role": "system", "content": "你是一个聪明且富有创造力的小说作家"},
    {"role": "user", "content": "请你作为童话故事大王,写一篇短篇童话故事"}
    ],
    top_p=0.7,
    temperature=0.9
    )

    print(completion.choices[0].message.content)
  • 举例2:使用Langchain SDK

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    from langchain_openai import ChatOpenAI
    from langchain.schema import HumanMessage, SystemMessage

    # 创建LLM实例
    llm = ChatOpenAI(
    temperature=0.7,
    model="glm-4.5",
    openai_api_key="xxx",
    openai_api_base="https://open.bigmodel.cn/api/paas/v4/"
    )

    # 创建消息
    messages = [
    SystemMessage(content="你是一个有用的AI助手"),
    HumanMessage(content="请介绍一下人工智能的发展历程")
    ]

    # 调用模型
    response = llm(messages)
    print(response.content)

2.4.5 硅基流动平台

  • 官网:https://www.siliconflow.cn/

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import requests

    url = "https://api.siliconflow.cn/v1/chat/completions"

    payload = {
    "model": "Qwen/QwQ-32B",
    "messages": [
    {
    "role": "user",
    "content": "What opportunities and challenges will the Chinese large model industry face in 2025?"
    }
    ]
    }
    headers = {
    "Authorization": "Bearer xxx", #填写自己的api-key
    "Content-Type": "application/json"
    }

    response = requests.post(url, json=payload, headers=headers)

    print(response.json())

2.5 如何选择合适的大模型

2.5.1 有没有最好的大模型

2.5.2 获取大模型的标准方式

  • 后续的各种模型测试,都基于如下的模型展开:

    • 非对话模型:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      import os
      import dotenv
      from langchain_openai import OpenAI

      dotenv.load_dotenv()

      os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY")
      os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")

      llm = OpenAI( #非对话模型
      #max_tokens=512,
      #temperature=0.7,
      )
    • 对话模型:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      import os
      import dotenv
      from langchain_openai import ChatOpenAI

      dotenv.load_dotenv()

      os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY")
      os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")

      chat_model = ChatOpenAI( #对话模型
      model="gpt-4o-mini",
      #max_tokens=512,
      #temperature=0.7,
      )
  • 对应的配置文件:

    1
    2
    OPENAI_API_KEY="sk-xxxxxx"   #从CloseAI平台,注册自己的账号,并获取API KEY
    OPENAI_BASE_URL="https://api.openai-proxy.org/v1"

3、Model I/O之调用模型2

3.1 关于对话模型的Message(消息)

  • 标准的对话模型的调用过程:

    • invoke()的输入可以是多种类型,典型的类型有:① 字符串类型 ② 消息列表
    • invoke()的输出类型:BaseMessage的子类:AIMessage
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    from langchain_openai import ChatOpenAI
    import os
    import dotenv

    # 前提:加载配置文件
    dotenv.load_dotenv()

    os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY1")
    os.environ["OPENAI_BASE_URL"] = os.getenv("OPENAI_BASE_URL")

    # 1、获取对话模型
    chat_model = ChatOpenAI(
    # api_key=,
    # base_url=,
    model_name="gpt-4o-mini",
    )

    # 2、调用对话模型
    response = chat_model.invoke("帮我解释一下什么是langchain?")

    # 3、处理响应数据
    # print(response)
    print(response.content)
    print(type(response)) #<class 'langchain_core.messages.ai.AIMessage'>
  • LangChain有一些内置的消息类型:

    • 🔥SystemMessage:设定AI行为规则或背景信息。比如设定AI的初始状态、行为模式或对话的总体目标。比如“作为一个代码专家”,或者“返回json格式”。通常作为输入消息序列中的第一个传递。

    • 🔥HumanMessage:表示来自用户输入。比如“实现 一个快速排序方法”

    • 🔥AIMessage:存储AI回复的内容。这可以是文本,也可以是调用工具的请求

    • ChatMessage:可以自定义角色的通用消息类型

    • FunctionMessage/ToolMessage:函数调用/工具消息,用于函数调用结果的消息类型

    FunctionMessage和ToolMessage分别是在函数调用和工具调用场景下才会使用的特殊消息类型,HumanMessage、AIMessage和SystemMessage才是最常用的消息类型。

    举例1:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    from langchain_core.messages import SystemMessage, HumanMessage
    from langchain_openai import ChatOpenAI
    import os
    import dotenv

    # 前提:加载配置文件
    dotenv.load_dotenv()

    os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY1")
    os.environ["OPENAI_BASE_URL"] = os.getenv("OPENAI_BASE_URL")

    # 1、获取对话模型
    chat_model = ChatOpenAI(
    # api_key=,
    # base_url=,
    model_name="gpt-4o-mini",
    )

    system_message = SystemMessage(content="你是一个英语教学方向的专家")
    human_message = HumanMessage(content="帮我制定一个英语六级学习的计划")

    messages = [system_message, human_message]

    print(messages)
    # [SystemMessage(content='你是一个英语教学方向的专家', additional_kwargs={}, response_metadata={}), HumanMessage(content='帮我制定一个英语六级学习的计划', additional_kwargs={}, response_metadata={})]

    response = chat_model.invoke(messages)
    print(type(response)) # <class 'langchain_core.messages.ai.AIMessage'>
    print(response.content)

    举例2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from langchain_core.messages import SystemMessage, HumanMessage

    system_message = SystemMessage(
    content="你是一个英语教学方向的专家",
    additional_kwargs={"tool":"invoke_func1"}
    )
    human_message = HumanMessage(content="帮我制定一个英语六级学习的计划")

    messages = [system_message, human_message]

    print(messages)
    # [SystemMessage(content='你是一个英语教学方向的专家', additional_kwargs={'tool': 'invoke_func1'}, response_metadata={}), HumanMessage(content='帮我制定一个英语六级学习的计划', additional_kwargs={}, response_metadata={})]

    举例3:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # ChatMessage平时我们使用的不多,了解一下即可
    from langchain_core.messages import (
    AIMessage,
    HumanMessage,
    SystemMessage,
    ChatMessage
    )

    # 创建不同类型的消息
    system_message = SystemMessage(content="你是一个专业的数据科学家")
    human_message = HumanMessage(content="解释一下随机森林算法")
    ai_message = AIMessage(content="随机森林是一种集成学习方法...")
    custom_message = ChatMessage(role="analyst", content="补充一点关于超参数调优的信息")

    print(system_message.content)
    print(human_message.content)
    print(ai_message.content)
    print(custom_message.content)

3.2 关于多轮对话与上下文记忆

  • 前提:获取大模型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import os
    import dotenv
    from langchain_openai import ChatOpenAI

    dotenv.load_dotenv()

    os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY1")
    os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")

    chat_model = ChatOpenAI(
    model="gpt-4o-mini"
    )
  • 测试1:大模型本身是没有上下文记忆能力的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    from langchain_core.messages import SystemMessage, HumanMessage

    sys_message = SystemMessage(
    content="我是一个人工智能的助手,我的名字叫小智",
    )
    human_message = HumanMessage(content="猫王是一只猫吗?")

    messages = [sys_message, human_message]

    #调用大模型,传入messages
    response = chat_model.invoke(messages)
    # print(response.content)


    response1 = chat_model.invoke("你叫什么名字?")
    print(response1.content)
    # 我是一个人工智能助手,没有具体的名字。你可以叫我“助手”或者其他你喜欢的名字。如果有什么问题或者需要帮助的地方,随时问我!
  • 测试2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from langchain_core.messages import SystemMessage, HumanMessage

    sys_message = SystemMessage(
    content="我是一个人工智能的助手,我的名字叫小智",
    )
    human_message = HumanMessage(content="猫王是一只猫吗?")
    human_message1 = HumanMessage(content="你叫什么名字?")

    messages = [sys_message, human_message,human_message1]

    #调用大模型,传入messages
    response = chat_model.invoke(messages)
    print(response.content)
    # 我叫小智,很高兴认识你!有什么我可以帮助你的吗?
  • 测试3:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    from langchain_core.messages import SystemMessage, HumanMessage

    sys_message = SystemMessage(
    content="我是一个人工智能的助手,我的名字叫小智",
    )
    human_message = HumanMessage(content="猫王是一只猫吗?")

    sys_message1 = SystemMessage(
    content="我可以做很多事情,有需要就找我吧",
    )

    human_message1 = HumanMessage(content="你叫什么名字?")

    messages = [sys_message, human_message,sys_message1,human_message1]

    #调用大模型,传入messages
    response = chat_model.invoke(messages)
    print(response.content)
    # 我叫小智,很高兴为你服务!有什么我可以帮助你的吗?
  • 测试4:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    from langchain_core.messages import SystemMessage, HumanMessage

    # 第1组
    sys_message = SystemMessage(
    content="我是一个人工智能的助手,我的名字叫小智",
    )
    human_message = HumanMessage(content="猫王是一只猫吗?")

    messages = [sys_message, human_message]

    # 第2组
    sys_message1 = SystemMessage(
    content="我可以做很多事情,有需要就找我吧",
    )

    human_message1 = HumanMessage(content="你叫什么名字?")

    messages1 = [sys_message1,human_message1]

    #调用大模型,传入messages
    response = chat_model.invoke(messages)
    # print(response.content)

    response = chat_model.invoke(messages1)
    print(response.content)
    # 我是一个人工智能助手,没有自己的名字。你可以叫我助手或者其他你喜欢的称呼。有什么我可以帮助你的吗?
  • 测试5:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    from langchain_core.messages import SystemMessage, HumanMessage, AIMessage

    messages = [
    SystemMessage(content="我是一个人工智能助手,我的名字叫小智"),
    HumanMessage(content="人工智能英文怎么说?"),
    AIMessage(content="AI"),
    HumanMessage(content="你叫什么名字"),
    ]

    messages1 = [
    SystemMessage(content="我是一个人工智能助手,我的名字叫小智"),
    HumanMessage(content="很高兴认识你"),
    AIMessage(content="我也很高兴认识你"),
    HumanMessage(content="你叫什么名字"),
    ]

    messages2 = [
    SystemMessage(content="我是一个人工智能助手,我的名字叫小智"),
    HumanMessage(content="人工智能英文怎么说?"),
    AIMessage(content="AI"),
    HumanMessage(content="你叫什么名字"),
    ]

    chat_model.invoke(messages2)
    # AIMessage(content='我叫小智。有什么我可以帮助你的吗?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 13, 'prompt_tokens': 40, 'total_tokens': 53, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_efad92c60b', 'id': 'chatcmpl-C7Yc4CexF0a9rwfGrTHmp1OVT9xI3', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--d70d45e2-1c6f-4bb3-bedd-d3efba980561-0', usage_metadata={'input_tokens': 40, 'output_tokens': 13, 'total_tokens': 53, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})

3.3 关于模型调用的方法

  • 为了尽可能简化自定义链的创建,我们实现了一个”Runnable”协议。许多LangChain组件实现了 Runnable 协议,包括聊天模型、提示词模板、输出解析器、检索器、代理(智能体)等。

  • Runnable 接口定义的公共的调用方法如下:

    • invoke: 处理单条输入,等待LLM完全推理完成后再返回调用结果
    • stream: 流式响应,逐字输出LLM的响应结果
    • batch: 处理批量输入
  • 这些也有相应的异步方法,应该与 asyncio 的await语法一起使用以实现并发:

    • astream: 异步流式响应
    • ainvoke: 异步处理单条输入
    • abatch: 异步处理批量输入
    • astream_log: 异步流式返回中间步骤,以及最终响应
    • astream_events: (测试版)异步流式返回链中发生的事件(在 langchain-core 0.1.14 中引入)

3.3.1 流式输出与非流式输出

  • 在Langchain中,语言模型的输出分为了两种主要的模式:流式输出非流式输出

  • 下面是两个场景:

    • 非流式输出:这是Langchain与LLM交互时的默认行为,是最简单、最稳定的语言模型调用方式。 当用户发出请求后,系统在后台等待模型生成完整响应,然后一次性将全部结果返回
      • 举例:用户提问,请编写一首诗,系统在静默数秒后突然弹出了完整的诗歌。(体验较单调)
      • 在大多数问答、摘要、信息抽取类任务中,非流式输出提供了结构清晰、逻辑完整的结果,适 合快速集成和部署。
    • 流式输出:一种更具交互感的模型输出方式,用户不再需要等待完整答案,而是能看到模型逐个 token地实时返回内容。
      • 举例:用户提问,请编写一首诗,当问题刚刚发送,系统就开始一字一句 (逐个token)进行回复,感觉是一边思考一边输出。
      • 更像是“实时对话”,更为贴近人类交互的习惯,更有吸引力。
      • 适合构建强调“实时反馈”的应用,如聊天机器人、写作助手等。
      • Langchain 中通过设置stream=True并配合回调机制来启用流式输出。
  • 非流式输出:

    • 举例1:体会invoke()阻塞式的调用

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      import os
      import dotenv
      from langchain_core.messages import HumanMessage
      from langchain_openai import ChatOpenAI

      dotenv.load_dotenv()

      os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY1")
      os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")

      #初始化大模型
      chat_model = ChatOpenAI(model="gpt-4o-mini")

      # 创建消息
      messages = [HumanMessage(content="你好,请介绍一下自己")]

      # 非流式调用LLM获取响应
      response = chat_model.invoke(messages)

      # 打印响应内容
      print(response)
    • 举例3:特别的写法

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      import os
      import dotenv
      from langchain_core.messages import HumanMessage, SystemMessage
      from langchain_openai import ChatOpenAI

      dotenv.load_dotenv()

      os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY")
      os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")

      # 初始化大模型
      chat_model = ChatOpenAI(model="gpt-4o-mini")

      # 支持多个消息作为输入
      messages = [
      SystemMessage(content="你是一位乐于助人的助手。你叫于老师"),
      HumanMessage(content="你是谁?")
      ]
      response = chat_model(messages) #特别的写法
      print(response.content)

      底层调用BaseChatModel.__call__,内部调用的还是invoke()。后续还会有这种写法出现,了解即可。

  • 流式输出:一种更具交互感的模型输出方式,用户不再需要等待完整答案,而是能看到模型逐个token 地实时返回内容。适合构建强调“实时反馈”的应用,如聊天机器人、写作助手等。Langchain中通过设置并配合回调机制来启用流式输出。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    import os
    import dotenv
    from langchain_core.messages import HumanMessage
    from langchain_openai import ChatOpenAI

    dotenv.load_dotenv()

    os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY")
    os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")

    # 初始化大模型
    chat_model = ChatOpenAI(model="gpt-4o-mini",
    streaming=True # 启用流式输出
    )

    # 创建消息
    messages = [HumanMessage(content="你好,请介绍一下自己")]

    # 流式调用LLM获取响应
    print("开始流式输出:")
    for chunk in chat_model.stream(messages):
    # 逐个打印内容块
    print(chunk.content, end="", flush=True) # 刷新缓冲区 (无换行符,缓冲区未刷新,内容可能不会立即显示)

    print("\n流式输出结束")

3.3.2 批量调用

  • 使用batch,测试批量调用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    import os
    import dotenv
    from langchain_core.messages import HumanMessage, SystemMessage
    from langchain_openai import ChatOpenAI

    dotenv.load_dotenv()

    os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY1")
    os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")

    # 初始化大模型
    chat_model = ChatOpenAI(model="gpt-4o-mini")

    messages1 = [SystemMessage(content="你是一位乐于助人的智能小助手"),
    HumanMessage(content="请帮我介绍一下什么是机器学习"), ]

    messages2 = [SystemMessage(content="你是一位乐于助人的智能小助手"),
    HumanMessage(content="请帮我介绍一下什么是AIGC"), ]

    messages3 = [SystemMessage(content="你是一位乐于助人的智能小助手"),
    HumanMessage(content="请帮我介绍一下什么是大模型技术"), ]

    messages = [messages1, messages2, messages3]

    # 调用batch
    response = chat_model.batch(messages)

    print(response)

3.3.3 同步调用与异步调用(了解)

  • 同步调用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    import time

    def call_model():
    # 模拟同步API调用
    print("开始调用模型...")
    time.sleep(5) # 模拟调用等待,单位:秒
    print("模型调用完成。")

    def perform_other_tasks():
    # 模拟执行其他任务
    for i in range(5):
    print(f"执行其他任务 {i + 1}")
    time.sleep(1) # 单位:秒

    def main():
    start_time = time.time()
    call_model()
    perform_other_tasks()
    end_time = time.time()
    total_time = end_time - start_time
    return f"总共耗时:{total_time}秒"

    # 运行同步任务并打印完成时间
    main_time = main()
    print(main_time)

    # 开始调用模型...
    # 模型调用完成。
    # 执行其他任务 1
    # 执行其他任务 2
    # 执行其他任务 3
    # 执行其他任务 4
    # 执行其他任务 5
    # 总共耗时:10.033676385879517秒

    之前的本质上是一个同步调用。每个操作依次执行,直到当前操作完成后才开始下一个操作,从而导致总的执行时间是各个操作时间的总和。

  • 异步调用:允许程序在等待某些操作完成时继续执行其他任务,而不是阻塞等待。这在处理I/O操作(如 网络请求、文件读写等)时特别有用,可以显著提高程序的效率和响应性。

    • 写法1:此写法适合Jupyter Notebook

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      import asyncio
      import time

      async def async_call(llm):
      await asyncio.sleep(5) # 模拟异步操作
      print("异步调用完成")

      async def perform_other_tasks():
      await asyncio.sleep(5) # 模拟异步操作
      print("其他任务完成")

      async def run_async_tasks():
      start_time = time.time()
      await asyncio.gather(
      async_call(None), # 示例调用,替换None为模拟的LLM对象
      perform_other_tasks()
      )
      end_time = time.time()
      return f"总共耗时:{end_time - start_time}秒"

      # # 正确运行异步任务的方式
      # if __name__ == "__main__":
      # # 使用 asyncio.run() 来启动异步程序
      # result = asyncio.run(run_async_tasks())
      # print(result)


      # 在 Jupyter 单元格中直接调用
      result = await run_async_tasks()
      print(result)
    • 写法2:(此写法不适合Jupyter Notebook)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      import asyncio
      import time

      async def async_call(llm):
      await asyncio.sleep(5) # 模拟异步操作
      print("异步调用完成")

      async def perform_other_tasks():
      await asyncio.sleep(5) # 模拟异步操作
      print("其他任务完成")

      async def run_async_tasks():
      start_time = time.time()
      await asyncio.gather(
      async_call(None), # 示例调用,替换None为模拟的LLM对象
      perform_other_tasks()
      )
      end_time = time.time()
      return f"总共耗时:{end_time - start_time}秒"

      # 正确运行异步任务的方式
      if __name__ == "__main__":
      # 使用 asyncio.run() 来启动异步程序
      result = asyncio.run(run_async_tasks())
      print(result)

      # 异步调用完成
      # 其他任务完成
      # 总共耗时:5.0116283893585205秒

      使用并行执行时,理想情况下,因为两个任务几乎同时开始,它们的执行时间将重叠。如果两个任务的执行时间相同(这里都是5秒),那么总执行时间应该接近单个任务的执行时间,而不是两者时间之和。

    • 异步调用之ainvoke

      1
      2
      3
      4
      5
      # 举例1:验证ainvoke是否是异步
      import inspect

      print("ainvoke 是协程函数:", inspect.iscoroutinefunction(chat_model.ainvoke)) # ainvoke 是协程函数: True
      print("invoke 是协程函数:", inspect.iscoroutinefunction(chat_model.invoke)) # invoke 是协程函数: False
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      # 举例2:(不能在Jupyter Notebook中测试)
      import asyncio
      import os
      import time

      import dotenv
      from langchain_core.messages import HumanMessage, SystemMessage
      from langchain_openai import ChatOpenAI

      dotenv.load_dotenv()

      os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY1")
      os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")

      # 初始化大模型
      chat_model = ChatOpenAI(model="gpt-4o-mini")

      # 同步调用(对比组)
      def sync_test():
      messages1 = [SystemMessage(content="你是一位乐于助人的智能小助手"),
      HumanMessage(content="请帮我介绍一下什么是机器学习"), ]
      start_time = time.time()
      response = chat_model.invoke(messages1) # 同步调用
      duration = time.time() - start_time
      print(f"同步调用耗时:{duration:.2f}秒")
      return response, duration


      # 异步调用(实验组)
      async def async_test():
      messages1 = [SystemMessage(content="你是一位乐于助人的智能小助手"),
      HumanMessage(content="请帮我介绍一下什么是机器学习"), ]
      start_time = time.time()
      response = await chat_model.ainvoke(messages1) # 异步调用
      duration = time.time() - start_time
      print(f"异步调用耗时:{duration:.2f}秒")
      return response, duration


      # 运行测试
      if __name__ == "__main__":
      # 运行同步测试
      sync_response, sync_duration = sync_test()
      print(f"同步响应内容: {sync_response.content[:100]}...\n")

      # 运行异步测试
      async_response, async_duration = asyncio.run(async_test())
      print(f"异步响应内容: {async_response.content[:100]}...\n")

      # 并发测试 - 修复版本
      print("\n=== 并发测试 ===")
      start_time = time.time()


      async def run_concurrent_tests():
      # 创建3个异步任务
      tasks = [async_test() for _ in range(3)]
      # 并发执行所有任务
      return await asyncio.gather(*tasks)


      # 执行并发测试
      results = asyncio.run(run_concurrent_tests())

      total_time = time.time() - start_time
      print(f"\n3个并发异步调用总耗时: {total_time:.2f}秒")
      print(f"平均每个调用耗时: {total_time / 3:.2f}秒")

4、Model I/O之Prompt Template

  • Prompt Template,通过模板管理大模型的输入。

4.1 介绍与分类

  • Prompt Template 是LangChain中的一个概念,接收用户输入,返回一个传递给LLM的信息(即提示 词prompt)。

  • 在应用开发中,固定的提示词限制了模型的灵活性和适用范围。所以,prompt template 是一个模板化的字符串 ,你可以将变量插入到模板中,从而创建出不同的提示。调用时:

    • 字典作为输入,其中每个键代表要填充的提示模板中的变量。
    • 输出一个 PromptValue。这个 PromptValue 可以传递给 LLM 或 ChatModel,并且还可以转换为字符串或消息列表。
  • 有几种不同类型的提示模板:

    • PromptTemplate:LLM提示模板,用于生成字符串提示。它使用 Python 的字符串来模板提示。
    • ChatPromptTemplate:聊天提示模板,用于组合各种角色的消息模板,传入聊天模型。
      消息模板包括:SystemMessagePromptTemplate、HumanMessagePromptTemplate、AIMessagePromptTemplate、ChatMessagePromptTemplate等
    • FewShotPromptTemplate:样本提示模板,通过示例来教模型如何回答
    • PipelinePrompt:管道提示模板,用于把几个提示组合在一起使用。
    • 自定义模板:允许基于其它模板类来定制自己的提示模板。
  • 模版导入:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from langchain.prompts.prompt import PromptTemplate

    from langchain.prompts import ChatPromptTemplate

    from langchain.prompts import FewShotPromptTemplate

    from langchain.prompts.pipeline import PipelinePromptTemplate

    from langchain.prompts import (
    ChatMessagePromptTemplate,
    SystemMessagePromptTemplate,
    AIMessagePromptTemplate,
    HumanMessagePromptTemplate,
    )

4.2 具体使用:PromptTemplate

4.2.1 使用说明

  • PromptTemplate类,用于快速构建包含变量的提示词模板,并通过传入不同的参数值生成自定义的提示词。

  • 主要参数介绍:

    • template:定义提示词模板的字符串,其中包含文本变量占位符(如{name})

    • input_variables: 列表,指定了模板中使用的变量名称,在调用模板时被替换;

    • partial_variables:字典,用于定义模板中一些固定的变量名。这些值不需要再每次调用时被替换。

  • 函数介绍:

    • **format()**:给input_variables变量赋值,并返回提示词。利用format() 进行格式化时就一定要赋值,否则会报错。当在template中未设置input_variables,则会自动忽略。

4.2.2 两种实例化方式

  • 方式1:使用构造方法

    • 举例 1:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      from langchain_core.prompts import PromptTemplate

      #1、创建PromptTemplate的实例
      #参数中必须要指明:input_variables 、template
      prompt_template = PromptTemplate(
      template="你是一个{role},你的名字叫{name}",
      input_variables=["role","name"],
      )

      # print(prompt_template)


      #2、填充实例中的变量。暂且使用format()
      prompt = prompt_template.format(role="人工智能专家",name="小智")

      print(prompt)
      # 你是一个人工智能专家,你的名字叫小智

      可以直观的看到PromptTemplate可以将template中声明的变量topic准确提取出来,使prompt更清晰。

    • 举例 2:定义多变量模板

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      from langchain.prompts import PromptTemplate

      #定义多变量模板
      template = PromptTemplate(
      template="请评价{product}的优缺点,包括{aspect1}和{aspect2}。",
      input_variables=["product", "aspect1", "aspect2"])

      #使用模板生成提示词
      prompt_1 = template.format(product="智能手机", aspect1="电池续航", aspect2="拍照质量")
      prompt_2 = template.format(product="笔记本电脑", aspect1="处理速度", aspect2="便携性")

      print("提示词1:",prompt_1)
      # 提示词1: 请评价智能手机的优缺点,包括电池续航和拍照质量。
      print("提示词2:",prompt_2)
      # 提示词2: 请评价笔记本电脑的优缺点,包括处理速度和便携性。
  • 方式2:调用from_template(),推荐

    • 举例1:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      from langchain_core.prompts import PromptTemplate


      #1、创建PromptTemplate的实例
      prompt_template = PromptTemplate.from_template(template="你是一个{role},你的名字叫{name}")

      # print(prompt_template)


      #2、填充实例中的变量。暂且使用format()
      prompt = prompt_template.format(role="人工智能专家",name="小智")

      print(prompt)
      # 你是一个人工智能专家,你的名字叫小智
    • 举例2:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      from langchain.prompts import PromptTemplate

      #定义多变量模板
      template = PromptTemplate.from_template(template="请评价{product}的优缺点,包括{aspect1}和{aspect2}。")

      #使用模板生成提示词
      prompt_1 = template.format(product="智能手机", aspect1="电池续航", aspect2="拍照质量")

      print(prompt_1)
      # 请评价智能手机的优缺点,包括电池续航和拍照质量。
    • 举例3:如果提示词模板中不包含变量,则调用format()时,不需要传入参数!

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      #1.导入相关的包
      from langchain_core.prompts import PromptTemplate

      # 2.定义提示词模版对象
      text = """
      Tell me a joke
      """

      prompt_template = PromptTemplate.from_template(text)
      # 3.默认使用f-string进行格式化(返回格式好的字符串)
      prompt = prompt_template.format()
      print(prompt)
      # Tell me a joke

4.2.3 两种新的结构形式

  • 形式1:部分提示词模版,在生成prompt前就已经提前初始化部分的提示词,实际进一步导入模版的时候只导入除已初始化的变量即可。

    • 方式1:实例化过程中使用partial_variables变量

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      from langchain.prompts import PromptTemplate

      #定义多变量模板
      template = PromptTemplate.from_template(
      template="请评价{product}的优缺点,包括{aspect1}和{aspect2}。",
      partial_variables={"aspect1":"电池续航"}
      )

      #使用模板生成提示词
      prompt_1 = template.format(product="智能手机",aspect2="拍照质量")

      print(prompt_1)
      # 请评价智能手机的优缺点,包括电池续航和拍照质量。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      from langchain.prompts import PromptTemplate

      #定义多变量模板
      template = PromptTemplate(
      template="请评价{product}的优缺点,包括{aspect1}和{aspect2}。",
      input_variables=["product", "aspect1", "aspect2"],
      partial_variables={"aspect1":"电池续航","aspect2":"拍照质量"}
      )

      #使用模板生成提示词
      prompt_1 = template.format(product="智能手机")

      print("提示词1:",prompt_1)
      # 提示词1: 请评价智能手机的优缺点,包括电池续航和拍照质量。
    • 方式2:可以使用PromptTemplate.partial()方法创建部分提示模板

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      from langchain.prompts import PromptTemplate

      #定义多变量模板
      template = PromptTemplate(
      template="请评价{product}的优缺点,包括{aspect1}和{aspect2}。",
      input_variables=["product", "aspect1", "aspect2"],
      # partial_variables={"aspect1":"电池续航","aspect2":"拍照质量"}
      )

      # partial()调用完以后,不会对调用者这个模板对象产生影响;而其返回值是一个新的模板
      template1 = template.partial(aspect1="电池续航",aspect2="拍照质量")

      #使用模板生成提示词
      prompt_1 = template1.format(product="智能手机")

      print("提示词1:",prompt_1)
      # 提示词1: 请评价智能手机的优缺点,包括电池续航和拍照质量。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      from langchain.prompts import PromptTemplate

      #定义多变量模板
      template = PromptTemplate(
      template="请评价{product}的优缺点,包括{aspect1}和{aspect2}。",
      input_variables=["product", "aspect1", "aspect2"],
      ).partial(aspect1="电池续航",aspect2="拍照质量")

      #使用模板生成提示词
      prompt_1 = template.format(product="智能手机")

      print("提示词1:",prompt_1)
      # 提示词1: 请评价智能手机的优缺点,包括电池续航和拍照质量。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      from langchain.prompts import PromptTemplate

      #定义多变量模板
      template = (PromptTemplate
      .from_template(template="请评价{product}的优缺点,包括{aspect1}和{aspect2}。")
      .partial(aspect1="电池续航",aspect2="拍照质量"))

      #使用模板生成提示词
      prompt_1 = template.format(product="智能手机")

      print("提示词1:",prompt_1)
      # 提示词1: 请评价智能手机的优缺点,包括电池续航和拍照质量。
  • 形式2:组合提示词(了解)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    from langchain_core.prompts import PromptTemplate

    template = (
    PromptTemplate.from_template(template = "Tell me a joke about {topic}")
    + ", make it funny"
    + "\n\nand in {language}"
    )

    prompt = template.format(topic="sports", language="spanish")
    print(prompt)
    # Tell me a joke about sports, make it funny

    # and in spanish

4.2.4 format()与invoke()

  • 只要对象是RunnableSerializable接口类型,都可以使用invoke(),替换前面使用format()的调用方式。

  • format(),返回值为字符串类型;invoke(),返回值为PromptValue类型,接着调用to_string()返回字符串。

    • 举例1:调用format()

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      from langchain.prompts import PromptTemplate

      #定义多变量模板
      template = PromptTemplate.from_template(
      template="请评价{product}的优缺点,包括{aspect1}和{aspect2}。")

      #使用模板生成提示词
      prompt_1 = template.format(product="智能手机", aspect1="电池续航", aspect2="拍照质量")

      print(prompt_1)
      # 请评价智能手机的优缺点,包括电池续航和拍照质量。
      print(type(prompt_1))
      # <class 'str'>
    • 举例2:调用invoke(),推荐

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      from langchain.prompts import PromptTemplate

      #定义多变量模板
      template = PromptTemplate.from_template(
      template="请评价{product}的优缺点,包括{aspect1}和{aspect2}。")

      #使用模板生成提示词
      # prompt_1 = template.format(product="智能手机", aspect1="电池续航", aspect2="拍照质量")
      prompt_1 = template.invoke(input={"product":"智能手机","aspect1":"电池续航","aspect2":"拍照质量"})

      print(prompt_1)
      # text='请评价智能手机的优缺点,包括电池续航和拍照质量。'
      print(type(prompt_1)) #返回值类型:PromptValue
      # <class 'langchain_core.prompt_values.StringPromptValue'>

4.2.5 结合LLM调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from langchain_openai import ChatOpenAI
import os
import dotenv

#加载配置文件
dotenv.load_dotenv()


os.environ["OPENAI_BASE_URL"] = os.getenv("OPENAI_BASE_URL")
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY1")


# 获取对话模型:
chat_model = ChatOpenAI(
model="gpt-4o-mini",
max_tokens=500
)


# 生成提示词模板
template = PromptTemplate.from_template(
template="请评价{product}的优缺点,包括{aspect1}和{aspect2}。")

# 给模板的变量赋值
prompt = template.invoke(input={"product":"智能手机","aspect1":"电池续航","aspect2":"拍照质量"})

# 调用大模型,将提示词传入
response= chat_model.invoke(prompt)
print(response)
print(type(response))
# <class 'langchain_core.messages.ai.AIMessage'>

4.3 具体使用:ChatPromptTemplate

4.3.1 使用说明

  • ChatPromptTemplate是创建聊天消息列表的提示模板。它比普通 PromptTemplate 更适合处理多角色、多轮次的对话场景。
  • 特点
    • 支持 System/Human/AI 等不同角色的消息模板
    • 对话历史维护
  • 参数类型:列表参数格式是tuple类型(role:str content:str 组合最常用)
    • 元组的格式为:(role: str | type, content: str | list[dict] | list[object]),其中 role 是:字符串(如 "system""human""ai"

4.3.2 两种实例化方式

  • 方式1:使用构造方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

    # 创建实例
    chat_prompt_template = ChatPromptTemplate(
    messages=[
    ("system", "你是一个AI助手,你的名字叫{name}"),
    ("human", "我的问题是{question}")
    ],
    input_variables=["name", "question"],
    )

    response = chat_prompt_template.invoke(input={"name": "小智", "question": "1 + 2 * 3 = ?"})
    print(response)
    # messages=[SystemMessage(content='你是一个AI助手,你的名字叫小智', additional_kwargs={}, response_metadata={}), HumanMessage(content='我的问题是1 + 2 * 3 = ?', additional_kwargs={}, response_metadata={})]
    print(type(response))
    # <class 'langchain_core.prompt_values.ChatPromptValue'>
    print(len(response.messages))
    # 2
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 更简洁的方式
    from langchain_core.prompts import ChatPromptTemplate

    # 创建实例
    chat_prompt_template = ChatPromptTemplate([
    ("system", "你是一个AI助手,你的名字叫{name}"),
    ("human", "我的问题是{question}")
    ])

    response = chat_prompt_template.invoke({"name": "小智", "question": "1 + 2 * 3 = ?"})
    print(response)
    print(type(response)) #<class 'langchain_core.prompt_values.ChatPromptValue'>
    print(len(response.messages))
  • 方式2:调用from_messages()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    from langchain_core.prompts import ChatPromptTemplate

    # 创建实例
    # chat_prompt_template = ChatPromptTemplate([
    # ("system","你是一个AI助手,你的名字叫{name}"),
    # ("human","我的问题是{question}")
    # ])

    chat_prompt_template = ChatPromptTemplate.from_messages([
    ("system", "你是一个AI助手,你的名字叫{name}"),
    ("human", "我的问题是{question}")
    ])

    response = chat_prompt_template.invoke({"name": "小智", "question": "1 + 2 * 3 = ?"})
    print(response)
    print(type(response)) #<class 'langchain_core.prompt_values.ChatPromptValue'>
    print(len(response.messages))

4.3.3 模板调用的几种方式

  • 对比:format()invoke()format_messages()format_prompt()

    • invoke:传入的是字典,返回ChatPromptValue

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      from langchain_core.prompts import ChatPromptTemplate

      # 创建实例

      chat_prompt_template = ChatPromptTemplate.from_messages([
      ("system", "你是一个AI助手,你的名字叫{name}"),
      ("human", "我的问题是{question}")
      ])

      response = chat_prompt_template.invoke({"name": "小智", "question": "1 + 2 * 3 = ?"})
      print(response)
      print(type(response)) #<class 'langchain_core.prompt_values.ChatPromptValue'>
    • format():传入变量的值,返回str

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      from langchain_core.prompts import ChatPromptTemplate

      # 创建实例

      chat_prompt_template = ChatPromptTemplate.from_messages([
      ("system", "你是一个AI助手,你的名字叫{name}"),
      ("human", "我的问题是{question}")
      ])

      response = chat_prompt_template.format(name="小智", question="1 + 2 * 3 = ?")
      print(response)
      # System: 你是一个AI助手,你的名字叫小智
      # Human: 我的问题是1 + 2 * 3 = ?
      print(type(response))
      # <class 'str'>
    • format_messages():传入变量的值,返回消息构成的list

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      from langchain_core.prompts import ChatPromptTemplate

      # 创建实例

      chat_prompt_template = ChatPromptTemplate.from_messages([
      ("system", "你是一个AI助手,你的名字叫{name}"),
      ("human", "我的问题是{question}")
      ])

      response = chat_prompt_template.format_messages(name="小智", question="1 + 2 * 3 = ?")
      print(response)
      # [SystemMessage(content='你是一个AI助手,你的名字叫小智', additional_kwargs={}, response_metadata={}), HumanMessage(content='我的问题是1 + 2 * 3 = ?', additional_kwargs={}, response_metadata={})]
      print(type(response)) #from langchain_core.prompts import ChatPromptTemplate
      # <class 'list'>
    • format_prompt():传入变量的值,返回ChatPromptValue

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      from langchain_core.prompts import ChatPromptTemplate

      # 创建实例

      chat_prompt_template = ChatPromptTemplate.from_messages([
      ("system", "你是一个AI助手,你的名字叫{name}"),
      ("human", "我的问题是{question}")
      ])

      response = chat_prompt_template.format_prompt(name="小智", question="1 + 2 * 3 = ?")
      print(response)
      # messages=[SystemMessage(content='你是一个AI助手,你的名字叫小智', additional_kwargs={}, response_metadata={}), HumanMessage(content='我的问题是1 + 2 * 3 = ?', additional_kwargs={}, response_metadata={})]
      print(type(response))
      #<class 'langchain_core.prompt_values.ChatPromptValue'>
  • 如何实现ChatPromptValue与list[messages]、字符串之间的转换

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    from langchain_core.prompts import ChatPromptTemplate

    # 创建实例

    chat_prompt_template = ChatPromptTemplate.from_messages([
    ("system", "你是一个AI助手,你的名字叫{name}"),
    ("human", "我的问题是{question}")
    ])

    # response = chat_prompt_template.format_prompt(name="小智", question="1 + 2 * 3 = ?")
    response = chat_prompt_template.invoke({"name": "小智", "question": "1 + 2 * 3 = ?"})

    # 将ChatPromptValue类型转换为消息构成的list
    response_messages = response.to_messages()
    print(response_messages)
    # [SystemMessage(content='你是一个AI助手,你的名字叫小智', additional_kwargs={}, response_metadata={}), HumanMessage(content='我的问题是1 + 2 * 3 = ?', additional_kwargs={}, response_metadata={})]
    print(type(response_messages))
    # <class 'list'>

    # 将ChatPromptValue类型转换为字符串类型
    response_to_string = response.to_string()
    print(response_to_string)
    # System: 你是一个AI助手,你的名字叫小智
    # Human: 我的问题是1 + 2 * 3 = ?
    print(type(response_to_string))
    # <class 'str'>

4.3.4 更丰富的实例化参数类型

  • 本质:不管使用构造方法、还是使用from_message()来创建ChatPromptTemplate的实例,本质上来讲,传入的都是消息构成的列表。

  • 从调用上来讲,我们看到,不管使用构造方法,还是使用from_message(),messages参数的类型都是列表,但是列表的元素的类型是多样的。元素可以是:字符串类型、字典类型、消息类型、元组构成的列表(最常用、最基础、最简单)、Chat提示词模板类型、消息提示词模板类型。

    • 举例1:元组构成的列表(最常用、最基础、最简单)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      from langchain_core.prompts import ChatPromptTemplate

      # 创建实例
      #第1种方式
      chat_prompt_template1 = ChatPromptTemplate(
      messages=[
      ("system", "你是一个AI助手,你的名字叫{name}"),
      ("human", "我的问题是{question}")
      ]
      )
      #第2种方式
      chat_prompt_template2 = ChatPromptTemplate.from_messages([
      ("system", "你是一个AI助手,你的名字叫{name}"),
      ("human", "我的问题是{question}")
      ])

      response = chat_prompt_template1.invoke({"name": "小智", "question": "1 + 2 * 3 = ?"})
      print(response)
      # messages=[SystemMessage(content='你是一个AI助手,你的名字叫小智', additional_kwargs={}, response_metadata={}), HumanMessage(content='我的问题是1 + 2 * 3 = ?', additional_kwargs={}, response_metadata={})]
    • 举例2:字符串

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      from langchain_core.prompts import ChatPromptTemplate

      # 创建实例
      chat_prompt_template = ChatPromptTemplate.from_messages([
      "我的问题是{question}" #默认的角色是:human !
      ])

      response = chat_prompt_template.invoke({"question": "1 + 2 * 3 = ?"})
      print(response)
      # messages=[HumanMessage(content='我的问题是1 + 2 * 3 = ?', additional_kwargs={}, response_metadata={})]
    • 举例3:字典类型

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      from langchain_core.prompts import ChatPromptTemplate

      # 创建实例
      chat_prompt_template = ChatPromptTemplate.from_messages([
      {"role": "system", "content": "我是一个人工智能助手,我的名字叫{name}"},
      {"role": "human", "content": "我的问题是{question}"},
      ])

      #
      response = chat_prompt_template.invoke({"name": "小智", "question": "1 + 2 * 3 = ?"})
      print(response)
      # messages=[SystemMessage(content='我是一个人工智能助手,我的名字叫小智', additional_kwargs={}, response_metadata={}), HumanMessage(content='我的问题是1 + 2 * 3 = ?', additional_kwargs={}, response_metadata={})]
    • 举例4:消息类型,不支持变量

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      from langchain_core.messages import SystemMessage, HumanMessage
      from langchain_core.prompts import ChatPromptTemplate

      # 创建实例
      chat_prompt_template = ChatPromptTemplate.from_messages([
      SystemMessage(content="我是一个人工智能助手,我的名字叫{name}"),
      HumanMessage(content="我的问题是{question}")
      ])

      # response = chat_prompt_template.invoke({"name":"小智", "question":"1 + 2 * 3 = ?"})
      response = chat_prompt_template.invoke({})
      print(response)
      # messages=[SystemMessage(content='我是一个人工智能助手,我的名字叫{name}', additional_kwargs={}, response_metadata={}), HumanMessage(content='我的问题是{question}', additional_kwargs={}, response_metadata={})]
    • 举例5:Chat提示词模板类型

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      from langchain_core.prompts import ChatPromptTemplate

      # 使用 BaseChatPromptTemplate(嵌套的 ChatPromptTemplate)
      nested_prompt_template1 = ChatPromptTemplate.from_messages([
      ("system", "我是一个人工智能助手,我的名字叫{name}")
      ])
      nested_prompt_template2 = ChatPromptTemplate.from_messages([
      ("human", "很高兴认识你,我的问题是{question}")
      ])

      prompt_template = ChatPromptTemplate.from_messages([
      nested_prompt_template1,
      nested_prompt_template2
      ])

      prompt_template.format_messages(name="小智", question="你为什么这么帅?")
      # [SystemMessage(content='我是一个人工智能助手,我的名字叫小智', additional_kwargs={}, response_metadata={}),
      # HumanMessage(content='很高兴认识你,我的问题是你为什么这么帅?', additional_kwargs={}, response_metadata={})]
    • 举例6:消息提示词模板类型。LangChain提供不同类型的MessagePromptTemplate。最常用的是SystemMessagePromptTemplateHumanMessagePromptTemplateAIMessagePromptTemplate,分别创建系统消息、人工消息和AI消息,它们是ChatMessagePromptTemplate的特定角色子类。

      • HumanMessagePromptTemplate,专用于生成用户消息(HumanMessage)的模板类,是 ChatMessagePromptTemplate的特定角色子类。

        • 本质:预定义了 role="human" 的 ChatMessagePromptTemplate 快捷方式,且无需无需手动指定角色
        • 模板化:支持使用变量占位符,可以在运行时填充具体值
        • 格式化:能够将模板与输入变量结合生成最终的聊天消息
        • 输出类型:生成 HumanMessage 对象(content + role="human"
        • 设计目的 :简化用户输入消息的模板化构造,避免重复定义角色
      • SystemMessagePromptTemplate、AIMessagePromptTemplate:类似于上面,不再赘述。

      • ChatMessagePromptTemplate,用于构建聊天消息的模板。它允许你创建可重用的消息模板,这些模板可以动态地插入变量值来生成最终的聊天消息。

        • 角色指定:可以为每条消息指定角色(如 “system”、”human”、”ai”) 等,角色灵活。
        • 模板化:支持使用变量占位符,可以在运行时填充具体值
        • 格式化:能够将模板与输入变量结合生成最终的聊天消息
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      # 导入聊天消息类模板
      from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate, SystemMessagePromptTemplate

      # 创建消息模板
      system_template = "你是一个专家{role}"
      system_message_prompt = SystemMessagePromptTemplate.from_template(system_template)

      human_template = "给我解释{concept},用浅显易懂的语言"
      human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)

      # 组合成聊天提示模板
      chat_prompt = ChatPromptTemplate.from_messages([
      system_message_prompt, human_message_prompt
      ])

      # 格式化提示
      formatted_messages = chat_prompt.format_messages(
      role="物理学家",
      concept="相对论"
      )
      print(formatted_messages)
      # [SystemMessage(content='你是一个专家物理学家', additional_kwargs={}, response_metadata={}), HumanMessage(content='给我解释相对论,用浅显易懂的语言', additional_kwargs={}, response_metadata={})]

4.3.5 结合LLM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 1、提供大模型
from langchain_openai import ChatOpenAI
import os
import dotenv

#加载配置文件
dotenv.load_dotenv()

os.environ["OPENAI_BASE_URL"] = os.getenv("OPENAI_BASE_URL")
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY1")

# 获取对话模型:
chat_model = ChatOpenAI(
model="gpt-4o-mini"
)

# 2、通过Chat提示词模板,创建提示词
from langchain_core.prompts import ChatPromptTemplate

# 创建实例
chat_prompt_template = ChatPromptTemplate.from_messages([
("system", "你是一个AI助手,你的名字叫{name}"),
("human", "我的问题是{question}")
])

prompt_response = chat_prompt_template.invoke({"name": "小智", "question": "1 + 2 * 3 = ?"})
print(prompt_response)
# messages=[SystemMessage(content='你是一个AI助手,你的名字叫小智', additional_kwargs={}, response_metadata={}), HumanMessage(content='我的问题是1 + 2 * 3 = ?', additional_kwargs={}, response_metadata={})]
print(type(prompt_response))
# <class 'langchain_core.prompt_values.ChatPromptValue'>

# 3、通过大模型调用提示词,得到响应数据
response = chat_model.invoke(prompt_response)
print(response)

4.3.6 插入消息列表:MessagesPlaceholder

  • 当你不确定消息提示模板使用什么角色,或者希望在格式化过程中插入消息列表时,该怎么办? 这就需要使用 MessagesPlaceholder,负责在特定位置添加消息列表。

  • 使用场景:多轮对话系统存储历史消息以及Agent的中间步骤处理此功能非常有用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.prompts.chat import MessagesPlaceholder

    chat_prompt_template = ChatPromptTemplate.from_messages([
    ("system", "你是一个AI助手,你的名字叫{name}"),
    MessagesPlaceholder(variable_name="msgs")
    ])

    chat_prompt_template.invoke({
    "name": "小智",
    "msgs": [HumanMessage(content="我的问题是:1 + 2 * 3 = ?")]
    })
    # ChatPromptValue(messages=[SystemMessage(content='你是一个AI助手,你的名字叫小智', additional_kwargs={}, response_metadata={}), HumanMessage(content='我的问题是:1 + 2 * 3 = ?', additional_kwargs={}, response_metadata={})])
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from langchain_core.messages import AIMessage
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.prompts.chat import MessagesPlaceholder

    chat_prompt_template = ChatPromptTemplate.from_messages([
    ("system", "你是一个AI助手,你的名字叫{name}"),
    MessagesPlaceholder(variable_name="msgs")
    ])

    chat_prompt_template.invoke({
    "name": "小智",
    "msgs": [HumanMessage(content="我的问题是:1 + 2 * 3 = ?"),AIMessage(content="1 + 2 * 3 = 7")]
    })
    # ChatPromptValue(messages=[SystemMessage(content='你是一个AI助手,你的名字叫小智', additional_kwargs={}, response_metadata={}), HumanMessage(content='我的问题是:1 + 2 * 3 = ?', additional_kwargs={}, response_metadata={}), AIMessage(content='1 + 2 * 3 = 7', additional_kwargs={}, response_metadata={})])
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42

    from langchain_openai import ChatOpenAI
    import os
    import dotenv

    #加载配置文件
    dotenv.load_dotenv()

    os.environ["OPENAI_BASE_URL"] = os.getenv("OPENAI_BASE_URL")
    os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY1")

    from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
    from langchain_core.messages import AIMessage

    prompt = ChatPromptTemplate.from_messages(
    [
    ("system", "You are a helpful assistant."),
    MessagesPlaceholder("history"),
    ("human", "{question}")
    ]
    )

    prompt_value = prompt.format_messages(
    history=[HumanMessage(content="1+2*3 = ?"),AIMessage(content="1+2*3=7")],
    question="我刚才问题是什么?")
    # prompt.invoke(
    # {
    # "history": [("human", "what's 5 + 2"), ("ai", "5 + 2 is 7")],
    # "question": "now multiply that by 4"
    # }
    # )

    print(prompt_value)
    # [SystemMessage(content='You are a helpful assistant.', additional_kwargs={}, response_metadata={}), HumanMessage(content='1+2*3 = ?', additional_kwargs={}, response_metadata={}), AIMessage(content='1+2*3=7', additional_kwargs={}, response_metadata={}), HumanMessage(content='我刚才问题是什么?', additional_kwargs={}, response_metadata={})]

    # 获取对话模型:
    chat_model = ChatOpenAI(
    model="gpt-4o-mini"
    )

    chat_model.invoke(prompt_value)
    # AIMessage(content='你刚才的问题是“1+2*3 = ?”。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 45, 'total_tokens': 60, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_efad92c60b', 'id': 'chatcmpl-CPjAUJOxXZnANPPbxUW9WJkdv5i01', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--2c4b7ad9-4097-44c6-9cb9-91fa2c5da253-0', usage_metadata={'input_tokens': 45, 'output_tokens': 15, 'total_tokens': 60, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})

4.4 具体使用:少量样本示例的提示词模板

4.4.1 使用说明

  • 在构建prompt时,可以通过构建一个少量示例列表去进一步格式化prompt,这是一种简单但强大的指导生成的方式,在某些情况下可以显著提高模型性能

  • 每个示例的结构都是一个字典,其中是输入变量,是输入变量的值。

  • 基于LLM模型与聊天模型,可分别使用FewShotPromptTemplateFewShotChatMessagePromptTemplate,两者使用基本一致。

  • 少量示例提示模板可以由一组示例或一个负责从定义的集合中选择一部分示例的示例选择器构建。

    • 前者:使用FewShotPromptTemplateFewShotChatMessagePromptTemplate
    • 后者:使用Example selectors(示例选择器)
  • zeroshot会导致低质量回答

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    import os
    import dotenv
    from langchain_core.prompts import FewShotPromptTemplate
    from langchain_openai import ChatOpenAI

    dotenv.load_dotenv()

    os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY1")
    os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")

    chat_model = ChatOpenAI(model="gpt-4o-mini",
    temperature=0.4)

    res = chat_model.invoke("2 🦜 9是多少?")
    print(res.content)
    # 2 🦜 9 的意思可能不太明确。如果你是在问 2 和 9 的数学运算,比如加法、减法、乘法或除法,请告诉我具体的运算方式。如果是其他意思,请提供更多的上下文。

4.4.2 FewShotPromptTemplate的使用

  • 举例1:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    from langchain_core.prompts import PromptTemplate
    from langchain_core.prompts import FewShotPromptTemplate

    # 创建PromptTemplate的实例
    example_prompt = PromptTemplate.from_template(
    template="input:{input}\noutput:{output}",
    )

    # 提供一些示例
    examples = [
    {"input": "北京天气怎么样", "output": "北京市"},
    {"input": "南京下雨吗", "output": "南京市"},
    {"input": "武汉热吗", "output": "武汉市"}
    ]

    # 创建FewShotPromptTemplate的实例
    few_shot_template = FewShotPromptTemplate(
    example_prompt=example_prompt,
    examples = examples,
    suffix="input:{input}\noutput:", #声明在示例后面的提示词模板
    input_variables=["input"],
    )

    few_shot_template.invoke({"input":"天津会下雨吗?"})
    # StringPromptValue(text='input:北京天气怎么样\noutput:北京市\n\ninput:南京下雨吗\noutput:南京市\n\ninput:武汉热吗\noutput:武汉市\n\ninput:天津会下雨吗?\noutput:')
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import os
    import dotenv
    from langchain_openai import ChatOpenAI

    dotenv.load_dotenv()

    os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY1")
    os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")

    chat_model = ChatOpenAI(model="gpt-4o-mini")

    chat_model.invoke(few_shot_template.invoke({"input":"天津会下雨吗?"}))
    # AIMessage(content='天津市', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 3, 'prompt_tokens': 50, 'total_tokens': 53, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_efad92c60b', 'id': 'chatcmpl-CPkJ4Xdx0D3wJdZuano5Tn0g1s744', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--c7323657-b770-4d3a-bb8e-03fd2b7184e2-0', usage_metadata={'input_tokens': 50, 'output_tokens': 3, 'total_tokens': 53, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})
  • 举例2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    #1、创建提示模板
    from langchain.prompts import PromptTemplate

    # 创建提示模板,配置一个提示模板,将一个示例格式化为字符串
    prompt_template = "你是一个数学专家,算式: {input} 值: {output} 使用: {description} "

    # 这是一个提示模板,用于设置每个示例的格式
    prompt_sample = PromptTemplate.from_template(prompt_template)

    #2、提供示例
    examples = [
    {"input": "2+2", "output": "4", "description": "加法运算"},
    {"input": "5-2", "output": "3", "description": "减法运算"},
    ]


    #3、创建一个FewShotPromptTemplate对象
    from langchain.prompts.few_shot import FewShotPromptTemplate


    prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=prompt_sample,
    suffix="你是一个数学专家,算式: {input} 值: {output}",
    input_variables=["input", "output"]
    )
    # print(prompt.invoke({"input":"2*5", "output":"10"}))

    #4、初始化大模型,然后调用
    import os
    import dotenv
    from langchain_openai import ChatOpenAI

    dotenv.load_dotenv()

    os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY1")
    os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")

    chat_model = ChatOpenAI(model="gpt-4o-mini")

    result = chat_model.invoke(prompt.invoke({"input":"2*5", "output":"10"}))
    print(result)
    # content='你是一个数学专家,算式: 2*5 值: 10 使用: 乘法运算 \n\n如果你需要更多数学运算的示例或解释,请告诉我!' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 43, 'prompt_tokens': 77, 'total_tokens': 120, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_efad92c60b', 'id': 'chatcmpl-CPkU6KokZtBqpmnZPftzVGt6hZfN4', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--cbf09b52-46d1-40b6-ac9d-6a929f4fe219-0' usage_metadata={'input_tokens': 77, 'output_tokens': 43, 'total_tokens': 120, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}

4.4.3 FewShotChatMessagePromptTemplate的使用

  • 除了FewShotPromptTemplate之外,FewShotChatMessagePromptTemplate是专门为聊天对话场景设计的少样本(few-shot)提示模板,它继承自 FewShotPromptTemplate,但针对聊天消息的格式进行了优化。

  • 特点

    • 自动将示例格式化为聊天消息(HumanMessage/AIMessage 等)

    • 输出结构化聊天消息(List[BaseMessage]

    • 保留对话轮次结构

  • 举例1:实例化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    from langchain.prompts import (
    FewShotChatMessagePromptTemplate,
    ChatPromptTemplate
    )

    # 1.示例消息格式
    examples = [
    {"input": "1+1等于几?", "output": "1+1等于2"},
    {"input": "法国的首都是?", "output": "巴黎"}
    ]

    # 2.定义示例的消息格式提示词模版
    msg_example_prompt = ChatPromptTemplate.from_messages([
    ("human", "{input}"),
    ("ai", "{output}"),
    ])

    # 3.定义FewShotChatMessagePromptTemplate对象
    few_shot_prompt = FewShotChatMessagePromptTemplate(
    example_prompt=msg_example_prompt,
    examples=examples
    )
    # 4.输出格式化后的消息
    print(few_shot_prompt.format())
    # Human: 1+1等于几?
    # AI: 1+1等于2
    # Human: 法国的首都是?
    # AI: 巴黎
  • 举例2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    # 1.导入相关包
    from langchain_core.prompts import (FewShotChatMessagePromptTemplate, ChatPromptTemplate)

    # 2.定义示例组
    examples = [
    {"input": "2🦜2", "output": "4"},
    {"input": "2🦜3", "output": "6"},
    ]

    # 3.定义示例的消息格式提示词模版
    example_prompt = ChatPromptTemplate.from_messages([
    ('human', '{input} 是多少?'),
    ('ai', '{output}')
    ])

    # 4.定义FewShotChatMessagePromptTemplate对象
    few_shot_prompt = FewShotChatMessagePromptTemplate(
    examples=examples, # 示例组
    example_prompt=example_prompt, # 示例提示词词模版
    )
    # 5.输出完整提示词的消息模版
    final_prompt = ChatPromptTemplate.from_messages(
    [
    ('system', '你是一个数学奇才'),
    few_shot_prompt,
    ('human', '{input}'),
    ]
    )

    #6.提供大模型
    import os
    import dotenv
    from langchain_openai import ChatOpenAI

    dotenv.load_dotenv()

    os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY1")
    os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")

    chat_model = ChatOpenAI(model="gpt-4o-mini",
    temperature=0.4)

    chat_model.invoke(final_prompt.invoke(input="2🦜4")).content
    # '8'

4.4.4 Example selectors(示例选择器)

  • 前面FewShotPromptTemplate的特点是,无论输入什么问题,都会包含全部示例。在实际开发中,我 们可以根据当前输入,使用示例选择器,从大量候选示例中选取最相关的示例子集。

  • 使用的好处:避免盲目传递所有示例,减少 token 消耗的同时,还可以提升输出效果。

  • 示例选择策略:语义相似选择、长度选择、最大边际相关示例选择等。

    • 语义相似选择:通过余弦相似度等度量方式评估语义相关性,选择与输入问题最相似的k个示例。
    • 长度选择:根据输入文本的长度,从候选示例中筛选出长度最匹配的示例。增强模型对文本结构的理解。比语义相似度计算更轻量,适合对响应速度要求高的场景。
    • 最大边际相关示例选择:优先选择与输入问题语义相似的示例;同时,通过惩罚机制避免返回同质化的内容。

    余弦相似度是通过计算两个向量的夹角余弦值来衡量它们的相似性。它的值范围在-1到1之间:当两个向量方向相同时值1;夹角为90°时值为0;方向完全相反时为-1。

    数学表达式:余弦相似度=(A•B)/(||A|| * ||B||)。其中A•B是点积,||A||和||B||是向量的模(长度)。

  • 举例1:

    1
    pip install chromadb
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    # 1.导入相关包
    from langchain_community.vectorstores import Chroma
    from langchain_core.example_selectors import SemanticSimilarityExampleSelector
    import os
    import dotenv
    from langchain_openai import OpenAIEmbeddings

    dotenv.load_dotenv()

    # 2.定义嵌入模型
    os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY1")
    os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")

    embeddings_model = OpenAIEmbeddings(
    model="text-embedding-ada-002"
    )

    # 3.定义示例组
    examples = [
    {
    "question": "谁活得更久,穆罕默德·阿里还是艾伦·图灵?",
    "answer": """
    接下来还需要问什么问题吗?
    追问:穆罕默德·阿里去世时多大年纪?
    中间答案:穆罕默德·阿里去世时享年74岁。
    """,
    },
    {
    "question": "craigslist的创始人是什么时候出生的?",
    "answer": """
    接下来还需要问什么问题吗?
    追问:谁是craigslist的创始人?
    中级答案:Craigslist是由克雷格·纽马克创立的。
    """,
    },
    {
    "question": "谁是乔治·华盛顿的外祖父?",
    "answer": """
    接下来还需要问什么问题吗?
    追问:谁是乔治·华盛顿的母亲?
    中间答案:乔治·华盛顿的母亲是玛丽·鲍尔·华盛顿。
    """,
    },
    {
    "question": "《大白鲨》和《皇家赌场》的导演都来自同一个国家吗?",
    "answer": """
    接下来还需要问什么问题吗?
    追问:《大白鲨》的导演是谁?
    中级答案:《大白鲨》的导演是史蒂文·斯皮尔伯格。
    """,
    },
    ]

    # 4.定义示例选择器
    example_selector = SemanticSimilarityExampleSelector.from_examples(
    # 这是可供选择的示例列表
    examples,
    # 这是用于生成嵌入的嵌入类,用于衡量语义相似性
    embeddings_model,
    # 这是用于存储嵌入并进行相似性搜索的 VectorStore 类
    Chroma,
    # 这是要生成的示例数量
    k=1,
    )

    # 选择与输入最相似的示例
    question = "玛丽·鲍尔·华盛顿的父亲是谁?"
    selected_examples = example_selector.select_examples({"question": question})
    print(f"与输入最相似的示例:{selected_examples}")
    # 与输入最相似的示例:[{'question': '谁是乔治·华盛顿的外祖父?', 'answer': '\n 接下来还需要问什么问题吗?\n 追问:谁是乔治·华盛顿的母亲?\n 中间答案:乔治·华盛顿的母亲是玛丽·鲍尔·华盛顿。\n '}]

    # for example in selected_examples:
    # print("\n")
    # for k, v in example.items():
    # print(f"{k}: {v}")
  • 举例2:结合 FewShotPromptTemplate使用,这里使用FAISS,需安装:

    1
    pip install faiss-cpu
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    # 1.导入相关包
    from langchain_community.vectorstores import FAISS
    from langchain_core.example_selectors import SemanticSimilarityExampleSelector
    from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
    from langchain_openai import OpenAIEmbeddings

    # 2.定义示例提示词模版
    example_prompt = PromptTemplate.from_template(
    template="Input: {input}\nOutput: {output}",
    )

    # 3.创建一个示例提示词模版
    examples = [
    {"input": "高兴", "output": "悲伤"},
    {"input": "高", "output": "矮"},
    {"input": "长", "output": "短"},
    {"input": "精力充沛", "output": "无精打采"},
    {"input": "阳光", "output": "阴暗"},
    {"input": "粗糙", "output": "光滑"},
    {"input": "干燥", "output": "潮湿"},
    {"input": "富裕", "output": "贫穷"},
    ]

    # 4.定义嵌入模型
    embeddings = OpenAIEmbeddings(
    model="text-embedding-ada-002"
    )

    # 5.创建语义相似性示例选择器
    example_selector = SemanticSimilarityExampleSelector.from_examples(
    examples,
    embeddings,
    FAISS,
    k=2,
    )
    #或者
    #example_selector = SemanticSimilarityExampleSelector(
    # examples,
    # embeddings,
    # FAISS,
    # k=2
    #)

    # 6.定义小样本提示词模版
    similar_prompt = FewShotPromptTemplate(
    example_selector=example_selector,
    example_prompt=example_prompt,
    prefix="给出每个词组的反义词",
    suffix="Input: {word}\nOutput:",
    input_variables=["word"],
    )

    response = similar_prompt.invoke({"word":"忧郁"})
    print(response.text)
    # 给出每个词组的反义词
    #
    # Input: 高兴
    # Output: 悲伤
    #
    # Input: 阳光
    # Output: 阴暗
    #
    # Input: 忧郁
    # Output:

4.5 具体使用:PipelinePromptTemplate(了解)

  • 用于将多个提示模板按顺序组合成处理管道,实现分阶段、模块化的提示构建。它的核心作用类似于软件开发中的管道模式 (Pipeline Pattern),通过串联多个提示处理步骤,实现复杂的提示生成逻辑。

  • 特点

    • 将复杂提示拆解为多个处理阶段,每个阶段使用独立的提示模板
    • 前一个模板的输出作为下一个模板的输入变量
    • 使用场景:解决单一超大提示模板难以维护的问题
  • 说明:PipelinePromptTemplate在langchain 0.3.22版本中被标记为过时,在 langchain-core==1.0 之前不会删除它。https://python.langchain.com/api_reference/core/prompts/langchain_core.prompts.pipeline.PipelinePromptTemplate.html

  • 举例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    from langchain_core.prompts.pipeline import PipelinePromptTemplate
    from langchain_core.prompts.prompt import PromptTemplate


    # 阶段1:问题分析
    analysis_template = PromptTemplate.from_template("""
    分析这个问题:{question}
    关键要素:
    """)

    # 阶段2:知识检索
    retrieval_template = PromptTemplate.from_template("""
    基于以下要素搜索资料:
    {analysis_result}
    搜索关键词:
    """)

    # 阶段3:生成最终回答
    answer_template = PromptTemplate.from_template("""
    综合以下信息回答问题:
    {retrieval_result}
    最终答案:
    """)

    # 构建管道
    pipeline = PipelinePromptTemplate(
    final_prompt=answer_template,
    pipeline_prompts=[
    ("analysis_result", analysis_template),
    ("retrieval_result", retrieval_template)
    ]
    )

    print(pipeline.format(question="量子计算的优势是什么?"))

    上述代码执行时,提示PipelinePromptTemplate已过时,代码更新如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    from langchain_core.prompts.prompt import PromptTemplate

    # 阶段1:问题分析
    analysis_template = PromptTemplate.from_template("""
    分析这个问题:{question}
    关键要素:
    """)

    # 阶段2:知识检索
    retrieval_template = PromptTemplate.from_template("""
    基于以下要素搜索资料:
    {analysis_result}
    搜索关键词:
    """)

    # 阶段3:生成最终回答
    answer_template = PromptTemplate.from_template("""
    综合以下信息回答问题:
    {retrieval_result}
    最终答案:
    """)

    # 逐步执行管道提示
    pipeline_prompts = [
    ("analysis_result", analysis_template),
    ("retrieval_result", retrieval_template)
    ]


    my_input = {"question": "量子计算的优势是什么?"}

    # print(pipeline_prompts)

    # [('analysis_result', PromptTemplate(input_variables=['question'], input_types={}, partial_variables={}, template='\n分析这个问题:{question}\n关键要素:\n')), ('retrieval_result', PromptTemplate(input_variables=['analysis_result'], input_types={}, partial_variables={}, template='\n基于以下要素搜索资料:\n{analysis_result}\n搜索关键词:\n'))]

    for name, prompt in pipeline_prompts:
    # 调用当前提示模板并获取字符串结果
    result = prompt.invoke(my_input).to_string()
    # 将结果添加到输入字典中供下一步使用
    my_input[name] = result

    # 生成最终答案
    my_output = answer_template.invoke(my_input).to_string()
    print(my_output)

4.6 具体使用:自定义提示词模版(了解)

  • 在创建prompt时,我们也可以按照自己的需求去创建自定义的提示模版。

  • 步骤

    • 自定义类继承提示词基类模版BasePromptTemplate

    • 重写format、format_prompt、from_template方法

  • 举例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    # 1.导入相关包
    from typing import List, Dict, Any
    from langchain.prompts import BasePromptTemplate
    from langchain.prompts import PromptTemplate
    from langchain.schema import PromptValue

    # 2.自定义提示词模版
    class SimpleCustomPrompt(BasePromptTemplate):
    """简单自定义提示词模板"""
    template: str

    def __init__(self, template: str, **kwargs):
    # 使用PromptTemplate解析输入变量
    prompt = PromptTemplate.from_template(template)

    super().__init__(
    input_variables=prompt.input_variables,
    template=template,
    **kwargs
    )

    def format(self, **kwargs: Any) -> str:
    """格式化提示词"""
    # print("kwargs:", kwargs)
    # print("self.template:", self.template)

    return self.template.format(**kwargs)

    def format_prompt(self, **kwargs: Any) -> PromptValue:
    """实现抽象方法"""
    return PromptValue(text=self.format(**kwargs))

    @classmethod
    def from_template(cls, template: str, **kwargs) -> "SimpleCustomPrompt":
    """从模板创建实例"""
    return cls(template=template, **kwargs)

    # 3.使用自定义提示词模版
    custom_prompt = SimpleCustomPrompt.from_template(
    template="请回答关于{subject}的问题:{question}"
    )

    # 4.格式化提示词
    formatted = custom_prompt.format(
    subject="人工智能",
    question="什么是LLM?"
    )

    print(formatted)

4.7 从文档中加载Prompt(了解)

  • 一方面,将想要设定prompt所支持的格式保存为JSON或者YAML格式文件。

  • 另一方面,通过读取指定路径的格式化文件,获取相应的prompt。

  • 目的与使用场景:

    • 为了便于共享、存储和加强对prompt的版本控制。

    • 当我们的prompt模板数据较大时,我们可以使用外部导入的方式进行管理和维护。

4.7.1 yaml格式提示词

  • asset下创建yaml文件:prompt.yaml

    1
    2
    3
    4
    5
    6
    _type:
    "prompt"
    input_variables:
    ["name","what"]
    template:
    "请给{name}讲一个关于{what}的故事"
  • 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    from langchain_core.prompts import load_prompt
    from dotenv import load_dotenv

    load_dotenv()

    prompt = load_prompt("asset/prompt.yaml", encoding="utf-8")
    # print(prompt)
    print(prompt.format(name="年轻人", what="滑稽"))
    # 请给年轻人讲一个关于滑稽的故事

4.7.2 json格式提示词

  • asset下创建json文件:simple_prompt.json

    1
    2
    3
    4
    5
    {
    "_type": "prompt",
    "input_variables": ["name", "what"],
    "template": "请{name}讲一个{what}的故事。"
    }
  • 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    from langchain_core.prompts import load_prompt
    from dotenv import load_dotenv

    load_dotenv()

    prompt = load_prompt("asset/simple_prompt.json",encoding="utf-8")
    print(prompt.format(name="张三",what="搞笑的"))
    # 请张三讲一个搞笑的的故事。

5、Model I/O之Output Parsers

  • 语言模型返回的内容通常都是字符串的格式(文本格式),但在实际AI应用开发过程中,往往希望model可以返回更直观、更格式化的内容,LangChain提供的输出解析器就派上用场了。
  • 输出解析器(Output Parser)负责获取 LLM 的输出并将其转换为更合适的格式。这在应用开发中及其重要

5.1 输出解析器的分类

  • LangChain有许多不同类型的输出解析器

    • StrOutputParser:字符串解析器

    • JsonOutputParser:JSON解析器,确保输出符合特定JSON对象格式

    • DatetimeOutputParser:日期时间解析器,可用于将 LLM 输出解析为日期时间格式

    • CommaSeparatedListOutputParser:CSV解析器,模型的输出以逗号分隔,以列表形式返回输出

    • XMLOutputParser:XML解析器,允许以流行的XML格式从LLM获取结果

  • 除了上述常用的输出解析器之外,还有:

    • EnumOutputParser:枚举解析器,将LLM的输出,解析为预定义的枚举值

    • StructuredOutputParser:将非结构化文本转换为预定义格式的结构化数据(如字典)

    • OutputFixingParser:输出修复解析器,用于自动修复格式错误的解析器,比如将返回的不符合预期格式的输出,尝试修正为正确的结构化数据(如 JSON)

    • PydanticOutputParser:将输出自动解析为 Pydantic 模型实例的组件

    • RetryOutputParser:重试解析器,当主解析器(如 PydanticOutputParser 或 JSONOutputParser)因格式错误无法解析 LLM 的输出时,通过调用另一个 LLM 自动修正错误,并重新尝试解析

5.2 具体解析器的使用

5.2.1 字符串解析器StrOutputParser

  • StrOutputParser 简单地将任何输入转换为字符串。它是一个简单的解析器,从结果中提取content字段

  • 举例:将一个对话模型的输出结果,解析为字符串输出

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    # 1、获取大模型
    from langchain_core.messages import HumanMessage, SystemMessage
    from langchain_core.output_parsers import StrOutputParser, XMLOutputParser

    import os
    import dotenv
    from langchain_core.utils import pre_init
    from langchain_openai import ChatOpenAI

    dotenv.load_dotenv()

    os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY1")
    os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")

    chat_model = ChatOpenAI(model="gpt-4o-mini")

    # 2、调用大模型
    response = chat_model.invoke("什么是大语言模型?")
    # print(type(response)) #AIMessage

    #3、如何获取一个字符串的输出结果呢?
    # 方式1:自己调用输出结果的content
    # print(response.content)

    # 方式2:使用StrOutputParser
    parser = StrOutputParser()
    str_response = parser.invoke(response)
    print(type(str_response)) #<class 'str'>
    print(str_response)

5.2.2 JSON解析器JsonOutputParser

  • JSON Output Parser,即JSON 解析器,是一种用于将大模型的自由文本输出转换为结构化JSON数据的工具。

  • 适合场景:特别适用于需要严格结构化输出的场景,比如 API 调用、数据存储或下游任务处理。

  • 实现方式

    • 方式1:用户自己通过提示词指明返回Json格式

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      from langchain_core.output_parsers import JsonOutputParser
      from langchain_core.prompts import ChatPromptTemplate
      from langchain_openai import ChatOpenAI
      import dotenv
      import os

      dotenv.load_dotenv()

      os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY1")
      os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL")

      chat_model = ChatOpenAI(model="gpt-4o-mini")

      chat_prompt_template = ChatPromptTemplate.from_messages([
      ("system", "你是一个靠谱的{role}"),
      ("human", "{question}")
      ])

      # 正确的:
      prompt = chat_prompt_template.invoke(
      input={"role": "人工智能专家", "question": "人工智能用英文怎么说?问题用q表示,答案用a表示,返回一个JSON格式的数据"})

      # 错误的:
      # prompt = chat_prompt_template.invoke(input={"role":"人工智能专家","question":"人工智能用英文怎么说?"})

      response = chat_model.invoke(prompt)
      print(response.content)
      # ```json
      # {
      # "q": "人工智能用英文怎么说?",
      # "a": "Artificial Intelligence"
      # }
      # ```

      # 获取一个JsonOutputParser的实例
      parser = JsonOutputParser()

      json_result = parser.invoke(response)
      print(json_result)
      # {'q': '人工智能用英文怎么说?', 'a': 'Artificial Intelligence'}

      扩展:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      from langchain_core.output_parsers import JsonOutputParser
      from langchain_core.prompts import ChatPromptTemplate

      chat_model = ChatOpenAI(model="gpt-4o-mini")

      chat_prompt_template = ChatPromptTemplate.from_messages([
      ("system", "你是一个靠谱的{role}"),
      ("human", "{question}")
      ])

      # 获取一个JsonOutputParser的实例
      parser = JsonOutputParser()

      # 写法1:
      # prompt = chat_prompt_template.invoke(input={"role":"人工智能专家","question":"人工智能用英文怎么说?问题用q表示,答案用a表示,返回一个JSON格式的数据"})
      #
      # response = chat_model.invoke(prompt)
      #
      # json_result = parser.invoke(response)
      # print(json_result)


      # 写法2:
      chain = chat_prompt_template | chat_model | parser
      json_result1 = chain.invoke(
      input={"role": "人工智能专家", "question": "人工智能用英文怎么说?问题用q表示,答案用a表示,返回一个JSON格式的数据"})
      print(json_result1)
      # {'q': '人工智能用英文怎么说?', 'a': 'Artificial Intelligence'}
    • 方式2:借助JsonOutputParser的get_format_instructions(),生成格式说明,指导模型输出JSON结构。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      # 引入依赖包
      from langchain_core.output_parsers import JsonOutputParser
      from langchain_core.prompts import PromptTemplate

      # 初始化语言模型
      chat_model = ChatOpenAI(model="gpt-4o-mini")

      joke_query = "告诉我一个笑话。"

      # 定义Json解析器
      parser = JsonOutputParser()
      print(parser.get_format_instructions())
      # Return a JSON object.

      #以PromptTemplate为例
      prompt_template = PromptTemplate.from_template(
      template="回答用户的查询\n 满足的格式为{format_instructions}\n 问题为{question}\n",
      partial_variables={"format_instructions": parser.get_format_instructions()},
      )

      prompt = prompt_template.invoke(input={"question": joke_query})
      response = chat_model.invoke(prompt)
      print(response.content)
      # ```json
      # {
      # "joke": "为什么计算机很冷?因为它们总是把窗口打开!"
      # }
      # ```

      json_result = parser.invoke(response)
      print(json_result)
      # {'joke': '为什么计算机很冷?因为它们总是把窗口打开!'}

      扩展:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      # 引入依赖包
      from langchain_core.output_parsers import JsonOutputParser
      from langchain_core.prompts import PromptTemplate

      # 初始化语言模型
      chat_model = ChatOpenAI(model="gpt-4o-mini")

      joke_query = "告诉我一个笑话。"

      # 定义Json解析器
      parser = JsonOutputParser()

      #以PromptTemplate为例
      prompt_template = PromptTemplate.from_template(
      template="回答用户的查询\n 满足的格式为{format_instructions}\n 问题为{question}\n",
      partial_variables={"format_instructions": parser.get_format_instructions()},
      )
      # 写法1:
      # prompt = prompt_template.invoke(input={"question":joke_query})
      # response = chat_model.invoke(prompt)
      # json_result = parser.invoke(response)

      chain = prompt_template | chat_model | parser
      json_result = chain.invoke(input={"question": joke_query})
      print(json_result)

5.2.3 XML解析器XMLOutputParser

  • XMLOutputParser,将模型的自由文本输出转换为可编程处理的XML数据。

  • 如何实现:在PromptTemplate中指定XML格式要求,让模型返回 <tag>content</tag> 形式的数据。

  • 注意:XMLOutputParser 不会直接将模型的输出保持为原始XML字符串,而是会解析XML并转换成Python字典(或类似结构化的数据)。目的是为了方便程序后续处理数据,而不是单纯保留XML格式。

    • 举例1:不使用XMLOutputParser,通过大模型的能力,返回xml格式数据。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      chat_model = ChatOpenAI(model="gpt-4o-mini")

      actor_query = "周星驰的简短电影记录"
      response = chat_model.invoke(f"请生成{actor_query},将影片附在<movie></movie>标签中")

      print(type(response))
      # <class 'langchain_core.messages.ai.AIMessage'>
      print(response.content)
      # <movie>
      # <title>大话西游之月光宝盒</title>
      # <year>1995</year>
      # <description>这是一部融合了喜剧、爱情和奇幻元素的经典电影,讲述了至尊宝和紫霞仙子的爱情故事,打破了传统的西游记情节,成为华语电影的经典之作。</description>
      # </movie>
    • 举例2:体会XMLOutputParser的格式以及使用。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      # 1.导入相关包
      from langchain_core.output_parsers import XMLOutputParser
      from langchain_core.prompts import PromptTemplate
      from langchain_openai import ChatOpenAI

      # 2. 初始化语言模型
      chat_model = ChatOpenAI(model="gpt-4o-mini")

      # 3.测试模型的xml解析效果
      actor_query = "生成汤姆·汉克斯的简短电影记录,使用中文回复"

      # 4.定义XMLOutputParser对象
      parser = XMLOutputParser()
      print(parser.get_format_instructions())
      # The output should be formatted as a XML file.
      # 1. Output should conform to the tags below.
      # 2. If tags are not given, make them on your own.
      # 3. Remember to always open and close all the tags.
      #
      # As an example, for the tags ["foo", "bar", "baz"]:
      # 1. String "<foo>
      # <bar>
      # <baz></baz>
      # </bar>
      # </foo>" is a well-formatted instance of the schema.
      # 2. String "<foo>
      # <bar>
      # </foo>" is a badly-formatted instance.
      # 3. String "<foo>
      # <tag>
      # </tag>
      # </foo>" is a badly-formatted instance.
      #
      # Here are the output tags:
      # ```
      # None
      # ```

      # 5. 生成提示词模板
      prompt_template1 = PromptTemplate.from_template(
      template="用户的问题:{query}\n使用的格式:{format_instructions}"
      )

      prompt_template2 = prompt_template1.partial(format_instructions=parser.get_format_instructions())

      response = chat_model.invoke(prompt_template2.invoke(input={"query": actor_query}))
      print(response.content)
      # ```xml
      # <电影记录>
      # <演员>
      # <名字>汤姆·汉克斯</名字>
      # <出生年份>1956</出生年份>
      # <代表作品>
      # <作品>《阿甘正传》</作品>
      # <作品>《拯救大兵瑞恩》</作品>
      # <作品>《失而复得》</作品>
      # <作品>《外星人E.T.》</作品>
      # <作品>《费城故事》</作品>
      # </代表作品>
      # <获奖经历>
      # <奖项>奥斯卡金像奖</奖项>
      # <奖项>金球奖</奖项>
      # <奖项>BAFTA奖</奖项>
      # </获奖经历>
      # </演员>
      # </电影记录>
      # ```

      xml_result = parser.invoke(response)
      print(xml_result)
      # {'电影记录': [{'演员': [{'名字': '汤姆·汉克斯'}, {'出生年份': '1956'}, {'代表作品': [{'作品': '《阿甘正传》'}, {'作品': '《拯救大兵瑞恩》'}, {'作品': '《失而复得》'}, {'作品': '《外星人E.T.》'}, {'作品': '《费城故事》'}]}, {'获奖经历': [{'奖项': '奥斯卡金像奖'}, {'奖项': '金球奖'}, {'奖项': 'BAFTA奖'}]}]}]}

5.2.4 列表解析器CommaSeparatedListOutputParser

  • 列表解析器:利用此解析器可以将模型的文本响应转换为一个用逗号分隔的列表(List[str])

    • 举例1:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      from langchain_core.output_parsers import CommaSeparatedListOutputParser

      output_parser = CommaSeparatedListOutputParser()

      # 返回一些指令或模板,这些指令告诉系统如何解析或格式化输出数据
      format_instructions = output_parser.get_format_instructions()
      print(format_instructions)
      # Your response should be a list of comma separated values, eg: `foo, bar, baz` or `foo,bar,baz`

      messages = "大象,猩猩,狮子"
      result = output_parser.parse(messages)
      print(result)
      # ['大象', '猩猩', '狮子']
      print(type(result))
      # <class 'list'>
    • 举例2:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      from langchain_core.prompts import PromptTemplate
      from langchain_openai import ChatOpenAI
      from langchain.output_parsers import CommaSeparatedListOutputParser

      # 初始化语言模型
      chat_model = ChatOpenAI(model="gpt-4o-mini")

      # 创建解析器
      output_parser = CommaSeparatedListOutputParser()

      # 创建LangChain提示模板
      chat_prompt = PromptTemplate.from_template(
      "生成5个关于{text}的列表.\n\n{format_instructions}",
      partial_variables={
      "format_instructions": output_parser.get_format_instructions()
      })

      # 提示模板与输出解析器传递输出
      # chat_prompt = chat_prompt.partial(format_instructions=output_parser.get_format_instructions())

      # 将提示和模型合并以进行调用
      chain = chat_prompt | chat_model | output_parser
      res = chain.invoke({"text": "电影"})
      print(res)
      # ['1. 动作片', '科幻片', '恐怖片', '喜剧片', '爱情片 ', '2. 经典电影', '现代电影', '外国电影', '动画电影', '纪录片 ', '3. 导演', '编剧', '主演', '配角', '制片人 ', '4. 票房收入', '影评评分', '观众评分', '参赛奖项', '影展获奖 ', '5. 电影类型', '放映时间', '电影时长', '电影评分', '观看方式 ']
      print(type(res))
      # <class 'list'>

5.2.5 日期解析器DatetimeOutputParser(了解)

  • 利用此解析器可以直接将LLM输出解析为日期时间格式。

    • **get_format_instructions()**: 获取日期解析的格式化指令,指令为:”Write a datetime string that matches the following pattern: ‘%Y-%m-%dT%H:%M:%S.%fZ’。举例:1206-08-16T17:39:06.176399Z
  • 举例1:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from langchain.output_parsers import DatetimeOutputParser

    output_parser = DatetimeOutputParser()

    format_instructions = output_parser.get_format_instructions()
    print(format_instructions)
    # Write a datetime string that matches the following pattern: '%Y-%m-%dT%H:%M:%S.%fZ'.
    #
    # Examples: 1853-04-07T06:45:24.945854Z, 0835-04-16T12:35:51.978680Z, 1877-10-31T12:04:45.397316Z
    #
    # Return ONLY this string, no other words!
  • 举例2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    from langchain_openai import ChatOpenAI
    from langchain.prompts.chat import HumanMessagePromptTemplate
    from langchain_core.prompts import ChatPromptTemplate
    from langchain.output_parsers import DatetimeOutputParser

    chat_model = ChatOpenAI(model="gpt-4o-mini")


    chat_prompt = ChatPromptTemplate.from_messages([
    ("system","{format_instructions}"),
    ("human", "{request}")
    ])

    output_parser = DatetimeOutputParser()

    # 方式1:
    # model_request = chat_prompt.format_messages(
    # request="中华人民共和国是什么时候成立的",
    # format_instructions=output_parser.get_format_instructions()
    # )

    # response = chat_model.invoke(model_request)
    # result = output_parser.invoke(response)
    # print(result)
    # print(type(result))

    # 方式2:
    chain = chat_prompt | chat_model | output_parser
    resp = chain.invoke({"request":"中华人民共和国是什么时候成立的",
    "format_instructions":output_parser.get_format_instructions()})
    print(resp)
    # 1949-10-01 00:00:00
    print(type(resp))
    # <class 'datetime.datetime'>