LangChain for Python: 基本使用场景与实现
目录
核心概念
LangChain是一个用于构建AI应用的框架,主要功能:
- 连接语言模型与其他数据源
- 管理对话上下文
- 构建复杂的工作流
核心组件:
LLM Provider (e.g. OpenAI)
│
├── Prompt Templates
├── Memory
├── Chains
└── Agents/Tools
典型使用场景
1. 文档问答系统
2. 对话机器人
3. 数据增强ETL
实现流程(重点介绍场景1)
1. 安装
!pip install langchain
2. 基本操作,引入llm(tongyi qwen-turbo)
from langchain_community.llms import Tongyi
import os
# 检查环境变量
DASHSCOPE_API_KEY = os.getenv('DASHSCOPE_API_KEY')
if not DASHSCOPE_API_KEY:
raise ValueError("请设置 DASHSCOPE_API_KEY 环境变量")
# 模型配置
# EMBEDDING_MODEL = "text-embedding-v1"
LLM_MODEL = "qwen-turbo" # 可以根据需要调整模型
llm = Tongyi(
model_name=LLM_MODEL,
temperature=0.7,
dashscope_api_key=DASHSCOPE_API_KEY
)
llm.invoke("中国的首都在哪里?")
'中国的首都是北京。'
3. 构建chain :提示+模型+输出解析器
# 创建提示模板
from langchain.prompts import ChatPromptTemplate
topic=""
prompt = ChatPromptTemplate.from_template("""
请基于用户输入的主题,编写一篇小红书营销短文。
主题:{topic}
回答:""")
from langchain_core.output_parsers import StrOutputParser
output_parser=StrOutputParser()
chain=prompt|llm|output_parser
chain.invoke({"topic":"大众ID4"})
'✨城市探索新伙伴——大众ID.4,开启你的电动未来!🚗💨\n\n你是否厌倦了燃油车的高油耗?...'
- 定义chain旧方法不建议使用
# from langchain.chains import LLMChain
# langChainDeprecationWarning: The class `LLMChain` was deprecated in LangChain 0.1.17 and will be removed in 1.0. Use :meth:`~RunnableSequence, e.g., `prompt | llm`` instead.
# chain = LLMChain(llm=llm, prompt=prompt)
- chain=prompt|llm|output_parser 是管道拼接的功能,是以下三步的链接
prompt_value=prompt.invoke("人工智能将改变世界")
prompt_value
ChatPromptValue(messages=[HumanMessage(content='\n请基于用户输入的主题,编写一篇小红书营销短文。\n主题:人工智能将改变世界\n\n回答:', additional_kwargs={}, response_metadata={})])
message= llm.invoke(prompt_value)
message
'🌟【未来已来 | 人工智能将如何改变我们的生活?】🌟\n\n姐妹们!你有没有想过,有一天早晨醒来,...'
output_parser.invoke(message)
'🌟【未来已来 | 人工智能将如何改变我们的生活?】🌟\n\n姐妹们!你有没有想过,有一天早晨醒来,...'
等同于:
chain=prompt|llm|output_parser
chain.invoke("人工智能将改变世界")
'🌟【未来已来,人工智能将如何改变我们的生活?】🌟\n\n你是否曾幻想过像科幻电影里一样,...'
数据处理流程
组件说明
-
Dict
- 原始输入数据(字典格式)
-
PromptTemplate
- 将输入字典转换为标准提示模板
-
PromptValue
- 格式化后的提示值对象
-
ChatModel
- 语言模型处理核心
-
ChatMessage
- 模型生成的原始消息输出
-
StrOutputParser
- 输出解析器,功能包括:
- 接受BaseOutput或BaseMessage作为输入
- 将任何输入转换为字符串格式
- 输出解析器,功能包括:
-
String
- 标准化字符串输出
-
Result
- 最终处理结果
4. 简单的文档问答实现
使用langchain的WebBaseLoader,VectorstoreIndexCreator,DashScopeEmbeddings和FAISS向量数据库实现简单的RAG功能
from langchain.document_loaders import WebBaseLoader
from langchain.indexes import VectorstoreIndexCreator
from langchain_community.embeddings import DashScopeEmbeddings # 使用DashScope的嵌入模型
from langchain_community.llms import Tongyi
from langchain_community.vectorstores import FAISS # 显式指定向量存储
import os
# 0. 设置必要的环境变量
# os.environ["DASHSCOPE_API_KEY"] = "your-dashscope-api-key" # 您的DashScope API Key,已经设置过
os.environ["USER_AGENT"] = "MyApp/1.0" # 解决USER_AGENT警告
DASHSCOPE_API_KEY = os.getenv('DASHSCOPE_API_KEY')
EMBEDDING_MODEL = "text-embedding-v2"
LLM_MODEL = "qwen-turbo" # 可以根据需要调整模型
if not DASHSCOPE_API_KEY:
raise ValueError("请设置 DASHSCOPE_API_KEY 环境变量")
# 1. 配llm
from langchain_community.llms import Tongyi
llm = Tongyi(
model_name=LLM_MODEL,
temperature=0.7,
dashscope_api_key=DASHSCOPE_API_KEY
)
# 2. 创建DashScope的embedding
embedding = DashScopeEmbeddings(
model = EMBEDDING_MODEL, # 推荐使用的模型
dashscope_api_key = DASHSCOPE_API_KEY
)
# 3. 配置IndexCreator(解决内存存储警告和embedding缺失问题)
# index_creator = VectorstoreIndexCreator(
# embedding=embedding,
# llm=llm,
# vectorstore_kwargs={"persist_directory": "db"} # 可选:持久化存储路径
# )
# 3. 正确配置IndexCreator
index_creator = VectorstoreIndexCreator(
vectorstore_cls=FAISS, # 显式指定向量存储
embedding=embedding,
# 注意:这里不再直接传入llm
)
# 4. 加载网页数据
loader = WebBaseLoader("https://blog.csdn.net/alva_xu/article/details/147249709")
index = index_creator.from_loaders([loader])
# 5. 提问查询
query = "这篇文章的主要观点是什么?"
result = index.query(question=query, llm=llm) # 必须传入llm参数
result
'这篇文章的主要观点是介绍和对比了自然语言处理中的三种重要技术:N-Gram、TF-IDF 和 Word Embedding。文章详细解释了每种技术的基本概念、工作原理、优缺点以及应用场景,并通过实际案例展示了如何结合这些技术来解决具体问题,例如基于酒店描述的推荐系统。此外,文章还总结了 Word Embedding 的核心思想和常见方法(如 Word2Vec、GloVe、BERT),并指出了它们的优点和局限性。整体目的是帮助读者理解这些技术的特点及其在实际应用中的价值。'
完整示例:知识库问答系统
1. 环境准备:
! pip install unstructured
! pip install python-docx unstructured
! pip install nltk
! pip install --upgrade langchain-core langchain
手动下载NLTK数据(推荐)
- 1.手动下载数据包,并解压:
访问 https://github.com/nltk/nltk_data/tree/gh-pages/packages
下载以下两个zip文件:
tokenizers/punkt.zip
tokenizers/punkt_tab.zip -
- 手动安装:
import nltk
from nltk import data
# 指定自定义数据路径(可选)
custom_path = r'D:\cursorprj\langchain\ntlk_data'
nltk.data.path.append(custom_path)
from nltk.tokenize import sent_tokenize
text = "This is a test. This is another sentence."
sent_tokenize(text) # 应该输出句子列表
['This is a test.', 'This is another sentence.']
用pycharm执行以下py程序, 下载NLTK到C:\Users\Administrator\AppData\Roaming\nltk_data
# import nltk
# nltk.download('punkt') # 基础分词数据(必须)
# nltk.download('stopwords') # 停用词(可选)
# nltk.download('averaged_perceptron_tagger') # 词性标注(可选)
# nltk.download('wordnet') # 词库(可选)
# nltk.download('averaged_perceptron_tagger_eng')
#测试
from nltk.tokenize import sent_tokenize
text = "This is a test. This is another sentence."
sent_tokenize(text) # 应该输出句子列表
['This is a test.', 'This is another sentence.']
2. 正式代码:
# 1. 准备数据
from langchain.document_loaders import (
DirectoryLoader,
TextLoader,
UnstructuredWordDocumentLoader # 处理doc文件
)
# 加载txt文件
txt_loader = DirectoryLoader(
directory,
glob="**/*.txt",
loader_cls=TextLoader,
show_progress=True
)
# 加载doc/docx文件
doc_loader = DirectoryLoader(
directory,
glob="**/*.doc*", # 匹配.doc和.docx
loader_cls=UnstructuredWordDocumentLoader,
show_progress=True
)
# 合并所有文档
documents = txt_loader.load() + doc_loader.load()
documents
# 2. 分割文本
from langchain.text_splitter import RecursiveCharacterTextSplitter
directory = "./docs" # 替换为你的文档目录路径
chunk_size = 500 # 每个chunk的字符数
chunk_overlap = 50 # chunk之间的重叠字符数
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
separators=["\n\n", "\n", "。", "!", "?", ";", "……"],
length_function=len,
is_separator_regex=False
)
chunks = text_splitter.split_documents(documents)
chunks
print(f"\n共处理 {len(documents)} 个文档")
print(f"生成 {len(chunks)} 个文本块\n")
for i, chunk in enumerate(chunks[:3]): # 显示前3个chunk
print(f"Chunk {i+1}:")
print("-"*40)
print(chunk.page_content[:200] + "...")
print(f"来源: {chunk.metadata['source']}")
print("="*40 + "\n")
共处理 3 个文档
生成 62 个文本块
Chunk 1:
----------------------------------------
上海市数字经济发展“十四五”规划
...
========================================
Chunk 2:
----------------------------------------
...
来源: docs\上海市数字经济发展.txt
========================================
Chunk 3:
----------------------------------------
...
来源: docs\上海市数字经济发展.txt
========================================
# 3. 实现知识库查询
from langchain_community.embeddings import DashScopeEmbeddings # 使用DashScope的嵌入模型
from langchain_community.llms import Tongyi
from langchain_community.vectorstores import FAISS # 显式指定向量存储
import os
# 0. 设置必要的环境变量
# os.environ["DASHSCOPE_API_KEY"] = "your-dashscope-api-key" # 您的DashScope API Key,已经设置过
os.environ["USER_AGENT"] = "MyApp/1.0" # 解决USER_AGENT警告
DASHSCOPE_API_KEY = os.getenv('DASHSCOPE_API_KEY')
EMBEDDING_MODEL = "text-embedding-v2"
LLM_MODEL = "qwen-turbo" # 可以根据需要调整模型
if not DASHSCOPE_API_KEY:
raise ValueError("请设置 DASHSCOPE_API_KEY 环境变量")
# 1. 配llm
from langchain_community.llms import Tongyi
llm = Tongyi(
model_name=LLM_MODEL,
temperature=0.7,
dashscope_api_key=DASHSCOPE_API_KEY
)
# 2. 创建DashScope的embedding
embedding = DashScopeEmbeddings(
model = EMBEDDING_MODEL, # 推荐使用的模型
dashscope_api_key = DASHSCOPE_API_KEY
)
# 3.创建向量数据库
db = FAISS.from_documents(chunks, embedding)
2.1 不对prompt进行设置,用默认的prompt
# 4. 创建问答链
from langchain.chains import RetrievalQA
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=db.as_retriever(search_kwargs={"k": 3}), # # 控制返回的文档数量为3
)
qa_chain
# prompt.input_variables
# db.as_retriever(search_kwargs={"k": 3})
# 5. 提问
question = "知识库中有哪些内容?"
result = qa_chain.invoke({"query": question})
result
result输出内容
{'query': '知识库中有哪些内容?',
'result': '根据提供的信息,知识库中包含以下内容:\n\n1. **数字内容相关**:\n - 数字内容产业的新业态新模式。\n ...'}
2.2 自定义Prompt的方式
# 6. 创建prompt
from langchain.prompts import PromptTemplate
template = """根据以下上下文信息回答问题:
{context}
问题:{question}
回答:
请用中文简洁回答,若不知道答案请如实说明。"""
QA_PROMPT = PromptTemplate(
input_variables=["context", "question"], # 必须包含这两个变量
template=template
)
# 7. 创建问答链
from langchain.chains import RetrievalQA
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=db.as_retriever(search_kwargs={"k": 3}), # # 控制返回的文档数量为3
chain_type_kwargs={
"prompt": QA_PROMPT,
"document_variable_name": "context" # 必须与模板变量名一致,context 的值是自动从检索器(retriever)获取并注入到 prompt
},
return_source_documents=True # 返回参考文档
)
# qa_chain
# prompt.input_variables
db.as_retriever(search_kwargs={"k": 3})
VectorStoreRetriever(tags=['FAISS', 'DashScopeEmbeddings'], vectorstore=<langchain_community.vectorstores.faiss.FAISS object at 0x000001E9C87AA780>, search_kwargs={'k': 3})
# 8. 提问
# 问答循环
print("\n系统已准备就绪,可以开始提问了。输入'退出'结束对话。")
while True:
question = input("\n请输入问题:")
if question.lower() == '退出':
break
# 生成回答
result = qa_chain.invoke({"query": question})
# print(result)
# 输出结果
print("答案:", result["result"])
print("\n参考文档:")
for doc in result["source_documents"]:
print(f"- {doc.page_content[:100]}...") # 显示文档前100字符
运行情况
系统已准备就绪,可以开始提问了。输入'退出'结束对话。
请输入问题: 请问浦发银行客户经理违反规定要扣几分?
答案: 根据上下文信息,如果浦发银行客户经理在工作中有不廉洁自律的情况,每发现一次扣50分。其他违反规定的情况需具体分析,例如资产质量考核和逾期处理等,都有相应的扣分标准。若不知道具体违规类型,则无法确定扣分分数。
参考文档:
- 7、在工作中有不廉洁自律情况的每发现一次扣 50 分。
(二)个人资产质量考核:
当季考核收息率 97%以上为合格,每降 1 个百分点扣 2 分;不
良资产零为合格,每超一个个百分点扣 1 分。...
- 第八章 管理与奖惩
第十八条 个金客户经理管理机构为分行客户经理管理委员会。管理委员会组成人员:行长或主管业务副行长,个人业务部、人力资源部、风险管理部负责人。
第十九条 客户经理申报的各种信息必...
- 助理客户经理待遇按照人事部门对主办科员以下人员的待遇标准;客户经理待遇按照人事部门对主办科员的待遇标准;高级客户经理待遇按照人事部门对付科级的待遇标准;资深客户经理待遇按照人事部门对正科级的待遇标准。...
请输入问题:
↑↓ for history. Search history with c-↑/c-↓