前言

在数字时代,如何让传统文学作品焕发新的生命力,为读者提供更智能、更深入的阅读体验?由宁渡 allen 开发的 “图书智能检索系统” 给出了创新答案。该系统基于检索增强生成(RAG)技术,将传统文学作品与现代 AI 技术深度融合,构建了一套完整的智能化文学问答体系,尤其在古典文学如《红楼梦》的深度解析方面展现出独特优势

项目概述:技术与文学的跨界融合

图书智能检索系统的核心目标是打破传统文本检索的局限,通过 AI 技术实现对文学作品的深度理解与智能问答。

效果

请添加图片描述

核心技术栈

  • 核心框架: Python 3.13
  • 编辑器: PyCharm
  • AI 模型: DeepSeek API
  • 向量化: TF-IDF + scikit-learn
  • 中文分词: jieba
  • 文档处理: 自定义文本分块算法
  • 缓存机制: pickle 序列化
  • 可视化界面: streamlit

系统核心流程

用户问题 → 文本预处理 → 向量化 → 相似度检索 → 上下文构建 → AI生成答案

系统形成从问题输入到精准回答的完整闭环,为文学爱好者、研究者提供专业级的文本解析服务。

核心架构:SmartLibRAG 类的设计与实现

系统的核心功能集中于SmartLibRAG类,其设计体现了模块化、可扩展的架构思想,关键核心代码如下:

1. 初始化设计

def __init__(self, api_key: str, docs_dir: str = "docs"):
    # 依赖注入API密钥,便于测试和部署
    self.api_key = api_key
    # 路径抽象处理
    self.docs_dir = Path(docs_dir)
    # 预设缓存目录
    self.cache_dir = Path(".cache")
    self.cache_dir.mkdir(exist_ok=True)
    # 组件分离管理
    self.vectorizer = None
    self.vector_index = None
    self.documents = []
    self.chunks = []
    # 加载停用词
    self.stopwords = {'的', '了', '在', '是', '我', '有', '和', '就', '不', '人', '都', '一', '一个', '上', '也', '很', '到', '说', '要', '去', '你', '会', '着', '没有', '看', '好', '自己', '这'}

2.文档加载策略

def load_documents(self) -> None:
    """使用生成器模式遍历文件,支持异常处理"""
    if not self.docs_dir.exists():
        self.docs_dir.mkdir(exist_ok=True)
        return
    
    # 生成器遍历文档目录
    for file_path in self.docs_dir.glob("*.txt"):
        try:
            with open(file_path, "r", encoding="utf-8") as f:
                content = f.read()
            # 结构化存储元信息
            self.documents.append({
                "filename": file_path.name,
                "path": str(file_path),
                "content": content
            })
        except Exception as e:
            print(f"加载文件 {file_path.name} 失败: {str(e)}")
            continue

3. 智能文本分块算法

def split_text_into_chunks(self, text: str, chunk_size: int = 300, overlap: int = 50):
    """基于语义边界的文本分块,保持语义完整性"""
    # 按中文标点分句
    sentences = re.split(r'([。!?;:""()【】《》、])', text)
    # 重组句子(保留标点)
    sentences = [''.join(pair) for pair in zip(sentences[::2], sentences[1::2])] if len(sentences) > 1 else sentences
    chunks = []
    current_chunk = ""
    
    for sentence in sentences:
        if len(current_chunk) + len(sentence) <= chunk_size:
            current_chunk += sentence
        else:
            if current_chunk:
                chunks.append(current_chunk.strip())
            # 动态调整:如果单句超长,直接作为一个块
            current_chunk = sentence if len(sentence) <= chunk_size else sentence[:chunk_size]
    
    if current_chunk:
        chunks.append(current_chunk.strip())
    
    # 可扩展重叠逻辑
    if len(chunks) > 1 and overlap > 0:
        # 示例重叠实现(当前未启用)
        pass
    
    return chunks

4. 中文 NLP 处理

