当前位置:   article > 正文

LangChain 入门上篇:模型 I/O 封装_langchain prompt 封装

langchain prompt 封装

LangChain 是面向大模型的开发框架,是 AGI 时代软件工程的探索和原型。学习 LangChain 需要关注接口的变更。

LangChain 的核心组件

1.模型 I/O 封装

  • LLMS 大语言模型
  • Chat Models 一套基于 LLMS,但按对话结构重新封装
  • PromptTemplate 提示词模板
  • OutputParser 解析输出

2.数据连接封装

  • Document Loaders 各种格式文件的加载器
  • Document Transformers 对文档的常用操作,如 split, filter,translate,extract, metadata, etc
  • Text Embedding Models 文本向量化表示,用于检索等操作
  • Verctorstores 向量存储
  • Retrievers 向量检索

3.记忆封装

  • Memory 这里不是物理内存,从文本的角度可以理解为“上文”,“历史记录”或者说“记忆”的管理

4.架构封装

  • Chain 实现一个功能或者一系列顺序功能组合
  • Agent 根据用户输入,自动规划执行不搜,自动选择每个步骤需要的工具,最终完成用户指定的功能
  • Tools 调用外部功能的函数,例如:调用 google 搜索,文件I/O,Linux Shell 等等。
  • Toolkits 操作某软件的一组工具集, 例如:操作 DB, 操作 Gmail 等等

5.Callbacks

准备工作

依赖包安装

!pip install --upgrade langchain
!pip install --upgrade langchain-openai

设置环境变量

  1. os.environ["OPENAI_API_KEY"] = "sk-xxxxx"
  2. os.environ["OPENAI_BASE_URL"] = "https://your.proxy.address/v1"

模型 I/O 封装

OpenAI 模型封装

  1. from langchain_openai import ChatOpenAI
  2. llm = ChatOpenAI() # 默认是gpt-3.5-turbo
  3. response = llm.invoke("你是谁")
  4. print(response.content)

输出:

我是一个人工智能助手,可以回答你的问题和提供帮助。有什么可以帮助你的吗?

多轮对话 Session 封装

  1. from langchain.schema import (
  2. AIMessage, # 等价于OpenAI接口中的assistant role
  3. HumanMessage, # 等价于OpenAI接口中的user role
  4. SystemMessage # 等价于OpenAI接口中的system role
  5. )
  6. messages = [
  7. SystemMessage(content="你是文档编写小能手。"),
  8. HumanMessage(content="我是学生,我叫 Gem"),
  9. AIMessage(content="欢迎!"),
  10. HumanMessage(content="我是谁")
  11. ]
  12. ret = llm.invoke(messages)
  13. print(ret.content)

输出:

您是Gem,一个学生。您有什么问题需要帮助吗?

换国产大模型

安装依赖包

pip install qianfan

  1. # 其它模型分装在 langchain_community 底包中
  2. from langchain_community.chat_models import QianfanChatEndpoint
  3. from langchain_core.messages import HumanMessage
  4. import os
  5. llm = QianfanChatEndpoint(
  6. qianfan_ak=os.getenv('ERNIE_CLIENT_ID'), # 需要到百度智能云平台 https://cloud.baidu.com/ 开通应用
  7. qianfan_sk=os.getenv('ERNIE_CLIENT_SECRET')
  8. )
  9. messages = [
  10. HumanMessage(content="你是谁")
  11. ]
  12. ret = llm.invoke(messages)
  13. print(ret.content)

输出:

你好,我是一名文本生成的人工智能模型,我没有具体的身份和实体形态。我可以回答问题和提供信息,帮助你解决问题。有什么我可以帮助你的吗?

模型的输入输出

Prompt 模板封装

1. promptTemplate 可以在模板中自定义变量

  1. from langchain.prompts import PromptTemplate
  2. template = PromptTemplate.from_template("给我讲个关于{subject}的笑话")
  3. print("===Template===")
  4. print(template)
  5. print("===Prompt===")
  6. print(template.format(subject='小明'))
===Template===
input_variables=['subject'] template='给我讲个关于{subject}的笑话'
===Prompt===
给我讲个关于小明的笑话

