大模型学习笔记四:LangChain开发框架解析

文章目录

    • 一、langChain核心组件介绍
    • 二、模块I/O封装
      • 1)多轮对话 Session 封装
      • 2)模型的输入
        • (1)Prompt模板封装
        • (2)从文件加载Prompt模板
      • 3)模型的输出
        • (1)Pydantic (JSON) Parser
        • (2)Auto-Fixing Parser
    • 三、数据连接封装
      • 1)文档加载器
      • 2)文档处理器
      • 3)内置RAG实现
      • 4)小结
      • 5)补充说明embedding
    • 四、记忆封装
      • 1)对话上下文ConversationBufferMemory
      • 2)只保留一个窗口的上下文ConversationBufferWindowMemory
      • 3)通过Token数控制上下文长度ConversationTokenBufferMemory
      • 4)总结

  • langChain的定义
    面向大模型的开发框架

一、langChain核心组件介绍

1、模型I/O封装

  • LLMs:大语言模型
  • Chat Models:一般基于LLMs,但按对话结构重新封装
  • PromptTemple:提示词模板
  • OutputParser:解析输出
    2、数据连接封装
  • Document Loaders:各种格式文件的加载器
  • Document transformers:对文档的常用操作,如:split,filter,translate,extract metadata,etc
  • Textr Embedding Models:文本向量化表示,用于检索等操作
  • Vertor strores:(面向检索的)向量的存储
  • Retrievers:向量的检索
    3、记忆封装
  • Memory:这里不是物理内存,从文本角度可以理解为上下文
    4、架构封装
  • Chain:实现一个和功能或者一些顺序功能组合
  • Agent:根据用户据输入,自动挂画执行步骤,自动选择每步需要的工具,最终完成用户指定的功能
    – Tools:调用外部功能的函数,例如:调用google搜索篇,文件I/O、LInux Shell等等
    – Toolskits:操作某软件的一组工具及,例如:操作DB、操作Gmail等等
    5、Callbacks
    在这里插入图片描述

二、模块I/O封装

  • 安装
#安装最新版本
!pip install langchain==0.1.0
!pip install langchain-openai # v0.1.0新增的底包
  • 简单模型OpenAI 模型封装交互
from langchain_openai import ChatOpenAIllm = ChatOpenAI(model="gpt-4") # 默认是gpt-3.5-turbo
response = llm.invoke("你是谁")
print(response.content)

答复:
我是OpenAI的人工智能助手。我被设计出来是为了帮助解答问题、提供信息和帮助用户完成各种任务。

1)多轮对话 Session 封装

  • 举例一
from langchain.schema import (AIMessage, #等价于OpenAI接口中的assistant roleHumanMessage, #等价于OpenAI接口中的user roleSystemMessage #等价于OpenAI接口中的system role
)messages = [SystemMessage(content="你是AGIClass的课程助理。"), HumanMessage(content="我是学员,我叫王卓然。"), AIMessage(content="欢迎!"),HumanMessage(content="我是谁") 
]
llm.invoke(messages) 

答复:
AIMessage(content=‘您是学员王卓然。’)

  • 举例二
# 其它模型分装在 langchain_community 底包中
from langchain_community.chat_models import ErnieBotChat
from langchain.schema import HumanMessageernie = ErnieBotChat()messages = [HumanMessage(content="你是谁") 
]ernie.invoke(messages)

答复:
AIMessage(content=‘您好,我是百度研发的知识增强大语言模型,中文名是文心一言,英文名是ERNIE Bot。我能够与人对话互动,回答问题,协助创作,高效便捷地帮助人们获取信息、知识和灵感。\n\n如果您有任何问题,请随时告诉我。’)

2)模型的输入

(1)Prompt模板封装

①主题格式化封装

from langchain.prompts import PromptTemplatetemplate = PromptTemplate.from_template("给我讲个关于{subject}的笑话")
print(template)
print(template.format(subject='小明'))

答复:
input_variables=[‘subject’] template=‘给我讲个关于{subject}的笑话’
给我讲个关于小明的笑话

②更加复杂的主题应用

from langchain.prompts import ChatPromptTemplate
from langchain.prompts.chat import SystemMessagePromptTemplate, HumanMessagePromptTemplate
from langchain.chat_models import ChatOpenAItemplate = ChatPromptTemplate.from_messages([SystemMessagePromptTemplate.from_template("你是{product}的客服助手。你的名字叫{name}"),HumanMessagePromptTemplate.from_template("{query}"),]
)llm = ChatOpenAI()
prompt = template.format_messages(product="AGI课堂",name="瓜瓜",query="你是谁")llm.invoke(prompt)

