讲师中心 微信公众号
AI工具推荐 视频效率加速

基于LangChain和FAISS构建RAG问答机器人:CSV数据集成指南

酷婷酱_4652

酷婷酱_4652

发布时间:2025-11-21 13:45:11

|

348人浏览过

|

来源于php中文网

原创

基于LangChain和FAISS构建RAG问答机器人:CSV数据集成指南

本文详细介绍了如何利用langchain、faiss和huggingface embeddings构建一个基于检索增强生成(rag)的问答机器人,使其能够根据csv文件中的特定数据生成答案。教程涵盖了从数据加载、向量数据库创建到检索器集成和llm交互的完整流程,并提供了具体的代码示例和实现细节,帮助开发者高效地将外部数据融入大型语言模型应用中。

1. 引言:检索增强生成(RAG)在问答系统中的应用

在构建基于大型语言模型(LLM)的问答系统时,一个常见的挑战是LLM可能缺乏特定领域或最新信息。检索增强生成(Retrieval Augmented Generation, RAG)是一种有效的解决方案,它允许LLM在生成答案之前,先从外部知识库中检索相关信息。本教程将指导您如何使用LangChain框架,结合FAISS向量数据库和HuggingFace Embeddings,从CSV文件中提取信息并构建一个RAG驱动的问答机器人。

2. 数据准备与向量数据库构建

首先,我们需要将CSV文件中的结构化数据转换为LLM可以理解和检索的格式。这涉及到数据加载、文本分割和嵌入生成。

2.1 数据加载与文本分割

使用LangChain的CSVLoader可以方便地加载CSV文件。为了确保每个数据点(例如CSV中的一行)都能被独立检索,我们通常会以行作为分割单位。

from langchain.vectorstores import FAISS
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.document_loaders.csv_loader import CSVLoader
import os

# 定义FAISS向量数据库的存储路径
DB_FAISS_PATH = "vectorstore/db_faiss"
# 确保目录存在
os.makedirs(DB_FAISS_PATH, exist_ok=True)

# 加载CSV文件,指定编码和分隔符
loader = CSVLoader(file_path="./data/cleanTripLisbon.csv", encoding="utf-8", csv_args={'delimiter': ','})
data = loader.load()

# 文本分割器,这里我们假设每行数据已经足够独立,或者根据实际需求进行更细致的分割
# 如果CSV每行代表一个完整的文档,可以简化分割策略
text_splitter = CharacterTextSplitter(separator='\n', chunk_size=1000, chunk_overlap=0)
text_chunks = text_splitter.split_documents(data)

print(f"Loaded {len(data)} documents from CSV, split into {len(text_chunks)} chunks.")

2.2 嵌入生成与FAISS向量数据库创建

接下来,我们需要将文本块转换为数值向量(嵌入),以便进行语义相似性搜索。HuggingFace的sentence-transformers/all-MiniLM-L6-v2是一个高效且性能良好的嵌入模型。FAISS是一个用于高效相似性搜索的库,LangChain提供了与FAISS集成的接口。

# 初始化HuggingFace嵌入模型
embeddings = HuggingFaceEmbeddings(model_name='sentence-transformers/all-MiniLM-L6-v2')

# 从文本块和嵌入模型创建FAISS向量数据库
docsearch = FAISS.from_documents(text_chunks, embeddings)

# 将FAISS索引保存到本地,以便后续加载和使用
docsearch.save_local(DB_FAISS_PATH)
print(f"FAISS vector store saved to {DB_FAISS_PATH}")

注意事项:

  • chunk_size和chunk_overlap参数在CharacterTextSplitter中非常重要,它们决定了文档如何被分割。对于CSV的每一行作为一个独立记录的情况,可以根据行内容的长度调整。
  • 选择合适的嵌入模型对检索质量至关重要。all-MiniLM-L6-v2是一个不错的起点,但对于特定领域,可能需要微调或选择更专业的模型。
  • 保存FAISS索引可以避免每次运行时都重新生成嵌入,节省时间和计算资源。

3. 构建基础聊天机器人模块

在集成检索功能之前,我们先构建一个与OpenAI API交互的基础聊天机器人模块。

3.1 OpenAI API交互封装

GPT_Helper类负责与OpenAI的聊天完成API进行交互,管理对话历史。

from openai import OpenAI
import os # 假设local_settings.py或环境变量中存储API密钥

# 为了教程的独立性,这里模拟local_settings.py
class LocalSettings:
    def __init__(self):
        self.OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") # 从环境变量获取
        if not self.OPENAI_API_KEY:
            raise ValueError("OPENAI_API_KEY environment variable not set.")

local_settings = LocalSettings()