2.ChatPromptTemplate 用模板表示的对话上下文

  1. from langchain.prompts import (
  2. ChatPromptTemplate,
  3. HumanMessagePromptTemplate,
  4. SystemMessagePromptTemplate,
  5. )
  6. from langchain_openai import ChatOpenAI
  7. template = ChatPromptTemplate.from_messages(
  8. [
  9. SystemMessagePromptTemplate.from_template(
  10. "你是{product}助手。你的名字叫{name}"),
  11. HumanMessagePromptTemplate.from_template("{query}"),
  12. ]
  13. )
  14. llm = ChatOpenAI()
  15. prompt = template.format_messages(
  16. product="中式美食专家",
  17. name="瓜瓜",
  18. query="你是谁"
  19. )
  20. ret = llm.invoke(prompt)
  21. print(ret.content)

输出:

我是一个人工智能助手,可以回答您关于中式美食的问题。如果您有任何疑问或需要帮助,请随时告诉我哦!

3.MessagesPlaceholder 把多轮对话变成模板

  1. from langchain.prompts import ChatPromptTemplate, HumanMessagePromptTemplate, MessagesPlaceholder
  2. human_prompt = "Translate your answer to {language}."
  3. human_message_template = HumanMessagePromptTemplate.from_template(human_prompt)
  4. chat_prompt = ChatPromptTemplate.from_messages(
  5. [
  6. # conversation 是 message placeholder 中的变量名用于在赋值时使用
  7. MessagesPlaceholder(variable_name="conversation"),
  8. human_message_template
  9. ]
  10. )
  1. from langchain_core.messages import AIMessage, HumanMessage
  2. human_message = HumanMessage(content="who is Elon Musk?")
  3. ai_message = AIMessage(
  4. content="Elon Musk is a billionaire entrepreneur, inventor, and industrial designer"
  5. )
  6. messages = chat_prompt.format_prompt(
  7. conversation=[human_message, ai_message],
  8. language="韩语"
  9. )
  1. result = llm.invoke(messages)
  2. print(result.content)

输出:

Elon Musk는 억만장자 기업가, 발명가 및 산업 디자이너입니다.

重点:可以把 Prompt 模板看做带有参数的函数,可类比为 SK 的 Semantic Function

4. Prompt 模板也可以直接从文件加载

  1. from langchain.prompts import PromptTemplate
  2. template = PromptTemplate.from_file("example_prompt_template.txt") # 文件内容:举一个关于{topic}的例子
  3. print("===Template===")
  4. print(template)
  5. print("===Prompt===")
  6. print(template.format(topic='黑色幽默'))

输出:

===Template===
input_variables=['topic'] template='举一个关于{topic}的例子'
===Prompt===
举一个关于黑色幽默的例子
输出封装 OutputParser

自动把 LLM 输出的字符串按指定格式加载。

LangChain 内置的 OutputParser 包括:

  • ListParser
  • DatetimeParser
  • EnumParser
  • JsonOutputParser
  • PydanticParser
  • XMLParser

等等

Pydantic (JSON) Parser

可以根据 Pydantic 类的定义生成输出的格式说明

  1. from langchain_core.pydantic_v1 import BaseModel, Field, validator
  2. from typing import List, Dict
  3. # 定义你的输出对象
  4. class Date(BaseModel):
  5. year: int = Field(description="Year")
  6. month: int = Field(description="Month")
  7. day: int = Field(description="Day")
  8. era: str = Field(description="BC or AD")
  9. # ----- 可选机制 --------
  10. # 你可以添加自定义的校验机制
  11. @validator('month')
  12. def valid_month(cls, field):
  13. if field <= 0 or field > 12:
  14. raise ValueError("月份必须在1-12之间")
  15. return field
  16. @validator('day')
  17. def valid_day(cls, field):
  18. if field <= 0 or field > 31:
  19. raise ValueError("日期必须在1-31日之间")
  20. return field
  21. @validator('day', pre=True, always=True)
  22. def valid_date(cls, day, values):
  23. year = values.get('year')
  24. month = values.get('month')
  25. # 确保年份和月份都已经提供
  26. if year is None or month is None:
  27. return day # 无法验证日期,因为没有年份和月份
  28. # 检查日期是否有效
  29. if month == 2:
  30. if cls.is_leap_year(year) and day > 29:
  31. raise ValueError("闰年2月最多有29天")
  32. elif not cls.is_leap_year(year) and day > 28:
  33. raise ValueError("非闰年2月最多有28天")
  34. elif month in [4, 6, 9, 11] and day > 30:
  35. raise ValueError(f"{month}月最多有30天")
  36. return day
  37. @staticmethod
  38. def is_leap_year(year):
  39. if year % 400 == 0 or (year % 4 == 0 and year % 100 != 0):
  40. return True
  41. return False
  1. from langchain.prompts import PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate
  2. from langchain_openai import ChatOpenAI
  3. from langchain_core.output_parsers import PydanticOutputParser
  4. model_name = 'gpt-3.5-turbo'
  5. temperature = 0
  6. model = ChatOpenAI(model_name=model_name, temperature=temperature)
  7. # 根据Pydantic对象的定义,构造一个OutputParser
  8. parser = PydanticOutputParser(pydantic_object=Date)
  9. template = """提取用户输入中的日期。
  10. {format_instructions}
  11. 用户输入:
  12. {query}"""
  13. prompt = PromptTemplate(
  14. template=template,
  15. input_variables=["query"],
  16. # 直接从OutputParser中获取输出描述,并对模板的变量预先赋值
  17. partial_variables={"format_instructions": parser.get_format_instructions()}
  18. )
  19. print("====Format Instruction=====")
  20. print(parser.get_format_instructions())
  21. query = "2023年四月6日天气晴..."
  22. model_input = prompt.format_prompt(query=query)
  23. print("====Prompt=====")
  24. print(model_input.to_string())
  25. output = model.invoke(model_input.to_messages())
  26. print("====模型原始输出=====")
  27. print(output.content)
  28. print("====Parse后的输出=====")
  29. date = parser.parse(output.content)
  30. print(date.dict())

