技术干货

你真的会写 Prompt ? 剖析 RAG 应用中的指代消解

2023-12-19
张晨

张晨

你真的会写 Prompt ? 剖析 RAG 应用中的指代消解

随着 ChatGPT 等大语言模型(LLM)的不断发展,越来越多的研究人员开始关注语言模型的应用。

其中,检索增强生成(Retrieval-augmented generation,RAG)是一种针对知识密集型 NLP 任务的生成方法,它通过在生成过程中引入检索组件,从已知的知识库中检索相关信息,并将这些信息与 LLM 的生成能力结合,从而提高生成的准确性和可靠性。这种方法可以用于实现各种知识密集型 NLP 任务,如问答、文摘生成、语义推理等。

本文将从解决优化 RAG 系统里的一个具体问题出发,通过展示使用 LLM Prompt Engineering 的方法,来解析传统 NLP 的问题。

01.解决方案初探

开源项目 Akcio 就是一套完整的 RAG 问答系统,用户导入各类私有专业知识,就可以构建专业领域的问答系统。

|Akcio 的架构图。专业知识是各类 Documents,通过 DataLoader 导入进 Store。在每次提问 Question 后,LLM 可以结合召回知识,加上 LLM 自身的自然语言生成能力,给出对应的回答。

举个例子,比如我们将一篇名为《2023 大模型落地进展趋势洞察报告》的文章,将它导入 Akcio,就可以问它这篇报告里的问题了,比如:

2023年,大模型行业的应用场景可以分为哪几类?

通过一些召回策略,在 Store 里召回出了《报告》中,与问题最相关的 3 条原文片段:

['在2023年,大模型行业的应用场景可分为生成和决策两类应用场景,决策场景预期业务值更高。',
'大模型行业的生成场景主要有对话交互,代码开发,智能体等。',
'NLP的应用场景有文本分类,机器翻译,情感分析,自动摘要等。']

很显然,最有用的片段是第一条,但没关系,Akcio 会把这 3 条都作为 context,去问 LLM,比如它是这样问的:

请根据下面知识回答问题:

知识:

在2023年,大模型行业的应用场景可分为生成和决策两类应用场景,决策场景预期业务值更高。
大模型行业的生成场景主要有对话交互,代码开发,智能体等。
NLP的应用场景有文本分类,机器翻译,情感分析,自动摘要等。

问题:

2023年,大模型行业的应用场景可以分为哪几类?

LLM 就可以给出合理的回答:

大模型行业的应用场景可以分为生成和决策两类应用场景。

这样的话整条链路就走通了。这套架构逻辑看似并不复杂,但如果深入到开发过程中,就会发现其中有一些难点需要解决。

比如在多轮对话的情况下,就需要解决一个问题:如果在最新一轮的提问,里面有些指代上文的代词,那么如果直接用这个问题去做召回,很可能会召回错误的知识,比如:

1: 2023年,大模型行业的应用场景可以分为哪几类?
答1: 大模型行业的应用场景可以分为生成和决策两类应用场景。
问2: 它们有什么区别,能举例说明吗?

这里的“它们”很显然指的是“生成和决策两类应用场景”,问题的原意是“生成和决策场景有什么区别,能举例说明吗?”。但如果直接用这个问题“它们有什么区别,能举例说明吗?”去做召回,那很有可能召回的是比如这样的知识片段:

['BERT和GPT都是NLP领域的重要模型,但它们的设计和应用场景有很大的区别。',
'大模型和小模型的区别在于其规模和复杂度。大模型通常具有更多的参数和更复杂的结构,需要更多的计算资源和时间来训练和推理。而小模型则相对简单,参数较少,训练和推理速度较快。',
'但没有更多的信息来区分这两个产品,因为它们看起来非常相似。']

显然主体错了,那用这些召回的知识肯定也就不对了,LLM 利用这些无用的知识也不用给用户很好的回答了。

那么要解决这个问题有什么好的办法呢?

首先可以想到的是NLP领域中的一个常见任务:指代消解(Coreference resolution)。指代消解是自然语言处理(NLP)中的一项重要任务,用于确定文本中指代相同实体的词语。该任务旨在识别代词、名词短语等,将它们与先前提到的实体关联起来。例如,在句子“John saw Mary. He waved to her.”中,coreference resolution会将“He”和“John”以及“her”和“Mary”归纳为同一实体。

也许这个任务可以帮助我们解决这个问题,但经过实践发现,无论是通过 spacy,还是 huggingface,目前的开源模型,处理指代消解这个任务都有一定的局限性,只能处理比较简单的场景,比如:

1:大模型是什么?
问2:它有什么用?

可以找出“它”指的是“大模型”。然而,对于复杂的指代,却不能识别出来,比如:

1:GPT3是什么?
问2:GPT4又是什么时候发布的?
问3:二者有什么区别?后者有什么优势?

