LangChain使用总结

LangChain介绍

介绍

LangChain自身并不开发LLMs,它的核心理念是为各种LLMs实现通用的接口,把LLMs相关的组件“链接”在一起,简化LLMs应用的开发难度,方便开发者快速地开发复杂的LLMs应用.

组件类型

  1. Models:模型,各种类型的模型和模型继承,比如GPT-4

  2. Prompts:提示,包括提示管理、提示优化和提示序列化

  3. Memory:记忆,用来保存和模型交互时的上下文状态

  4. Indexes:索引,用来结构化文档,以便和模型交互

  5. Chains:链,一系列对各种组件的调用

  6. Agents:代理,决定模型采取哪些行动,执行并且观察流程,直到完成为止

Models组件

LLMs

大语言模型接收文本字符作为输入,返回的也是文本字符。

from langchain_community.llms import Ollama
# from langchain.llms import Ollama
import shutup
​
shutup.please()
​
model = Ollama(model='qwen2.5:7b')
res = model('给我讲个鬼故事吧')
print(res)

Chat Models

基于LLMs, 不同的是它接收聊天消息(一种特定格式的数据)作为输入,返回的也是聊天消息。

Chat Models和LLMs效果在某些场景表现基本类似,但是使用时需要按照约定传入合适的值。

聊天模式:

from langchain_community.chat_models import ChatOllama
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
​
​
model = ChatOllama(model='qwen2.5:7b')
​
# message = [
#     SystemMessage(content='现在你是一个诗人'),
#     HumanMessage(content='给我写一首唐诗')
# ]
#
# res = model.invoke(message)
# print(res)
# print(res.content)
​
message = [
    SystemMessage(content='现在你是一个诗人'),      # 类似指定任务类型,同时可以指定返回格式
    HumanMessage(content='给我写一首唐诗'),        # 提出问题
    AIMessage(content='清风拂柳绿,江水映碧空。\n鸟鸣山更幽,心静万物融。'),    # 用于存储历史信息
    HumanMessage(content='再写一首宋词')
]
res = model.invoke(message)
print(res)
print(res.content)

Embedding Models

文本嵌入模型接收文本作为输入, 返回的是浮点数列表。

Embeddings Models特点:将字符串作为输入,返回一个浮动数的列表。在NLP中,Embedding的作用就是将数据进行文本向量化。

from langchain_community.embeddings import OllamaEmbeddings
​
​
# model = OllamaEmbeddings(model='mxbai-embed-large', temperaure=0)
model = OllamaEmbeddings(model='qwen2.5:7b', temperature=0)
res1 = model.embed_query('这是一个测试文档')
print(res1)
print(len(res1))    # qwen2.5:7b: 3584      mxbai-embed-large:1024
​
​
res2 = model.embed_documents(['这是第一个测试文档', '这是第二个测试文档'])
# print(res2)

Prompts组件

Prompt是指当用户输入信息给模型时加入的提示,这个提示的形式可以是zero-shot或者few-shot等方式,目的是让模型理解更为复杂的业务场景以便更好的解决问题。

提示模板:如果你有了一个起作用的提示,你可能想把它作为一个模板用于解决其他问题,LangChain就提供了PromptTemplates组件,它可以帮助你更方便的构建提示。

zero-shot

from langchain import PromptTemplate
from langchain_community.llms import Ollama
​
​
model = Ollama(model='qwen2.5:7b')
template = "我的邻居姓{lastname},他的妻子姓{wname},他生了个儿子,给他儿子取个名字"
prompt = PromptTemplate(
    input_variables=['lastname', 'wname'],
    template=template
)
​
prompt_text =prompt.format(lastname='杜', wname='李')
print(prompt_text)
res = model(prompt_text)
print(res)

few-shot

# from langchain import PromptTemplate, FewShotPromptTemplate
from langchain import PromptTemplate, FewShotPromptTemplate
from langchain_community.llms import Ollama
​
model = Ollama(model='qwen2.5:7b')
​
examples = [
    {'word': '开心', 'antonym': '难过'},
    {'word': '高', 'antonym': '矮'}
]
​
example_template = """
单词: {word}
反义词: {antonym}\n
"""
​
example_prompt = PromptTemplate(
    input_variables=['word', 'antonym'],
    template=example_template
)
​
few_shot_prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    prefix='给出每个单词的反义词',
    suffix='单词: {input}\n反义词:',
    input_variables=['input'],
    example_separator='\n'
)
​
prompt_tex = few_shot_prompt.format(input='粗')
print(model(prompt_tex))

Chains组件

单一链

