"""
langchain支持3种模型:
* LLM
* ChatModel
* Embedding model
"""
####################LangChain组件:Models####################
# LLM
def dm01():
# 0.x版本
# from langchain.llms import Ollama
# 1.x版本 方式一
from langchain_community.llms import Ollama
model = Ollama(model="deepseek-r1:1.5b", temperature=0)
# 1.x版本 方式二
# from langchain_ollama import OllamaLLM
# model = OllamaLLM(model="deepseek-r1:1.5b", temperature=0)
result = model.invoke("请给我讲个鬼故事")
print("result-->", result)
# ChatModel
def dm02():
from langchain_core.messages import HumanMessage, SystemMessage
# 0.x版本
# from langchain.chat_models import ChatOllama
# 1.x版本
# from langchain_community.chat_models import ChatOllama
from langchain_ollama import ChatOllama
model = ChatOllama(model="deepseek-r1:1.5b", temperature=0)
messages = [
SystemMessage(content="现在你是一个著名的歌手"),
HumanMessage(content="给我写一首歌词")
]
result = model.invoke(messages)
print('result-->', result)
print('result.content-->', result.content)
# embedding model
def dm03():
# from langchain_community.embeddings import OllamaEmbeddings
from langchain_ollama import OllamaEmbeddings
model = OllamaEmbeddings(model="mxbai-embed-large", temperature=0)
res1 = model.embed_query('这是第一个测试文档')
print('res1-->', res1, len(res1))
res2 = model.embed_documents(['这是第一个测试文档', '这是第二个测试文档'])
print('res2-->', res2, len(res2))
####################LangChain组件:Prompt####################
# TODO 掌握:提示模板(非Chat版本)
def dm04():
# from langchain import PromptTemplate # Langchain 0.x版本使用
from langchain_core.prompts import PromptTemplate
# from langchain_community.llms import Ollama # Langchain 0.x版本使用
from langchain_ollama import OllamaLLM
# model = Ollama(model="qwen2.5:0.5b") # Langchain 0.x版本使用
model = OllamaLLM(model="qwen2.5:0.5b")
# 提示词模板
prompt = PromptTemplate.from_template("我的邻居姓{lastname}, 他最近生了个儿子,请帮他儿子取个名字")
prompt_str = prompt.format(lastname="王")
print("result1-->", prompt_str)
prompt = PromptTemplate(template="我的邻居姓{lastname}, 他最近生了个儿子,请帮他儿子取个名字", input_variables=['lastname'])
prompt_str = prompt.format(lastname='王')
print("result2-->", prompt_str)
result = model.invoke(prompt_str)
print("result-->", result)
# 了解:Langchain源码写法
def dm05():
from langchain_core.prompts import ChatPromptTemplate
template = ChatPromptTemplate(
[
("system", "You are a helpful AI bot. Your name is {name}."),
("human", "Hello, how are you doing?"),
("ai", "I'm doing well, thanks!"),
("human", "{user_input}"),
])
prompt_value = template.invoke(
{
"name": "Bob",
"user_input": "What is your name?",
})
print("prompt_value-->", prompt_value)
# TODO 掌握:Chat版本提示词模板
def dm06():
from langchain_community.chat_models import ChatOllama
# 0.x版本
# from langchain.prompts import ChatPromptTemplate
# 1.x版本
from langchain_core.prompts import ChatPromptTemplate
# 创建原始模板
template_str = """您是一位专业的鲜花店文案撰写员。\n
对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?"""
# 把字符串传给提示词模板
prompt = ChatPromptTemplate.from_template(template=template_str)
# 给模板中的变量赋值
prompt_result = prompt.format_messages(price='68', flower_name='玫瑰')
print("prompt_result-->", prompt_result)
# 把提示词送给大模型
model = ChatOllama(model="deepseek-r1:1.5b", temperature=0)
result = model.invoke(prompt_result)
print("result-->", result)
# 了解:FewShot提示词模板
def dm07():
from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate
from langchain_ollama.llms import OllamaLLM
model = OllamaLLM(model="qwen2.5:0.5b")
examples = [
{"word": "开心", "antonym": "难过"},
{"word": "高", "antonym": "矮"},
]
example_template = """
单词: {word}
反义词: {antonym}
"""
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_text = few_shot_prompt.format(input="粗")
print(prompt_text)
print('*' * 80)
print(model.invoke(prompt_text))
####################LangChain组件:Chains####################
# TODO 掌握:Chains
def dm08():
from langchain_core.prompts import PromptTemplate
from langchain_community.llms import Ollama
from langchain_classic.chains.llm import LLMChain
# 定义模板
template = "你是一个取名专家,我的邻居姓{lastname},他生了个儿子,请给他儿子起个名字。"
prompt = PromptTemplate(
input_variables=["lastname"],
template=template,
)
llm = Ollama(model="qwen2.5:0.5b")
# 调用方式一:普通调用
chain = LLMChain(llm=llm,
prompt=prompt)
print('1-->', chain.invoke("王"))
# 调用方式二:LCEL(Langchain 表达式语言)
chain = prompt | llm
# 执行链
print('2-->', chain.invoke("王"))
# 了解:Chains 多条链
def dm09():
from langchain_core.prompts import PromptTemplate
from langchain_ollama import OllamaLLM
# 创建第一条链
template = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字"
first_prompt = PromptTemplate(
input_variables=["lastname"],
template=template, )
# 实例化模型
llm = OllamaLLM(model="deepseek-r1:1.5b")
# LCEL表达式
first_chain = first_prompt | llm
# 创建第二条链
second_prompt = PromptTemplate(
input_variables=["child_name"],
template="邻居的儿子名字叫{child_name},给他起一个小名")
second_chain = second_prompt | llm
# 链接两条链
overall_chain = first_chain | second_chain
print(overall_chain)
print('*' * 80)
# 执行链,只需要传入第一个参数
catchphrase = overall_chain.invoke("王")
print(catchphrase)
####################OutputParser:对大模型输出结果进行解析(转换)####################
# 结果美化:字符串
def dm10():
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaLLM
# 实例化模型
model = OllamaLLM(model="qwen2.5:0.5b")
# 创建简单链
prompt = ChatPromptTemplate.from_template("解释{topic}是什么?回答控制20字以内")
chain1 = prompt | model
result1 = chain1.invoke({"topic": "ai"})
print(f"result1-->{result1}")
# 添加字符串解析器
parser = StrOutputParser()
chain2 = prompt | model | parser
result2 = chain2.invoke({"topic": "ai"})
print(f"result2-->{result2}")
# 结果美化:列表
def dm11():
from langchain_core.output_parsers import CommaSeparatedListOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaLLM
# 实例化模型
model = OllamaLLM(model="qwen2.5:0.5b")
# 创建列表解析器
parser = CommaSeparatedListOutputParser()
# 创建带格式说明的提示模板
# format_instructions = parser.get_format_instructions()
# print(format_instructions)
prompt = ChatPromptTemplate.from_template(
"用中文列出{topic}的五个最重要特点。\n{format_instructions}"
)
# 组合组件
chain = prompt | model | parser
# 调用链
result = chain.invoke({
"topic": "大模型",
"format_instructions": "你的回答应该是一个用逗号分隔的值的列表,例如:foo, bar, baz或 foo,bar,baz"
})
print(result)
# 结果美化:JSON
def dm12():
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaLLM
# 实例化模型
model = OllamaLLM(model="qwen2.5:0.5b")
# 创建JSON解析器
json_parser = JsonOutputParser()
# 创建带格式说明的提示模板
json_format_instructions = json_parser.get_format_instructions()
print(json_format_instructions)
json_prompt = ChatPromptTemplate.from_template(
"生成一个包含{person}基本信息的JSON。应包括姓名、职业、年龄和技能列表, 不要包含任何注释或额外说明。\n{format_instructions}"
)
# 组合组件
json_chain = json_prompt | model | json_parser
# 调用链
result = json_chain.invoke({
"person": "雷军",
"format_instructions": "返回一个JSON对象"
})
print(result)
# 结果美化:Pydantic类型校验
def dm13():
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import PydanticOutputParser
from langchain_ollama import OllamaLLM
# pydantic
from pydantic import BaseModel, Field
from typing import List
# 实例化模型
model = OllamaLLM(model="qwen2.5:0.5b")
# 定义Pydantic模型
class Movie(BaseModel):
title: str = Field(description="电影标题")
director: str = Field(description="导演姓名")
year: int = Field(description="上映年份")
# todo : 单标签多分类 (每个电影只能有个类型)、 多标签多分类(一个电影可以有多个类型)
genre: List[str] = Field(description="电影类型")
rating: float = Field(description="评分(1-10)")
# 创建Pydantic解析器
pydantic_parser = PydanticOutputParser(pydantic_object=Movie)
# 创建带格式说明的提示模板
format_instructions = pydantic_parser.get_format_instructions()
print('1-->', format_instructions)
pydantic_prompt = ChatPromptTemplate.from_template(
"生成一部{genre}电影的信息。\n{format_instructions}"
)
# 组合组件
pydantic_chain = pydantic_prompt | model | pydantic_parser
# 调用链
movie_data = pydantic_chain.invoke({
"genre": "科幻",
"format_instructions": format_instructions
})
print('2-->', movie_data)
####################LangChain组件:Memory####################
def dm14():
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.messages import messages_to_dict, messages_from_dict
import json
# 1.创建一个ChatMessageHistory对象,用来存储对话信息
history = ChatMessageHistory()
# 添加用户消息
history.add_user_message("在吗?")
# 添加大模型消息
history.add_ai_message("在")
# 打印所有消息
print(f'history.messages1-->{history.messages}')
# 2.可以将history.messages中的信息保存到字典中,然后保存到数据库或者文件中,方便后续读取
# 2.1 messages_to_dict()方法将history.messages中的信息转换成字典
dicts = messages_to_dict(history.messages)
print(f'dicts-->{dicts}')
# 2.2 这里将dicts保存到文件中
with open('history.json', 'w', encoding='utf-8') as f:
f.write(json.dumps(dicts, indent=2, ensure_ascii=False))
# 3.从文件中读取出字典,然后将字典转换成消息
# 3.1 读取文件
messages = json.load(open('history.json', 'r', encoding='utf-8'))
# 3.2 然后将字典转换成消息
chat_messages = messages_from_dict(messages)
print(f'chat_messages2-->{chat_messages}')
####################LangChain组件:VectorStore####################
def dm15():
from langchain_text_splitters import CharacterTextSplitter
from langchain_chroma import Chroma
from langchain_community.document_loaders import TextLoader
from langchain_ollama import OllamaEmbeddings
# 1.加载文档
# 创建 TextLoader 对象
loader = TextLoader('./pku.txt', encoding='utf-8')
# 加载文档
# metadata:描述数据的数据。数据大小,路径,创建日期,作者,权限...
docs = loader.load()
print(f'docs-->{docs}')
# 2.将文档进行分块
# 创建 CharacterTextSplitter 对象
text_splitter = CharacterTextSplitter(separator="\n\n", chunk_size=200, chunk_overlap=30)
# 分块
split_docs = text_splitter.split_documents(docs)
print(f'split_docs-->{split_docs}')
# 3.将分割后的文档存储到向量数据库中
# 加载embedding模型
embedding = OllamaEmbeddings(model="mxbai-embed-large")
# 创建向量数据库,需要指定 存储的文档和向量模型名称以及持久化目录
chromadaDB = Chroma.from_documents(documents=split_docs,
embedding=embedding,
persist_directory='./chroma_db')
print("chromadaDB-->", chromadaDB)
# 假如你的向量数据库已经存在,那么可以直接加载
# chromadaDB = Chroma(persist_directory='./chroma_db', embedding_function=embedding)
# 4.使用向量数据库进行查询
query = "1937年北京大学发生了什么?"
result = chromadaDB.similarity_search(query, k=1)
print(f'result-->{result}')
####################LangChain组件:检索器####################
def dm16():
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import OllamaEmbeddings
from langchain_text_splitters import CharacterTextSplitter
from langchain_community.document_loaders import TextLoader
loader = TextLoader('./pku.txt', encoding='utf-8')
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
print("texts-->", texts)
embeddings = OllamaEmbeddings(model="mxbai-embed-large")
print("embeddings-->", embeddings)
db = FAISS.from_documents(texts, embeddings)
print("db-->", db)
result = db.similarity_search("北京大学什么时候成立的", k=2)
print("result-->", result)
####################LangChain组件:Indexes加载器####################
def dm17():
from langchain_community.document_loaders import UnstructuredFileLoader
loader = UnstructuredFileLoader('衣服属性.txt', encoding='utf8')
docs = loader.load()
print('1-->', docs)
print(len(docs))
first_01 = docs[0].page_content[:4]
print('2-->', first_01)
print('*' * 80)
from langchain_community.document_loaders import TextLoader
loader = TextLoader('衣服属性.txt', encoding='utf8')
docs = loader.load()
print('3-->', docs)
print(len(docs))
first_01 = docs[0].page_content[:4]
print('4-->', first_01)
####################LangChain组件:Indexes分割器####################
def dm18():
from langchain_core.documents import Document
from langchain_text_splitters import CharacterTextSplitter
# 创建分词器 separator参数指的是分割的分隔符,chunk_size指的是分割出来的每个块的大小,chunk_overlap指的是每个块之间重叠的大小
text_splitter = CharacterTextSplitter(separator=" ", chunk_size=5, chunk_overlap=1)
# 一句话分割
result1 = text_splitter.split_text("a b c d e f")
print(f'result1--->{result1}')
# 多句话分割
result2 = text_splitter.create_documents(["a b c d e f", "e f g h"])
print(f'result2--->{result2}')
# 多句话分割
result3 = text_splitter.split_documents([Document(page_content="a b c d e f", metadata={"id": "1"})])
print(f'result3--->{result3}')
def dm19():
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 4个参数:
# 1. 块大小 2.重叠字符数 3. 长度衡量方式:传入一个函数进来,调用函数判断长度
# 4. 分割符号: 按照列表中的分割符号,从左到右依次进行分割,直到满足块大小限制。 如果分割到最后一个符号未满足块大小,直接截断
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=30, # 每个块最多 30 个字符
chunk_overlap=6, # 相邻分块会共享 6 个字符
# 使用len,中文和英文没有区别;byte
length_function=len, # 用字符数来衡量长度
separators=["\n\n", "\n", " ", ""] # 会优先尝试按 \n\n 分段,如果太长,再按 \n → 空格 → 逐字符切分。
)
text = """
人工智能正在快速发展,尤其是大语言模型的应用,正在改变人类的工作方式。
它们可以帮助人们进行写作、代码生成、甚至是科研探索。
相比之下,新能源的发展同样重要。
电动车和太阳能正在逐渐替代传统能源,减少碳排放,对全球环境保护至关重要。
"""
docs = text_splitter.split_text(text)
print('docs-->', docs)
print('docs-->', len(docs)) # 4
def dm20():
from langchain_experimental.text_splitter import SemanticChunker
from langchain_ollama import OllamaEmbeddings
embed = OllamaEmbeddings(model="mxbai-embed-large")
text_splitter = SemanticChunker(
embeddings=embed,
breakpoint_threshold_type='percentile',
# 更低的百分位会更“积极”地切分(数值越小 => 切得越多)
breakpoint_threshold_amount=40.0,
# 句子拆分正则为同时识别中/英文终结符
sentence_split_regex=r'(?<=[。!?.!?])\s*',
# 每个切分后片段(chunk)至少要有多少个字符
min_chunk_size=10
)
text = """
人工智能正在快速发展,尤其是大语言模型的应用,正在改变人类的工作方式。
它们可以帮助人们进行写作、代码生成、甚至是科研探索。
相比之下,新能源的发展同样重要。
电动车和太阳能正在逐渐替代传统能源,减少碳排放,对全球环境保护至关重要。
"""
docs = text_splitter.split_text(text)
print("docs-->", docs)
if __name__ == '__main__':
# dm01()
# dm02()
# dm03()
# dm04()
# dm05()
# dm06()
# dm07()
# dm08()
# dm09()
# dm10()
# dm11()
# dm12()
# dm13()
# dm14()
# dm15()
# dm16()
# dm17()
# dm18()
# dm19()
dm20()