本地部署资讯问答机器人:Langchain+Ollama+RSSHub 实现 RAG

一、背景

在这个信息爆炸💥的时代,人工筛选对自己有价值的信息无异于大海捞针。不过,幸好现在有了 AI 这个强大的工具,我们可以让它来帮我们做集检索、整合与分析为一体的工作。

这里,我想以 A 股行情(其他场景也类似)问答为例,希望构建这么一个 Bot,当我问它诸如「XX股票今天表现怎么样?」、「复盘今天的家电板块」等问题时,它可以迅速从海量市场数据中找到有价值的信息,帮我进行整合与分析,然后为我提供个性化的回复。

另外,这里我还有个要求,希望能在本地私有化部署,这就意味着与 coze 无缘了。

关于 coze,可以参考我之前写的几篇文章:

经过调研,我决定先采取 Langchain+Ollama 的技术栈来作为 demo 实现,当然,后续我也会考虑使用 dify、fastgpt 等更加直观易用的 AI 开发平台。

整体框架设计思路如下

另外,本次开发的运行环境是 Intel Mac,其他操作系统也可以。下载模型等可能需要梯子。

二、Langchain 简介

www.langchain.com/langchain

Langchain 是当前大模型应用开发的主流框架之一,旨在帮助开发者构建和部署基于大型语言模型(LLM)的应用。它提供了一系列的工具和接口,使得与LLM交互变得简单。通过 Langchain,开发者可以轻松创建定制的高级应用,如聊天机器人、问答系统和多种智能应用。

Langchain 的核心在于其"链"概念,这是一个模块化的组件系统,包括 Model I/O(模型输入输出)、Retrieval(数据检索)、Chains(链)、Agents(代理)、Memory(内存)、和 Callbacks(回调)。这些组件可灵活组合,以支持复杂的应用逻辑。

Model I/O 模块负责处理与语言模型的直接交互,包括发送请求和解析响应。Retrieval 模块用于增强语言模型的回答能力,通过向量数据库检索相关信息来支持回答生成。Chains 模块则是多个组件的集成,用于构建更复杂的应用逻辑。

Langchain 的生态系统还包括 LangSmith、LangGraph 和 LangServe 等工具,这些工具能帮助开发者高效管理从原型到生产的各个阶段,以便优化 LLM 应用。

三、Ollama 简介

ollama.com/

Ollama 是一个开箱即用的用于在本地运行大模型的框架。它的主要功能和特点包括:

  1. 支持多种大型语言模型:Ollama 支持包括 通义千问、Llama 2、Mistral 和 Gemma 等在内的多种大型语言模型,这些模型可用于不同的应用场景。

  2. 易于使用:Ollama 旨在使用户能够轻松地在本地环境中启动和运行大模型,适用于 macOS、Windows 和 Linux 系统,同时支持 cpu 和 gpu。

  3. 模型库:Ollama 提供了一个模型库,用户可以从中下载不同的模型。这些模型有不同的参数和大小,以满足不同的需求和硬件条件。

  4. 自定义模型:用户可以通过简单的步骤自定义模型,例如修改模型的温度参数来调整创造性和连贯性,或者设置特定的系统消息。

  5. API 和集成:Ollama 还提供了 REST API,用于运行和管理模型,以及与其他应用程序的集成选项。

  6. 社区贡献:Ollama 社区贡献丰富,包括多种集成插件和界面,如 Web 和桌面应用、Telegram 机器人、Obsidian 插件等。

总的来说,Ollama 是一个为了方便用户在本地运行和管理大型语言模型而设计的框架,具有良好的可扩展性和多样的使用场景。

后面在捏 Bot 的过程中需要使用 Ollama,我们需要先安装,访问以下链接进行下载安装。

ollama.com/download/

安装完之后,确保 ollama 后台服务已启动(在 mac 上启动 ollama 应用程序即可,在 linux 上可以通过 ollama serve 启动)。我们可以通过 ollama list 进行确认,当我们还没下载模型的时候,正常会显示空:

