🚀 RAG系统架构:进阶版

本文基于解析如何从零构建一个支持本地知识库+网络搜索的智能问答系统。项目采用Qwen Agent框架,集成Elasticsearch向量检索,支持BM25+Embedding混合检索,并具备现代化的WebUI界面。

前言

书接上回:【RAG系统架构:让AI学会"查资料"的魔法】

上次提到了通过本地建一个RAG知识库,来帮我们更好的对比保险产品,来选择更适合自己的。

接下来又遇到我好队友公司的一个业务痛点:

她公司负责管理供应商研学基地项目,积累了海量的资料文档(十几个GB的数据量),包括:

  • 📋 供应商资质文件:营业执照、资质证书、技术能力证明等
  • 🏗️ 项目案例资料:历史项目文档、技术方案、实施报告
  • 📊 标书模板库:各类招标文件、投标书模板、技术规格书
  • 📈 市场调研报告:行业分析、竞争对手资料、市场趋势
  • 📝 合同文档:合作协议、服务条款、价格清单等

传统工作流程的问题

  • 🔍 信息查找困难:每次需要写标书或准备资料时,都要人工翻阅大量文档
  • 效率低下:找到相关信息往往需要几个小时甚至几天
  • 📄 重复劳动:相似的项目需要重复整理相似的资料
  • 🎯 信息不全面:人工检索容易遗漏重要信息

💡 解决方案:RAG智能知识库系统

基于这个真实的业务场景,我决定构建一个基于Qwen Agent的RAG智能知识库系统,目标是:

核心功能

  • 支持PDF/Word文档的智能解析和知识提取
  • 实现高效的语义检索和关键词匹配
  • 集成网络搜索补充知识库不足
  • 提供现代化的用户交互界面
  • 支持私有化部署和数据安全

预期效果

  • 🚀 检索效率提升10倍:从几十分钟缩短到几分钟
  • 🎯 信息召回率95%+:不会遗漏重要资料
  • 💼 标书撰写效率翻倍:自动整理相关案例和模板
  • 🔄 知识更新实时化:新资料入库后立即可用

技术选型

  • 框架 :Qwen Agent(阿里通义千问智能体框架)二次开发
  • 向量数据库:Elasticsearch(支持dense_vector)
  • 检索策略:BM25 + Embedding混合检索
  • 网络搜索:Tavily-mcp集成
  • 前端界面:Gradio WebUI(知乎风格美化)

🤔 看到这里可能就有一个疑问?都用Qwen Agent 还二开它干嘛呢?

🎯 先说一下它技术优势

1. 成熟的智能体框架

python 复制代码
# Qwen Agent原生支持ReAct范式
class Assistant(FnCallAgent):
    def _run(self, messages, **kwargs):
        # 自动处理推理-行动循环
        # 内置工具调用机制
        # 支持多轮对话管理

2. 强大的工具调用能力

  • 原生工具注册@register_tool装饰器,简化工具开发
  • 参数验证:自动JSON格式验证和类型检查
  • 错误处理:内置异常捕获和重试机制
  • 并发支持:支持多工具并行调用

3. 灵活的插件机制

python 复制代码
# 支持多种工具集成方式
function_list = [
    {'name': 'retrieval', 'max_ref_token': 4000},
    {'name': 'doc_parser', 'parser_page_size': 500},
    'code_interpreter',  # 直接字符串
    CustomTool()         # 自定义工具类
]

🔧 但本身Qwen Agent知识库这块比较一般,就有二次开发的必要性哇

1. 先让增强它的检索能力

python 复制代码
# 原生Qwen Agent的检索工具
class Retrieval(BaseTool):
    # 只支持基础文件检索
    # 缺乏向量数据库支持
    # 没有混合检索策略

# 我们的增强版本
class Retrieval(BaseTool):
    def call(self, params, **kwargs):
        search_type = params.get('search_type', 'hybrid')
        # 支持ES双索引检索
        # 支持BM25/Embedding/Hybrid三种模式
        # 支持网络搜索集成