没法识别出“二者”指的是 GPT3 和 GPT4,“后者”指的是“GPT4”。再比如:

1:GPT4又是什么时候发布的?
答1:GPT4是在 2023 年发布的
问2:这一年在计算机视觉有什么进展?

没法识别出“这一年”指的是“2023年”。

也就是说,现有的 NLP 小模型,只能处理识别“它”,“他”,“她”,“这个”等简单的代词,而对于复杂的指代表述,没法识别处理。

那该怎么办呢,对于复杂语言场景,也许最好的处理就是用大模型,毕竟 ChatGPT 火爆时可是号称是“让 NLP 不存在的”的终极武器。于是我们可以尝试,让 LLM 来做这个指代消解任务。

02.用 ChatGPT 做指代消解

我们尝试使用便宜又好用的 ChatGPT 来做这个任务。这里面的关键,其实就是 prompt 怎么写的问题,也就是常说 prompt engineering。这其实是一个看起来好像很简单,但要做好,其实并不简单的一个事情。

比如我们最开始用一些简单的命令类的 prompt,试着让 ChatGPT 去代换最新问题中的代词:

prompt = f'''Please return a new question with the following requirements:
1. If there are pronouns or conditions are missing in the question, please make a complete question according to the context.
2. If the question is complete, please keep the original question.

{history}
Question: {question}'''

这个 prompt 并不复杂,提出要求,要么替换代词,要么保留原问题不变,并把历史上下文,和最新问题给到 GPT,让它来帮我们完成这个任务。那来测一些效果(相对中文来说,GPT 更擅长英文,所以直接用英文测试):

history = ''' What is NLP? 
NLP stands for Natural Language Processing. It is a field of computer science and artificial intelligence that focuses on the interaction between computers and humans using natural language. '''
question = 'What problem does it solve?'

ChatGPT给的返回是:

What problem does Natural Language Processing (NLP) solve?

好像还不错,它把“it”识别出了“NLP”,而且还用“Natural Language Processing (NLP)”来补充全称。

再试试复杂的例子:

history = '''When was GPT4 released?
GPT4 was released in 2023'''
question = 'What progress has been made in computer vision this year?'

返回是:

What progress has been made in computer vision this year?

GPT 并没有成功替换掉 “this year”,在这个例子下它失败了。

再试个复杂例子:

history = '''What is GPT3?
GPT-3 (Generative Pre-trained Transformer 3) is a state-of-the-art language processing model developed by OpenAI.
When was GPT4 released?
GPT4 was released in 2023'''
question = 'What is the difference between the two? What are the advantages of the latter?'

返回是:

Sorry, the information provided about GPT-4's release date is not accurate as it has not been officially announced by OpenAI. Therefore, it is not possible to answer the question about the difference between GPT-3 and GPT-4 or the advantages of the latter.

ChatGPT 并没有按照我们的要求,去改写掉代词,而是直接去回答这个问题了(这里用的 GPT3 模型是偏早期的,它的训练资料里还没有关于 GPT4 的信息,因此它回答称自己不知道)。

在我们的后面的测试中,发现 ChatGPT 有一定的概率会去直接回答问题,而不是按照我们的要求 prompt 去改写代词。我们尝试在 prompt 里加一些要求,让它不要去直接回答问题,但这一问题还是有小的概率会出现。看来ChatGPT 并不是所有要求都能听懂,有时候也容易被其它信息干扰错乱。

在传统 NLP 小模型,和 ChatGPT 这样的大模型都无法解决这个问题的情况下,应该怎么办呢?也许我们从另外一个角度尝试优化我们的 prompt,可以让 ChatGPT 更加听话。

03.Few-shot prompt + CoT

在 prompt engineering 里有一些技巧,可以让 LLM 更加理解并服从指令,比如,我们给 LLM 多看几个参考答案,让它模仿我们的参考例题继续作答,这种 few-shot context learning 的方法,即不需要 fine-tune LLM 模型,又能产生很好的效果。一般给 LLM 看 5 次 shot 后,LLM 就能很好地顺从你的参考案例继续回答。

但是否需要做代词替换,还是要保留原问题,是一个比较复杂的 NLP 理解问题。即使是 ChatGPT 这样的 LLM,也不一定可以按照几个参考例子,直接给出正确的回答。还好,在 prompt engineering 里还有一个常见的方法,可以让 LLM 更好地处理逻辑问题,那就是思维链 CoT。

“思维链 (Chain-of-thought,CoT) 的概念是在 Google 的论文 "Chain-of-Thought Prompting Elicits Reasoning in Large Language Models" 中被首次提出。思维链(CoT)是一种改进的提示策略,用于提高 LLM 在复杂推理任务中的性能,如算术推理、常识推理和符号推理。大概思想就是,让 LLM 在回答的过程中,把中间过程推导也一并回答出来,让 LLM 逐步推导出最后的答案。这样比让 LLM 直接回答出最后的答案的准确率要高得多。

所以,我们完全可以在给 few-shot examples 时,也给到 LLM Chain-of-thought,就是也让它看到思考推理的过程。这样可以提高准确率。

于是,我们按照这样的思想,写出我们的最终 prompt:

REWRITE_TEMP = f'''
HISTORY:
[]
NOW QUESTION: Hello, how are you?
NEED COREFERENCE RESOLUTION: No => THOUGHT: So output question is the same as now question. => OUTPUT QUESTION: Hello, how are you?
-------------------
HISTORY:
[Q: Is Milvus a vector database?
A: Yes, Milvus is a vector database.]
NOW QUESTION: How to use it?
NEED COREFERENCE RESOLUTION: Yes => THOUGHT: I need to replace 'it' with 'Milvus' in now question. => OUTPUT QUESTION: How to use Milvus?
-------------------
HISTORY:
[]
NOW QUESTION: What is the features of it?
NEED COREFERENCE RESOLUTION: Yes => THOUGHT: I need to replace 'it' in now question, but I can't find a word in history to replace it, so the output question is the same as now question. => OUTPUT QUESTION: What is the features of it?
-------------------
HISTORY:
[Q: What is PyTorch?
A: PyTorch is an open-source machine learning library for Python. It provides a flexible and efficient framework for building and training deep neural networks. 
Q: What is Tensorflow?
A: TensorFlow is an open-source machine learning framework. It provides a comprehensive set of tools, libraries, and resources for building and deploying machine learning models.]
NOW QUESTION: What is the difference between them?
NEED COREFERENCE RESOLUTION: Yes => THOUGHT: I need replace 'them' with 'PyTorch and Tensorflow' in now question. => OUTPUT QUESTION: What is the different between PyTorch and Tensorflow?
-------------------
HISTORY:
[{history}]
NOW QUESTION: {question}
NEED COREFERENCE RESOLUTION: '''

这里给 ChatGPT 看 4 个参考例子。第一个是一个空的对话历史,第二个是最简单的例子,第三个是一个替换失败的例子,最后一个是替换两个指代的例子。

在格式上,“HISTORY:”后面就是历史上下文,为了和其它行区分开,在格式上,每次问题前加上“Q:”,每次回答前加上“A:”。“NOW QUESTION”就是最新一轮的提问。而“NEED COREFERENCE RESOLUTION:”这一行后面,就是一次CoT的推导,先让LLM先判断是否需要做“COREFERENCE RESOLUTION”, 然后“THOUGHT:”一下,看看在尝试去替换时,是否成功。最后“OUTPUT QUESTION:”后输出改写后的问题。

最后解析 LLM 的返回时,只需要把 LLM 返回字符串的格式拆解开,只有在“NEED COREFERENCE RESOLUTION:”后跟“Yes”的情况,才去拿最后“OUTPUT QUESTION:”改写的最终问题。

接下来,我们来看看用这个 prompt 的使用效果,还是用上面失败的两个例子,LLM 还是用 ChatGPT:

history = '''When was GPT4 released?
GPT4 was released in 2023'''
question = 'What progress has been made in computer vision this year?'

返回:

Yes => THOUGHT: I need to replace "this year" with "2023" in the now question. => OUTPUT QUESTION: What progress has been made in computer vision in 2023?
```python
可以看到 ChatGPT 成功返回了我们想要的结果,成功将“this year”替换成“2023”。



下一个例子:


```python
history = '''What is GPT3?
GPT-3 (Generative Pre-trained Transformer 3) is a state-of-the-art language processing model developed by OpenAI.
When was GPT4 released?
GPT4 was released in 2023'''
question = 'What is the difference between the two? What are the advantages of the latter?'

返回:

Yes => THOUGHT: I need to replace 'the two' with 'GPT-3 and GPT-4' and 'the latter' with 'GPT-4' in the now question. => OUTPUT QUESTION: What is the difference between GPT-3 and GPT-4? What are the advantages of GPT-4?

可以看到这种复杂问题,也能成功将“the two”替换成“GPT-3 and GPT-4”,“the latter”替换成“GPT-4”。

04.总结

本文从解决优化 RAG 系统里的一个具体问题出发,讨论了使用 LLM prompt engineering 的方法,来解析传统 NLP 的问题,并得到一定的质量提升。可以看到,写 prompt 有时很简单,有时却是一个很难的事。所以在 LLM 爆火之后,prompt engineering 分支领域也逐渐形成并发展,各种写 prompt 层出不穷。也许本文展示的最终 prompt 可能并非最优解,但一定比传统 NLP 方法好得多。这也让我们看到了,用 LLM 大模型,确实可以帮助优化和解决很多传统 NLP 领域的问题,也许就是大模型之所以强大的地方吧。

随着GPT-4之后的大模型能力越来越强,我相信也许多年后 NLP 领域的很多问题可能已不是问题,通用的人工智能会慢慢走近我们。