AIMessage(content=‘我是AGI课堂的客服助手,名字叫瓜瓜。我可以回答关于AGI课堂的问题,提供帮助和支持。有什么我可以帮助你的吗?’)

(2)从文件加载Prompt模板

①Yaml格式

 _type: prompt
input_variables:["adjective", "content"]
template: Tell me a {adjective} joke about {content}.

②json个数

{"_type": "prompt","input_variables": ["adjective", "content"],"template": "Tell me a {adjective} joke about {content}."
}
  • 加载配置代码
from langchain.prompts import load_promptprompt = load_prompt("simple_prompt.yaml")# OR 
# prompt = load_prompt("simple_prompt.json")print(prompt.format(adjective="funny", content="Xiao Ming"))

回复:
Tell me a funny joke about Xiao Ming.

3)模型的输出

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

LangChain 内置的 OutputParser 包括:

  • ListParser
  • DatetimeParser
  • EnumParser
  • PydanticParser
  • XMLParser
(1)Pydantic (JSON) Parser
  • 根据Pydantic类定义的需求类
from langchain_core.pydantic_v1  import BaseModel, Field, validator
from typing import List, Dict# 定义你的输出对象
class Date(BaseModel):year: int = Field(description="Year")month: int = Field(description="Month")day: int = Field(description="Day")era: str = Field(description="BC or AD")# ----- 可选机制 --------# 你可以添加自定义的校验机制@validator('month')def valid_month(cls, field):if field <= 0 or field > 12:raise ValueError("月份必须在1-12之间")return field@validator('day')def valid_day(cls, field):if field <= 0 or field > 31:raise ValueError("日期必须在1-31日之间")return field@validator('day', pre=True, always=True)def valid_date(cls, day, values):year = values.get('year')month = values.get('month')# 确保年份和月份都已经提供if year is None or month is None:return day  # 无法验证日期,因为没有年份和月份# 检查日期是否有效if month == 2:if cls.is_leap_year(year) and day > 29:raise ValueError("闰年2月最多有29天")elif not cls.is_leap_year(year) and day > 28:raise ValueError("非闰年2月最多有28天")elif month in [4, 6, 9, 11] and day > 30:raise ValueError(f"{month}月最多有30天")return day@staticmethoddef is_leap_year(year):if year % 400 == 0 or (year % 4 == 0 and year % 100 != 0):return Truereturn False
  • 询问python代码
from langchain.prompts import PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate
from langchain_openai import ChatOpenAIfrom langchain.output_parsers import PydanticOutputParsermodel_name = 'gpt-4'
temperature = 0
model = ChatOpenAI(model_name=model_name, temperature=temperature)# 根据Pydantic对象的定义,构造一个OutputParser
parser = PydanticOutputParser(pydantic_object=Date)template = """提取用户输入中的日期。
{format_instructions}
用户输入:
{query}"""prompt = PromptTemplate(template=template,input_variables=["query"], #每次用户询问都会变化的query# 直接从OutputParser中获取输出描述,并对模板的变量预先赋值,一开始就赋值的format_instructionspartial_variables={"format_instructions": parser.get_format_instructions()} 
)print("====Format Instruction=====")
print(parser.get_format_instructions())query = "2023年四月6日天气晴..."
model_input = prompt.format_prompt(query=query)print("====Prompt=====")
print(model_input.to_string())output = model(model_input.to_messages())
print("====模型原始输出=====")
print(output)
print("====Parse后的输出=====")
date = parser.parse(output.content)
print(date)

回复:
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日天气晴…
模型原始输出=
content=‘{“year”: 2023, “month”: 4, “day”: 6, “era”: “AD”}’
Parse后的输出=
year=2023 month=4 day=6 era=‘AD’

(2)Auto-Fixing Parser
  • 说明
    利用LLM自动根据解析异常修复并重新解析
  • 代码
from langchain.output_parsers import OutputFixingParsernew_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI(model="gpt-4"))#我们把之前output的格式改错
output = output.content.replace("4","四月")
print("===格式错误的Output===")
print(output)
try:date = parser.parse(output)
except Exception as e:print("===出现异常===")print(e)#用OutputFixingParser自动修复并解析
date = new_parser.parse(output)
print("===重新解析结果===")
print(date)