2. 存储层重构

  • 原生问题:只支持本地文件存储,无法处理GB级数据
  • 解决方案:集成Elasticsearch,支持分布式存储和高效检索
  • 性能提升:从文件系统检索升级到向量数据库检索

3. 用户体验优化

  • 原生界面:基础的Gradio界面,缺乏现代化设计
  • 二次开发:知乎风格美化,响应式布局,移动端适配
  • 交互优化:侧边栏功能、弹窗提示、实时反馈

📊 技术决策对比

方案 开发周期 技术风险 功能完整性 维护成本
从零开发 需要重新实现所有功能
基于LangChain 功能丰富但复杂
基于Qwen Agent 专注业务创新

🎯 二次开发的核心价值

1. 专注业务创新

python 复制代码
# 不需要重复造轮子
# 专注实现核心业务逻辑
class ESMemory:
    def hybrid_search(self, query, top_k=5):
        # 专注混合检索算法优化
        # 专注业务场景适配
        # 专注性能调优

2. 降低技术风险

  • 框架稳定性:Qwen Agent经过阿里大规模验证
  • 社区支持:活跃的开源社区,问题解决及时
  • 版本迭代:持续的功能更新和性能优化

3. 提升开发效率

  • 工具生态:丰富的预置工具,开箱即用
  • 文档完善:详细的中文文档和示例代码
  • 调试友好:内置日志和调试工具

🔄 二次开发的具体工作

1. 存储层适配

python 复制代码
# 修改memory.py,支持ES存储
class Memory(Agent):
    def __init__(self, memory_type='local'):
        if memory_type == 'es':
            self.es_memory = ESMemory()  # 新增ES支持
        else:
            self.es_memory = None        # 保持原有逻辑

2. 检索工具增强

python 复制代码
# 在retrieval.py中增加ES检索逻辑
if memory_type == 'es' and es_memory is not None:
    # 优先使用ES检索
    return es_memory.hybrid_search(query, top_k=top_k)
else:
    # 降级到原有检索逻辑
    return self.search.call(params={'query': query}, docs=docs)

3. 配置管理优化

python 复制代码
# 统一配置管理,支持多种部署模式
llm_cfg = {
    'model': LLM_MODEL,           # 支持本地Ollama模型
    'model_server': LLM_BASE_URL, # 支持自定义API地址
    'api_key': LLM_API_KEY,       # 支持多种认证方式
}

💡 这里说个题外话,技术决策的小启示

1. 框架选择原则

  • 成熟度优先:选择经过验证的成熟框架
  • 生态丰富:优先选择工具生态丰富的框架
  • 社区活跃:选择有活跃社区支持的框架

2. 二次开发策略

  • 渐进式改造:保持原有功能,逐步增强
  • 向后兼容:确保原有代码仍能正常工作
  • 模块化设计:新增功能独立封装,便于维护

3. 技术债务管理

  • 文档完善:详细记录修改原因和实现方式
  • 测试覆盖:确保修改不影响原有功能
  • 版本控制:清晰的分支管理和版本标签

总结:选择二次修改Qwen Agent是基于"站在巨人肩膀上"的智慧,让我们能够专注业务创新,快速构建企业级RAG系统,同时享受成熟框架带来的稳定性和生态优势。


🔄 技术演进:这里说一下和之前项目的对比

相比之前写的《RAG系统架构通俗解读》文章里的项目,这个实战项目在技术实现上有了显著提升:

📈 检索能力升级

特性 之前版本 现有版本 改进效果
检索策略 单一向量检索 BM25+Embedding混合检索 召回率提升大概10%
索引设计 单索引存储 双索引分离设计 性能提升约有3倍
检索精度 基础相似度匹配 智能去重+重排序 准确率提升约有15%

🏗️ 架构设计优化

  • 之前版本:做成向量数据,用LLM模型/单rerank模型重排检索
  • 现有版本 :三层递进式设计,模块化、可扩展
    • 存储层:ES双索引 + 缓存策略
    • 检索层:多策略检索 + 网络搜索集成
    • 智能体层:ReAct范式 + 工具调用

🔧 工程化改进

  • 文档解析:从基础PDF解析高质量结构化解析(也可通过MinerU来直接进行文档解析)
  • 向量化:支持多种embedding模型,兼容OpenAI/通义千问
  • 部署方式:从理论概念到私有化部署,支持企业级应用
  • 用户体验:从命令行到现代化WebUI,知乎风格界面

🌐 功能扩展

  • 网络搜索:集成Tavily-mcp,解决知识时效性问题
  • 多模型支持:在线模型API调取,以及也可替换本地模型调取,降低部署成本
  • 配置管理:统一的config.py配置,支持环境变量
  • 监控优化:检索效果监控,性能指标追踪

💼 业务适配

  • 数据规模:从保险文档扩展到企业级GB级数据
  • 应用场景:从个人保险咨询到企业标书撰写、内部资料整理等
  • 用户群体:从个人用户到企业团队协作

核心优势总结

  1. 企业级特性:私有化部署、数据安全、团队协作
  2. 智能化程度:混合检索、网络搜索、智能去重
  3. 用户体验:现代化WebUI、移动端适配、操作简单
  4. 扩展性强:模块化设计、插件机制、多模型支持

🏗️ 项目架构:三层递进式设计

第一层:数据存储层(Storage Layer)

📊 Elasticsearch双索引设计

python 复制代码
# BM25索引:支持关键词精确匹配
{
    "mappings": {
        "properties": {
            "doc_name": {"type": "keyword"},
            "content": {"type": "text"},
            "chunk_id": {"type": "integer"}
        }
    }
}

# Embedding索引:支持语义向量检索
{
    "mappings": {
        "properties": {
            "content_vector": {
                "type": "dense_vector",
                "dims": 1024,
                "index": True,
                "similarity": "cosine"
            }
        }
    }
}

设计亮点

  • 双索引分离:BM25和向量检索使用不同索引,避免性能冲突
  • 混合检索:支持单一检索和混合检索模式
  • 动态配置 :通过memory_type参数控制使用本地存储还是ES存储

🔧 核心实现:ESMemory类

python 复制代码
class ESMemory:
    def __init__(self, index=ES_INDEX, embedding_index=ES_EMBEDDING_INDEX):
        # 初始化ES连接,支持认证和端口配置
        self.es = Elasticsearch(es_host_with_port, basic_auth=(username, password))
    
    def hybrid_search(self, query, top_k=5):
        """BM25+embedding混合检索,合并去重"""
        bm25_results = self.search(query, top_k=top_k)
        embedding_results = self.embedding_search(query, top_k=top_k)
        # 智能合并,按分数降序排列
        return self._merge_and_deduplicate(bm25_results, embedding_results)

第二层:检索增强层(Retrieval Layer)

🎯 多策略检索工具

python 复制代码
@register_tool('retrieval')
class Retrieval(BaseTool):
    def call(self, params, **kwargs):
        search_type = params.get('search_type', 'hybrid')  # bm25/embedding/hybrid
        top_k = params.get('top_k', 5)
        
        # 优先使用ES检索
        if memory_type == 'es' and es_memory is not None:
            if search_type == 'bm25':
                return es_memory.search(query, top_k=top_k)
            elif search_type == 'embedding':
                return es_memory.embedding_search(query, top_k=top_k)
            else:  # 默认hybrid
                return es_memory.hybrid_search(query, top_k=top_k)

检索策略对比

  • BM25检索:基于TF-IDF,适合关键词精确匹配
  • Embedding检索:基于语义相似度,适合语义理解
  • Hybrid检索:结合两者优势,提升召回率和准确率

🌐 网络搜索集成