def chinese_tokenizer(self, text):
    """中文分词与过滤:分词→长度过滤→停用词过滤→标点过滤"""
    import jieba
    # jieba分词
    words = jieba.cut(text)
    filtered_words = []
    
    for word in words:
        # 多重过滤逻辑
        if (word and 
            len(word) > 1 and  # 过滤单字符
            word not in self.stopwords and  # 过滤停用词
            not word.isspace() and  # 过滤空白字符
            not all(char in ',。!?;:""()【】《》、' for char in word)):  # 过滤纯标点
            filtered_words.append(word)
    
    return filtered_words

5. 向量索引构建(TF-IDF)

核心公式

"""
TF-IDF = 词频(TF) × 逆文档频率(IDF)
TF = 某个词在文章中的出现次数 / 文章总词数
IDF = log(语料库的文档总数 / 包含该词的文档数 + 1)
"""

示例代码

def build_vector_index(self) -> None:
    """构建TF-IDF向量索引,支持缓存恢复"""
    from sklearn.feature_extraction.text import TfidfVectorizer
    import numpy as np
    
    # 检查缓存
    cache_file = self.cache_dir / "vector_index.pkl"
    if cache_file.exists():
        with open(cache_file, "rb") as f:
            cache_data = pickle.load(f)
        self.vectorizer = TfidfVectorizer(
            tokenizer=self.chinese_tokenizer,
            vocabulary=cache_data['vocabulary']
        )
        self.vectorizer.idf_ = cache_data['idf']
        self.vector_index = cache_data['index']
        return
    
    # 构建向量器
    self.vectorizer = TfidfVectorizer(
        tokenizer=self.chinese_tokenizer,
        max_features=5000,  # 控制词汇表大小
        ngram_range=(1, 2),  # 包含单词和双词组合
        min_df=1,  # 过滤低频词
        max_df=0.95  # 过滤高频词
    )
    
    # 训练并生成向量索引
    chunk_texts = [chunk['content'] for chunk in self.chunks]
    self.vector_index = self.vectorizer.fit_transform(chunk_texts)
    
    # 缓存保存
    cache_data = {
        'vocabulary': self.vectorizer.vocabulary_,
        'idf': self.vectorizer.idf_,
        'index': self.vector_index
    }
    with open(cache_file, "wb") as f:
        pickle.dump(cache_data, f)

# TF-IDF示例演示
tf = TfidfVectorizer(norm='l2')
train = ["Chinese Beijing Chinese", "Chinese Chinese shanghai", "Chinese Macao", "Tokyo Japan, Chinese"]
tf.fit(train)
print(tf.get_feature_names_out())  # 输出:['beijing' 'chinese' 'japan' 'macao' 'shanghai' 'tokyo']
test = ["Chinese Chinese Chinese Tokyo Japan"]
tf_fit = tf.transform(test)
print(tf_fit.toarray())  # 输出:[[0.        0.7420575 0.4739993 0.        0.        0.4739993]]

6. 检索算法优化

def search_relevant_chunks(self, query: str, top_k: int = 10, similarity_threshold: float = 0.01):
    """优化检索:阈值过滤→有效结果排序→数量控制"""
    import numpy as np
    from sklearn.metrics.pairwise import cosine_similarity
    
    #  query向量化
    query_vec = self.vectorizer.transform([query])
    # 计算相似度
    similarities = cosine_similarity(query_vec, self.vector_index)[0]
    
    # 性能优化:只处理有效结果
    valid_indices = np.where(similarities > similarity_threshold)[0]
    # 降序排序
    sorted_indices = valid_indices[np.argsort(similarities[valid_indices])[::-1]]
    
    # 取top_k结果
    top_indices = sorted_indices[:top_k]
    results = []
    for idx in top_indices:
        results.append({
            "content": self.chunks[idx]['content'],
            "source": self.chunks[idx]['source'],
            "similarity": float(similarities[idx])
        })
    
    return results

