# 引言
这几年,大型语言模型的崛起算是生成式AI领域的一个标志性转折点,也确实让很多行业的生产力有了质的提升。不过话说回来,这些模型虽然亮眼,但短板也很明显,有些领域想充分用好它们,还真不太容易。
最让人头疼的,一个是幻觉问题——模型会一本正经地胡说八道;另一个是它们对专业领域知识掌握得不够深。说白了,LLMs的知识都来自训练数据,如果不加点别的技术手段,让它们处理非常垂直的领域任务,效果往往不怎么样。
要搞出一个LLM,第一步是预训练——拿一个巨大的、通用的文本语料库去训练Transformer模型。这些数据覆盖面广,但既不专精于某个行业,也不会自动更新。所以像ChatGPT这样的模型,回答常识问题还行,一碰上专业性强、难度高的问题就容易露怯。而且,模型能在多大程度上搞定某个主题,很大程度上取决于这个主题在训练数据里出现了多少次。那些出现频率低的信息,LLMs天然就不擅长。金融领域的专业知识、行业术语,基本都属于这个范畴。这就是为什么标准LLM在特定领域的问答上总是差一口气。
那“知识注入”是怎么回事?就是让模型能接触到超出原始训练数据的信息,这是提升LLMs在特定领域任务上表现的主要思路。具体有两种主流做法:一种是给模型做额外的训练或微调,另一种是上下文学习,而RAG(检索增强生成)就是上下文学习里最火的那个版本。
## 微调
微调,就是调整模型参数,让它更适应某个特定任务或行业。通过微调,我们可以在特定领域的数据集上继续训练LLM,这样它就掌握了原始训练数据里没有的新知识。另外,用指令微调还能让模型的输出更一致、更可控。
微调主要有三种:无监督微调、监督式微调,还有强化学习。我们之前在金融特定问题上做过实验,用监督式微调来优化几种不同的模型。尤其是指令微调,它特别适合根据标注好的“输入-输出对”来让模型按我们的要求行事。不过,监督式微调有个明显的瓶颈——你得有高质量的数据才能有效训练。在问答任务里,这些数据集通常得靠人类专家来整理,有时也会借助其他LLMs来生成靠谱的问答对。
至于无监督微调,数据是没有标签的,相当于预训练过程的延续——只不过用的是一堆特定领域的文档和文本,而不是通用语料。但这里有个问题:模型不会从这些数据里拿到任何额外的指令或标签。我们只是希望它能记住这些训练数据里的信息,在遇到非常垂直的问答时能想起来用上。和监督式微调比起来,这种方法数据好找,扩展性更强,但微调完的效果可能不那么稳定。而且,就算用了领域数据,也不能保证LLM在需要的时候真能调出这些知识——尤其当领域数据量和预训练语料相比小得可怜时,这种不确定性就更大了。
## 检索增强生成
RAG是一种上下文学习方法,它让LLM能接触到新的知识源来回答问题。上下文学习的思路是:不更新模型参数(微调才需要动参数),而是直接把额外信息和用户的查询拼在一起,让模型参考。这样做的好处很明显——知识是直接喂给模型的,它能看到,不用像无监督微调那样担心知识淹没在训练数据里找不着。但缺点是,LLM的上下文窗口有限,能拼进去的信息也就那么多,往往比我们想注入给模型的总知识量少得多。
所以,RAG里“检索”这一步就特别关键——它得决定把哪个文本块加到输入查询里。这里我们重点聊的是基于文档的问答,尤其是金融文件和金融查询。假设手头有好几份报告,比如10-K表格或业绩电话会记录,你想跟它们“对话”、提问题。这种情况下,就得想办法高效地把这些金融文件的知识注入到LLM里。为了防止模型胡编乱造,最好的办法还是用上下文学习——在提示里明确告诉模型:不要自己发挥,只能参考问题后面附上的额外上下文。
问题是,这些文件又长又复杂,不可能每次提问都把整份文件塞进去当上下文。所以必须设计一套检索算法,从文档里挑出最相关的文本片段,然后把这个片段作为额外输入交给LLM,模型再根据问题和这个上下文生成回答。
下面这个图展示了传统RAG的流程。首先用户提个问题——以金融问答为例,用户可能会问(这里可以放一个金融问题的示例)。然后,问题会被转换成嵌入向量文本的数值表示。为了找到相关的上下文,系统会在查询嵌入和知识中心的嵌入之间做相似性搜索(比如余弦相似度)。这个知识中心,是由我们想要交流的那些文档构建的。先把非结构化文档处理一下,切成块,每块转成向量形式的嵌入,然后全部存进某个数据库(本地或云端都可以)。算法从库里捞出最相关的文本块,拼到查询里,作为上下文交给LLM。
## 当前RAG流程的局限性
传统RAG架构有不少硬伤,直接影响了它在知识密集型和领域特定任务中的表现。
最常见的问题就是把文档均匀地切成块——完全不管文档的结构和内容。每个块的大小一样(按单词或token数量),块和块之间可能有点重叠来保证上下文。检索器通常会返回最相似的top-k个块,每个块尺寸差不多。但这种做法根本没考虑文档本身的性质,有时候会漏掉关键信息。比如,问题的答案分布在好几个块里,但这些块在语义上不一定最相似——传统RAG压根不会返回最理想的组合。
语义搜索(用余弦相似度)是RAG的核心组件,但它也有自己的问题:可能检索到无关甚至相反的信息。这说明模型对语言的细微差别很敏感,结果也可能出人意料。最相似的块不等于最相关的块——但很多RAG流程都默认两者是一回事。另外,大多数标准嵌入算法没有任何领域特定知识,它们不理解某个专业领域里某些词或短语的特殊含义。
那种简单的分块加相似性搜索,在知识库只有一本长篇小说或一篇文章时可能还行。但大多数情况下,我们想打交道的是多种不同类型的文档,结构复杂得多,有标题、有表格。如果所有块都被一视同仁地丢进一个向量数据库,关键信息就丢了。比如文档集可能是不同公司或不同年份的财务报告。每个文本块,如果它在文档里的位置没被记住,可能就漏了公司名称或年份。这会导致检索返回过时或无用的块,因为它忽略了文本和文档的附加数据。
传统检索算法还缺乏那种更高级的、有推理能力的问答。它通常只是基于原始问题做相似性搜索,不会像人类那样经过逻辑步骤去找相关部分。打个比方,你让一位财务分析师计算指标X,他会推理:先想好怎么算这个指标,再找到文档里对应的数据。这个过程有好几个步骤。但简单的问题相似性搜索,完全抓不住这些复杂性。有时候,查询本身的信息就不足以告诉模型最相关的块在哪,还得靠额外的信息和逻辑步骤。
# 改进检索的技术
既然标准RAG管道有这么多局限,那显然得想办法解决。下面我们来聊一系列能优化RAG性能的技术,重点是金融文档问答这个场景。
## 分块技术
分块方法是检索过程里的关键,因为它决定了算法返回的上下文长什么样。分块策略不好,可能导致上下文不完整,或者反过来——塞了太多无关信息。
当固定了块大小时,大部分RAG管道都会遇到一个问题:信息要么太多要么太少,没法精准匹配每个查询。理想的方法得看知识库里文档的性质、模型期望的查询长度,以及回答这些问题需要多少上下文。
递归分块就是一个更灵活的策略。它用一些额外的指标和规则(比如标点符号)来让分块更动态。虽然块的大小还是相对一致的,但附加参数可以保证块不会在句子中间被切断。用Spacy和NLTK这样的Python库,我们可以实现更复杂的句子拆分技术,利用NLP技术更好地理解文档上下文。
在财务报告里,文档通常很长,而且包含复杂的结构比如表格。同一类的文档(比如10-K)通常有固定的格式,可以通过标题和副标题来识别。考虑到这些财务报告的特殊性,一种基于元素的分块策略可能会更有效。我们可以采用Unstructured论文里用的方法:如果遇到标题元素,就新开一个块;如果遇到表格元素,也新开一个块,并且保留整个表格。这样每个上下文返回的信息会更充足,能更有效地回答用户的问题。
## 查询扩展
查询扩展,也叫查询转换,指的是改变输入到RAG管道的问题,以便能基于用户的原始问题找到更合适的块。背后的逻辑是:用户的问题可能没有明确包含所有信息,来指示算法该在文档的哪里找上下文——尤其是通过余弦相似度搜索的时候。有时候,用户的问题本身甚至会误导算法找错方向,结果返回一个无关片段。对于更复杂的问题和文档,需要更多的推理步骤才能知道该去查哪里,而基本RAG管道完全缺乏这种能力。
一种模拟人类分析师逻辑的技术是假设文档嵌入(HyDE)。传统方法是只用用户原始查询做相似性搜索,而HyDE会先用LLM生成一个理论文档来响应查询,然后用原始问题和这个假设答案一起做相似性搜索。这种技术已经被证明优于标准检索器,而且不需要自定义嵌入算法。但缺点是有时可能导致不正确的结果——因为它依赖另一个LLM来提供额外上下文。
## 元数据注释和索引
当需要和多个不同文档交互时,元数据里可能藏着关键信息,但标准检索算法完全无视它们。我们之前遇到的一个问题是:原始的RAG管道会把不同文档的块混淆在一起。为了解决这个问题,我们试着为每个文档创建单独的向量数据库。但这种方法在大规模应用时不太现实,尤其当用户想在不同文档之间切换或同时跟多个文档交流的时候。
元数据注释可以克服这个障碍,进一步增强检索。元数据注释的性质应该和分块策略相匹配。比如,如果我们按元素把文档分块,那么可以在注释里包含每个元素的详细信息。例如,表格被单独放进一个块时,元数据可以记录这个表格的类型(比如利润表、现金流量表等)。另外,通常还会往元数据注释里加摘要和有代表性的关键词,提供更多上下文信息。
## 重新排序算法
在标准RAG管道里,我们可以指定算法应该返回多少个文档或块,以及有多少块会作为上下文提供给输入查询。通常top-1或top-2的块会被纳入上下文,这些是基于余弦相似度或k最近邻搜索给出的最佳结果。但问题是,这样的算法给出的是最相似的块,不一定是最相关的。
重新排序算法就是用来解决这个问题的——它优先考虑相关性,而不是相似性。简单说,余弦相似度这类方法可能会先给top-10的块排个序,但另一个独立的算法会重新按相关性排一遍,然后排序后的前一两个块会被作为上下文提供给输入查询。Cohere的重新排序算法就是一个流行的例子,它和其他算法一样,会用额外的机器学习和NLP技术来进一步评估相关性,超越简单的相似性搜索。
## 微调嵌入算法
嵌入算法负责把文本转换成数值表示,在RAG管道里作用巨大。我们可以根据特定领域的知识来微调嵌入算法,让它在该领域的检索上表现更好。嵌入还可以是动态的——当词语根据上下文有不同含义时,它们会自动调整。OpenAI的嵌入就是动态嵌入的例子。不过,领域特定的微调需要访问包含查询、文本语料库和相关文档的数据集。
# 评估
评估RAG系统时,主要看两个部分:模型检索上下文的能力,以及基于上下文回答问题的能力。在数据集中,我们有人类财务分析师给出的真实上下文和标准答案。把模型的响应和这些标准答案做个对比,叫做结构化评估;没有标准答案时做的评估叫非结构化评估。结构化评估能更准确地反映模型的水平,但非结构化评估也能告诉我们关于分块质量和答案质量的信息——而且大多数情况下,我们并没有真实数据可用,所以非结构化评估也是必需的。
## 检索质量
用结构化数据测试检索质量,主要看页面级和段落级准确性。在数据里,我们能看到整个文档,也知道人类分析师参考的是哪部分。把这部分和检索算法返回的块比较就行。如果参考上下文和算法上下文在同一页上,那检索准确性就高;段落级准确性也是类似的道理。
对于非结构化数据,可以用RAGAS框架定义的上下文相关性来评估检索到的块。具体做法是:让LLM计算与回答问题相关的上下文句子的数量。提取的句子数量与上下文中总句子数量的比率,就是上下文相关性得分。这个得分会惩罚冗余信息,奖励那些包含最多有用信息来回答问题的块。
## 回答准确性
对于结构化的问答评估,我们评估模型与数据集中标准答案的匹配程度。常用的指标包括BLEU、Rouge-L得分,以及余弦相似度。但这些指标不太理想——它们没法比较两个不同答案的语义含义,所以有时会有误导性。因此我们还会用LLM评估:给GPT这样的模型一个特定的提示,让它根据标准答案来判断候选答案的准确性。
我们也可以用非结构化的方式进一步评估生成器的答案与检索到的上下文的质量。这些指标衡量的是模型在给定上下文的情况下,响应的质量有多高。RAGAS框架提出了“上下文忠实度”这个指标,用来衡量模型的答案在多大程度上是基于给定上下文的。它通过计算答案中受上下文支持的陈述数量,除以答案中的总句子数量来衡量。这个指标也可以看作是评估模型是否在没有标准答案的情况下产生了幻觉——如果忠实度得分高,说明生成的答案里几乎所有句子都有上下文支持,模型没有额外编造信息。
# 数据集
为了评估使用RAG的模型性能,我们用到了Patronus AI开发的FinanceBench基准测试。这个测试包含针对美国上市公司的10,231个问题,覆盖了2015年到2023年间发布的财务文件,比如10-K、10-Q、8-K和业绩报告。
FinanceBench里每一条记录都包含一个问题(例如:“AMCOR在2023财年的调整后非GAAP EBITDA是多少”)、一个答案(例如:“AMCOR在2023财年的调整后EBITDA为20.18亿美元”)、一个证据字符串(包含验证答案所需的信息),以及相关文档的页码。这个数据集能全面评估RAG模型检索和生成准确答案的能力,也能很好地展示LLM在金融分析和决策中的实际应用潜力。
# 影响
在这个实验里,我们试图解决当前RAG管道的一些关键局限。有些问题有特定的技术能解决,有些则更难对付。随着这个领域的研究继续深入,肯定会有更多想法冒出来,让这些系统越来越准、越来越稳。
我们锁定的关键问题可以分成三类。第一个是:相关上下文往往分布在好几个位置,但当前算法只检索1到2个块。就算算法检索了前5到10个块,这些块也不一定是人类分析师知道该去找的那几个最相关的部分。第二个是:当前RAG管道认为相似性就等于相关性——这显然不对。第三个是:当前RAG管道把文档切成统一大小的片段,完全无视文档结构,结果导致一些部分不完整。
# 结果
由于AI这个领域发展太快,我们暂时不公开披露这些技术的结果。需要了解的话,可以联系我们的团队,我们可以根据具体情况进行说明。
# 结论和下一步
提升检索性能,能直接提高整个文档问答系统的质量。检索到正确的块,不仅能提供更好的引用,还能给出更好的答案。这也说明了一个强大的检索算法有多重要——就算生成器再强,没有正确的上下文,照样给出错误答案。
我们这次主要关注金融领域的RAG系统,特别是针对10-K文件的问答。但其实同样的思路也适用于医疗、法律等其他行业,因为它提供了一个系统框架,来改进面向特定领域任务的RAG管道。我们还用各种评估指标展示了这些增强技术是如何克服一些局限的。每个指标单独看可能不够全面,但放在一起,就能对系统的表现有一个清晰的感觉——不管有没有结构化数据可用。
虽然这篇文章探讨的技术已经解决了一些关键局限,但在其他领域还有不少工作可以做。尤其是检索算法面临的一个核心挑战:当上下文跨越文档的多个部分时,模型必须找到所有这些部分才能给出答案。引入知识图谱可能有助于检索系统做到这一点——给它们一套具体的指令,告诉它们怎么根据提出的问题来检索和回答。另一个值得探索的方向是:根据用户标注的数据对嵌入算法进行微调,让模型能更好地理解特定领域上下文中每个词和短语的细微差别。金融文件问答中RAG检索效果优化策略
大型语言模型借助RAG提升回答准确性,但传统RAG存在分块机械、相关性不足、缺乏领域知识等局限。采用递归分块、查询扩展、元数据注释、重排序和微调嵌入算法,可显著改善检索质量,提升金融文件问答准确性与可靠性。基于FinanceBench评估,聚焦检索与回答精度。
# 摘要
大型语言模型(LLMs)能不能给出准确答案?很大程度上得看输入的质量——特别是当你用上检索增强生成(RAG)技术的时候。RAG的核心思路,就是先把那些最相关的文本片段找出来,喂给大模型,让它有个扎实的“底稿”来回答问题。这几年LLMs的响应能力确实突飞猛进,但用户还是会碰到不太准确、甚至跑偏的答案。问题其实不在模型本身,多半是RAG那块儿没捞对东西。
所以,想让LLMs发挥得更稳,关键就得把RAG这个“前置环节”打磨好。这篇文章会聊聊当前RAG流程里有哪些坑,再介绍几种能提升文本检索效果的方法。比如更聪明的分块策略、查询扩展、给数据加元数据标签、用重新排序算法,还有对嵌入算法进行微调。把这些招数用上,检索质量会明显改善,连带着LLMs在回答问题时的整体表现也能上一个台阶。
# 引言
这几年,大型语言模型的崛起算是生成式AI领域的一个标志性转折点,也确实让很多行业的生产力有了质的提升。不过话说回来,这些模型虽然亮眼,但短板也很明显,有些领域想充分用好它们,还真不太容易。
最让人头疼的,一个是幻觉问题——模型会一本正经地胡说八道;另一个是它们对专业领域知识掌握得不够深。说白了,LLMs的知识都来自训练数据,如果不加点别的技术手段,让它们处理非常垂直的领域任务,效果往往不怎么样。
要搞出一个LLM,第一步是预训练——拿一个巨大的、通用的文本语料库去训练Transformer模型。这些数据覆盖面广,但既不专精于某个行业,也不会自动更新。所以像ChatGPT这样的模型,回答常识问题还行,一碰上专业性强、难度高的问题就容易露怯。而且,模型能在多大程度上搞定某个主题,很大程度上取决于这个主题在训练数据里出现了多少次。那些出现频率低的信息,LLMs天然就不擅长。金融领域的专业知识、行业术语,基本都属于这个范畴。这就是为什么标准LLM在特定领域的问答上总是差一口气。
那“知识注入”是怎么回事?就是让模型能接触到超出原始训练数据的信息,这是提升LLMs在特定领域任务上表现的主要思路。具体有两种主流做法:一种是给模型做额外的训练或微调,另一种是上下文学习,而RAG(检索增强生成)就是上下文学习里最火的那个版本。
## 微调
微调,就是调整模型参数,让它更适应某个特定任务或行业。通过微调,我们可以在特定领域的数据集上继续训练LLM,这样它就掌握了原始训练数据里没有的新知识。另外,用指令微调还能让模型的输出更一致、更可控。
微调主要有三种:无监督微调、监督式微调,还有强化学习。我们之前在金融特定问题上做过实验,用监督式微调来优化几种不同的模型。尤其是指令微调,它特别适合根据标注好的“输入-输出对”来让模型按我们的要求行事。不过,监督式微调有个明显的瓶颈——你得有高质量的数据才能有效训练。在问答任务里,这些数据集通常得靠人类专家来整理,有时也会借助其他LLMs来生成靠谱的问答对。
至于无监督微调,数据是没有标签的,相当于预训练过程的延续——只不过用的是一堆特定领域的文档和文本,而不是通用语料。但这里有个问题:模型不会从这些数据里拿到任何额外的指令或标签。我们只是希望它能记住这些训练数据里的信息,在遇到非常垂直的问答时能想起来用上。和监督式微调比起来,这种方法数据好找,扩展性更强,但微调完的效果可能不那么稳定。而且,就算用了领域数据,也不能保证LLM在需要的时候真能调出这些知识——尤其当领域数据量和预训练语料相比小得可怜时,这种不确定性就更大了。
## 检索增强生成
RAG是一种上下文学习方法,它让LLM能接触到新的知识源来回答问题。上下文学习的思路是:不更新模型参数(微调才需要动参数),而是直接把额外信息和用户的查询拼在一起,让模型参考。这样做的好处很明显——知识是直接喂给模型的,它能看到,不用像无监督微调那样担心知识淹没在训练数据里找不着。但缺点是,LLM的上下文窗口有限,能拼进去的信息也就那么多,往往比我们想注入给模型的总知识量少得多。
所以,RAG里“检索”这一步就特别关键——它得决定把哪个文本块加到输入查询里。这里我们重点聊的是基于文档的问答,尤其是金融文件和金融查询。假设手头有好几份报告,比如10-K表格或业绩电话会记录,你想跟它们“对话”、提问题。这种情况下,就得想办法高效地把这些金融文件的知识注入到LLM里。为了防止模型胡编乱造,最好的办法还是用上下文学习——在提示里明确告诉模型:不要自己发挥,只能参考问题后面附上的额外上下文。
问题是,这些文件又长又复杂,不可能每次提问都把整份文件塞进去当上下文。所以必须设计一套检索算法,从文档里挑出最相关的文本片段,然后把这个片段作为额外输入交给LLM,模型再根据问题和这个上下文生成回答。
下面这个图展示了传统RAG的流程。首先用户提个问题——以金融问答为例,用户可能会问(这里可以放一个金融问题的示例)。然后,问题会被转换成嵌入向量文本的数值表示。为了找到相关的上下文,系统会在查询嵌入和知识中心的嵌入之间做相似性搜索(比如余弦相似度)。这个知识中心,是由我们想要交流的那些文档构建的。先把非结构化文档处理一下,切成块,每块转成向量形式的嵌入,然后全部存进某个数据库(本地或云端都可以)。算法从库里捞出最相关的文本块,拼到查询里,作为上下文交给LLM。
## 当前RAG流程的局限性
传统RAG架构有不少硬伤,直接影响了它在知识密集型和领域特定任务中的表现。
最常见的问题就是把文档均匀地切成块——完全不管文档的结构和内容。每个块的大小一样(按单词或token数量),块和块之间可能有点重叠来保证上下文。检索器通常会返回最相似的top-k个块,每个块尺寸差不多。但这种做法根本没考虑文档本身的性质,有时候会漏掉关键信息。比如,问题的答案分布在好几个块里,但这些块在语义上不一定最相似——传统RAG压根不会返回最理想的组合。
语义搜索(用余弦相似度)是RAG的核心组件,但它也有自己的问题:可能检索到无关甚至相反的信息。这说明模型对语言的细微差别很敏感,结果也可能出人意料。最相似的块不等于最相关的块——但很多RAG流程都默认两者是一回事。另外,大多数标准嵌入算法没有任何领域特定知识,它们不理解某个专业领域里某些词或短语的特殊含义。
那种简单的分块加相似性搜索,在知识库只有一本长篇小说或一篇文章时可能还行。但大多数情况下,我们想打交道的是多种不同类型的文档,结构复杂得多,有标题、有表格。如果所有块都被一视同仁地丢进一个向量数据库,关键信息就丢了。比如文档集可能是不同公司或不同年份的财务报告。每个文本块,如果它在文档里的位置没被记住,可能就漏了公司名称或年份。这会导致检索返回过时或无用的块,因为它忽略了文本和文档的附加数据。
传统检索算法还缺乏那种更高级的、有推理能力的问答。它通常只是基于原始问题做相似性搜索,不会像人类那样经过逻辑步骤去找相关部分。打个比方,你让一位财务分析师计算指标X,他会推理:先想好怎么算这个指标,再找到文档里对应的数据。这个过程有好几个步骤。但简单的问题相似性搜索,完全抓不住这些复杂性。有时候,查询本身的信息就不足以告诉模型最相关的块在哪,还得靠额外的信息和逻辑步骤。
# 改进检索的技术
既然标准RAG管道有这么多局限,那显然得想办法解决。下面我们来聊一系列能优化RAG性能的技术,重点是金融文档问答这个场景。
## 分块技术
分块方法是检索过程里的关键,因为它决定了算法返回的上下文长什么样。分块策略不好,可能导致上下文不完整,或者反过来——塞了太多无关信息。
当固定了块大小时,大部分RAG管道都会遇到一个问题:信息要么太多要么太少,没法精准匹配每个查询。理想的方法得看知识库里文档的性质、模型期望的查询长度,以及回答这些问题需要多少上下文。
递归分块就是一个更灵活的策略。它用一些额外的指标和规则(比如标点符号)来让分块更动态。虽然块的大小还是相对一致的,但附加参数可以保证块不会在句子中间被切断。用Spacy和NLTK这样的Python库,我们可以实现更复杂的句子拆分技术,利用NLP技术更好地理解文档上下文。
在财务报告里,文档通常很长,而且包含复杂的结构比如表格。同一类的文档(比如10-K)通常有固定的格式,可以通过标题和副标题来识别。考虑到这些财务报告的特殊性,一种基于元素的分块策略可能会更有效。我们可以采用Unstructured论文里用的方法:如果遇到标题元素,就新开一个块;如果遇到表格元素,也新开一个块,并且保留整个表格。这样每个上下文返回的信息会更充足,能更有效地回答用户的问题。
## 查询扩展
查询扩展,也叫查询转换,指的是改变输入到RAG管道的问题,以便能基于用户的原始问题找到更合适的块。背后的逻辑是:用户的问题可能没有明确包含所有信息,来指示算法该在文档的哪里找上下文——尤其是通过余弦相似度搜索的时候。有时候,用户的问题本身甚至会误导算法找错方向,结果返回一个无关片段。对于更复杂的问题和文档,需要更多的推理步骤才能知道该去查哪里,而基本RAG管道完全缺乏这种能力。
一种模拟人类分析师逻辑的技术是假设文档嵌入(HyDE)。传统方法是只用用户原始查询做相似性搜索,而HyDE会先用LLM生成一个理论文档来响应查询,然后用原始问题和这个假设答案一起做相似性搜索。这种技术已经被证明优于标准检索器,而且不需要自定义嵌入算法。但缺点是有时可能导致不正确的结果——因为它依赖另一个LLM来提供额外上下文。
## 元数据注释和索引
当需要和多个不同文档交互时,元数据里可能藏着关键信息,但标准检索算法完全无视它们。我们之前遇到的一个问题是:原始的RAG管道会把不同文档的块混淆在一起。为了解决这个问题,我们试着为每个文档创建单独的向量数据库。但这种方法在大规模应用时不太现实,尤其当用户想在不同文档之间切换或同时跟多个文档交流的时候。
元数据注释可以克服这个障碍,进一步增强检索。元数据注释的性质应该和分块策略相匹配。比如,如果我们按元素把文档分块,那么可以在注释里包含每个元素的详细信息。例如,表格被单独放进一个块时,元数据可以记录这个表格的类型(比如利润表、现金流量表等)。另外,通常还会往元数据注释里加摘要和有代表性的关键词,提供更多上下文信息。
## 重新排序算法
在标准RAG管道里,我们可以指定算法应该返回多少个文档或块,以及有多少块会作为上下文提供给输入查询。通常top-1或top-2的块会被纳入上下文,这些是基于余弦相似度或k最近邻搜索给出的最佳结果。但问题是,这样的算法给出的是最相似的块,不一定是最相关的。
重新排序算法就是用来解决这个问题的——它优先考虑相关性,而不是相似性。简单说,余弦相似度这类方法可能会先给top-10的块排个序,但另一个独立的算法会重新按相关性排一遍,然后排序后的前一两个块会被作为上下文提供给输入查询。Cohere的重新排序算法就是一个流行的例子,它和其他算法一样,会用额外的机器学习和NLP技术来进一步评估相关性,超越简单的相似性搜索。
## 微调嵌入算法
嵌入算法负责把文本转换成数值表示,在RAG管道里作用巨大。我们可以根据特定领域的知识来微调嵌入算法,让它在该领域的检索上表现更好。嵌入还可以是动态的——当词语根据上下文有不同含义时,它们会自动调整。OpenAI的嵌入就是动态嵌入的例子。不过,领域特定的微调需要访问包含查询、文本语料库和相关文档的数据集。
# 评估
评估RAG系统时,主要看两个部分:模型检索上下文的能力,以及基于上下文回答问题的能力。在数据集中,我们有人类财务分析师给出的真实上下文和标准答案。把模型的响应和这些标准答案做个对比,叫做结构化评估;没有标准答案时做的评估叫非结构化评估。结构化评估能更准确地反映模型的水平,但非结构化评估也能告诉我们关于分块质量和答案质量的信息——而且大多数情况下,我们并没有真实数据可用,所以非结构化评估也是必需的。
## 检索质量
用结构化数据测试检索质量,主要看页面级和段落级准确性。在数据里,我们能看到整个文档,也知道人类分析师参考的是哪部分。把这部分和检索算法返回的块比较就行。如果参考上下文和算法上下文在同一页上,那检索准确性就高;段落级准确性也是类似的道理。
对于非结构化数据,可以用RAGAS框架定义的上下文相关性来评估检索到的块。具体做法是:让LLM计算与回答问题相关的上下文句子的数量。提取的句子数量与上下文中总句子数量的比率,就是上下文相关性得分。这个得分会惩罚冗余信息,奖励那些包含最多有用信息来回答问题的块。
## 回答准确性
对于结构化的问答评估,我们评估模型与数据集中标准答案的匹配程度。常用的指标包括BLEU、Rouge-L得分,以及余弦相似度。但这些指标不太理想——它们没法比较两个不同答案的语义含义,所以有时会有误导性。因此我们还会用LLM评估:给GPT这样的模型一个特定的提示,让它根据标准答案来判断候选答案的准确性。
我们也可以用非结构化的方式进一步评估生成器的答案与检索到的上下文的质量。这些指标衡量的是模型在给定上下文的情况下,响应的质量有多高。RAGAS框架提出了“上下文忠实度”这个指标,用来衡量模型的答案在多大程度上是基于给定上下文的。它通过计算答案中受上下文支持的陈述数量,除以答案中的总句子数量来衡量。这个指标也可以看作是评估模型是否在没有标准答案的情况下产生了幻觉——如果忠实度得分高,说明生成的答案里几乎所有句子都有上下文支持,模型没有额外编造信息。
# 数据集
为了评估使用RAG的模型性能,我们用到了Patronus AI开发的FinanceBench基准测试。这个测试包含针对美国上市公司的10,231个问题,覆盖了2015年到2023年间发布的财务文件,比如10-K、10-Q、8-K和业绩报告。
FinanceBench里每一条记录都包含一个问题(例如:“AMCOR在2023财年的调整后非GAAP EBITDA是多少”)、一个答案(例如:“AMCOR在2023财年的调整后EBITDA为20.18亿美元”)、一个证据字符串(包含验证答案所需的信息),以及相关文档的页码。这个数据集能全面评估RAG模型检索和生成准确答案的能力,也能很好地展示LLM在金融分析和决策中的实际应用潜力。
# 影响
在这个实验里,我们试图解决当前RAG管道的一些关键局限。有些问题有特定的技术能解决,有些则更难对付。随着这个领域的研究继续深入,肯定会有更多想法冒出来,让这些系统越来越准、越来越稳。
我们锁定的关键问题可以分成三类。第一个是:相关上下文往往分布在好几个位置,但当前算法只检索1到2个块。就算算法检索了前5到10个块,这些块也不一定是人类分析师知道该去找的那几个最相关的部分。第二个是:当前RAG管道认为相似性就等于相关性——这显然不对。第三个是:当前RAG管道把文档切成统一大小的片段,完全无视文档结构,结果导致一些部分不完整。
# 结果
由于AI这个领域发展太快,我们暂时不公开披露这些技术的结果。需要了解的话,可以联系我们的团队,我们可以根据具体情况进行说明。
# 结论和下一步
提升检索性能,能直接提高整个文档问答系统的质量。检索到正确的块,不仅能提供更好的引用,还能给出更好的答案。这也说明了一个强大的检索算法有多重要——就算生成器再强,没有正确的上下文,照样给出错误答案。
我们这次主要关注金融领域的RAG系统,特别是针对10-K文件的问答。但其实同样的思路也适用于医疗、法律等其他行业,因为它提供了一个系统框架,来改进面向特定领域任务的RAG管道。我们还用各种评估指标展示了这些增强技术是如何克服一些局限的。每个指标单独看可能不够全面,但放在一起,就能对系统的表现有一个清晰的感觉——不管有没有结构化数据可用。
虽然这篇文章探讨的技术已经解决了一些关键局限,但在其他领域还有不少工作可以做。尤其是检索算法面临的一个核心挑战:当上下文跨越文档的多个部分时,模型必须找到所有这些部分才能给出答案。引入知识图谱可能有助于检索系统做到这一点——给它们一套具体的指令,告诉它们怎么根据提出的问题来检索和回答。另一个值得探索的方向是:根据用户标注的数据对嵌入算法进行微调,让模型能更好地理解特定领域上下文中每个词和短语的细微差别。
# 引言
这几年,大型语言模型的崛起算是生成式AI领域的一个标志性转折点,也确实让很多行业的生产力有了质的提升。不过话说回来,这些模型虽然亮眼,但短板也很明显,有些领域想充分用好它们,还真不太容易。
最让人头疼的,一个是幻觉问题——模型会一本正经地胡说八道;另一个是它们对专业领域知识掌握得不够深。说白了,LLMs的知识都来自训练数据,如果不加点别的技术手段,让它们处理非常垂直的领域任务,效果往往不怎么样。
要搞出一个LLM,第一步是预训练——拿一个巨大的、通用的文本语料库去训练Transformer模型。这些数据覆盖面广,但既不专精于某个行业,也不会自动更新。所以像ChatGPT这样的模型,回答常识问题还行,一碰上专业性强、难度高的问题就容易露怯。而且,模型能在多大程度上搞定某个主题,很大程度上取决于这个主题在训练数据里出现了多少次。那些出现频率低的信息,LLMs天然就不擅长。金融领域的专业知识、行业术语,基本都属于这个范畴。这就是为什么标准LLM在特定领域的问答上总是差一口气。
那“知识注入”是怎么回事?就是让模型能接触到超出原始训练数据的信息,这是提升LLMs在特定领域任务上表现的主要思路。具体有两种主流做法:一种是给模型做额外的训练或微调,另一种是上下文学习,而RAG(检索增强生成)就是上下文学习里最火的那个版本。
## 微调
微调,就是调整模型参数,让它更适应某个特定任务或行业。通过微调,我们可以在特定领域的数据集上继续训练LLM,这样它就掌握了原始训练数据里没有的新知识。另外,用指令微调还能让模型的输出更一致、更可控。
微调主要有三种:无监督微调、监督式微调,还有强化学习。我们之前在金融特定问题上做过实验,用监督式微调来优化几种不同的模型。尤其是指令微调,它特别适合根据标注好的“输入-输出对”来让模型按我们的要求行事。不过,监督式微调有个明显的瓶颈——你得有高质量的数据才能有效训练。在问答任务里,这些数据集通常得靠人类专家来整理,有时也会借助其他LLMs来生成靠谱的问答对。
至于无监督微调,数据是没有标签的,相当于预训练过程的延续——只不过用的是一堆特定领域的文档和文本,而不是通用语料。但这里有个问题:模型不会从这些数据里拿到任何额外的指令或标签。我们只是希望它能记住这些训练数据里的信息,在遇到非常垂直的问答时能想起来用上。和监督式微调比起来,这种方法数据好找,扩展性更强,但微调完的效果可能不那么稳定。而且,就算用了领域数据,也不能保证LLM在需要的时候真能调出这些知识——尤其当领域数据量和预训练语料相比小得可怜时,这种不确定性就更大了。
## 检索增强生成
RAG是一种上下文学习方法,它让LLM能接触到新的知识源来回答问题。上下文学习的思路是:不更新模型参数(微调才需要动参数),而是直接把额外信息和用户的查询拼在一起,让模型参考。这样做的好处很明显——知识是直接喂给模型的,它能看到,不用像无监督微调那样担心知识淹没在训练数据里找不着。但缺点是,LLM的上下文窗口有限,能拼进去的信息也就那么多,往往比我们想注入给模型的总知识量少得多。
所以,RAG里“检索”这一步就特别关键——它得决定把哪个文本块加到输入查询里。这里我们重点聊的是基于文档的问答,尤其是金融文件和金融查询。假设手头有好几份报告,比如10-K表格或业绩电话会记录,你想跟它们“对话”、提问题。这种情况下,就得想办法高效地把这些金融文件的知识注入到LLM里。为了防止模型胡编乱造,最好的办法还是用上下文学习——在提示里明确告诉模型:不要自己发挥,只能参考问题后面附上的额外上下文。
问题是,这些文件又长又复杂,不可能每次提问都把整份文件塞进去当上下文。所以必须设计一套检索算法,从文档里挑出最相关的文本片段,然后把这个片段作为额外输入交给LLM,模型再根据问题和这个上下文生成回答。
下面这个图展示了传统RAG的流程。首先用户提个问题——以金融问答为例,用户可能会问(这里可以放一个金融问题的示例)。然后,问题会被转换成嵌入向量文本的数值表示。为了找到相关的上下文,系统会在查询嵌入和知识中心的嵌入之间做相似性搜索(比如余弦相似度)。这个知识中心,是由我们想要交流的那些文档构建的。先把非结构化文档处理一下,切成块,每块转成向量形式的嵌入,然后全部存进某个数据库(本地或云端都可以)。算法从库里捞出最相关的文本块,拼到查询里,作为上下文交给LLM。
## 当前RAG流程的局限性
传统RAG架构有不少硬伤,直接影响了它在知识密集型和领域特定任务中的表现。
最常见的问题就是把文档均匀地切成块——完全不管文档的结构和内容。每个块的大小一样(按单词或token数量),块和块之间可能有点重叠来保证上下文。检索器通常会返回最相似的top-k个块,每个块尺寸差不多。但这种做法根本没考虑文档本身的性质,有时候会漏掉关键信息。比如,问题的答案分布在好几个块里,但这些块在语义上不一定最相似——传统RAG压根不会返回最理想的组合。
语义搜索(用余弦相似度)是RAG的核心组件,但它也有自己的问题:可能检索到无关甚至相反的信息。这说明模型对语言的细微差别很敏感,结果也可能出人意料。最相似的块不等于最相关的块——但很多RAG流程都默认两者是一回事。另外,大多数标准嵌入算法没有任何领域特定知识,它们不理解某个专业领域里某些词或短语的特殊含义。
那种简单的分块加相似性搜索,在知识库只有一本长篇小说或一篇文章时可能还行。但大多数情况下,我们想打交道的是多种不同类型的文档,结构复杂得多,有标题、有表格。如果所有块都被一视同仁地丢进一个向量数据库,关键信息就丢了。比如文档集可能是不同公司或不同年份的财务报告。每个文本块,如果它在文档里的位置没被记住,可能就漏了公司名称或年份。这会导致检索返回过时或无用的块,因为它忽略了文本和文档的附加数据。
传统检索算法还缺乏那种更高级的、有推理能力的问答。它通常只是基于原始问题做相似性搜索,不会像人类那样经过逻辑步骤去找相关部分。打个比方,你让一位财务分析师计算指标X,他会推理:先想好怎么算这个指标,再找到文档里对应的数据。这个过程有好几个步骤。但简单的问题相似性搜索,完全抓不住这些复杂性。有时候,查询本身的信息就不足以告诉模型最相关的块在哪,还得靠额外的信息和逻辑步骤。
# 改进检索的技术
既然标准RAG管道有这么多局限,那显然得想办法解决。下面我们来聊一系列能优化RAG性能的技术,重点是金融文档问答这个场景。
## 分块技术
分块方法是检索过程里的关键,因为它决定了算法返回的上下文长什么样。分块策略不好,可能导致上下文不完整,或者反过来——塞了太多无关信息。
当固定了块大小时,大部分RAG管道都会遇到一个问题:信息要么太多要么太少,没法精准匹配每个查询。理想的方法得看知识库里文档的性质、模型期望的查询长度,以及回答这些问题需要多少上下文。
递归分块就是一个更灵活的策略。它用一些额外的指标和规则(比如标点符号)来让分块更动态。虽然块的大小还是相对一致的,但附加参数可以保证块不会在句子中间被切断。用Spacy和NLTK这样的Python库,我们可以实现更复杂的句子拆分技术,利用NLP技术更好地理解文档上下文。
在财务报告里,文档通常很长,而且包含复杂的结构比如表格。同一类的文档(比如10-K)通常有固定的格式,可以通过标题和副标题来识别。考虑到这些财务报告的特殊性,一种基于元素的分块策略可能会更有效。我们可以采用Unstructured论文里用的方法:如果遇到标题元素,就新开一个块;如果遇到表格元素,也新开一个块,并且保留整个表格。这样每个上下文返回的信息会更充足,能更有效地回答用户的问题。
## 查询扩展
查询扩展,也叫查询转换,指的是改变输入到RAG管道的问题,以便能基于用户的原始问题找到更合适的块。背后的逻辑是:用户的问题可能没有明确包含所有信息,来指示算法该在文档的哪里找上下文——尤其是通过余弦相似度搜索的时候。有时候,用户的问题本身甚至会误导算法找错方向,结果返回一个无关片段。对于更复杂的问题和文档,需要更多的推理步骤才能知道该去查哪里,而基本RAG管道完全缺乏这种能力。
一种模拟人类分析师逻辑的技术是假设文档嵌入(HyDE)。传统方法是只用用户原始查询做相似性搜索,而HyDE会先用LLM生成一个理论文档来响应查询,然后用原始问题和这个假设答案一起做相似性搜索。这种技术已经被证明优于标准检索器,而且不需要自定义嵌入算法。但缺点是有时可能导致不正确的结果——因为它依赖另一个LLM来提供额外上下文。
## 元数据注释和索引
当需要和多个不同文档交互时,元数据里可能藏着关键信息,但标准检索算法完全无视它们。我们之前遇到的一个问题是:原始的RAG管道会把不同文档的块混淆在一起。为了解决这个问题,我们试着为每个文档创建单独的向量数据库。但这种方法在大规模应用时不太现实,尤其当用户想在不同文档之间切换或同时跟多个文档交流的时候。
元数据注释可以克服这个障碍,进一步增强检索。元数据注释的性质应该和分块策略相匹配。比如,如果我们按元素把文档分块,那么可以在注释里包含每个元素的详细信息。例如,表格被单独放进一个块时,元数据可以记录这个表格的类型(比如利润表、现金流量表等)。另外,通常还会往元数据注释里加摘要和有代表性的关键词,提供更多上下文信息。
## 重新排序算法
在标准RAG管道里,我们可以指定算法应该返回多少个文档或块,以及有多少块会作为上下文提供给输入查询。通常top-1或top-2的块会被纳入上下文,这些是基于余弦相似度或k最近邻搜索给出的最佳结果。但问题是,这样的算法给出的是最相似的块,不一定是最相关的。
重新排序算法就是用来解决这个问题的——它优先考虑相关性,而不是相似性。简单说,余弦相似度这类方法可能会先给top-10的块排个序,但另一个独立的算法会重新按相关性排一遍,然后排序后的前一两个块会被作为上下文提供给输入查询。Cohere的重新排序算法就是一个流行的例子,它和其他算法一样,会用额外的机器学习和NLP技术来进一步评估相关性,超越简单的相似性搜索。
## 微调嵌入算法
嵌入算法负责把文本转换成数值表示,在RAG管道里作用巨大。我们可以根据特定领域的知识来微调嵌入算法,让它在该领域的检索上表现更好。嵌入还可以是动态的——当词语根据上下文有不同含义时,它们会自动调整。OpenAI的嵌入就是动态嵌入的例子。不过,领域特定的微调需要访问包含查询、文本语料库和相关文档的数据集。
# 评估
评估RAG系统时,主要看两个部分:模型检索上下文的能力,以及基于上下文回答问题的能力。在数据集中,我们有人类财务分析师给出的真实上下文和标准答案。把模型的响应和这些标准答案做个对比,叫做结构化评估;没有标准答案时做的评估叫非结构化评估。结构化评估能更准确地反映模型的水平,但非结构化评估也能告诉我们关于分块质量和答案质量的信息——而且大多数情况下,我们并没有真实数据可用,所以非结构化评估也是必需的。
## 检索质量
用结构化数据测试检索质量,主要看页面级和段落级准确性。在数据里,我们能看到整个文档,也知道人类分析师参考的是哪部分。把这部分和检索算法返回的块比较就行。如果参考上下文和算法上下文在同一页上,那检索准确性就高;段落级准确性也是类似的道理。
对于非结构化数据,可以用RAGAS框架定义的上下文相关性来评估检索到的块。具体做法是:让LLM计算与回答问题相关的上下文句子的数量。提取的句子数量与上下文中总句子数量的比率,就是上下文相关性得分。这个得分会惩罚冗余信息,奖励那些包含最多有用信息来回答问题的块。
## 回答准确性
对于结构化的问答评估,我们评估模型与数据集中标准答案的匹配程度。常用的指标包括BLEU、Rouge-L得分,以及余弦相似度。但这些指标不太理想——它们没法比较两个不同答案的语义含义,所以有时会有误导性。因此我们还会用LLM评估:给GPT这样的模型一个特定的提示,让它根据标准答案来判断候选答案的准确性。
我们也可以用非结构化的方式进一步评估生成器的答案与检索到的上下文的质量。这些指标衡量的是模型在给定上下文的情况下,响应的质量有多高。RAGAS框架提出了“上下文忠实度”这个指标,用来衡量模型的答案在多大程度上是基于给定上下文的。它通过计算答案中受上下文支持的陈述数量,除以答案中的总句子数量来衡量。这个指标也可以看作是评估模型是否在没有标准答案的情况下产生了幻觉——如果忠实度得分高,说明生成的答案里几乎所有句子都有上下文支持,模型没有额外编造信息。
# 数据集
为了评估使用RAG的模型性能,我们用到了Patronus AI开发的FinanceBench基准测试。这个测试包含针对美国上市公司的10,231个问题,覆盖了2015年到2023年间发布的财务文件,比如10-K、10-Q、8-K和业绩报告。
FinanceBench里每一条记录都包含一个问题(例如:“AMCOR在2023财年的调整后非GAAP EBITDA是多少”)、一个答案(例如:“AMCOR在2023财年的调整后EBITDA为20.18亿美元”)、一个证据字符串(包含验证答案所需的信息),以及相关文档的页码。这个数据集能全面评估RAG模型检索和生成准确答案的能力,也能很好地展示LLM在金融分析和决策中的实际应用潜力。
# 影响
在这个实验里,我们试图解决当前RAG管道的一些关键局限。有些问题有特定的技术能解决,有些则更难对付。随着这个领域的研究继续深入,肯定会有更多想法冒出来,让这些系统越来越准、越来越稳。
我们锁定的关键问题可以分成三类。第一个是:相关上下文往往分布在好几个位置,但当前算法只检索1到2个块。就算算法检索了前5到10个块,这些块也不一定是人类分析师知道该去找的那几个最相关的部分。第二个是:当前RAG管道认为相似性就等于相关性——这显然不对。第三个是:当前RAG管道把文档切成统一大小的片段,完全无视文档结构,结果导致一些部分不完整。
# 结果
由于AI这个领域发展太快,我们暂时不公开披露这些技术的结果。需要了解的话,可以联系我们的团队,我们可以根据具体情况进行说明。
# 结论和下一步
提升检索性能,能直接提高整个文档问答系统的质量。检索到正确的块,不仅能提供更好的引用,还能给出更好的答案。这也说明了一个强大的检索算法有多重要——就算生成器再强,没有正确的上下文,照样给出错误答案。
我们这次主要关注金融领域的RAG系统,特别是针对10-K文件的问答。但其实同样的思路也适用于医疗、法律等其他行业,因为它提供了一个系统框架,来改进面向特定领域任务的RAG管道。我们还用各种评估指标展示了这些增强技术是如何克服一些局限的。每个指标单独看可能不够全面,但放在一起,就能对系统的表现有一个清晰的感觉——不管有没有结构化数据可用。
虽然这篇文章探讨的技术已经解决了一些关键局限,但在其他领域还有不少工作可以做。尤其是检索算法面临的一个核心挑战:当上下文跨越文档的多个部分时,模型必须找到所有这些部分才能给出答案。引入知识图谱可能有助于检索系统做到这一点——给它们一套具体的指令,告诉它们怎么根据提出的问题来检索和回答。另一个值得探索的方向是:根据用户标注的数据对嵌入算法进行微调,让模型能更好地理解特定领域上下文中每个词和短语的细微差别。来源:https://www.53ai.com/news/LargeLanguageModel/1099.html
相关热点
继续查看同栏目近期热点。
延伸阅读
补充最近整理过的热点入口。
