mcpField
D
document-chat-interface

document-chat-interface

github.com/qodex-ai开发47146 次安装42 周前更新
代码仓库

关于 document-chat-interface

用于构建文档对话界面的开发指南,让用户以自然语言查询文档。内容涵盖文档导入、检索、对话上下文和引用,并提供 LangChain、LlamaIndex 与 RAG 实现示例。

主要功能

  1. 01处理 PDF、代码库、邮件和网页
  2. 02提取、清理、分块并标注文本
  3. 03维护对话上下文
  4. 04生成带来源引用的回答
  5. 05支持问题改写和后续提问

适用场景

  1. 01为报告或研究论文构建问答
  2. 02以对话方式搜索邮件归档
  3. 03通过提问探索代码库
  4. 04创建可交互的公司文档资源

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/qodex-ai/ai-agent-skills --skill document-chat-interface

安装后在 Claude Code 中输入/document-chat-interface确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

examples/
conversation_manager.py
document_processors.py
text_processor.py

详细介绍

文档聊天界面

构建智能聊天界面,让用户能够使用自然语言查询文档并与之互动,将静态文档转变为交互式知识源。

概述

文档聊天界面结合了三种能力:

  1. 文档处理 - 提取并准备文档
  2. 语义理解 - 理解问题并查找相关内容
  3. 对话界面 - 保持上下文并提供自然的回复
常见应用
  • PDF 问答:回答有关研究论文、报告和书籍的问题
  • 电子邮件搜索:以对话方式查找电子邮件存档中的信息
  • GitHub 探索器:询问有关代码仓库的问题
  • 知识库:交互式访问公司文档
  • 合同审查:使用自然语言查询法律文档
  • 研究助手:交互式探索学术论文

架构

Document Source
    ↓
Document Processor
    ├→ Extract text
    ├→ Process content
    └→ Generate embeddings
    ↓
Vector Database
    ↓
Chat Interface ← User Question
    ├→ Retrieve relevant content
    ├→ Maintain conversation history
    └→ Generate response

核心组件

1. 文档来源

实现示例请参见 examples/document_processors.py:

PDF 文档
  • 从 PDF 页面中提取文本
  • 保留文档结构和元数据
  • 使用 OCR(pytesseract)处理扫描版 PDF
  • 提取表格(pdfplumber)
GitHub 仓库
  • 从仓库中提取代码文件
  • 解析仓库结构
  • 处理多种文件类型
电子邮件存档
  • 提取电子邮件元数据(发件人、收件人、主题、日期)
  • 解析电子邮件正文内容
  • 处理多种邮箱格式
网页
  • 提取页面文本和结构
  • 保留标题层级
  • 提取链接和导航
YouTube/音频
  • 获取 YouTube 视频的文字稿
  • 转录音频文件
  • 处理多种格式
2. 文档处理

实现示例请参见 examples/text_processor.py:

文本提取与清理
  • 移除多余的空白和特殊字符
  • 使用重叠片段进行智能文本分块
  • 智能检测句子边界
元数据提取
  • 提取标题、作者、日期和语言
  • 计算字数和文档统计信息
  • 跟踪文档来源和格式
保留结构
  • 在文本块中保留标题层级
  • 保留章节上下文
  • 支持分层检索
3. 聊天界面设计

实现示例请参见 examples/conversation_manager.py:

对话管理
  • 在大小限制内保留对话历史
  • 跟踪消息元数据(时间戳、角色)
  • 为大模型集成提供上下文
  • 按需清除历史记录
问题完善
  • 补全问题中的隐含指代
  • 处理代词和上下文指代
  • 利用先前的上下文改善问题表述
回复生成
  • 使用文档上下文回答问题
  • 在提示词中保留对话历史
  • 提供来源引用
  • 处理超出范围的问题
4. 用户体验功能
引用与来源
def format_response_with_citations(response: str, sources: List[Dict]) -> str:
    """Add source citations to response"""

    formatted = response + "\n\n**Sources:**\n"
    for i, source in enumerate(sources, 1):
        formatted += f"[{i}] Page {source['page']} of {source['source']}\n"
        if 'excerpt' in source:
            formatted += f"    \"{source['excerpt'][:100]}...\"\n"

    return formatted
澄清问题
def generate_follow_up_questions(context: str, response: str) -> List[str]:
    """Suggest follow-up questions to user"""

    prompt = f"""
    Based on this Q&A, generate 3 relevant follow-up questions:
    Context: {context[:500]}
    Response: {response[:500]}
    """

    follow_ups = llm.generate(prompt)
    return follow_ups
错误处理
def handle_query_failure(question: str, error: Exception) -> str:
    """Handle when no relevant documents found"""

    if isinstance(error, NoRelevantDocuments):
        return (
            "I couldn't find information about that in the documents. "
            "Try asking about different topics like: "
            + ", ".join(get_main_topics())
        )
    elif isinstance(error, ContextTooLarge):
        return (
            "The answer requires too much context. "
            "Can you be more specific about what you'd like to know?"
        )
    else:
        return f"I encountered an issue: {str(error)[:100]}"

实现框架

使用 LangChain
from langchain.document_loaders import PDFLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chat_models import ChatOpenAI
from langchain.chains import ConversationalRetrievalChain

# Load document
loader = PDFLoader("document.pdf")
documents = loader.load()

# Split into chunks
splitter = CharacterTextSplitter(chunk_size=1000)
chunks = splitter.split_documents(documents)