7. AI 生成模块(Prompt 工程 + 错误处理)

系统提示词

SYSTEM_PROMPT = """
# Role: 红楼梦研究专家
## Profile
- language: 中文
- description: 精通《红楼梦》文本及红学研究,能够深入解析作品的人物、情节、诗词及文化内涵
- background: 多年从事《红楼梦》研究与教学,参与过多项红学课题研究
- personality: 严谨细致,富有文人气质,善于引经据典
- expertise: 文本分析、人物研究、诗词鉴赏、文化解读
- target_audience: 红学爱好者、文学研究者、学生群体
## Skills
1. 文本解析能力:情节梳理、细节把握、人物分析、诗词解读
2. 学术研究能力:文献考证、文化阐释、比较研究、版本鉴别
## Rules
1. 回答原则:基于文本、严谨准确、深度解析、客观公正
2. 行为准则:引经据典、语言典雅、层次分明、深入浅出
3. 限制条件:不涉争议、不妄评续作、不越文本、不代作者
## Workflows
- 步骤 1: 仔细理解用户问题,明确询问重点
- 步骤 2: 检索相关文本段落,确认信息准确性
- 步骤 3: 组织回答内容,适当引用原文
- 步骤 4: 以典雅文风呈现完整解答
## Initialization
作为红楼梦研究专家,你必须遵守上述Rules,按照Workflows执行任务。
"""

生成函数

def generate_answer(self, query: str, context_chunks: List[Dict]) -> str:
    """基于上下文生成专业回答,包含错误处理"""
    import requests
    
    # 构建上下文
    context_text = "\n\n".join([f"【参考片段】{chunk['content']}" for chunk in context_chunks])
    user_prompt = f"用户问题:{query}\n\n参考上下文:{context_text}\n\n请基于上述参考上下文,以红楼梦研究专家的身份回答用户问题,要求引经据典、语言典雅、准确严谨。"
    
    try:
        # 调用DeepSeek API
        response = requests.post(
            "https://api.deepseek.com/v1/chat/completions",
            headers={
                "Content-Type": "application/json",
                "Authorization": f"Bearer {self.api_key}"
            },
            json={
                "model": "deepseek-chat",
                "messages": [
                    {"role": "system", "content": SYSTEM_PROMPT},
                    {"role": "user", "content": user_prompt}
                ],
                "temperature": 0.3
            }
        )
        response.raise_for_status()
        return response.json()["choices"][0]["message"]["content"]
    
    except Exception as e:
        error_type = type(e).__name__
        error_details = str(e) if str(e) else "未知错误"
        return f"生成答案时出错: {error_type} - {error_details}"

8. 统一问答接口

def ask(self, question: str, top_k: int = 10, similarity_threshold: float = 0.01) -> Dict:
    """统一问答接口:参数可配置、结构化返回、来源追踪"""
    # 检索相关片段
    relevant_chunks = self.search_relevant_chunks(question, top_k, similarity_threshold)
    # 生成答案
    answer = self.generate_answer(question, relevant_chunks)
    # 构建来源信息
    sources = [
        {
            "source": chunk["source"],
            "similarity": chunk["similarity"],
            "content_preview": chunk["content"][:100] + "..." if len(chunk["content"]) > 100 else chunk["content"]
        }
        for chunk in relevant_chunks
    ]
    
    # 结构化返回
    return {
        'question': question,
        'answer': answer,
        'sources': sources
    }

部署与使用

1.环境配置

# 根目录创建.env文件
DEEPSEEK_API_KEY=your_api_key_here

2. 初始化流程

from smart_lib_rag import SmartLibRAG
import os
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()
api_key = os.getenv("DEEPSEEK_API_KEY")

# 初始化系统
rag = SmartLibRAG(api_key=api_key)
rag.initialize()  # 一键初始化所有组件(加载文档→分块→构建向量索引)

3.streamlit 可视化界面

页面配置

