在信息爆炸的时代,我们每天都需要处理大量文档。无论是PDF报告、Word文档还是Excel表格,从中快速提取关键信息并与之交互变得至关重要。今天,我将分享如何使用LangChain和Gradio构建一个强大的文档智能对话助手,让你可以通过自然语言与任何文档进行对话。

一、项目概述

这个文档对话助手能够:
支持多种格式:PDF、Word、Excel、TXT
智能文档处理:自动分割、向量化存储
精准检索:基于语义相似度查找相关信息
自然对话:用自然语言提问并获得准确回答

二、技术架构

文档上传 → 文本提取 → 文档分割 → 向量嵌入 → 向量数据库 → 语义检索 → LLM生成回答

三、分步解析实现原理

步骤1:文档加载器 - 多格式支持
def read_file(self, doc_path):
    """读取文档"""
    loaders = {
        "docx": Docx2txtLoader,
        "pdf": PyPDFLoader,
        "xlsx": UnstructuredExcelLoader,
        "txt": TextLoader
    }
    file_extension = doc_path.split(".")[-1].lower()
    loader_class = loaders.get(file_extension)
    
    if loader_class:
        try:
            if file_extension == "txt":
                loader = loader_class(doc_path, encoding="utf-8")
            else:
                loader = loader_class(doc_path)
            documents = loader.load()
            return documents
        except Exception as e:
            raise Exception(f"文档读取失败: {str(e)}")
    else:
        raise Exception(f"不支持的文件格式: {file_extension}")

原理说明:

使用LangChain的文档加载器将不同格式的文件转换为统一格式
PyPDFLoader:解析PDF文件,提取文本和元数据
Docx2txtLoader:处理Word文档,保留格式信息
UnstructuredExcelLoader:读取Excel表格,转换为结构化文本
TextLoader:直接读取纯文本文件,支持UTF-8编码

步骤2:文本分割 - 优化检索效果
def split_document(self, documents):
    """分割文档"""
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=300,  # 每个文本块的大小
        chunk_overlap=50,  # 块之间的重叠部分
        separators=["\n\n", "\n", "。", "!", "?", "\.", "!", "\?", " ", ""],
        length_function=len,
        is_separator_regex=False,
        keep_separator=True
    )
    split_content = text_splitter.split_documents(documents)
    return split_content

原理说明:
递归字符分割器:按照优先级的顺序尝试不同的分隔符
块大小与重叠:300字符的块大小平衡了上下文完整性和检索精度,50字符的重叠确保重要信息不丢失
中文友好分隔符:特别加入了中文标点作为分隔符,如"。“、”!“、”?"

步骤3:向量嵌入 - 语义理解核心
def create_embeddings(self):
    """创建向量库"""
    # 3. 创建嵌入模型
    embedding_model = OllamaEmbeddings(
        model=EMBEDDING_MODEL,
        base_url=OLLAMA_BASE_URL
    )
    # 4. 创建向量库
    self.vector_db = Chroma.from_documents(
        documents=self.split_content,
        embedding=embedding_model,
        collection_name="document_chat",
        persist_directory=self.chroma_dir
    )

原理说明:
嵌入模型:使用Ollama运行BGE-M3模型,将文本转换为高维向量
语义理解:相似的文本内容会生成相近的向量表示
Chroma向量数据库:轻量级、高效的向量存储和检索系统
持久化存储:临时目录保存向量数据,支持重启后恢复

步骤4:智能检索 - 上下文压缩技术
def retrieve_context(self, question):
    """检索相关上下文"""
    # 使用上下文压缩检索降低冗余信息
    compressor = LLMChainExtractor.from_llm(llm=llm)
    # 通过LLM提取最相关的信息
    compressor_retriever = ContextualCompressionRetriever(
        base_retriever=self.vector_db.as_retriever(),
        base_compressor=compressor
    )
    results = compressor_retriever.invoke(question)
    return results

原理说明:
上下文压缩:使用LLM筛选和压缩检索结果,去除冗余信息
双重过滤:先进行向量相似度检索,再用LLM进行精炼
提高精度:确保返回的上下文最相关、最简洁

步骤5:提示工程 - 引导AI正确回答
self.template = [
    ("system", """你是一个专业的文档处理助手。请根据下面提供的文档上下文内容回答问题。
    上下文内容:
    {context}
    要求:
    1. 只基于提供的上下文回答,不要编造信息
    2. 保持回答简洁、专业
    3. 如果用户询问文档内容总结,请基于上下文提供关键点"""),
    ("human", "{question}")
]
self.prompt = ChatPromptTemplate.from_messages(self.template)

原理说明:
系统指令:明确AI的角色和行为规范
上下文注入:将检索到的文档片段作为上下文提供
约束条件:防止AI产生幻觉,确保回答基于文档
任务指导:针对总结类问题提供具体指导

步骤6:对话处理 - 完整的问答流程
def chat(self, question, history):
    """处理聊天"""
    # 1. 检索相关上下文
    context_docs = self.retrieve_context(question)
    # 2. 合并上下文
    context_text = "\n\n".join([doc.page_content for doc in context_docs])
    # 3. 格式化prompt
    formatted_prompt = self.prompt.format(
        context=context_text[:3000],  # 限制长度
        question=question
    )
    # 4. 调用LLM
    response = llm.invoke(formatted_prompt)
    return response

原理说明:
检索增强生成(RAG):结合检索和生成的优势
上下文长度限制:避免超过模型的最大上下文长度
流式响应:支持逐步显示回答内容

步骤7:Gradio界面 - 用户友好交互
def chat_with_doc(message, history):
    if message is None:
        return "", ""
    # 1. 确保history是列表
    if history is None:
        history = []
    history.append({"role": "user", "content": message})
    history.append({"role": "assistant", "content": "⏳ 文档检索中..."})
    yield "", history
    # 2. 获取响应
    response = chat_assistant.chat(message, history)
    response_text = str(response.content)
    # 3. 添加到历史
    history.pop()
    history.append({"role": "assistant", "content": response_text})
    yield "", history

界面特点:
分栏布局:左侧文档处理,右侧对话交互
状态反馈:实时显示处理进度和结果
示例问题:提供常用问题模板,降低使用门槛
响应式设计:适配不同屏幕尺寸

四、功能演示

以学术论文分析为场景进行演示
上传一篇DOCX格式的论文,可以提问:
“这篇论文的研究方法是什么?”
“实验的主要结论有哪些?”
“与之前的研究相比有什么创新?”

1. 上传文档并进行向量化处理

选择一篇毕业设计论文,点击处理文档按钮
在这里插入图片描述

2. 处理完成后进行对话

在这里插入图片描述

3. 对话演示

Q1:整个系统的主要架构是什么?
在这里插入图片描述
Q2:整个系统有哪些数据库表?
在这里插入图片描述
Q3:这篇论文的指导老师是谁?
在这里插入图片描述

五、总结

这个文档智能对话助手展示了LangChain和Gradio的强大组合:
LangChain:提供了完整的LLM应用开发框架
Gradio:快速构建直观的用户界面
RAG架构:结合了检索的准确性和生成的自然性

通过这个项目,你可以:
深入理解RAG(检索增强生成)的工作原理
掌握多格式文档处理的技术细节
学习如何构建实用的AI应用界面
为更复杂的文档处理任务打下基础

未来可以进一步扩展的功能包括:
支持更多文件格式(PPT、图片OCR等)
多文档联合检索
对话历史持久化
高级检索算法(HyDE、Multi-Query等)

希望这个项目能帮助你更好地理解和应用现代AI技术,构建更智能的文档处理工具!

Logo

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

更多推荐