可以通过 ollama 命令下载模型,

bash 复制代码
# 模型列表参考:https://ollama.com/library
$ ollama pull [model] 

目前,我下载了 4 个模型:

几个模型简介如下:

  • Gemma:Gemma 是由 Google 推出的轻量级模型,Google 表示,"Gemma 2B 和 7B 与其他开放式模型相比,在其规模上实现了同类最佳的性能。" 本次开发,下载的是 7B 模型。

  • Mistral:Mistral 是由欧洲法国 Mistral AI 团队推出的大模型,该模型采用了分组查询注意力(GQA)以实现更快的推断速度。本次开发,下载的是 7B 模型。

  • Mixtral:Mixtral 也是由 Mistral AI 团队推出的大模型,但 Mixtral 是一个 8*7B 的 MoE 模型,在大多数基准测试中都优于 Llama 2 70B 和 GPT-3.5 。

  • Qwen:Qwen(通义千问)是由阿里巴巴推出的大模型,本次开发,下载的是 7B 模型。

四、万物皆可 RSS

巧妇难为无米之炊。不管是获取日常新闻,还是获取 A 股行情,都需要有稳定靠谱的数据源。大家可能第一时间会想到爬虫,但自己去搭建和维护这样一个爬虫系统还是比较麻烦的。有没有其他更好的方式呢?

这就需要用到「上古神器」RSS 了!

大家可能会觉得 RSS 已经过时了。现如今,打开手机,今日头条、微博、微信等 APP 时不时就会给你推送最新的资讯,日常生活工作好像没有用到 RSS 的场景。

确实,大部分情况下,我们想要获取资讯,手机 APP 基本够用了。

但是,如果你想针对一些特定的需求,需要从某些网站上获取最新通知或相关信息呢?

比如,

在这种情况下,我们可能会把网站添加到书签栏,然后时不时就会打开看一下,这种做法无疑是比较低效的,一旦网站变多,更是不现实。

如果我们能把真正想要关注的信息汇聚在同一个平台上,并且一旦有更新,就能第一时间在各种终端(如电脑、手机、Kindle 等)收到提醒,那岂不是美哉。

这里,我给大家推荐一个宝藏项目:

RSSHub

docs.rsshub.app/zh/

感谢 RSSHub 这个开源项目,它给各种各样的网站生成了 RSS 源,堪称「万物皆可 RSS」。

你能想到的大部分社交媒体(如 微博、Twitter、知乎等)、传统媒体(如央视新闻、路透社等)和金融媒体(如财联社、东方财富、格隆汇等),都能够配合 RSSHub,进行订阅。

通过 RSSHub 以及其他渠道,我个人维护了一个订阅源,如下:

五、流程拆解

有了数据,就意味着成功了一半。

5.1 创建 Python 虚拟环境

创建 python 虚拟环境,并安装相关库,我安装的是当前最新的库,版本如下:

  • ollama:0.1.8
  • langchain:0.1.14
  • faiss-cpu:1.8.0 (如果有gpu,则安装gpu版本)
  • gradio:4.25.0
  • feedparser:6.0.11
  • sentence-transformers:2.6.1
  • lxml:5.2.1
bash 复制代码
$ conda create -n finance_bot python=3.10
$ conda activate finance_bot
$ pip install ollama langchain faiss-cpu gradio feedparser sentence-transformers lxml

5.2 导入依赖库

加载所需的库和模块。

python 复制代码
import ollama
import feedparser
import gradio as gr

from lxml import etree
from langchain.vectorstores import FAISS
from langchain.docstore.document import Document
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings.huggingface import HuggingFaceEmbeddings

其中,

  • feedparse 用于解析 RSS 订阅源
  • ollama 用于在 python 程序中跑大模型,使用前请确保 ollama 服务已经开启并下载好模型

5.3 从订阅源获取内容

下面函数用于从指定的 RSS 订阅 url 提取内容,这里只是给了一个 url,如果需要接收多个 url,只要稍微改动即可。然后,通过一个专门的文本拆分器将长文本拆分成较小的块,并附带相关的元数据如标题、发布日期和链接。最终,这些文档被合并成一个列表并返回,可用于进一步的数据处理或信息提取任务。