# Create embeddings
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(chunks, embeddings)

# Create chat chain
llm = ChatOpenAI(model="gpt-4")
qa = ConversationalRetrievalChain.from_llm(
    llm=llm,
    retriever=vectorstore.as_retriever(),
    return_source_documents=True
)

# Chat interface
chat_history = []
while True:
    question = input("You: ")
    result = qa({"question": question, "chat_history": chat_history})
    print(f"Assistant: {result['answer']}")
    chat_history.append((question, result['answer']))
使用 LlamaIndex
from llama_index import GPTVectorStoreIndex, SimpleDirectoryReader, ChatMemoryBuffer
from llama_index.llms import ChatMessage, MessageRole

# Load documents
documents = SimpleDirectoryReader("./docs").load_data()

# Create index
index = GPTVectorStoreIndex.from_documents(documents)

# Create chat engine with memory
chat_engine = index.as_chat_engine(
    memory=ChatMemoryBuffer.from_defaults(token_limit=3900),
    llm="gpt-4"
)

# Chat loop
while True:
    question = input("You: ")
    response = chat_engine.chat(question)
    print(f"Assistant: {response}")
使用基于 RAG 的方法
from sentence_transformers import SentenceTransformer
import faiss
import numpy as np

# Load and embed documents
model = SentenceTransformer('all-MiniLM-L6-v2')
documents = load_documents("document.pdf")
embeddings = model.encode(documents)

# Create FAISS index
dimension = embeddings.shape[1]
index = faiss.IndexFlatL2(dimension)
index.add(np.array(embeddings).astype('float32'))

# Chat function
def chat(question):
    # Embed question
    q_embedding = model.encode(question)

    # Retrieve documents
    k = 5
    distances, indices = index.search(
        np.array([q_embedding]).astype('float32'), k
    )

    # Get relevant documents
    context = " ".join([documents[i] for i in indices[0]])

    # Generate response
    response = llm.generate(
        f"Context: {context}\nQuestion: {question}\nAnswer:"
    )
    return response

最佳实践

文档处理
  • ✓ 支持多种格式(PDF、TXT、docx 等)
  • ✓ 高效处理大型文档
  • ✓ 保留文档结构
  • ✓ 提取元数据
  • ✓ 处理多种语言
  • ✓ 为扫描版 PDF 实现 OCR
对话质量
  • ✓ 保持对话上下文
  • ✓ 提出澄清问题
  • ✓ 引用来源
  • ✓ 处理歧义
  • ✓ 建议后续问题
  • ✓ 处理超出范围的问题
性能
  • ✓ 优化检索速度
  • ✓ 实现缓存
  • ✓ 处理大型文档集
  • ✓ 批量处理文档
  • ✓ 监控延迟
  • ✓ 实现分页
用户体验
  • ✓ 清晰的回复格式
  • ✓ 支持引用来源
  • ✓ 文档浏览器/探索器
  • ✓ 搜索建议
  • ✓ 查询历史
  • ✓ 导出对话

常见挑战与解决方案

挑战:回答无关

解决方案:

  • 改进检索(提供更多上下文,使用更好的嵌入)
  • 根据上下文验证答案
  • 提出澄清问题
  • 实施置信度评分
  • 使用混合搜索
挑战:多轮对话中丢失上下文

解决方案:

  • 保留对话记忆
  • 根据历史记录更新检索
  • 总结较长的对话
  • 重新调整先前查询的权重
挑战:处理长文档

解决方案:

  • 分层分块
  • 先进行总结
  • 优化问题
  • 多跳检索
  • 文档导航
挑战:上下文窗口有限

解决方案:

  • 压缩检索到的上下文
  • 使用文档摘要
  • 分层检索
  • 聚焦最相关的章节
  • 迭代优化

高级功能

多文档分析
def compare_documents(question: str, documents: List[str]):
    """Analyze and compare across multiple documents"""
    results = []

    for doc in documents:
        response = query_document(doc, question)
        results.append({
            "document": doc.name,
            "answer": response
        })

    # Compare and synthesize
    comparison = llm.generate(
        f"Compare these answers: {results}"
    )
    return comparison
交互式文档探索
class DocumentExplorer:
    def __init__(self, documents):
        self.documents = documents

    def browse_by_topic(self, topic):
        """Find documents by topic"""
        pass

    def get_related_documents(self, doc_id):
        """Find similar documents"""
        pass

    def get_key_terms(self, document):
        """Extract key terms and concepts"""
        pass

资源

文档处理库
  • PyPDF:处理 PDF
  • python-docx:处理 Word 文档
  • BeautifulSoup:网页抓取
  • youtube-transcript-api:YouTube 字幕文本
聊天框架
  • LangChain:综合框架
  • LlamaIndex:专注于文档
  • RAG 库:集成向量数据库

实施清单

  • 选择要支持的文档来源
  • 实现文档加载和处理
  • 设置向量数据库/嵌入
  • 构建聊天界面
  • 实现对话管理
  • 添加来源引用
  • 处理边缘情况(大型文档、OCR 等)
  • 实现错误处理
  • 添加性能监控
  • 使用真实文档进行测试
  • 部署并监控

开始使用

  1. 从简单开始:单个 PDF,基础聊天
  2. 添加功能:多文档、对话历史
  3. 提升质量:更好的分块和检索
  4. 扩展规模:支持更多格式和更大的文档
  5. 完善体验:改进用户体验,处理错误

评论

支持 Markdown