答复:
=格式错误的Output=
{“year”: 2023, “month”: 四月, “day”: 6, “era”: “AD”}
=出现异常=
Failed to parse Date from completion {“year”: 2023, “month”: 四月, “day”: 6, “era”: “AD”}. Got: Expecting value: line 1 column 25 (char 24)
=重新解析结果=
year=2023 month=4 day=6 era=‘AD’

三、数据连接封装

在这里插入图片描述

1)文档加载器

  • 安装
!pip install pypdf
  • 加载
from langchain.document_loaders import PyPDFLoaderloader = PyPDFLoader("llama2.pdf")
pages = loader.load_and_split()print(pages[0].page_content)

2)文档处理器

代码拆分段落

from langchain.text_splitter import RecursiveCharacterTextSplittertext_splitter = RecursiveCharacterTextSplitter(chunk_size=200,chunk_overlap=100,  # 思考:为什么要做overlaplength_function=len,add_start_index=True,
)paragraphs = text_splitter.create_documents([pages[0].page_content])
for para in paragraphs:print(para.page_content)print('-------')
  • 注意
    LangChain 的 PDFLoader 和 TextSplitter 实现都比较粗糙,实际生产中不建议使用。

3)内置RAG实现

  • 安装
!pip install chromadb
  • 代码实现
from langchain.document_loaders import UnstructuredMarkdownLoader
from langchain_openai import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.document_loaders import PyPDFLoader# 加载文档
loader = PyPDFLoader("llama2.pdf")
pages = loader.load_and_split()# 文档切分
text_splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=100,length_function=len,add_start_index=True,
)texts = text_splitter.create_documents([pages[2].page_content,pages[3].page_content])# 灌库
embeddings = OpenAIEmbeddings()
db = Chroma.from_documents(texts, embeddings)# LangChain内置的 RAG 实现
qa_chain = RetrievalQA.from_chain_type(llm=ChatOpenAI(temperature=0), retriever=db.as_retriever() 
)query = "llama 2有多少参数?"
response = qa_chain.invoke(query)
print(response["result"])

答复:
Llama 2有7B、13B和70B参数的变体。

4)小结

1、这部分能力 LangChain 的实现非常粗糙;
2、实际生产中,建议自己实现,不建议用 LangChain 的工具。

5)补充说明embedding

  • 定义:
    需要一种方法,有效计算词与词之间的关系
  • 方法
    词与词之间做方向的计算
    在这里插入图片描述
  • 总结
    句子、篇章都可以向量化
    在这里插入图片描述

四、记忆封装

1)对话上下文ConversationBufferMemory

  • 代码
from langchain.memory import ConversationBufferMemory, ConversationBufferWindowMemoryhistory = ConversationBufferMemory()
history.save_context({"input": "你好啊"}, {"output": "你也好啊"})print(history.load_memory_variables({}))history.save_context({"input": "你再好啊"}, {"output": "你又好啊"})print(history.load_memory_variables({}))

回复:
{‘history’: ‘Human: 你好啊\nAI: 你也好啊’}
{‘history’: ‘Human: 你好啊\nAI: 你也好啊\nHuman: 你再好啊\nAI: 你又好啊’}

2)只保留一个窗口的上下文ConversationBufferWindowMemory

  • 代码
from langchain.memory import ConversationBufferWindowMemorywindow = ConversationBufferWindowMemory(k=1)
window.save_context({"input": "第一轮问"}, {"output": "第一轮答"})
window.save_context({"input": "第二轮问"}, {"output": "第二轮答"})
window.save_context({"input": "第三轮问"}, {"output": "第三轮答"})
print(window.load_memory_variables({}))

回复:
{‘history’: ‘Human: 第三轮问\nAI: 第三轮答’}

3)通过Token数控制上下文长度ConversationTokenBufferMemory

  • 代码
from langchain.memory import ConversationTokenBufferMemory
from langchain_openai import ChatOpenAImemory = ConversationTokenBufferMemory(llm=ChatOpenAI(),max_token_limit=40
)
memory.save_context({"input": "你好啊"}, {"output": "你好,我是你的AI助手。"})
memory.save_context({"input": "你会干什么"}, {"output": "我什么都会"})print(memory.load_memory_variables({}))

回复:
{‘history’: ‘Human: 你会干什么\nAI: 我什么都会’}

4)总结