python 复制代码
def get_content(url):
    # 使用 feedparser 库来解析提供的 URL,通常用于读取 RSS 或 Atom 类型的数据流
    data = feedparser.parse(url)
    
    docs = []
    for news in data['entries']:
        # 通过 xpath 提取干净的文本内容
        summary = etree.HTML(text=news['summary']).xpath('string(.)')
        
        # 初始化文档拆分器,设定块大小和重叠大小
        text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200, length_function=len)
        
        # 拆分文档
        split_docs = text_splitter.create_documents(texts=[summary], metadatas=[{k: news[k] for k in ('title', 'published', 'link')}])
        
        # 合并文档
        docs.extend(split_docs)
                
    return data, docs

5.4 为文档内容生成向量

这里,我们使用文本向量模型 bge-m3

huggingface.co/BAAI/bge-m3

bge-m3 是智源研究院发布的新一代通用向量模型,它具有以下特点:

  • 支持超过100种语言的语义表示及检索任务,多语言、跨语言能力全面领先(Multi-Lingual)
  • 最高支持8192长度的输入文本,高效实现句子、段落、篇章、文档等不同粒度的检索任务(Multi-Granularity)
  • 同时集成了稠密检索、稀疏检索、多向量检索三大能力,一站式支撑不同语义检索场景(Multi-Functionality)

从 hf 下载好模型之后,假设放置在某个路径 /path/to/bge-m3,通过下面函数,利用 FAISS 创建一个高效的向量存储。

python 复制代码
def create_docs_vector(docs):
    # 基于 embeddings,为 docs 创建向量
    embeddings = HuggingFaceEmbeddings(model_name="/path/to/bge-m3", encode_kwargs={'normalize_embeddings': True})
    vector_store = FAISS.from_documents(docs, embeddings)
    return vector_store

5.5 实现 RAG

基于用户的问题,从向量数据库中检索相关段落,并根据设定的阈值进行过滤,最后让模型参考上下文信息回答用户的问题,从而实现 RAG。

python 复制代码
def rag_chain(question, vector_store, model='qwen', threshold=0.3):
    # 从向量数据库中检索与 question 相关的文档
    related_docs = vector_store.similarity_search_with_relevance_scores(question)

    # 过滤掉小于设定阈值的文档
    related_docs = list(filter(lambda x: x[1] > threshold, related_docs))

    # 格式化检索到的文档
    context = "\n\n".join([f'[citation:{i}] {doc[0].page_content}' for i, doc in enumerate(related_docs)])

    # 保存文档的 meta 信息,如 title、link 等
    metadata = {str(i): doc[0].metadata for i, doc in enumerate(related_docs)}

    # 设定系统提示词
    system_prompt = f"""
    当你收到用户的问题时,请编写清晰、简洁、准确的回答。
    你会收到一组与问题相关的上下文,每个上下文都以参考编号开始,如[citation:x],其中x是一个数字。
    请使用这些上下文,并在适当的情况下在每个句子的末尾引用上下文。

    你的答案必须是正确的,并且使用公正和专业的语气写作。请限制在1024个tokens之内。
    不要提供与问题无关的信息,也不要重复。
    不允许在答案中添加编造成分,如果给定的上下文没有提供足够的信息,就说"缺乏关于xx的信息"。

    请用参考编号引用上下文,格式为[citation:x]。
    如果一个句子来自多个上下文,请列出所有适用的引用,如[citation:3][citation:5]。
    除了代码和特定的名字和引用,你的答案必须用与问题相同的语言编写,如果问题是中文,则回答也是中文。

    这是一组上下文:

    {context}

    """

    user_prompt = f"用户的问题是:{question}"

    response = ollama.chat(model=model, messages=[
        {
            'role': 'system',
            'content': system_prompt
        },
        {
            'role': 'user',
            'content': user_prompt
        }
    ])

    print(system_prompt + user_prompt)

    return response['message']['content'], context