输出:

====Format Instruction=====
The output should be formatted as a JSON instance that conforms to the JSON schema below.

As an example, for the schema {"properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}
the object {"foo": ["bar", "baz"]} is a well-formatted instance of the schema. The object {"properties": {"foo": ["bar", "baz"]}} is not well-formatted.

Here is the output schema:
```
{"properties": {"year": {"title": "Year", "description": "Year", "type": "integer"}, "month": {"title": "Month", "description": "Month", "type": "integer"}, "day": {"title": "Day", "description": "Day", "type": "integer"}, "era": {"title": "Era", "description": "BC or AD", "type": "string"}}, "required": ["year", "month", "day", "era"]}
```
====Prompt=====
提取用户输入中的日期。
The output should be formatted as a JSON instance that conforms to the JSON schema below.

As an example, for the schema {"properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}
the object {"foo": ["bar", "baz"]} is a well-formatted instance of the schema. The object {"properties": {"foo": ["bar", "baz"]}} is not well-formatted.

Here is the output schema:
```
{"properties": {"year": {"title": "Year", "description": "Year", "type": "integer"}, "month": {"title": "Month", "description": "Month", "type": "integer"}, "day": {"title": "Day", "description": "Day", "type": "integer"}, "era": {"title": "Era", "description": "BC or AD", "type": "string"}}, "required": ["year", "month", "day", "era"]}
```
用户输入:
2023年四月6日天气晴...
====模型原始输出=====
{
  "year": 2023,
  "month": 4,
  "day": 6,
  "era": "AD"
}
====Parse后的输出=====
{'year': 2023, 'month': 4, 'day': 6, 'era': 'AD'}
Auto-Fixing Parser

利用 LLM 自动根据解析异常重新解析修复

  1. from langchain.output_parsers import OutputFixingParser
  2. new_parser = OutputFixingParser.from_llm(
  3. parser=parser, llm=ChatOpenAI(model="gpt-3.5-turbo")
  4. )
  5. # 将前面的 output 格式改错
  6. output = output.content.replace("4", "四月")
  7. print("===格式错误的Output===")
  8. print(output)
  9. try:
  10. date = parser.parse(output)
  11. except Exception as e:
  12. print("===出现异常===")
  13. print(e)
  14. # 用 OutputFixingParser 自动修复并解析
  15. date = new_parser.parse(output)
  16. print("===重新解析结果===")
  17. print(date.json())

输出:

===格式错误的Output===
{
  "year": 2023,
  "month": 四月,
  "day": 6,
  "era": "AD"
}
===出现异常===
Invalid json output: {
  "year": 2023,
  "month": 四月,
  "day": 6,
  "era": "AD"
}
===重新解析结果===
{"year": 2023, "month": 4, "day": 6, "era": "AD"}

小结:

  1. LangChain 统一封装了各种模型的调用接口,包括补全型和对话型两种
  2. LangChain 提供了 PromptTemplate 类,可以自定义带变量的模板
  3. LangChain 提供了一些列输出解析器,用于将大模型的输出解析成结构化对象;额外带有自动修复功能。
  4. 上述模型属于 LangChain 中较为优秀的部分;美中不足的是 OutputParser 自身的 Prompt 维护在代码中,耦合度较高。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/991487
推荐阅读
相关标签
  

闽ICP备14008679号