class GPT_Helper:
    def __init__(self, OPENAI_API_KEY: str, system_behavior: str = "", model="gpt-3.5-turbo"):
        self.client = OpenAI(api_key=OPENAI_API_KEY)
        self.messages = []
        self.model = model

        if system_behavior:
            self.messages.append({
                "role": "system",
                "content": system_behavior
            })

    def get_completion(self, prompt, temperature=0):
        # 将用户提示添加到消息历史
        self.messages.append({"role": "user", "content": prompt})

        # 调用OpenAI API获取完成
        completion = self.client.chat.completions.create(
            model=self.model,
            messages=self.messages,
            temperature=temperature,
        )

        # 将助手的回复添加到消息历史
        assistant_response = completion.choices[0].message.content
        self.messages.append(
            {
                "role": "assistant",
                "content": assistant_response
            }
        )
        return assistant_response

3.2 抽象问答机器人AttractionBot

AttractionBot类封装了聊天机器人的核心逻辑,包括用户管理和响应生成。

class AttractionBot:
    def __init__(self, system_behavior: str):
        self._system_behavior = system_behavior
        self._username = None

        self.engine = GPT_Helper(
            OPENAI_API_KEY=local_settings.OPENAI_API_KEY,
            system_behavior=system_behavior
        )

    def set_username(self, username):
        self._username = username

    def generate_response(self, message: str):
        user_message = f"{self._username}: {message}" if self._username else message
        response = self.engine.get_completion(user_message)
        return response

    def reset(self):
        # 实现重置逻辑,例如清空对话历史
        self.engine.messages = []
        if self._system_behavior:
            self.engine.messages.append({"role": "system", "content": self._system_behavior})

    @property
    def memory(self):
        return self.engine.messages

    @property
    def system_behavior(self):
        return self._system_behavior

    @system_behavior.setter
    def system_behavior(self, system_config: str):
        self._system_behavior = system_config
        # 更新GPT_Helper的系统行为,并重置对话
        self.engine.messages = [{"role": "system", "content": system_config}]

4. 整合检索增强生成(RAG)功能

现在,我们将FAISS向量数据库的检索能力集成到AttractionBot中,使其能够根据用户查询从CSV数据中检索相关信息,并将其作为上下文传递给LLM。

OpenAI Codex Operator
OpenAI Codex Operator

在目标项目目录中运行 OpenAI Codex CLI,完成实现、调试等编码任务。当用户请求 OpenClaw 使用 Codex 时触发。

下载

4.1 初始化检索器

LangChain的docsearch对象提供了一个as_retriever()方法,可以将其转换为一个检索器(Retriever)。这个检索器能够根据给定的查询,从向量数据库中查找并返回最相关的文档块。

为了将检索器集成到AttractionBot中,我们需要在机器人初始化时传入docsearch对象,并将其转换为doc_retriever。

# 修改AttractionBot类的__init__方法
class AttractionBot:
    def __init__(self, system_behavior: str, docsearch): # 接受docsearch对象
        self._system_behavior = system_behavior
        self._username = None

        self.engine = GPT_Helper(
            OPENAI_API_KEY=local_settings.OPENAI_API_KEY,
            system_behavior=system_behavior
        )

        # 将docsearch转换为检索器
        self.doc_retriever = docsearch.as_retriever() # 新增行

4.2 在生成响应时使用检索器

在generate_response方法中,我们首先使用self.doc_retriever根据用户消息检索相关信息。然后,我们将这些检索到的信息与用户原始查询结合起来,构建一个新的、更丰富的提示(prompt),再将其发送给LLM。

# 修改AttractionBot类的generate_response方法
class AttractionBot:
    # ... (init方法如上所示) ...

    def generate_response(self, message: str):
        user_message = f"{self._username}: {message}" if self._username else message

        # 使用检索器获取相关信息
        # retrieve方法返回的是Document对象列表
        relevant_docs = self.doc_retriever.invoke(user_message) 

        # 将检索到的文档内容提取出来,并格式化为LLM可理解的上下文
        context = "\n".join([doc.page_content for doc in relevant_docs])

        # 构建增强后的提示,将上下文和用户问题结合
        # 这是一个关键步骤,确保LLM能够利用检索到的信息
        augmented_prompt = f"""根据以下上下文信息,回答用户的问题。
        如果上下文没有足够的信息,请说明你无法回答。

        上下文:
        {context}

        用户问题:
        {user_message}
        """

        # 使用增强后的提示生成响应
        response = self.engine.get_completion(augmented_prompt)

        return response

    # ... (其他方法) ...

关键改进点:

  • self.doc_retriever.invoke(user_message):LangChain 0.2.x 版本中,retrieve方法已更名为invoke。它接收用户查询并返回一个Document对象列表,每个Document包含page_content(文本内容)和metadata(元数据)。
  • 提示工程(Prompt Engineering):这是RAG成功的核心。我们将检索到的context明确地包含在发送给LLM的提示中。通过这种方式,LLM被“引导”去参考这些外部信息来生成答案,从而避免幻觉(hallucinations)并提高回答的准确性。提示中还加入了“如果上下文没有足够的信息,请说明你无法回答”的指令,以增强模型的鲁棒性。