5.6 创建网页 UI

最后,通过 gradio 创建网页 UI,并进行评测。

python 复制代码
if __name__ == "__main__":
    hf_embedding = HuggingFaceEmbeddings(model_name="/path/to/bge-m3",
                                         encode_kwargs={'normalize_embeddings': True})
    
    # 财联社 RSS
    url = "https://rsshub.app/cls/depth/1003"
    data, docs = get_content(url)
    vector_store = create_docs_vector(docs, hf_embedding)
    
    # 创建 Gradio 界面
    interface = gr.Interface(
        fn=lambda question, model, threshold: rag_chain(question, vector_store, model, threshold),
        inputs=[
            gr.Textbox(lines=2, placeholder="请输入你的问题...", label="问题"),
            gr.Dropdown(['gemma', 'mistral', 'mixtral', 'qwen:7b'], label="选择模型", value='gemma'),
            gr.Number(label="检索阈值", value=0.3)
        ],
        outputs=[
            gr.Text(label="回答"),
            gr.Text(label="相关上下文")
        ],
        title="资讯问答Bot",
        description="输入问题,我会查找相关资料,然后整合并给你生成回复"
    )

    # 运行界面
    interface.launch()

生成的 Web UI 如下:

六、问答测试

对于同样的问题和上下文,我基于 Qwen-7b、Gemma、Mistral、Mixtral 和 GPT-4 分别进行了多次测试。下面是一些 case:

qwen

gemma

mistral

mixtral

gpt4

主要结论(只是针对有限的几次测试,个人主观评判)如下:

  • 👍 GPT-4 表现最好,指令遵循能力很强,在回答的时候能附上引用段落编号
  • ✌️ Mixtral 表现第二,但没有在回答的时候附上引用
  • 💪 Qwen-7b 表现第三,也没有在回答的时候附上引用
  • 😅 Gemma 表现一般,而且回答里面有一些幻觉
  • 😅 Mistral 表现一般,使用英文回复,不过在回答的时候附上了引用段落编号

总结

  1. 本文展示了如何使用 LangchainOllama 技术栈在本地部署一个资讯问答机器人,同时结合 RSSHub 来处理和提供资讯。

  2. 上下文数据质量大模型的性能决定了 RAG 系统性能的上限。

  3. RAG 通过结合检索技术和生成模型来提升答案的质量和相关性,可以缓解大模型幻觉、信息滞后的问题,但并不意味着可以消除

  4. 对于期望在本地环境利用 AI 技术来搭建 RAG 系统的用户来说,本文提供了一个具有实际操作价值的参考方案。

相关推荐
糖果店的幽灵2 分钟前
大模型测评DeepEval快速入门-安全与通用指标详解
人工智能·安全·langgraph·大模型测评·deepeval
江畔柳前堤6 小时前
roLabelImg 详细安装教程
开发语言·人工智能·后端·云原生
阿里云大数据AI技术6 小时前
分链路差异化设计的DSP准实时数仓|钛动科技基于阿里云实时计算 Flink 版 + DLF Paimon + EMR Serverless StarRocks 的实践
人工智能·flink
陕西企来客6 小时前
2026年7月AI智能搜索曝光趋势研判
大数据·人工智能·机器学习·ai智能搜索曝光
阿里云大数据AI技术7 小时前
从算力到智能体,面向 Agentic AI 的基础设施演进
人工智能·agent
hangyuekejiGEO7 小时前
GEO技术服务选型指南
大数据·人工智能·python
阿里云大数据AI技术8 小时前
EMR Serverless Spark AI Function 的双维降本实践
人工智能·sql·spark
维基框架8 小时前
GitHub源码处理提速 一趟扫描反而更慢
人工智能·github
冬奇Lab8 小时前
代码库知识库系列(05):向量检索 vs 知识图谱——加了调用图并没有变更好
人工智能
AKAMAI8 小时前
你的源服务器可能是你做出的最昂贵决定
运维·人工智能·云计算