目前基于RAG系统构建知识库的通用过程是将所有文档上传、切片、向量库,导入RAG向量库。

这种模式可以快速构建知识库,操作简单,并且在很多场合有效。然而,当用户的问题不是简单的内容查询,而是涉及一点统计逻辑时,比如“请列出库中架构相关的文档”,基于检索的RAG系统可能不能准确有效的响应问题。

这里通过"table+retriever"配置模式,基于langchain将数据库表和RAG向量库融合,扩展知识库应用的边界,尝试解决上述类似问题。

这里参考网络资料,准备实例代码,其中prompt和代码修改自reference资料的相关内容。

1 模式设计

1.1 概念探索

retriever模式处理带统计逻辑的问题时,往往面临缺乏全局信息,导致不能有效回答问题。

另外,所有文档混在一个向量库中,检索时会面临不同文档信息相互干扰的问题。

这里通过设计table+retriever,尝试解决这些问题,具体为:

基于table存储文档的全局信息,起到总领所有文档基本信息的作用。

针对每个文档构建独立检索器,避免不同文档内容之间相关干扰。

2. 具体设计

1)数据库表document

数据库表ducument示例如下,存储文档名、标签、检索器名称,页码数等基础元数据信息。

(2, 'GPU架构要点', 'retriever_arch', 68, '架构')")

document这里存储基础文档的基础元信息,能更有效的帮助langchain应对统计类问题。

2)retriever分别管理不同文档

针对不同文档,分别建立不同的retriever,目的是隔离来自不同文档切片间的相互干扰。

    v_db = FAISS.from_documents(texts, embeddings)
    v_retriever = v_db.as_retriever(search_kwargs={"k": 5})
    description = f"""名称: {contract_name} 
    标签: {tag}
    用于过滤文档内容,输入是一个用户问题question,问题与名称代表的文档内容相关。
    输出是文档中与问题question相关的内容。"""
    # 为file表示的文档单独构造工具
    retriever_tool = create_retriever_tool(
        v_retriever,
        name=name,
        description=description,
    )

目前langchain支持SQL数据库,并切通过EnsembleRetriever支持多个检索器。

由于faiss向量检索器运行开销很小,在文档数目有限情况下,针对每个文档构建检索器,运行成本开销总体可控。

2 实例示例

2.1 文档数据库表

langchain处理的文档数据库表,这里使用sqlite3创建数据库表docuemnts和导入文档数据。

import sqlite3

# 创建数据库连接
conn = sqlite3.connect('docs.db')

# 创建表
conn.execute('''CREATE TABLE documents
             (id INT PRIMARY KEY     NOT NULL,
             name           TEXT    NOT NULL,
             retriever_name      TEXT    NOT NULL,
             pages            INT     NOT NULL,
             tag         TEXT    NOT NULL);''')

# 插入数据
conn.execute("INSERT INTO documents (id, name, retriever_name, pages, tag) \
              VALUES (2, 'GPU架构要点', 'retriever_arch', 68, '架构')")
conn.execute("INSERT INTO contracts (id, name, retriever_name, pages, tag) \
              VALUES (3, 'GPU编程要点', 'retriever_coding', 13, '编程')")

# 提交更改
conn.commit()

# 关闭连接
conn.close()

2.2 文档检索器

针对每个文档,基于向量工具faiss,构建一个独立的文档检索器,主要用于文档内容检索。

import os
from langchain.agents.agent_toolkits import create_retriever_tool
from langchain_community.vectorstores import FAISS
from langchain_ollama import OllamaEmbeddings
from langchain_community.document_loaders import UnstructuredMarkdownLoader
from langchain_core.documents import Document

embeddings = OllamaEmbeddings(model="bge-m3")