5. 实例化与运行

现在,我们已经完成了所有模块的构建和集成。最后一步是实例化AttractionBot并开始与它交互。

# 确保在运行此代码之前,已经执行了“数据准备与向量数据库构建”部分的代码
# 并且DB_FAISS_PATH路径下有保存的FAISS索引

# 从本地加载FAISS向量数据库
# 需要重新初始化embeddings,因为docsearch.load_local需要它
embeddings = HuggingFaceEmbeddings(model_name='sentence-transformers/all-MiniLM-L6-v2')
loaded_docsearch = FAISS.load_local(DB_FAISS_PATH, embeddings, allow_dangerous_deserialization=True) # 注意:如果FAISS版本较新,可能需要allow_dangerous_deserialization=True

# 定义系统行为
system_behavior_config = "你是一个关于葡萄牙里斯本景点的智能助手,请根据提供的信息回答问题。"

# 实例化AttractionBot,传入系统行为和加载的docsearch对象
attraction_bot = AttractionBot(system_behavior=system_behavior_config, docsearch=loaded_docsearch)

# 设置用户名(可选)
attraction_bot.set_username("用户A")

# 模拟用户交互
print("Bot: 你好!我是里斯本景点助手,有什么可以帮你的吗?")

while True:
    user_query = input("你: ")
    if user_query.lower() == '退出':
        print("Bot: 再见!")
        break

    response = attraction_bot.generate_response(user_query)
    print(f"Bot: {response}")

    # 可以查看当前的对话历史
    # print("\n--- 对话历史 ---")
    # for msg in attraction_bot.memory:
    #     print(f"{msg['role']}: {msg['content']}")
    # print("-----------------\n")

重要提示:

  • 在加载FAISS索引时,如果遇到序列化错误,可能需要设置allow_dangerous_deserialization=True。这是由于FAISS的某些版本更新或安全策略变化导致的。
  • 确保您的OPENAI_API_KEY已正确配置为环境变量,或者在local_settings.py中安全地存储。

6. 总结与进一步优化

通过以上步骤,我们成功构建了一个基于LangChain、FAISS和CSV数据的RAG问答机器人。这个机器人能够从结构化数据中检索信息,并利用LLM生成高质量、信息丰富的答案。

进一步的优化方向:

  1. 更复杂的文本分割策略: 对于非常长的CSV行或包含多段信息的行,可能需要更智能的文本分割策略,例如基于语义或特定字段的分割。
  2. 高级检索技术: 探索使用更复杂的检索器,如多向量检索、混合检索(BM25 + 向量搜索)或上下文感知检索。
  3. RAG链(RAG Chain): LangChain提供了更高级的RAG链抽象,可以更优雅地处理检索和生成步骤,包括重排(re-ranking)检索结果、迭代检索等。
  4. 用户界面: 将此后端逻辑与Streamlit、Gradio或其他前端框架结合,可以构建一个交互式的Web应用。
  5. 错误处理与鲁棒性: 增加对API调用失败、检索无结果等情况的错误处理机制。
  6. 性能优化: 对于大规模数据集,考虑使用更高效的FAISS索引类型或分布式向量数据库。
  7. 评估: 建立评估指标来衡量RAG系统的性能,例如答案的相关性、准确性和流畅性。

通过不断迭代和优化,您可以构建出更加智能和强大的问答系统。

热门AI工具

更多
豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

火山引擎

火山引擎是一款面向企业的云计算与AI服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

相关专题

更多
什么是分布式
什么是分布式

分布式是一种计算和数据处理的方式,将计算任务或数据分散到多个计算机或节点中进行处理。本专题为大家提供分布式相关的文章、下载、课程内容,供大家免费下载体验。

1893

2023.08.11

分布式和微服务的区别
分布式和微服务的区别

分布式和微服务的区别在定义和概念、设计思想、粒度和复杂性、服务边界和自治性、技术栈和部署方式等。本专题为大家提供分布式和微服务相关的文章、下载、课程内容,供大家免费下载体验。

2554

2023.10.07

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

3048

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

4289

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

3689

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

386

2026.01.19

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

2285

2023.06.29

如何删除数据库
如何删除数据库

删除数据库是指在MySQL中完全移除一个数据库及其所包含的所有数据和结构,作用包括:1、释放存储空间;2、确保数据的安全性;3、提高数据库的整体性能,加速查询和操作的执行速度。尽管删除数据库具有一些好处,但在执行任何删除操作之前,务必谨慎操作,并备份重要的数据。删除数据库将永久性地删除所有相关数据和结构,无法回滚。

3641

2023.08.14

Buffalo框架数据库开发全教程
Buffalo框架数据库开发全教程

本专题围绕Buffalo框架数据库开发,讲解database.yml多环境配置、soda与fizz迁移生成回滚、模型结构体标签、增删改查与条件查询、一对多与多对多关联、数据校验、回调钩子、事务处理及原生SQL执行能力。

60

2026.09.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn