借助这个开源项目,我将 RAG 的准确性和召回率都提高了两倍!

本文首发于博客 LLM 应用开发实践

RAG(Retrieval Augmented Generation)是一种检索增强生成技术,它利用大型语言模型来处理用户查询,RAG 技术的主要组成包括数据提取---embedding---创建索引---检索---排序(Rerank)---LLM 归纳生成,不过实际落地过程来看,将用户查询转换为嵌入向量直接检索,很多时候的结果在相关度方面没有那么理想,本篇分享一种对用户查询进行重写再去进行检索从而提高准确性和召回率的方案。

RAG技术图解

直接检索的问题

将用户查询转换为嵌入向量直接检索会出现下面四类常见问题 👇:

查询结果不匹配

模型假设查询 embedding 和内容 embedding 在嵌入空间中是相似的,但基于要搜索的文本,匹配度不一定是最优的,仅仅靠内容在语义上相似的查询出的结果并不理想。

单一搜索后端

实际情况可能有多个搜索后端,每个后端都有自己的 API,可以考虑将查询路由到向量存储、搜索客户端、SQL 数据库等等。

文本搜索的局限性

文本搜索的限制是它仅限于单个字符串的复杂查询,牺牲了表达能力,无法使用关键词、过滤器和其他高级功能。例如,通过简单的文本搜索无法回答"我们上周解决了哪些问题",因为包含的关键词"问题"和"上周"的将在所有文档范围都存在。

有限的规划能力

假设查询是搜索后端的唯一输入,无法使用其他信息来改善搜索。

解决方案

将自然语言查询通过大语言模型转换为优化后的自定义查询语句,最终能够高效理解达到提高准确性和召回率的目的。

多个搜索后端RAG

案例一

比如搜索 "人工智能有哪些最新发展",通过系统内部限定发布日期范围和搜索域列表的方式重写查询。

python 复制代码
class DateRange(BaseModel):
    start: datetime.date
    end: datetime.date

class MetaphorQuery(BaseModel):
    rewritten_query: str
    published_daterange: DateRange
    domains_allow_list: List[str]

    async def execute():
        return await metaphor.search(...)

import instructor
import openai
# Enables response_model in the openai client
instructor.patch()
query = openai.ChatCompletion.create(
    model="gpt-4",
    response_model=MetaphorQuery,
    messages=[
        {
            "role": "system",
            "content": "You're a query understanding system for the Metafor Systems search engine. Here are some tips: ..."
        },
        {
            "role": "user",
            "content": "What are some recent developments in AI?"
        }
    ],
)

重写后的查询内容为在arxiv上搜索最近三个月带有 最新进展 先进人工智能 机器学习 几个关键字的论文,通过限定条件限制了查询范围,提高查询精度

json 复制代码
{
    "rewritten_query": "novel developments advancements ai artificial intelligence machine learning",
    "published_daterange": {
        "start": "2023-10-12",
        "end": "2021-07-12"
    },
    "domains_allow_list": ["arxiv.org"]
}

案例二

个人助理的例子,当你问智能助理"我今天有什么事情要做?",从一个模糊的查询中可能需要获取事件、邮件、提醒等,这些数据可能存在于多个后端,但你想要的是一个统一的结果汇总,这种场景下不能假设这些相关的文本都嵌入在一个搜索后端中,可能会有一个日历客户端、邮件客户端等等。

python 复制代码
class ClientSource(enum.Enum):
    GMAIL = "gmail"
    CALENDAR = "calendar"

class SearchClient(BaseModel):
    query: str
    keywords: List[str]
    email: str
    source: ClientSource
    start_date: datetime.date
    end_date: datetime.date

    async def execute(self) -> str:
        if self.source == ClientSource.GMAIL:
            ...
        elif self.source == ClientSource.CALENDAR:
            ...

class Retrival(BaseModel):
    queries: List[SearchClient]

    async def execute(self) -> str:
        return await asyncio.gather(*[query.execute() for query in self.queries])

import instructor
import openai

# Enables response_model in the openai client
instructor.patch()
retrival = openai.ChatCompletion.create(
    model="gpt-4",
    response_model=Retrival,
    messages=[
        {"role": "system", "content": "You are Jason's personal assistant."},
        {"role": "user", "content": "What do I have today?"}
    ],
)

重写后的查询为今天的邮件和日程表上有会议、电话、zoom等关键字的内容,通过查询列表路由到不同的搜索后端(电子邮件和日历),异步分发,也可以提高性能

python 复制代码
{
    "queries": [
        {
            "query": None,
            "keywords": None,
            "email": "jason@example.com",
            "source": "gmail",
            "start_date": "2023-10-12",
            "end_date": None
        },
        {
            "query": None,
            "keywords": ["meeting", "call", "zoom"],
            "email": "jason@example.com",
            "source": "calendar",
            "start_date": "2023-10-12",
            "end_date": None

        }
    ]
}

结语

能够实现这一切,得益于开源项目 instructor,封装了复杂的建模过程,拿来即用即可。 本文参考自 RAG is more than just embedding search

更多内容在公号:LLM 应用全栈开发

相关推荐
爱吃土豆的程序员8 分钟前
文心一言与千帆大模型平台的区别:探索百度AI生态的双子星
人工智能·百度·文心一言·千帆大模型
奔跑的犀牛先生12 分钟前
【小白学机器学习36】关于独立概率,联合概率,交叉概率,交叉概率和,总概率等 概念辨析的例子
人工智能·机器学习·概率论
bbppooi20 分钟前
堆的实现(完全注释版本)
c语言·数据结构·算法·排序算法
AI浩22 分钟前
上下文信息、全局信息、局部信息
人工智能·transformer
FFDUST28 分钟前
C++ 优先算法 —— 无重复字符的最长子串(滑动窗口)
c语言·c++·算法·leetcode
Elastic 中国社区官方博客33 分钟前
Elasticsearch:Retrievers 介绍
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
m0_7380545644 分钟前
【leetcode】全排列 回溯法
c++·算法·leetcode·回溯法
不爱说话郭德纲1 小时前
Stylus、Less 和 Sass 的使用与区别
前端·css·面试·less·sass·stylus
ZZZ_O^O1 小时前
【贪心算法第五弹——300.最长递增子序列】
c++·学习·算法·leetcode·贪心算法
&黄昏的乐师1 小时前
Opencv+ROS实现颜色识别应用
人工智能·opencv·学习·计算机视觉