加餐篇:LlamaIndex 与 LangChain 的无缝集成
问题背景:在实际应用中,开发者常常需要结合多个框架的优势。例如,使用 LangChain 管理复杂的业务逻辑链,同时利用 LlamaIndex 的高效索引和检索能力构建知识库。本文在基于 第56篇:LangChain快速入门与应用示例和 第57篇:LlamaIndex使用指南:构建高效知识库基础上,通过 cmd方式集成、基于Streamlit UI集成、基于Ollama本地大模型集成 三个步骤以实战案例展示如何将两者无缝集成,构建一个智能客服系统,抛砖引玉、以飨读者。
1. LlamaIndex 与 LangChain CMD界面集成
完整代码案例
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.retrievers import VectorIndexRetriever
# Step 1: 使用 LlamaIndex 构建知识库索引
# 数据加载:从本地目录加载文档
documents = SimpleDirectoryReader("./knowledge_base").load_data()
# 创建向量索引
index = VectorStoreIndex.from_documents(documents)
# 初始化检索器
retriever = VectorIndexRetriever(index=index, similarity_top_k=5)
# 创建查询引擎
query_engine = RetrieverQueryEngine(retriever=retriever)
# Step 2: 使用 LangChain 构建对话链
# 定义提示模板
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个智能客服助手,以下是相关文档内容:\n{context}"),
("human", "{query}")
])
# 初始化大模型
llm = ChatOpenAI(model="gpt-4o")
# 将 LlamaIndex 查询引擎嵌入到 LangChain 链中
def retrieve_context(query):
response = query_engine.query(query)
return response.response
# 构建 LangChain 链路
chain = (
{"context": RunnablePassthrough() | retrieve_context, "query": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
# Step 3: 执行查询
query = "公司2023年的主要产品有哪些?"
result = chain.invoke(query)
print(result)
输出结果
"根据知识库内容,公司2023年的主要产品包括智能客服系统、数据分析平台和区块链解决方案。"
说明
Step 1: 使用 LlamaIndex 构建知识库索引
- 数据加载:通过
SimpleDirectoryReader
加载本地文档(如 PDF、Word 或文本文件)。 - 索引构建:使用
VectorStoreIndex
创建向量索引,支持高效的相似性检索。 - 查询引擎:通过
RetrieverQueryEngine
提供对索引的访问接口。
Step 2: 使用 LangChain 构建对话链
- 提示模板:定义对话模板,动态注入检索到的上下文信息。
- 检索函数:通过
RunnablePassthrough
将用户输入传递给 LlamaIndex 查询引擎,获取相关上下文。 - 链式调用:将检索结果与用户输入组合后传递给大模型,生成最终答案。
Step 3: 执行查询
- 用户提问“公司2023年的主要产品有哪些?”时:
- LlamaIndex 从知识库中检索相关内容。
- LangChain 将检索到的内容与用户问题结合,生成最终回答。
关键点解析
为什么选择 LlamaIndex 和 LangChain 集成?
- LlamaIndex 的优势:专注于知识库构建,擅长处理大规模文档和复杂检索任务。
- LangChain 的优势:提供灵活的链式调用机制,适合管理复杂的业务逻辑。
- 无缝集成:通过自定义函数(如
retrieve_context
),可以轻松将 LlamaIndex 的检索能力嵌入到 LangChain 的工作流中。
代码中的亮点
动态上下文注入:
- 使用
RunnablePassthrough
动态传递用户输入,并调用 LlamaIndex 的查询引擎。 - 这种方式确保了检索结果始终与用户问题相关。
- 使用
模块化设计:
- LlamaIndex 负责知识库的管理和检索。
- LangChain 负责对话管理和最终答案生成。
- 两者的分工明确,便于维护和扩展。
应用场景
- 企业智能客服:结合知识库和对话链,构建多轮对话的客服助手。
- 文档问答系统:快速检索和生成答案,适用于技术支持和内部培训。
- 研究文献分析:通过混合检索和链式调用,生成高质量的研究报告。
2. LlamaIndex 与 LangChain 集成 + 前端 UI
问题背景:为了提升用户体验,我们不仅需要一个强大的后端系统,还需要一个直观、友好的前端界面。以下案例将展示如何结合 LlamaIndex 和 LangChain 构建后端逻辑,同时使用 Streamlit(一个流行的 Python 前端框架)打造一个交互式应用。
完整代码案例
后端逻辑:整合 LlamaIndex 和 LangChain
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnablePassthrough
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.retrievers import VectorIndexRetriever
# Step 1: 使用 LlamaIndex 构建知识库索引
def build_knowledge_base():
# 数据加载:从本地目录加载文档
documents = SimpleDirectoryReader("./knowledge_base").load_data()
# 创建向量索引
index = VectorStoreIndex.from_documents(documents)
# 初始化检索器
retriever = VectorIndexRetriever(index=index, similarity_top_k=5)
# 创建查询引擎
query_engine = RetrieverQueryEngine(retriever=retriever)
return query_engine
# Step 2: 使用 LangChain 构建对话链
def build_langchain_chain(query_engine):
# 定义提示模板
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个智能客服助手,以下是相关文档内容:\n{context}"),
("human", "{query}")
])
# 初始化大模型
llm = ChatOpenAI(model="gpt-4o")
# 将 LlamaIndex 查询引擎嵌入到 LangChain 链中
def retrieve_context(query):
response = query_engine.query(query)
return response.response
# 构建 LangChain 链路
chain = (
{"context": RunnablePassthrough() | retrieve_context, "query": RunnablePassthrough()}
| prompt
| llm
)
return chain
前端实现:使用 Streamlit 构建用户界面
import streamlit as st
# 初始化后端逻辑
query_engine = build_knowledge_base()
chain = build_langchain_chain(query_engine)
# Streamlit 应用界面
st.title("智能客服助手")
st.markdown("请输入您的问题,我们将为您快速解答!")
# 用户输入框
user_query = st.text_input("您的问题:", "")
if user_query:
# 显示加载动画
with st.spinner("正在为您查找答案..."):
# 调用后端逻辑生成回答
response = chain.invoke(user_query)
# 显示回答
st.subheader("回答:")
st.write(response)
# 显示上下文信息
st.subheader("参考内容:")
retrieved_context = query_engine.query(user_query).source_nodes
for i, node in enumerate(retrieved_context):
st.write(f"**来源 {i+1}:** {node.node.text[:200]}...")
运行方式
安装依赖:
pip install llama-index langchain openai streamlit
启动应用:
- 将上述代码保存为
app.py
。 - 在终端运行以下命令:
streamlit run app.py
- 打开浏览器访问
http://localhost:8501
,即可看到交互式界面。
- 将上述代码保存为
输出结果
界面截图
首页布局:
输入问题:
- 用户输入问题:“公司2023年的主要产品有哪些?”
生成回答:
回答: 根据知识库内容,公司2023年的主要产品包括智能客服系统、数据分析平台和区块链解决方案。 参考内容: 来源 1: 公司2023年发布了一系列新产品,其中包括智能客服系统... 来源 2: 数据分析平台采用了最新的机器学习算法...
说明
Step 1: 后端逻辑
- LlamaIndex:
- 负责构建知识库索引,支持高效检索。
- 通过
VectorStoreIndex
和RetrieverQueryEngine
提供上下文信息。
- LangChain:
- 负责管理对话链,动态注入检索到的上下文。
- 通过
RunnablePassthrough
和ChatPromptTemplate
生成最终回答。
Step 2: 前端实现
- Streamlit:
- 提供了一个简单易用的前端框架,适合快速构建交互式应用。
- 使用
st.text_input
获取用户输入,st.spinner
显示加载动画,st.write
展示结果。
- 用户体验:
- 界面简洁直观,用户只需输入问题即可获得答案。
- 显示参考内容,增强透明度和可信度。
关键点解析
为什么选择 Streamlit?
- 简单易用:无需复杂的前端开发经验,仅需几行代码即可构建交互式界面。
- 实时更新:支持动态刷新,用户输入后立即显示结果。
- 跨平台支持:可在本地或云端部署,方便扩展。
代码中的亮点
- 前后端分离:
- 后端逻辑专注于数据处理和业务逻辑。
- 前端负责用户交互和结果展示。
- 动态加载:
- 使用
st.spinner
提供加载动画,提升用户体验。
- 使用
- 参考内容展示:
- 显示检索到的上下文信息,帮助用户理解答案来源。
3. LlamaIndex 与 LangChain 集成 + 前端 UI+ Ollama
在案例中,如果需要将大模型调用从云端(如 OpenAI 的 ChatOpenAI
)改为本地运行的 Ollama,我们需要调整代码以适配 Ollama 提供的接口。以下是详细的调整步骤和完整代码示例。
模型接口说明
Ollama 简介:
- Ollama 是一个用于本地运行大语言模型(LLM)的工具,支持多种开源模型(如 Llama、Mistral、GPT-NeoX 等)。
- 它提供了 RESTful API 接口,可以通过 HTTP 请求与本地模型交互。
调整点:
- 替换
langchain_openai.ChatOpenAI
为适配 Ollama 的自定义实现。 - 使用
ollama
的 Python SDK 或直接通过 HTTP 请求调用本地模型。 - 修改 LangChain 的链式调用逻辑,确保与 Ollama 的输出格式兼容。
- 替换
本地Ollama大模型调用代码实现
后端逻辑:整合 LlamaIndex 和 LangChain + Ollama
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnablePassthrough
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.retrievers import VectorIndexRetriever
import requests
# Step 1: 使用 LlamaIndex 构建知识库索引
def build_knowledge_base():
# 数据加载:从本地目录加载文档
documents = SimpleDirectoryReader("./knowledge_base").load_data()
# 创建向量索引
index = VectorStoreIndex.from_documents(documents)
# 初始化检索器
retriever = VectorIndexRetriever(index=index, similarity_top_k=5)
# 创建查询引擎
query_engine = RetrieverQueryEngine(retriever=retriever)
return query_engine
# Step 2: 配置 Ollama 模型调用
class OllamaLLM:
def __init__(self, model_name="llama2", base_url="http://localhost:11434"):
self.model_name = model_name
self.base_url = base_url
def invoke(self, prompt):
# 发送请求到 Ollama
response = requests.post(
f"{self.base_url}/api/generate",
json={
"model": self.model_name,
"prompt": prompt,
"stream": False
}
)
if response.status_code == 200:
result = response.json()
return result.get("response", "")
else:
raise Exception(f"Error calling Ollama: {response.text}")
# Step 3: 使用 LangChain 构建对话链
def build_langchain_chain(query_engine, ollama_llm):
# 定义提示模板
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个智能客服助手,以下是相关文档内容:\n{context}"),
("human", "{query}")
])
# 将 LlamaIndex 查询引擎嵌入到 LangChain 链中
def retrieve_context(query):
response = query_engine.query(query)
return response.response
# 构建 LangChain 链路
chain = (
{"context": RunnablePassthrough() | retrieve_context, "query": RunnablePassthrough()}
| prompt
| ollama_llm.invoke
)
return chain
前端实现:使用 Streamlit 构建用户界面
import streamlit as st
# 初始化后端逻辑
query_engine = build_knowledge_base()
ollama_llm = OllamaLLM(model_name="llama2") # 使用本地 Ollama 模型
chain = build_langchain_chain(query_engine, ollama_llm)
# Streamlit 应用界面
st.title("智能客服助手")
st.markdown("请输入您的问题,我们将为您快速解答!")
# 用户输入框
user_query = st.text_input("您的问题:", "")
if user_query:
# 显示加载动画
with st.spinner("正在为您查找答案..."):
# 调用后端逻辑生成回答
response = chain.invoke(user_query)
# 显示回答
st.subheader("回答:")
st.write(response)
# 显示上下文信息
st.subheader("参考内容:")
retrieved_context = query_engine.query(user_query).source_nodes
for i, node in enumerate(retrieved_context):
st.write(f"**来源 {i+1}:** {node.node.text[:200]}...")
运行方式
安装依赖:
pip install llama-index langchain requests streamlit
启动 Ollama:
- 确保 Ollama 已安装并运行在本地(默认地址为
http://localhost:11434
)。 - 下载并加载目标模型(如
llama2
):ollama pull llama2
- 确保 Ollama 已安装并运行在本地(默认地址为
启动应用:
- 将上述代码保存为
app.py
。 - 在终端运行以下命令:
streamlit run app.py
- 打开浏览器访问
http://localhost:8501
。
- 将上述代码保存为
输出结果
界面截图
首页布局:
输入问题:
- 用户输入问题:“公司2023年的主要产品有哪些?”
生成回答:
回答: 根据知识库内容,公司2023年的主要产品包括智能客服系统、数据分析平台和区块链解决方案。 参考内容: 来源 1: 公司2023年发布了一系列新产品,其中包括智能客服系统... 来源 2: 数据分析平台采用了最新的机器学习算法...
关键调整点解析
Ollama 模型调用:
- 使用
requests.post
向 Ollama 的/api/generate
接口发送请求。 - 参数包括
model
(模型名称)和prompt
(输入提示)。 - 返回值为 JSON 格式,提取
response
字段作为模型输出。
- 使用
LangChain 集成:
- 自定义
OllamaLLM
类,提供与 LangChain 兼容的invoke
方法。 - 将
OllamaLLM.invoke
嵌入到链式调用中,替代原有的云端模型。
- 自定义
性能优化:
- 本地运行模型减少了网络延迟,提升了响应速度。
- 可根据硬件性能选择合适的模型(如
llama2
、mistral
等)。
应用场景
- 离线环境:适用于无法访问云端服务的场景,如内网部署。
- 隐私保护:数据完全在本地处理,避免敏感信息泄露。
- 低成本运行:无需支付云端服务费用,适合预算有限的项目。
通过将大模型调用从云端切换为本地 Ollama,我们实现了更高的灵活性和隐私保护。结合 LlamaIndex 和 LangChain 的强大功能,以及 Streamlit 的友好界面,最终构建了一个高效、易用的智能客服应用。
如果你有任何疑问或想法,欢迎在评论区交流讨论!
总结
通过本案例,我们展示了如何将 LlamaIndex 和 LangChain 的强大功能与 Streamlit 的友好界面以及本地Ollama大模型API相结合,构建一个完整的智能客服应用。这种组合不仅提升了系统的功能性,还极大地改善了用户体验。
如果你有任何疑问或想法,欢迎在评论区交流讨论!