1、ConversationSummaryMemory: 对上下文做摘要
https://python.langchain.com/docs/modules/memory/types/summary
2、ConversationSummaryBufferMemory: 保存 Token 数限制内的上下文,对更早的做摘要
https://python.langchain.com/docs/modules/memory/types/summary_buffer
3、VectorStoreRetrieverMemory: 将 Memory 存储在向量数据库中,根据用户输入检索回最相关的部分
https://python.langchain.com/docs/modules/memory/types/vectorstore_retriever_memory
4、LangChain 的 Memory 管理机制属于可用的部分,尤其是简单情况如按轮数或按 Token 数管理;对于复杂情况,它不一定是最优的实现,例如检索向量库方式,建议根据实际情况和效果评估;但是它对内存的各种维护方法的思路在实际生产中可以借鉴

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2812008.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

c入门第二十四篇: 学生成绩管理系统优化(可执行文件传参)

前言 我&#xff1a;“师弟&#xff0c;review完你的代码之后&#xff0c;你觉得有没有什么地方可以优化&#xff1f;” 师弟一脸懵。 我&#xff1a;“比如&#xff0c;你把客户端和服务端的可执行文件生成之后&#xff0c;我把服务端部署到我的测试机器上&#xff0c;客户端…

通过css修改video标签的原生样式

通过css修改video标签的原生样式 描述实现结果 描述 修改video标签的原生样式 实现 在控制台中打开设置&#xff0c;勾选显示用户代理 shadow DOM&#xff0c;就可以审查video标签的内部样式了 箭头处标出来的就是shodow DOM的内容&#xff0c;这些内容正常不可见的&#x…

下载huggingface数据集到本地并读取.arrow文件遇到的问题

文章目录 1. 524MB中文维基百科语料&#xff08;需要下载的数据集&#xff09;2. 下载 hugging face 网站上的数据集3. 读取 .arrow 文件报错代码4. 纠正后代码 1. 524MB中文维基百科语料&#xff08;需要下载的数据集&#xff09; 2. 下载 hugging face 网站上的数据集 要将H…

07_第七章 前端工程化(es6,Vue3,Element_plus组件库)

文章目录 第七章 前端工程化一、前端工程化开篇1.1 什么是前端工程化1.2 前端工程化实现技术栈 二、ECMA6Script2.1. es6的介绍2.2 es6的变量和模板字符串2.3 es6的解构表达式2.4 es6的箭头函数2.4.1 声明和特点2.4.2 实践和应用场景2.4.3 rest和spread 2.5 es6的对象创建和拷贝…

绝地求生:春节部分活动将结束,3月有新版本上线,通行证不偷懒可换成长型

嗨&#xff0c;我是闲游盒~ 感觉过年就在眼前但是已经结束了&#xff0c;时间过的太快了又回归了工作的生活中&#xff0c;而年前更新的28.1新春版本也进行到了小一半的进度。 ◆ 春节版本部分活动即将结束 在大厅首页右上角的活动中心里&#xff0c;春节积分商店和觉醒之旅活动…

MATLAB环境下一种改进的瞬时频率(IF)估计方法

相对于频率成分单一、周期性强的平稳信号来说&#xff0c;具有非平稳、非周期、非可积特性的非平稳信号更普遍地存在于自然界中。调频信号作为非平稳信号的一种&#xff0c;由于其频率时变、距离分辨率高、截获率低等特性&#xff0c;被广泛应用于雷达、地震勘测等领域。调频信…

sqllabs第46关 order by 注入(通过盲注)