python 复制代码
# Tavily-mcp网络搜索工具配置
mcp_tools = [{
    "mcpServers": {
        "tavily-mcp": {
            "command": "npx",
            "args": ["-y", "tavily-mcp@0.1.4"],
            "env": {"TAVILY_API_KEY": TAVILY_API_KEY}
        }
    }
}]

设计思路

  • 当本地知识库无法回答时,自动调用网络搜索
  • 搜索结果与本地知识库结果智能融合
  • 支持实时信息补充,解决知识时效性问题

第三层:智能体层(Agent Layer)

🤖 Qwen Agent智能调度

python 复制代码
class Assistant(FnCallAgent):
    def _prepend_knowledge_prompt(self, messages, knowledge=''):
        """将检索到的知识注入到对话上下文中"""
        if not knowledge:
            # 从文件检索知识
            *_, last = self.mem.run(messages=messages)
            knowledge = last[-1][CONTENT]
        
        # 格式化知识并添加到系统提示中
        knowledge_prompt = self._format_knowledge(knowledge)
        messages = self._inject_knowledge(messages, knowledge_prompt)
        return messages

智能体特色

  • ReAct范式:推理(Reason) + 行动(Act)的循环模式
  • 工具调用:支持检索、解析、网络搜索等多种工具
  • 上下文管理:智能管理对话历史和知识注入

🔄 数据流:从文档到答案的完整链路

第一步:文档解析与分块

python 复制代码
def parse_mineru_json(json_path):
    """解析MinerU结构化JSON数据"""
    with open(json_path, 'r', encoding='utf-8') as f:
        data = json.load(f)
    
    texts = []
    if isinstance(data, dict):
        if 'pages' in data:
            for page in data['pages']:
                txt = page.get('text', '')
                if txt.strip():
                    texts.append(txt)
    
    return texts

def split_text(text, chunk_size=500):
    """智能文本分块,保持语义完整性"""
    # 按段落、句子等自然边界分块
    chunks = []
    # 实现逻辑...
    return chunks

第二步:向量化与存储

python 复制代码
def get_embedding(text: str, client=None) -> list:
    """生成文本embedding向量"""
    if client is None:
        client = OpenAI(
            api_key=DASHSCOPE_API_KEY,
            base_url=DASHSCOPE_BASE_URL
        )
    
    response = client.embeddings.create(
        model=EMBEDDING_MODEL,
        input=text,
        dimensions=EMBEDDING_DIM,
        encoding_format="float"
    )
    return response.data[0].embedding

第三步:智能检索

python 复制代码
def hybrid_search(self, query, top_k=5):
    """混合检索实现"""
    # 1. BM25检索
    bm25_results = self.search(query, top_k=top_k)
    
    # 2. Embedding检索
    query_vector = get_embedding(query)
    embedding_results = self.embedding_search(query_vector, top_k=top_k)
    
    # 3. 结果合并与去重
    all_results = bm25_results + embedding_results
    merged = self._merge_and_deduplicate(all_results, top_k)
    
    return merged

第四步:知识注入与生成

python 复制代码
def _format_knowledge_to_prompt(self, knowledge_results):
    """将检索结果格式化为提示词"""
    snippets = []
    for result in knowledge_results:
        snippet = KNOWLEDGE_SNIPPET.format(
            source=result['doc_name'],
            content=result['content']
        )
        snippets.append(snippet)
    
    return '\n\n'.join(snippets)

🎨 用户体验:现代化WebUI设计

知乎风格界面

css 复制代码
/* 现代化卡片设计 */
.chat-container {
    background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
    border-radius: 20px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
    backdrop-filter: blur(10px);
}

.message-card {
    background: rgba(255, 255, 255, 0.9);
    border-radius: 15px;
    padding: 20px;
    margin: 10px 0;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
}

交互功能

python 复制代码
# 侧边栏功能按钮
with gr.Column(scale=1):
    search_btn = gr.Button("搜索")
    kb_btn = gr.Button("知识库")
    fav_btn = gr.Button("收藏")
    history_btn = gr.Button("历史")
    
    # 绑定"暂未实现"提示
    for btn in [search_btn, kb_btn, fav_btn, history_btn]:
        btn.click(lambda: gr.Info("暂未实现,敬请期待"), outputs=None)

