【RAG从入门到精通系列】【RAG From Scratch 系列教程3: Routing】


前言

"检索增强生成”(RAG)系列教程3:Routing 路由模块,即怎么将用户问题连接到最相关的数据源。

一、概述

1-1、RAG概念

概念:目前的LLM通常是用很多已经存在的文字数据训练出来的。这就导致一个问题:LLM对最新的信息或者个人隐私信息不太了解,因为这些内容在训练时没有被包括进去。虽然可以通过“微调”(也就是针对特定任务再训练一下LLM)来解决这个问题,但微调成本很高,技术相对比较复杂,现在出现了一种新的方法,叫“检索增强生成”(RAG)。这个方法的思路是:从外部的数据源(比如数据库或者网页)中找到相关的资料,然后把这些资料“喂”给聊天机器人,帮助它更好地回答问题。这种方法就像是给聊天机器人提供了一个“外挂”,让它能够接触到更多的知识。

在这里插入图片描述

1-2、前置知识

1-2-1、ModelScopeEmbeddings 词嵌入模型

ModelScope Embeddings 是阿里巴巴达摩院推出的嵌入模型,旨在将文本、图像等数据转换为高维向量,便于机器学习模型处理。这些嵌入向量能够捕捉数据的语义信息,广泛应用于自然语言处理(NLP)、计算机视觉(CV)等领域。

安装库:

pip install modelscope

Demo:

from langchain.embeddings import ModelScopeEmbeddings

model_id = "damo/nlp_corom_sentence-embedding_english-base"
embeddings = ModelScopeEmbeddings(model_id=model_id)
text = "This is a test document."
query_result = embeddings.embed_query(text)
doc_results = embeddings.embed_documents(["foo"])

输出:

在这里插入图片描述
在这里插入图片描述

1-2-2、FAISS介绍&安装 (向量相似性搜索)

FAISS(Facebook AI Similarity Search)是由 Meta(前 Facebook)开发的一个高效相似性搜索和密集向量聚类库。它主要用于在大规模数据集中进行向量相似性搜索,特别适用于机器学习和自然语言处理中的向量检索任务。FAISS 提供了多种索引类型和算法,可以在 CPU 和 GPU 上运行,以实现高效的向量搜索。

FAISS 的主要特性

  • 高效的相似性搜索:支持大规模数据集的高效相似性搜索,包括精确搜索和近似搜索。
  • 多种索引类型:支持多种索引类型,如扁平索引(Flat Index)、倒排文件索引(IVF)、产品量化(PQ)等。
  • GPU 加速:支持在 GPU 上运行,以加速搜索过程。
  • 批量处理:支持批量处理多个查询向量,提高搜索效率。
  • 灵活性:支持多种距离度量,如欧氏距离(L2)、内积(Inner Product)等。

安装:

# cpu或者是GPU版本
pip install faiss-cpu
# 或者
pip install faiss-gpu

Demo分析: 使用 LangChain 库来处理一个长文本文件,将其分割成小块,然后使用 Hugging Face 嵌入和 FAISS 向量存储来执行相似性搜索。

  • CharacterTextSplitter:用于将长文本分割成小块。
  • FAISS:用于创建向量数据库。
  • TextLoader:用于加载文本文件。
  • HuggingFaceEmbeddings:另一个用于生成文本嵌入向量的类。
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import FAISS
from langchain.document_loaders import TextLoader
from langchain.embeddings import HuggingFaceEmbeddings

# This is a long document we can split up.
with open('./index.txt', encoding='utf-8') as f:
    state_of_the_union = f.read()

text_splitter = CharacterTextSplitter(        
    chunk_size = 100,
    chunk_overlap  = 0,
)
docs = text_splitter.create_documents([state_of_the_union])

embeddings = HuggingFaceEmbeddings()
db = FAISS.from_documents(docs, embeddings)

query = "学生的表现怎么样?"
docs = db.similarity_search(query)
print(docs[0].page_content)

输出:

在这里插入图片描述
Notice: 查询分数,这里的分数为L2距离,因此越低越好
在这里插入图片描述

1-2-3、Tiktoken 分词工具

Tiktoken 是 OpenAI 开发的一个高效的分词工具,专门用于处理 GPT 系列模型(如 GPT-3、GPT-4)的文本输入和输出。它能够将自然语言文本转换为模型可以理解的 token 序列,同时支持从 token 序列还原为文本。Tiktoken 的设计目标是高效、灵活且易于集成到各种自然语言处理(NLP)任务中。

安装:

pip install tiktoken

使用:

import tiktoken
# 编码器的加载
encoder = tiktoken.get_encoding("cl100k_base")
text = "这是一个示例文本。"

# 对文本进行编码
tokens = encoder.encode(text)
print(tokens)

# 对文本进行解码
decoded_text = encoder.decode(tokens)
print(decoded_text)

二、Rag From Scratch: Routing

Rag From Scratch: Routing模块: 几种将用户查询路由到最相关的数据源的方法。
在这里插入图片描述

2-1、Logical routing(通过逻辑路由)

在这里插入图片描述

2-1-1、结构化输出

  • RouteQuery: 该数据模型定义了结构化输出的格式。枚举值:“python_docs”, “js_docs”, “golang_docs”。确保LLM的输出必须是以上的一种。
from typing import Literal

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_openai import ChatOpenAI

# Data model
class RouteQuery(BaseModel):
    """Route a user query to the most relevant datasource."""

    datasource: Literal["python_docs", "js_docs", "golang_docs"] = Field(
        ...,
        description="Given a user question choose which datasource would be most relevant for answering their question",
    )

2-1-2、初始化LLM

  • ChatOpenAI:初始化一个 LLM 实例,使用 qwen-max 模型。
  • temperature=0: 控制生成文本的随机性,值为 0 时生成确定性结果。
  • max_tokens=1024: 限制生成文本的最大长度。
  • base_url:指定 API 的基础 URL。
  • **llm.with_structured_output: ** 将LLM的输出限制为 RouteQuery的结构。
from langchain_openai import ChatOpenAI
import os

llm = ChatOpenAI(
    model="qwen-max",
    temperature=0,
    max_tokens=1024,
    timeout=None,
    max_retries=2,
    api_key=os.environ.get('DASHSCOPE_API_KEY'),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

structured_llm = llm.with_structured_output(RouteQuery)

2-1-3、路由构建

  • Prompt: 你是将用户问题路由到适当数据源的专家。根据问题所引用的编程语言,将其路由到相关的数据源。
  • router: 将问题传递给structured_llm,生成结构化输出。
  • choose_route: 根据结构化输出来返回对应的字符串
  • full_chain: 结合 router 和 choose_route 函数,实现完整的路由和处理逻辑。
  • RunnableLambda: 将一个普通的python函数包装成为一个可运行的LangChain组件,使其能够无缝地与其他LangChain组件组合在一起。(入参为Python函数)
# Prompt
system = """You are an expert at routing a user question to the appropriate data source.
Based on the programming language the question is referring to, route it to the relevant data source."""

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", system),
        ("human", "{question}"),
    ]
)

# Define router
router = prompt | structured_llm

question = """Why doesn't the following code work:
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages(["human", "speak in {language}"])
prompt.invoke("french")
"""

result = router.invoke({"question": question})
print(result)

def choose_route(result):
    if "python_docs" in result.datasource.lower():
        ### Logic here
        return "chain for python_docs"
    elif "js_docs" in result.datasource.lower():
        ### Logic here
        return "chain for js_docs"
    else:
        ### Logic here
        return "golang_docs"

from langchain_core.runnables import RunnableLambda

full_chain = router | RunnableLambda(choose_route)

print(full_chain.invoke({"question": question}))

输出:

datasource=‘python_docs’
chain for python_docs

参考文章
rag-from-scratch 官方GitHub仓库.


总结

反方向的钟🤣

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ㄣ知冷煖★

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值