打开第46关 提示我们(请将参数输入为sort&#xff08;带数值&#xff09;) 用sort注入排序 尝试操作 order by注入 什么是order by 在MySQL支持使用ORDER BY语句对查询结果集进行排序处理&#xff0c;使用ORDER BY语句不仅支持对单列数据的排序&#xff0c;还支持对数据表中…

vulnhub----hackme2-DHCP靶机

文章目录 一&#xff0c;信息收集1.网段探测2.端口扫描3.目录扫描 二&#xff0c;信息分析三&#xff0c;sql注入1.判断SQL注入2.查询显示位3.查询注入点4.查询库5.查询表6.查字段7. 查user表中的值8.登陆superadmin用户 四&#xff0c;漏洞利用文件上传命令执行蚁剑连接 五&am…

商家入驻平台怎么让资金自动分配给商家

最近很多上线了多商户电商系统的朋友咨询&#xff0c;我们平台的用户支付后&#xff0c;钱进入了我们的对公账户&#xff0c;怎样让钱在走完流程后&#xff0c;自动进入商家的账户呢&#xff1f;今天商淘云为您分享商户入驻平台自动分配给商家资金的三种方法。 首先是平台应建立…

k8s二进制部署的搭建

1.1 常见k8s安装部署方式 ●Minikube Minikube是一个工具&#xff0c;可以在本地快速运行一个单节点微型K8S&#xff0c;仅用于学习、预览K8S的一些特性使用。 部署地址&#xff1a;Install Tools | Kubernetes ●Kubeadm Kubeadm也是一个工具&#xff0c;提供kubeadm init…

Java根据excel模版导出Excel(easyexcel、poi)——含项目测试例子拿来即用

Java根据excel模版导出Excel&#xff08;easyexcel、poi&#xff09;——含项目测试例子拿来即用 1. 前言1.1 关于Excel的一般导出2.2 关于easyexcel的根据模版导出 2. 先看效果2.1 模版2.2 效果 3. 代码实现&#xff08;核心代码&#xff09;3.1 项目代码结构3.2 静态填充例子…

数字电路 第四章—第一节(触发器——概述)

一、对触发器的基本要求 1、触发器的概念 在数字电路中&#xff0c;基本的工作信号是二进制数字信号和两状态逻辑信号&#xff0c;而触发器就是存放这些信号的单元电路。 2、对触发器的基本要求 &#xff08;1&#xff09;具有两个稳定状态——0状态和1状态&#xff0c;以正…

负载均衡.

简介: 将请求/数据【均匀】分摊到多个操作单元上执行&#xff0c;负载均衡的关键在于【均匀】。 负载均衡的分类: 网络通信分类 四层负载均衡:基于 IP 地址和端口进行请求的转发。七层负载均衡:根据访问用户的 HTTP 请求头、URL 信息将请求转发到特定的主机。 载体维度分类 硬…

物资管理新篇章:Java+SpringBoot实战

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

List去重有几种方式

目录 1、for循环添加去重 2、for 双循环去重 3、for 双循环重复坐标去重 4、Set去重 5、stream流去重 1、for循环添加去重 List<String> oldList new ArrayList<>();oldList.add("张三");oldList.add("张三");oldList.add("李四&q…

数字电路 第三章—第七节(用中规模集成电路实现组合逻辑函数)

一、用数据选择器实现组合逻辑函数 1、基本原理和步骤 &#xff08;1&#xff09;原理&#xff1a;选择器的输出为标准与或式&#xff0c;含地址变量的全部最小项&#xff08;如下图所示的红线标注部分&#xff09;&#xff0c;而任何组合逻辑函数都可以表示成为最小项之和的…

项目管理工具git

git 1. git介绍1.1. 版本控制系统 2. 创建本地版本库2.1 概念2.2 操作步骤 3. 修改文件4. 练习: 添加一个本地项目到仓库5. 添加远程仓库5.1 添加远程仓库5.2 本地仓库同步到远程仓库5.3 克隆远程仓库到本地5.4 SSH设置 6. 分支管理6.1 创建分支6.2 切换分支6.3 合并分支6.4 解…

实践航拍小目标检测,基于轻量级YOLOv8n开发构建无人机航拍场景下的小目标检测识别分析系统

关于无人机相关的场景在我们之前的博文也有一些比较早期的实践&#xff0c;感兴趣的话可以自行移步阅读即可&#xff1a; 《deepLabV3Plus实现无人机航拍目标分割识别系统》 《基于目标检测的无人机航拍场景下小目标检测实践》 《助力环保河道水质监测&#xff0c;基于yolov…

QT之项目经验(windows下的sqlite,c++开发)

目录 一、需要时间去磨练gui的调整和优化 1. 借鉴网上开源项目学习 2. gui的布局及调整是磨人的一件事情 3. gui的布局也是可以用组件复刻的 4. 耗时的设备树 二、多线程异步弹窗 三、定时任务动态变更设定 1.确定按钮触发 2.此处监听定时任务时间的改变 3.此处对改变做出具…

[算法沉淀记录]排序算法 —— 快速排序

排序算法 —— 快速排序介绍 基本概念 快速排序&#xff08;Quicksort&#xff09;是一种排序算法&#xff0c;最早由东尼霍尔提出。在平均状况下&#xff0c;排序 n 个项目要 Ο(n log n) 次比较。在最坏状况下则需要 Ο(n2) 次比较&#xff0c;但这种状况并不常见。事实上&…