for file in os.listdir(document_dir):
   
    tag = get_tag(file) # 获取文件的类别
    
    path = os.path.join(data_dir, file)
    loader = UnstructuredMarkdownLoader(path)
    pages = loader.load_and_split()
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=300,
        chunk_overlap=100,
        length_function=len,
        add_start_index=True,
    )
    
    texts = text_splitter.create_documents(
        [p.page_content for p in pages]
    )
    
    # 获取文件所示document的名称,与数据库中的retriever_name一致。
    name = get_doc_name(file)
    
    v_db = FAISS.from_documents(texts, embeddings)
    v_retriever = v_db.as_retriever(search_kwargs={"k": 5})
    description = f"""名称: {contract_name} 
    标签: {tag}
    用于过滤文档内容,输入是一个用户问题question,问题与名称代表的文档内容相关。
    输出是文档中与问题question相关的内容。"""
    
    # 为file表示的文档单独构造工具
    retriever_tool = create_retriever_tool(
        v_retriever,
        name=name,
        description=description,
    )

    contract_tools.append(retriever_tool)
 

2.3 工具集成

编写systemt_prompt,辅助langchain llm熟悉知识库的table+retriever的架构,以及如何基于用户问题选择sql工具或向量库检索工具。

from langchain_core.messages import HumanMessage
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
from langchain_core.messages import SystemMessage
from langchain_community.agent_toolkits import SQLDatabaseToolkit

# 数据库工具
toolkit = SQLDatabaseToolkit(db=db, llm=llm)
tools = toolkit.get_tools()
# 添加文档检索工具
tools += contract_tools 

# 系统提示,解释如何使用数据库表和文档检索器
SQL_PREFIX = """你是一个agent,主要用于和SQL数据库表documents和多个文档检索器交互。
每个文档,在数据库表docuemnts中有一条记录,同时对应一个文档检索工具。
示例如下,
文档 "CUDA编程指南", 在数据库表documents和检索器retriever重化工的信息示例如下
1)数据库表documents 
对应数据库documents中记录(id=10, name="CUDA编程指南", retriever_name="retriever_cuda", retriever_tag="编程", pages=10)。
2) 检索器retretiver
对应检索器retretiver中(name="retriever_cuda",  description='名称: CUDA编程指南 
标签: 编程),用于检索对应文档中的内容,输入为问题中与文档检索相关的关键词或内容,输出为文档中与问题相关的内容。

对于每个输入问题,尽力决定是使用sql检索数据库,还是使用与问题相关的检索工具直接检索文档。

你可以创建正确的sql检索并执行,之后查看直接结果。

你也可以使用文档检索器,去进一步检索相关文档中的内容,并依据文档返回内容,返回最终答案。

以下是一些执行过程中的注意事项。

You can order the results by a relevant column to return the most interesting examples in the database if you search the database.
Never query for all the columns from a specific table, only ask for the relevant columns given the question.

You have access to tools for interacting with the database and the retrievers.

Only use the below tools. Only use the information returned by the below tools to construct your final answer.
You MUST double check your query before executing it. If you get an error while executing a query, rewrite the query and try again.

DO NOT make any DML statements (INSERT, UPDATE, DELETE, DROP etc.) to the database.

To start you maybe look at the tables in the database to see what you can query. It is related to the input question.
"""

system_message = SystemMessage(content=SQL_PREFIX)

llm = ChatOpenAI(model="deepseek-r1")

agent_executor = create_react_agent(llm, tools, prompt=system_message)

2.4 应用实例

langchain针对问题,查询数据库表或检索文档,代码示例如下。

# 示例问题输入的判断和处理过程
for o1 in agent_executor.stream(
    {"messages": [HumanMessage(content="公司所有收入类项目的合同")]}
):
    print(o1)
    print("\n\n\n")

reference

---

如何使用python创建和维护sqlite3数据库

https://blog.csdn.net/liliang199/article/details/153471032

基于langgraph agent的SQL DB知识库系统

https://blog.csdn.net/liliang199/article/details/153317678

langchain基于EnsembleRetriever实现多检索器集成

https://blog.csdn.net/liliang199/article/details/153331761

langchain-examples

https://github.com/larkwins/langchain-examples

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