import streamlit as st

# 页面基础配置
st.set_page_config(
    page_title="图书智能检索系统",
    page_icon="📚",
    layout="wide",
    initial_sidebar_state="expanded"
)

自定义样式

# 注入自定义CSS
st.markdown("""
<style>
@import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;600;700&display=swap');
.main-header {
    font-size: 3rem;
    background: linear-gradient(135deg, #8B4513, #CD853F);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    text-align: center;
    margin-bottom: 2rem;
    font-weight: 700;
    font-family: 'Noto Serif SC', serif;
}
.chat-message {
    padding: 1.2rem;
    border-radius: 1rem;
    margin-bottom: 1rem;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.user-message {
    background: linear-gradient(135deg, #e3f2fd, #bbdefb);
    border-left: 4px solid #2196f3;
    margin-left: 2rem;
}
.assistant-message {
    background: linear-gradient(135deg, #fff8e1, #ffecb3);
    border-left: 4px solid #8B4513;
    margin-right: 2rem;
}
.source-info {
    background: linear-gradient(135deg, #f3e5f5, #e1bee7);
    padding: 0.8rem;
    border-radius: 0.8rem;
    margin-top: 0.8rem;
    font-size: 0.9rem;
}
</style>
""", unsafe_allow_html=True)

聊天消息显示函数

def display_chat_message(role, content, sources=None, typing=False):
    """显示聊天消息,支持来源展开"""
    if role == "user":
        st.markdown(f"""
        <div class="chat-message user-message">
            <strong>🙋‍♀️ 您:</strong> {content}
        </div>
        """, unsafe_allow_html=True)
    else:
        typing_indicator = '<span class="typing-indicator">💭</span>' if typing else '🤖'
        st.markdown(f"""
        <div class="chat-message assistant-message">
            <strong>{typing_indicator} 红楼梦助手:</strong> {content}
        </div>
        """, unsafe_allow_html=True)
        if sources:
            with st.expander(f"📖 参考文档片段 ({len(sources)}个)", expanded=False):
                for i, source in enumerate(sources, 1):
                    # 相似度颜色标记
                    similarity_color = "#4caf50" if source['similarity'] > 0.5 else "#ff9800" if source['similarity'] > 0.3 else "#f44336"
                    st.markdown(f"""
                    <div class="source-info">
                        <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem;">
                            <strong>📄 片段 {i}: {source['source']}</strong>
                            <span style="background: {similarity_color}; color: white; padding: 0.2rem 0.5rem; border-radius: 1rem; font-size: 0.8rem;">
                                相似度: {source['similarity']:.3f}
                            </span>
                        </div>
                        <div style="background: rgba(255,255,255,0.8); padding: 0.5rem; border-radius: 0.5rem; border-left: 3px solid {similarity_color};">
                            <em>📝 内容预览:</em><br>
                            {source['content_preview']}
                        </div>
                    </div>
                    """, unsafe_allow_html=True)

性能优化与扩展方向

性能优化建议

  1. 缓存策略优化:实现文件变更检测、添加内存缓存层、集成 Redis 外部缓存

  2. 检索算法优化:引入 Faiss 专业向量检索库、实现多路召回策略、添加查询扩展机制

  3. 并发处理:支持异步处理、实现请求队列管理、多进程部署

扩展方向

  1. 多模态支持:图片内容理解、音频问答功能

  2. 知识图谱集成:构建人物关系图谱、情节时间线可视化

  3. 个性化推荐:用户兴趣建模、智能问题推荐

总结

图书智能检索系统以 RAG 技术为核心,通过精巧的架构设计与细致的工程实现,打通了传统文学文本与现代 AI 的连接通道。其核心代码的模块化设计既保证了当前功能的稳定运行,也为未来扩展预留了充足空间,为文学智能分析领域提供了可复用、可扩展的解决方案。

文档资料

请添加图片描述
另外更多大模型面试题
请添加图片描述

更多推荐