fzd8 / app.py
fdbw's picture
Update app.py
3f35ad6 verified
Raw
History Blame Contribute Delete
5.22 kB
# 导入核心依赖(修复所有模块路径)
import os
# 环境变量管理(建议使用 python-dotenv)
from dotenv import load_dotenv
load_dotenv() # 加载 .env 文件中的环境变量
# --------------------------
# 1. 文本分割器:从 langchain_text_splitters 导入(v0.1.0+ 新版本路径)
# --------------------------
from langchain_text_splitters import CharacterTextSplitter
# --------------------------
# 2. 文档加载器:仍在 langchain_community 中
# --------------------------
from langchain_community.document_loaders import TextLoader
# --------------------------
# 3. 嵌入模型:根据版本选择路径
# --------------------------
# 方式1:OpenAI 嵌入(需安装 langchain-openai)
from langchain_openai import OpenAIEmbeddings
# 方式2:本地 HuggingFace 嵌入(需安装 sentence-transformers)
# from langchain_community.embeddings import HuggingFaceEmbeddings
# --------------------------
# 4. 向量存储:仍在 langchain_community 中
# --------------------------
from langchain_community.vectorstores import Chroma
# --------------------------
# 5. 大模型:根据版本选择路径
# --------------------------
# 方式1:OpenAI Chat 模型(需安装 langchain-openai)
from langchain_openai import ChatOpenAI
# 方式2:本地 Ollama 模型(需安装 langchain-community 和 ollama)
# from langchain_community.llms import Ollama
# --------------------------
# 6. RetrievalQA:仍在 langchain_community 中
# --------------------------
from langchain_community.chains import RetrievalQA
# 配置环境变量(也可通过 .env 文件设置)
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY", "your-openai-api-key") # 替换为你的 API Key
def load_and_split_documents(file_path="docs/knowledge.txt"):
"""加载文档并分割为小片段"""
# 确保文档目录存在
os.makedirs(os.path.dirname(file_path), exist_ok=True)
# 若文档不存在,创建临时测试文档
if not os.path.exists(file_path):
with open(file_path, "w", encoding="utf-8") as f:
f.write("LangChain 是一个用于构建 LLM 应用的框架,支持检索增强生成(RAG)等功能。\n")
f.write("RetrievalQA 是 LangChain 中用于检索问答的核心链,在 v0.1.0 后迁移到了 langchain_community 模块。\n")
f.write("CharacterTextSplitter 在 v0.1.0 后迁移到了 langchain_text_splitters 模块。\n")
# 1. 加载文档
loader = TextLoader(file_path, encoding="utf-8")
documents = loader.load()
# 2. 分割文档(修复后的文本分割器)
text_splitter = CharacterTextSplitter(
chunk_size=1000, # 每个片段的字符数
chunk_overlap=200, # 片段间重叠字符数
separator="\n"
)
split_docs = text_splitter.split_documents(documents)
return split_docs
def create_vector_store(docs):
"""创建向量存储(使用 Chroma 本地向量库)"""
# 初始化嵌入模型
# 方式1:OpenAI 嵌入
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# 方式2:本地 HuggingFace 嵌入
# embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh-v1.5")
# 创建向量库并存储文档
vector_store = Chroma.from_documents(
documents=docs,
embedding=embeddings,
persist_directory="./chroma_db" # 向量库持久化路径
)
# Chroma v0.4+ 不再需要手动 persist()
return vector_store
def create_retrieval_qa_chain(vector_store):
"""创建 RetrievalQA 检索问答链"""
# 1. 初始化大模型
# 方式1:OpenAI GPT-3.5/4
llm = ChatOpenAI(
model_name="gpt-3.5-turbo",
temperature=0.1 # 温度越低,回答越稳定
)
# 方式2:本地 Ollama 模型(如 Llama3)
# llm = Ollama(model="llama3:8b", temperature=0.1)
# 2. 创建检索器(从向量库中检索相关文档)
retriever = vector_store.as_retriever(
search_kwargs={"k": 3} # 检索前 3 个最相关的文档
)
# 3. 创建 RetrievalQA 链
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff", # 链类型:stuff/map_reduce/refine 等
retriever=retriever,
return_source_documents=True # 是否返回检索到的源文档
)
return qa_chain
if __name__ == "__main__":
# 1. 加载并分割文档
docs = load_and_split_documents()
# 2. 创建向量存储
vector_store = create_vector_store(docs)
# 3. 创建 RetrievalQA 链
qa_chain = create_retrieval_qa_chain(vector_store)
# 4. 测试问答
query = "CharacterTextSplitter 在 LangChain 新版本中被迁移到了哪里?"
result = qa_chain.invoke({"query": query}) # v0.1.0+ 推荐使用 invoke() 替代 __call__
# 输出结果
print("===== 问题 =====")
print(query)
print("\n===== 回答 =====")
print(result["result"])
print("\n===== 参考文档 =====")
for i, doc in enumerate(result["source_documents"]):
print(f"\n文档 {i+1}:")
print(f"内容:{doc.page_content}")
print(f"来源:{doc.metadata['source']}")