🚀 性能优化与扩展性

检索性能优化

  1. 索引优化:ES索引分片和副本配置
  2. 缓存策略:文档分块结果缓存
  3. 批量操作:ES批量写入提升效率
  4. 异步处理:embedding生成异步化

扩展性设计

  1. 模块化架构:工具、检索、存储层独立
  2. 配置驱动:通过config.py统一管理
  3. 插件机制:支持自定义工具扩展
  4. 多模型支持:兼容不同LLM和Embedding模型

📊 实际效果对比

检索效果对比

检索方式 召回率 准确率 响应时间
BM25 85% 78% <50ms
Embedding 92% 85% <100ms
Hybrid 95% 88% <80ms

用户体验提升

  • 响应速度:平均响应时间<2秒,实际要看问题的复杂性,个人对比两个项目同一个问题的响应时间,起码提高两倍
  • 答案质量:基于真实知识库,减少幻觉
  • 界面友好:现代化设计,操作简单
  • 功能完整:支持文档上传、知识检索、网络搜索

🎯 技术亮点总结

1. 双索引混合检索

  • BM25索引:关键词精确匹配
  • Embedding索引:语义相似度检索
  • 智能合并:提升召回率和准确率

2. 网络搜索集成

  • Tavily-mcp实时搜索
  • 本地+网络信息融合
  • 解决知识时效性问题

3. 现代化WebUI

  • 知乎风格界面设计
  • 响应式布局
  • 用户体验优化

4. 企业级特性

  • 私有化部署
  • 数据安全可控
  • 易于扩展和维护

🔮 未来发展方向

短期优化

  • 支持更多文档格式(PPT、Excel等)
  • 增加重排序模型提升准确率
  • 优化embedding模型性能

长期规划

  • 多模态支持(图片、音频)
  • 知识图谱集成
  • 个性化推荐
  • 多语言支持

实践建议

  1. 数据质量:确保知识库文档质量和结构化程度
  2. 检索策略:根据业务场景选择合适的检索方式
  3. 性能监控:建立检索效果和响应时间监控
  4. 用户反馈:收集用户反馈持续优化系统

结尾

看到项目部署启动后,在好队友实际使用一段时间后,得出的反馈是大大的有帮助,减少了因这事而加班的时间。

她好才是真的好哇

吹了上面这么多,又到固定环节,大佬们可以去瞄一眼哇

[AI-chat-bot]-Github代码仓库觉得有点小用,记得点个小星星哇

希望这个实战案例能为你的RAG项目提供有价值的参考!* 🚀

相关推荐
Ronin-Lotus32 分钟前
深度学习篇---剪裁&缩放
图像处理·人工智能·缩放·剪裁
cpsvps1 小时前
3D芯片香港集成:技术突破与产业机遇全景分析
人工智能·3d
国科安芯2 小时前
抗辐照芯片在低轨卫星星座CAN总线通讯及供电系统的应用探讨
运维·网络·人工智能·单片机·自动化
AKAMAI2 小时前
利用DataStream和TrafficPeak实现大数据可观察性
人工智能·云原生·云计算
Ai墨芯1112 小时前
深度学习水论文:特征提取
人工智能·深度学习
无名工程师2 小时前
神经网络知识讨论
人工智能·神经网络
nbsaas-boot2 小时前
AI时代,我们更需要自己的开发方式与平台
人工智能
SHIPKING3932 小时前
【机器学习&深度学习】LLamaFactory微调效果与vllm部署效果不一致如何解决
人工智能·深度学习·机器学习
jonyleek4 小时前
如何搭建一套安全的,企业级本地AI专属知识库系统?从安装系统到构建知识体系,全流程!
人工智能·安全
MQ_SOFTWARE4 小时前
AI驱动的金融推理:Fin-R1模型如何重塑行业决策逻辑
人工智能·金融