1. 背景
大型语言模型在众多关键领域均已取得显著进展,并在各种下游任务中展现出卓越性能。
在医疗领域,这些模型尤显潜力,特别是在对责任感和可靠性要求极高的健康护理领域。这些模型通过全面的医学知识预训练,不仅能支持医生做出精确诊断和制定治疗计划,还能改善医疗资源分配。
然而,尽管医疗LLMs取得了显著成就,仍面临一些关键挑战,包括如何避免幻觉、知识更新以及专业化知识等问题。为解决这些问题,提出了检索增强生成(RAG)技术,通过利用外部知识库提供的医疗知识作为上下文信息来增强内容生成:一种有前景且必要的解决方案。
然而,尽管现有通过RAG增强LLMs的方法表现出一定前景,但它们通常忽略了系统状态变量的引入,这些变量对于确保自适应控制、检索停止和系统收敛至关重要。
此外,这些现有的RAG方法并非图灵完备,缺乏动态管理和监控检索过程的能力,无法保证在复杂的医疗场景中得出可靠的结论。在这些复杂的医疗场景中,决策通常需要复杂的多步骤推理和自适应响应,图灵完备性的缺失显著限制了系统的有效性和可靠性。
所以作者提出一种新的方法:构建一个图灵完备(Turing-Complete)的系统来有效管理状态变量,利用有限的逻辑框架来增强RAG过程。这种方法旨在克服现有技术的局限,并提高系统在处理复杂查询时的效率和准确性。
1.1 挑战1: 设计具有监控状态变量的图灵完备RAG系统
现有的RAG方法并未整合能动态跟踪和控制检索过程的监控状态变量。设计一个图灵完备的RAG系统需要引入能够实时准确地计算和反映系统演变上下文的状态变量。这些变量对于指导检索过程中的关键决策——如是否继续、停止或改进检索过程——至关重要。挑战在于如何在模型的前向传递过程中有效管理这些状态变量,同时保持对复杂医疗查询的适应性。
1.2 挑战2: 动态规划检索以维持最佳状态
一旦可以评估状态,如何动态管理状态以达到预期的最优状态成为关键问题。在现实中,医生通常根据对问题的理解程度决定是否进行检索以及检索什么内容,而不是盲目进行检索。这可能导致模型基于已有冗余信息作出混乱甚至误导的推断。因此,挑战在于如何系统地分析和计划后续步骤,并有效利用LLMs内部的参数化知识来维持最佳状态。
1.3 挑战3: 避免无关噪声影响系统状态
传统的RAG检索过程通常由查询关键词驱动,而非根据模型的具体需求,这可能引入大量无关和噪声的上下文。错误的知识随着检索和推理过程的积累而持续增加,导致资源浪费、无效记忆的累积,以及“lost in middle”问题的出现。解决这一挑战的关键在于如何有效地消除错误知识,以维持系统状态的准确性和完整性。
1.4 解决方案
针对上述挑战,本文作者(蒋欣科、方悦、秋日红,以上名称均为音译)提出了图灵完备的RAG(TC-RAG):一个为领域特定LLMs提供可靠且可信的医疗分析的图灵完备系统。
-
• 对于挑战1,设计了一个具有内存堆栈的图灵完备RAG系统,该系统监控中间状态,确保检索过程可靠地收敛到最佳结论。
-
• 对于挑战2,通过广泛收集医疗数据并预训练医疗LLM,提高了其推理和规划能力。
-
• 对于挑战3,TC-RAG结合了内存堆栈系统,利用回溯和总结操作及时删除错误并压缩冗余知识,减轻了错误信息和噪声的积累,从而提升了整体系统的效率和准确性。
2. 图灵完备的记忆栈定义(Tc Stack)
在TC-RAG中,记忆栈是核心组件,用于管理和控制大模型的状态和决策过程。
记忆栈TC定义为 TC=(S,A,M,δ,s0,F,σ),其中各元素具有以下含义:
-
• S(状态):表示大模型可能处于的状态。这里使用具体数值表示大模型的确定性程度,数值越小,表示大模型对当前任务的回答越确定。
-
• A(动作):代表大模型可以执行的动作。在基于栈的记忆系统中,通过“push”和“pop”这两个基本操作的组合,TC-RAG能够有效地管理大模型的交互记忆,精炼交互过程中的记忆内容,以及消除检索过程中引入的噪声。
-
• M(记忆栈):表示大模型的记忆栈,任务开始时用户的查询将被压入栈底。
-
• δ(状态转移函数):管理状态的变化,控制模型从一个状态到另一个状态的过渡。
-
• s0(初始状态):表示大模型的起始状态,通常设为一个高值(Large_Value),代表起始时的不确定性。
-
• F(终止状态):表示大模型的停止状态。当模型需要输出结论,且状态值低于 σ 阈值时,推理结束,此时栈顶的内容作为最终输出。
3. TC-RAG
TC-RAG定义了五种操作行为
-
• 思考:激发大模型的决策能力,让模型根据已有信息分析和处理,然后决定下一步行为。相关内容会被push到记忆栈中。
-
• 工具调用:当大模型凭借现有知识无法解答问题时,可调用网络搜索、文档检索、知识图谱检索等外部工具获取辅助信息。工具的名称及检索结果随后被push到记忆栈中。
-
• 反思:如果大模型发现记忆栈顶的内容与任务无关或有害,可以通过pop操作将这些元素移除,避免干扰。
-
• 总结:当栈顶信息过长或包含噪音时,模型通过总结操作处理信息——先pop出栈顶元素,进行总结,然后将精炼后的文本push回栈中。
-
• 结论:当模型准备给出最终答案且系统状态变量满足终止条件时,执行结论操作,结束整个决策过程。
这种基于栈的动态记忆管理方式使TC-RAG能够在复杂的决策环境中有效地控制信息流,确保生成的输出既准确又相关。
3.1 记忆栈和系统监测方法
TC-RAG(图灵完备的检索增强生成)通过其基于栈的记忆系统和状态变量来管理整个RAG框架的状态,并实现终止判定,允许模型自适应地进行检索并在适当的时刻输出最终答案。这一过程的实施细节如下:
-
1. 初始化与操作执行:
-
• 压栈操作: 一开始,大模型将用户的查询(Query)压入栈底。
-
• 复合操作(Composed Action Set): 大模型继续执行定义好的一系列操作,如思考(push)、反思(pop)、工具执行(push)和总结(pop->push)。
在执行工具调用时,模型可以接入多源数据(如图谱、文档库、网页百科等),丰富回答的内容和质量。
-
-
2. 状态变量更新与重置:
-
• 状态更新: 在大模型执行到结论(Conclusion)或深入思考(Thought)的过程中,系统会不断更新其状态变量。
-
• 状态重置: 当执行包含pop动作的操作时,状态变量会被重置为上一个思考动作后的值,以保证系统的状态完备性和连续性。
-
-
3. 终止与输出:
-
• 判定终止条件: 当大模型输出结论且状态变量小于设定的阈值时,输出最终答案。
如果不满足条件,大模型将继续其推理过程。
-
3.2 状态变量的监控与停机问题的解决
为解决自适应检索中的停机问题,TC-RAG在系统中引入了状态变量,这些变量有助于监测系统状态并决定何时停止系统运行。这些状态变量主要包括:
-
• 条件困惑度(Conditional Perplexity): 这一度量通过计算大模型在用户提问的基础上生成栈顶输出内容时的困惑度来得到。困惑度越低,表明模型对其输出的确定性越高。
-
• 不确定性(Uncertainty): 通过计算栈顶输出信息的熵值得到,熵值较低表明大模型对输出结果的信心较高,即模型的输出更加确定。
当这些状态变量的值低于预设的阈值时,表明大模型对于最终结果具有较高的信心,系统则可以决定输出最终答案并停止运行。这种基于状态变量的动态监控和管理,确保了TC-RAG在处理复杂查询时的有效性和准确性,同时也解决了传统检索增强模型中的终止问题。
整个方法部分的伪代码如下:
def whitebox_pop_react_executor(self, text):# todo 引入了status value'''最关键的就是executor的执行循环了,executor会始终进行如下事件循环直到 目标被解决了 或者 思考迭代次数超过了最大次数:根据之前已经完成的所有步骤(一个步骤包括 ReAct框架中的 Thought、Action、Observation)和 目标(用户的问题)规划出接下来的Action(使用什么工具 以及 工具的输入)检测是否已经达成目标,即Action是不是ActionFinish。是的话就返回结果,不是的话说明还有行动要完成根据Action,执行具体的工具,等待工具返回结果。工具返回的结果就是这一轮步骤的Observation保存当前步骤到记忆上下文,如此反复'''# 0. 组装promptself.renew_message_list() # 将消息队列先置为空,并将当前状态置于最大值# 1. 将user query放入message list中user_query = "Question:" + textself.push_message(user_query)actions_taken = 0while actions_taken < self.rc_max_react_loop:# 1. 先plan,得到新的responsemessages = [{"role": "system", "content": self.system_prompt}, {"role": "user", "content": self.message_list_to_str()}]call_results = self.model.generate(messages, use_logprob=True, use_attention=True, use_entropy=True, use_logits=True)## 从call_results中取出text,attention和logprobs,entropies等信息出来new_response = call_results["text"] # 文本# 1.5 判错条件new_response = self.process_no_regular_output(new_response)logger.info(f"response: {new_response}")# 2. 判断是否包含结束标识符Final Answer (LLM如果理解错了new_response也会输出final answer)if 'Final Answer:' in new_response: # 忽略topK 次if actions_taken >= self.topK:# 将结果加入消息队列中new_response = self.parse_latest_final_answer(new_response)# 当出现是final_answer和thought的时候,再更新系统的状态变量需要用到的tensor:## 只取出new_response的内容,避免其他的影响self.update_status_value(call_results, new_response)self.calculate_now_state_value(top_content=new_response)## 停止条件:出现final answer且次数太多了,且小于sigmaif self.obtain_now_state() < self.sigma: # 为final answer且小于simga, 模型结束, 压栈self.push_message(new_response)breakelse:# 这个时候由于以及压栈status了,下面又会被替换为thought,所以会被重复压栈,需要pop出去状态statusself.backtrack_now_state()# else:# 如果未达到指定次数,或阈值不满足要求,则替换为thought => note 这里可以做创新,step back and rethoughtnew_response = new_response.replace("Final Answer:", "Thought:")# else: # action / thought# 3. 解析可能需要使用的工具:这里的response需要将大模型回答的observation截去;保留thoughtplugin_name, plugin_args, new_response_before_detact = self.parse_latest_plugin_call(new_response)# 3.5 如果new_response中存在Backtrack,这时应该丢弃所有其他的动作new_response = self.detact_backtrack(new_response_before_detact)# 保留当前栈顶信息,如果当前栈顶是thought,且下一次行动是backtrack,那么状态需要回撤top_stack_content = self.top_message()self.push_message(new_response)if "Thought" in new_response: # push进站,检查thought是否存在,以及是否需要更新status# 当出现是final_answer和thought的时候,再更新系统的状态变量需要用到的tensor:## fixme 只取出new_response的内容,避免其他的影响self.update_status_value(call_results, new_response)self.calculate_now_state_value() # 得到当前的state并更新系统status值self.pop_message() # 检查是否需要pop message# 如果pop了thought,那么就需要回撤statusif 'Thought' in top_stack_content and "Backtrack" in new_response:self.backtrack_now_state() # 回撤之前的status# 4. 解析完工具后调用, 添加observation进入记忆中if plugin_name and new_response == new_response_before_detact:observations = self.call_plugin(plugin_name, plugin_args)self.push_message(observations)actions_taken += 1return self.top_message(), self.message_list_to_str(), self.absoulte_message_list_to_str()
提示词如下所示:
3.3 和ReACT的对比:
Tc-RAG 做了一个实验与ReACT进行对比:
处理无关噪声的能力:
-
• 1.ReACT的限制: 在可视化分析中,ReACT处理无关噪声的累积存在困难,容易导致系统的过度自信和错误结论。例如,当遇到单位不一致时,ReACT可能会做出错误的判断。
-
• 2.TC-RAG的优势: 相比之下,TC-RAG通过其内存堆栈系统有效管理内存,并利用总结和回溯操作修剪错误的检索结果,避免了因噪声累积导致的误判,从而得出更加简洁和准确的结论。
状态管理和监控:
-
• 1.ReACT的缺陷:ReACT缺乏有效的状态管理机制,可能在系统状态值较高时过早地确定答案,导致结论的不准确。
-
• 2.TC-RAG的方法:TC-RAG则通过动态地监控整个RAG过程中的状态变量,确保系统状态值符合设定的终止条件。这种细致的状态管理使得TC-RAG在决策过程中更为谨慎,能够在适当的时刻给出最终答案。
4. 效果评估
TC-RAG(图灵完备的检索增强生成)系统通过在多个医疗相关数据集上的表现展示了其优越性。
4.1 TC-RAG在利用相同数据库资源的情况下,是否超越了当前最顶尖的RAG方法?
上表展示了在MMCU-Medical、CMB-Exam和CMB-Clin数据集上的准确率结果。
对比RAG方法与基础LLM。考虑到患者咨询的复杂度,发现Naive RAG方法相较于无RAG基准线的提升微乎其微。而Adaptive RAG的表现则显著优于Advanced RAG,大幅领先其他方法。表明在特定领域情境下,采用更精细子模块进行高级和自适应检索的重要性。
对比TC-RAG与其他RAG方法。TC-RAG模型在所有数据集上均明显超越了基线模型,各项指标的平均提升幅度高达7.20%。例如,EM和BLEU-4的得分分别提升了约2.60%-5.62%和8.23%-13.72%。这些成果凸显了TC-RAG模块在系统状态与记忆管理以及自适应检索方面的高效性。此外,特定领域的LLM显著优于通用LLM,这进一步证实了预训练医疗LLM以支持TC-RAG的必要性,与C2相契合。
4.2 TC-RAG的堆叠框架是否奏效?各个组成部分对整体效能有何具体影响?
通过消融实验来评估TC-RAG中各个组件的作用,包括三种变体:
-
• (1) 缺少回溯功能的TC-RAG(标记为“无回溯”)
-
• (2) 缺少摘要功能的TC-RAG(标记为“无摘要”)
-
• (3) 缺少状态监控器的TC-RAG,仅依赖LLM的“最终答案”来决定何时结束,转变为一个黑箱系统(标记为“无状态监控”)。
实验结果表明,每个组件都对TC-RAG的整体表现起到了积极作用。任何一个组件的缺失都会导致效果显著下降。特别是,缺少状态监控器会导致性能大幅下降,这凸显了监控过程中系统状态变量的关键性,对于防止过度自信和确保恰当的终止至关重要,从而避免检索过度或不足。
此外,移除回溯和摘要功能进一步强调了有效记忆管理的必要性。这些功能对于减少无关干扰和保持系统状态最优化至关重要。
4.3 TC-RAG能否真正地触发错误的执行记忆,注入噪声,并实现有效的记忆管理?
对比分析了两种RAG系统:一种缺乏记忆和状态管理功能的ReACT系统,以及TC-RAG系 统。
评估了这两种系统在状态管理、信息检索和推理过程中的表现,尤其是在处理不相关或错误噪声时。
基于ReACT的方法在积累不相关噪声时表现不佳,这会导致过度自信和错误结论。
与此相对,TC-RAG系统能够有效地管理其记忆,并运用摘要和回溯操作来剔除错误的检索结果,从而得出更精炼和准确的结论,这凸显了TC-RAG在处理复杂任务时的卓越性能(符合C3标准)。
此外,发现基于ReACT的方法在系统状态值较高时容易过早地确定答案,这是由于缺乏有效的状态管理。而TC-RAG则能动态监控RAG处理过程,确保系统状态值达到终止条件,这强调了构建系统状态的重要性。
4.4 TC-RAG对于不同系统类型cppl和uct的超参数σ的敏感度如何?
为展示系统状态变量的效能,在MMCU-Medical和CMB-Exam数据集上,利用两个大型语言模型(LLM)对TC-RAG进行了实验。
如上图所示,随着σ值的增加,系统状态受到的约束减少,LLM表现出“过度自信”,在未完全分析和规划必要步骤前便急于下结论。
反之,当σ值降低,状态变量对输出的影响增强,使得系统更难达到终止状态。因此,LLM变得过于谨慎,频繁尝试多种操作,从而略微降低了效率。总体来看,可以通过调整σ值来平衡TC-RAG的性能与准确性。
来源 | 大语言模型论文综述