> For the complete documentation index, see [llms.txt](https://fucloud.gitbook.io/sysu-introducer/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://fucloud.gitbook.io/sysu-introducer/module/bot/rag.md).

# RAG

本实现类型采用 `RAG` (Retrieval Augmented Generation) 检索增强生成技术，构建了相关的知识数据库，再与**检索器**，**提示工程**等技术结合，来提升大模型的知识能力。

此外，根据检索方式，我们又将其派生出 Sparse（稀疏）和 Dense（稠密）两种具体的实现类型，这两种实现会在**检索效率**和**检索质量**进行平衡。

## 处理逻辑

检索增强生成的流程可以直观地分为检索 -> 增强 -> 生成。此外，由于本项目仅搜集了中大相关的知识数据，因此检索时可能会出现无效检索的情况（也就是无法检索到与问题相关的文本），因此我们额外引入了兜底策略的逻辑。

```python
def talk(self, query: str) -> str:
    if self._searcher is None:
        return self._caller.single_call(query)

    # 1. 使用 searcher 进行向量检索
    data = self._searcher.search_with_label(query, 3)

    # 2. 当检索效果不好时执行兜底策略
    if len(data) == 0:
        return self._last_strategy(query)

    # 3. Prompt 生成
    final_prompt = self._generate_prompt(query, data)

    # 4. 生成最终回答
    return self._caller.single_call(final_prompt)
```

### 1. 检索

检索部分主要分为**数据集制作**和**检索方式**两个部分。

#### (1) 数据库制作

想要完成检索任务，首先我们需要有相对应的数据。下面简单介绍一下如何收集校庆数据，以及数据的格式：

1. 确定数据结构：首先，我们需要确定数据库的数据结构。为了便于后续的 ElasticSearch 索引构建，我们选择使用 JSON 格式来构建数据库，以使用键值对的方式组织数据，非常适合表示结构化的数据。
2. 设计数据字段：我们可以将每个数据项视为一个对象，其中包含三个字段：query、document 和 metadata。
   * query 字段表示查询的关键词或问题
   * document 字段表示查询结果的文本或内容
   * metadata 字段表示与查询结果相关的元数据/关键词信息。
3. 收集数据：我们在[中山大学官网](https://www.sysu.edu.cn/)、[中大百年校庆官网](https://sysu100.sysu.edu.cn/)、[中山大学百度百科](https://baike.baidu.com/item/%E4%B8%AD%E5%B1%B1%E5%A4%A7%E5%AD%A6/5672)、校园公众号、视频号等平台，收集有关校园生活、人文历史、招生政策、院系分布等数据，并将数据拆分为 300+个 JSON 对象。 下面是一个示例：

   ```json
   "1":{
       "query":"中山大学成立的校史",
       "document":"1924年,孙中山亲手将广州地区多所高校整合创立国立广东大学。1926年定名为国立中山大学。如今该校由1952年院系调整后分设的中山大学和中山医科大学于2001年10月合并而成。",
       "metadata":"校名,校史,简介,发展史,改称"
   },
   ```

#### (2) 检索方式

检索方式主要分为 Dense 和 Sparse 两种，两种比较如下。具体技术细节请查看 [检索器 Searcher](https://github.com/sse-digital-man/sysu-introducer-wiki/blob/main/module/bot/module/bot/README.md)。

|      | Dense            | Sparse        |
| ---- | ---------------- | ------------- |
| 检索对象 | 文本向量             | 文本            |
| 检索速度 | 较慢               | 较快            |
| 检索效果 | 较好               | 较差            |
| 实现   | FastText, Vector | ElasticSearch |

### 2. 增强

为了将检索的相关信息用于增强大模型能力，我们利用大模型强大的 `上下文学习(In-context Learning)` 能力，通过**提示词工程**来实现。 因此，我们定义了如下的 `prompt` 模板：

```python
system_prompt = \
"""### 示范一
[用户问题]
国际学生政策是怎样的？
[参考资料]
参考资料1:
标题:国际学生政策
内容:详情可见中山大学留学生办公室官网
[回答]
国际学生政策，官网有最权威的信息哦！快去中山大学留学生办公室官网看看吧，你会有新发现的！

### 示范二
[用户问题]
可以介绍一下你自己嘛？
[参考资料]
参考资料1:
标题:中山大学校校歌歌词
内容:白云山高,珠江水长,吾校矗立,蔚为国光,中山手创
[回答]
嗨！我是中小大，中大软件工程学院的大三学生，也是中大介绍官。我超爱写代码和阅读历史书籍！

### 示范三
[用户问题]
为什么皮卡丘喜欢放电
[参考资料]
参考资料1:
标题:中山大学的微电子科学与技术学院本科招生专业
内容:微电子科学与工程
参考资料2:
标题:中山大学的集成电路学院本科招生专业
内容:微电子科学与工程
[回答]
很抱歉，我是中大介绍官，不能回答关于皮卡丘的问题哦~

### 开始任务
[用户问题]
{query}
[参考资料]
{data_str}
[回答]"""

data_prompt = \
"""参考资料{i}:
标题:{query}
内容:{document}
"""
```

模板包含两个部分：

**示范(demonstration)：** 通过 `Few-shot Learning`，增强大模型的指令遵循能力。 我们提供了三个范例，分别对应三种情况：

* 问题与检索内容相关，可以根据问题与检索内容回答。
* 问题相关，检索得到的内容不相关，只根据用户问题。
* 用户问题与中大无关，不应该回答。

**检索增强内容：** 以 `[参考资料]` 的形式给到模型。

### 3. 生成

将最终融合的 `prompt` 给到[调用器 Caller](#调用器-caller) 生成答案。

### 4. 兜底策略

兜底策略并不会是任何 RAG 对象都是生效的，此处在实现时需要进行区分。例如以下 `HyDE` 兜底策略通常效果会在 Dense 中更好。

#### Hyde 兜底

`Hyde`(Hypothetical Document Embeddings，假设性文档嵌入)通过使用一个大语言模型，在响应查询的时候建立一个假设的文档。 通过计算假设文档的向量而在[向量数据库](#2-vector-similarity)中搜索。 该方法来源于论文 [Precise Zero-Shot Dense Retrieval without Relevance Labels](https://arxiv.org/abs/2212.10496)。

`HyDE` 考虑到的是在 `查询-回答` 任务中，`查询` 与 `回答` 的相似度可能不高，不如生成一个假设的回答，从而通过这个假设的回答在向量数据库中进行检索。

代码实现上也非常简单：

```python
# 基本的检查...

# 1. 生成 hyde 假设性回答
query = searcher.prompt_template.format(query=query)
query += caller.single_call(query, False)

# 2.使用 hyde 检索得到 top-k 相似结果
retrieve_res = searcher.search_with_label(query, k)

return retrieve_res
```

**效果**

部份来自用户的 `query` 可能包含的关键词带有一些昵称，比如 `鸭大`。 这种时候，直接使用 `Searcher`，可能无法检索到相应的结果。 比如下面的例子

```
[query]
send "鸭大什么水平" 

[w/o HyDE]
[] (超过相似度阈值的结果为空)
```

`HyDE` 在这时启动，生成的假设性文档嵌入以及检索结果如下：

```
[HyDE]
请回答用户关于中山大学信息的查询
查询: 鸭大什么水平
回答: 中山大学作为一所知名的综合性大学，位于广东省广州市，是中国一流大学之一。学校设有多个学科门类，涵盖文、理、工、医、法、经、教育等多个领域。中山大学在教学水平、科研水平以及社会影响力等方面 均属于国内前列大学，被广泛认可为高水平的学府之一。如果您对中山大学有更具体的问题，欢迎继续提问。

[w/ HyDE]
1. 中山大学简介...
2. 中山大学的办学情况,校区分布...
3. 中山大学的办学层次...
```

可见，`HyDE` 技术能够在用户查询措辞较为“奇特”的情况下，很好地完成检索工作。