from langchain import PromptTemplate
from langchain_community.llms import Ollama
from langchain.chains import LLMChain
​
template = "我的邻居姓{lastname},他生了个儿子,给他儿子取个名字"
​
prompt = PromptTemplate(
    input_variables=['lastname'],
    template=template
)
​
llm = Ollama(model='qwen2.5:7b')
​
# chain = LLMChain(llm=llm, prompt=prompt)
chain = prompt | llm        # 效果同上
print(chain.invoke('杜'))

多条链

from langchain import PromptTemplate
from langchain_community.llms import Ollama
from langchain.chains import LLMChain, SimpleSequentialChain
​
# 创建第一条链
first_prompt = PromptTemplate(
    input_variables=['name'],
    template="我的邻居姓{name},他生了个儿子,给他儿子取个名字"
)
​
llm = Ollama(model='qwen2.5:7b')
​
# 第一条链
# first_chain = first_prompt | llm
first_chain = LLMChain(llm=llm, prompt=first_prompt)
​
# 创建第二条链
second_prompt = PromptTemplate(
    input_variables=['child_name'],
    template="邻居的儿子叫{child_name},给他儿子取个小名"
)
​
# 第二条链
# second_chain = second_prompt | llm
second_chain = LLMChain(llm=llm, prompt=second_prompt)
​
# 组装两条链
overall_chain = SimpleSequentialChain(chains=[first_chain, second_chain], verbose=True)
​
print(overall_chain)
print('*'*80)
​
# 执行链
res = overall_chain.invoke('杜')
print(res)

Agents组件

在 LangChain 中 Agents 的作用就是根据用户的需求,来访问一些第三方工具(比如:搜索引擎或者数据库),进而来解决相关需求问题。

因为大模型虽然非常强大,但是也具备一定的局限性,比如不能回答实时信息、处理数学逻辑问题仍然非常的初级等等。因此,可以借助第三方工具来辅助大模型的应用。

from langchain.agents import load_tools, initialize_agent, AgentType
from langchain_community.llms import Ollama
from langchain_core.prompts import PromptTemplate
​
llm = Ollama(model='qwen2.5:7b')
​
tools = load_tools(['llm-math'], llm=llm)
​
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
​
prompt_template = """
解以下方程:3x + 4(x + 2) - 84 = y; 其中x为3,请问y是多少?
"""
​
prompt = PromptTemplate.from_template(prompt_template)
​
print('prompt-->', prompt)
​
res = agent.run(prompt)
print(res)
​
from langchain_community.agent_toolkits.load_tools import get_all_tool_names
​
results = get_all_tool_names()
print(results)
# ['sleep', 'wolfram-alpha', 'google-search', 'google-search-results-json', 'searx-search-results-json', 'bing-search',
#  'metaphor-search', 'ddg-search', 'google-books', 'google-lens', 'google-serper', 'google-scholar', 'google-finance',
#  'google-trends', 'google-jobs', 'google-serper-results-json', 'searchapi', 'searchapi-results-json', 'serpapi',
#  'dalle-image-generator', 'twilio', 'searx-search', 'merriam-webster', 'wikipedia', 'arxiv', 'golden-query', 'pubmed',
#  'human', 'awslambda', 'stackexchange', 'sceneXplain', 'graphql', 'openweathermap-api', 'dataforseo-api-search',
#  'dataforseo-api-search-json', 'eleven_labs_text2speech', 'google_cloud_texttospeech', 'read_file', 'reddit_search',
#  'news-api', 'tmdb-api', 'podcast-api', 'memorize', 'llm-math', 'open-meteo-api', 'requests', 'requests_get',
#  'requests_post', 'requests_patch', 'requests_put', 'requests_delete', 'terminal']

Memory组件

大模型本身不具备上下文的概念,它并不保存上次交互的内容,ChatGPT之所以能够和人正常沟通对话,因为它进行了一层封装,将历史记录回传给了模型。

因此 LangChain 也提供了Memory组件, Memory分为两种类型:短期记忆和长期记忆。

短期记忆一般指单一会话时传递数据,长期记忆则是处理多个会话时获取和更新信息。

记录

from langchain_community.chat_message_histories import ChatMessageHistory
import shutup

shutup.please()


history = ChatMessageHistory()
history.add_user_message('在吗?')
history.add_ai_message('干啥')
# print(history.messages)
# [HumanMessage(content='在吗?', additional_kwargs={}, response_metadata={}),
# AIMessage(content='干啥', additional_kwargs={}, response_metadata={})]


from langchain import ConversationChain
from langchain_community.llms import Ollama

llm = Ollama(model='qwen2.5:7b')
conv = ConversationChain(llm=llm)
res1 = conv.predict(input='小杜有1个纸片人')
print(res1)

res2 = conv.predict(input='小红有两只猫')
print(res2)

res3 = conv.predict(input='他们一共有多少物品')
print(res3)

保存

from langchain_community.chat_message_histories import ChatMessageHistory
from langchain.schema import messages_from_dict, messages_to_dict
import shutup

shutup.please()

history = ChatMessageHistory()
history.add_user_message('在吗?')
history.add_ai_message('干啥')

src_dict = messages_to_dict(history.messages)
print(src_dict)

new_dict = messages_from_dict(src_dict)
print(new_dict)

"""
[{
    'type': 'human',
    'data': {
        'content': '在吗?',
        'additional_kwargs': {},
        'response_metadata': {},
        'type': 'human',
        'name': None,
        'id': None,
        'example': False
    }
},
{
    'type': 'ai',
    'data': {
        'content': '干啥',
        'additional_kwargs': {},
        'response_metadata': {},
        'type': 'ai',
        'name': None,
        'id': None,
        'example': False,
        'tool_calls': [],
        'invalid_tool_calls': [],
        'usage_metadata': None
    }
}]
[HumanMessage(content='在吗?', additional_kwargs={}, response_metadata={}), AIMessage(content='干啥', additional_kwargs={}, response_metadata={})]
"""

Indexes组件

Indexes组件的目的是让LangChain具备处理文档处理的能力,包括:文档加载、检索等。注意,这里的文档不局限于txt、pdf等文本类内容,还涵盖email、区块链、视频等内容。

文档加载器

from langchain_community.document_loaders import TextLoader, PyPDFLoader
import shutup

shutup.please()


# loader = TextLoader('./data/衣服属性.txt', encoding='utf8')
loader = PyPDFLoader('./data/物流行业智能问答RAG系统.pdf')
docs = loader.load()

print(docs[0])
print(docs)

支持文档类型

文档分割器

由于模型对输入的字符长度有限制,我们在碰到很长的文本时,需要把文本分割成多个小的文本片段。

文本分割最简单的方式是按照字符长度进行分割,但是这会带来很多问题,比如说如果文本是一段代码,一个函数被分割到两段之后就成了没有意义的字符,所以整体的原则是把语义相关的文本片段放在一起。

from langchain.text_splitter import CharacterTextSplitter


my_spliter = CharacterTextSplitter(
    # 若分割前后包含空格,会自动将空格去除
    separator=' ',   # 分割标识,默认:\n\n
    chunk_size=5,       # 分割后每个片段的大小
    chunk_overlap=1     # 分割后两个片段的重叠部分大小
)

a = my_spliter.split_text('a b c d e f')
print(a)    # ['a b c', 'c d e', 'e f']


b = my_spliter.create_documents(['a b c d e f', 'e f g h'])
print(b)
# [Document(metadata={}, page_content='a b c'), 
# Document(metadata={}, page_content='c d e'), 
# Document(metadata={}, page_content='e f'), 
# Document(metadata={}, page_content='e f g'), 
# Document(metadata={}, page_content='g h')]

VectorStores

VectorStores是一种特殊类型的数据库,它的作用是存储由嵌入创建的向量,提供相似查询等功能。

我们使用其中一个 Chroma 组件作为例子(pip install chromadb):

from langchain_community.embeddings import OllamaEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain_community.vectorstores import Chroma


with open('./data/pku.txt', encoding='utf-8') as f:
    content = f.read()


my_spliter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)     # 虽然设置了最大切分长度,但是优先根据语义信息进行切分

texts = my_spliter.split_text(content)

print(texts)
print(len(texts))

embed = OllamaEmbeddings(model='mxbai-embed-large')

docsearch = Chroma.from_texts(texts, embed)

q = '1937年北京大学发生了什么事情?'
print(docsearch.similarity_search(q, k=1))

支持的向量数据库

检索器

检索器(retriever)是一种便于模型查询的存储数据的方式,LangChain约定检索器组件至少有一个方法get_relevant_texts,这个方法接收查询字符串,返回一组文档。(pip install faiss-cpu)

from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import OllamaEmbeddings


loader = TextLoader('./data/pku.txt', encoding='utf-8')
documents = loader.load()

my_spliter = CharacterTextSplitter(
    chunk_size=100,
    chunk_overlap=0
)

texts = my_spliter.split_documents(documents)
print(texts)
print(len(texts))

embed = OllamaEmbeddings(model='mxbai-embed-large')

db = FAISS.from_documents(texts, embed)
retriever = db.as_retriever(search_kwargs={'k': 1})
print(retriever.get_relevant_documents('北京大学是什么时候创建的?'))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值