增强推理的生成流程
🛠️ 为什么RAG有问题——而ReAG是如何解决这个问题的检索增强生成(RAG)曾承诺带来更智能的人工智能,但其缺陷正阻碍着我们的发展。这就是为什么我们需要推理增强生成(ReAG)来实现升级。
❌ 传统RAG的缺点传统的RAG系统就像那些记忆力不好的图书管理员一样:
- 语义搜索并不聪明 🤖:它们基于表面相似检索文档(例如,将“空气污染”匹配到“汽车排放”),但会遗漏上下文相关的相关内容(例如,题为“城市肺部疾病趋势”的研究)23。
- 基础设施噩梦 🏗️:分块、嵌入和向量数据库增加了复杂性。每一步都存在错误的风险,例如过时的索引或不匹配的拆分2。
- 静态知识 ⏳:对于医学或金融等需要每日更新数据的领域来说,更新索引的文档速度慢——这无异于死刑2。
想象一下问“为什么北极熊在减少?”却得到笼统的回答,比如“北极冰盖融化”,而忽略了关于“无冰觅食的中断”的关键研究。这就是RAG的问题。
🚀 迎接ReAG:不仅检索,还要推理ReAG 跳过了 RAG 管道。它不是将文档预处理成可搜索的片段,而是直接将 原始资料(文本文件、电子表格、网址)输入语言模型。然后,LLM 开始处理:
- 读取整个文档 📖:不拆分也不嵌入,完整上下文得以保留。
- 问两个问题 ❓:
-
“这份文档有用没?”(相关性检查)
- “哪些具体的部分最重要?”(内容筛选)
- 整合答案 🧩:像研究员一样结合洞察,即使关键词不匹配也能把各个点联系起来.
示例:对于北极熊的问题,ReAG系统可能会解析一篇名为《海冰的热动力学》的气候报告,并提取一段将冰层流失与饮食模式混乱相联系的内容——即使报告中从未提到过“北极熊”。
⚙️ ReAG是如何工作的:技术解析
📂文档输入:
- 无需预处理 — 文档按原样输入(如 Markdown、PDF 和 URL)
⚡并行分析的LLM:
- 每份文档都会同时进行着相关性检验和内容提取
🌐动态合成技术 :
- 无关文档会被过滤掉,经过验证的内容用来生成回答。
- 处理动态数据 📰:实时新闻、现场市场行情或不断变化的研究?ReAG 能实时处理更新,无需重新嵌入。
- 解决复杂查询 🧠:2008年后监管规定如何影响社区银行?这类问题需要将不同来源的信息拼接在一起。ReAG 在推断间接链接方面更胜一筹,比RAG 更强。
- 多模态掌握 📊:可以同时分析图表、表格和文本,无需额外预处理。
- 成本更高 💸:通过ReAG处理100份文档意味着需要调用大语言模型100次,而RAG只需进行25次便宜的向量搜索。
- 扩展性更差 🐢:对于包含百万文档的大型数据集,结合方法(RAG + ReAG)可能效果更好。
职责:相关性筛选:第一阶段过滤
为什么它这么出色:
- 通过GROQ的LPU架构,实现超快推理(每秒500+令牌) 🔥
- 70B参数支持对文档相关性进行细腻评分,即使是间接查询也能支持。
-
拥有128K令牌的大上下文窗口
示例:例如标记一篇名为《海冰热动力学》的气候报告为与“北极熊数量减少”相关,尽管报告中没有提到任何相关关键词。
(聪明的大脑来了!)
角色:响应合成 (二次推理)
你知道为什么它这么亮眼吗?
- 轻量级且成本效益高的14B模型,专门用于提取和总结。
- 通过Ollama在本地运行,既保证了数据隐私,又减少了云成本。
-
128K令牌的大上下文窗口
例子:从被标记的文档中提取 “2010年以来无冰喂食时段减少了22个百分点”。
朗链 🎼
注:LangChain为原文专有名词,保持不变。
角色:编排(Orchestration)与工作流自动处理
主要特点:
- 并行化GROQ(相关性)和Ollama(生成)任务。
- 管理文档流转、错误处理和输出聚合。
- 成本效益 💸:将繁重的任务交给GROQ的硬件优化API处理,而Ollama则在本地处理轻量级任务。
- 可扩展性 📈:GROQ的LPUs可以处理数千个并发文档的评估。
- 灵活性 🧩:可以轻松替换模型(例如,用Mistral替换Ollama)而无需重写管道。
注释:个人注意到,当文档页数超过50页时,为了更好地利用ReAG来处理大上下文窗口的LLM。
🪀代码实现 of ReAG安装所需的依赖
!pip install langchain langchain_groq langchain_ollama langchain_community pymupdf pypdf
下载资料
!mkdir ./data
!mkdir ./chunk_caches
!wget "https://www.binasss.sa.cr/int23/8.pdf" -O "./data/fibromyalgia.pdf" # 下载纤维肌痛症的相关PDF文件
安装LLM
from langchain_groq import ChatGroq # 导入ChatGroq类,用于Groq模型的聊天
from langchain_ollama import ChatOllama # 导入ChatOllama类,用于Ollama模型的聊天
import os # 引入操作系统库
os.environ["GROQ_API_KEY"] = "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" # 设置Groq API的环境变量
# 设置Groq模型的相关参数
llm_relevancy = ChatGroq(
model="llama-3.3-70b-versatile", # 使用llama-3.3-70b-versatile模型
temperature=0, # 设置温度为0,表示确定性输出
)
# 设置Ollama模型的相关参数
llm = ChatOllama(
model="deepseek-r1:14b", # 使用deepseek-r1:14b模型
temperature=0.6, # 设置温度为0.6,表示有一定的随机性
max_tokens=3000, # 设置最大生成的token数量为3000
)
设置系统提示
REAG_SYSTEM_PROMPT = """
# 角色与目标
你是一个智能的知识检索小助手。你的任务是分析提供的文档或链接,提取最相关的信息来帮助用户。
# 指令
1. 细心分析用户的查询,识别关键点和需求。
2. 通过提供的来源查找相关的信息,并在'content'字段中输出相关内容。
3. 如果在文档中找不到相关信息,返回'isIrrelevant: true',否则返回'isIrrelevant: false'。
# 约束
- 不要超出已有数据做额外假设
- 清楚表明如果找不到相关信息
- 在选取来源时保持客观
"""
定义RAG提示语
rag_prompt = """你是一个帮助回答问题的助手。请根据以下检索到的信息回答问题。如果不知道答案,请直接说不知道。请用简短的三句话回答。
问题:{question}
上下文:{context}
回答:(请在此处作答)
"""
定义响应方案
从 pydantic 导入 BaseModel 和 Field
从 typing 导入 List
从 langchain_core.output_parsers 导入 JsonOutputParser
class ResponseSchema(BaseModel):
content: str = Field(..., description="页面内容需要与问题相关或足够回答问题")
reasoning: str = Field(..., description="解释为什么选择这个页面内容来回答问题")
is_irrelevant: bool = Field(..., description="如果内容与问题无关或不充分,则指定为 'True',否则为 'False'")
class RelevancySchemaMessage(BaseModel):
source: ResponseSchema
relevancy_parser = JsonOutputParser(pydantic_object=RelevancySchemaMessage)
先加载文件,再进行处理
从 langchain_community.document_loaders 导入 PyMuPDFLoader 作为
file_path = "./data/fibromyalgia.pdf"
loader = PyMuPDFLoader(file_path)
# 加载文件
docs = loader.load()
print(len(docs))
print(docs[0].元数据)
回复
8
{'生成者': 'Acrobat Distiller 6.0 for Windows',
'创建者': 'Elsevier',
'创建时间': '2023-01-20 09:25:19',
'来源': './data/fibromyalgia.pdf',
'文件位置': './data/fibromyalgia.pdf',
'总页数': '8',
'格式': 'PDF 1.7',
'标题': '纤维肌痛:诊断与管理',
'作者': 'Bradford T. Winslow MD',
'主题': '美国家庭医生, 107 (2023) 137-144',
'关键词': '',
'修改时间': '2023-02-27 15:02:12',
'trapped': '',
'modDate': "D:20230227150212+05'30'",
'creationDate': "D:20230120092519-06'00'",
'页面编号': 0}
帮助格式化文档的函数
导入 langchain.schema 中的 Document
def format_doc(doc: Document) -> str:
return f"文档标题:{doc.metadata['title']}\n页码:{doc.metadata['page']}\n正文:{doc.page_content}"
提取相关上下文的辅助工具
### 辅助函数以提取相关上下文
from langchain_core.prompts import PromptTemplate
def extract_relevant_context(question, documents):
result = []
for doc in documents:
formatted_documents = format_doc(doc)
system = f"{REAG_SYSTEM_PROMPT}\n\n# 可用资源\n\n{formatted_documents}"
prompt = f"""判断提供的‘可用资源’内容是否足够且与问题相关。
问题:{question}
# 操作说明
1. 仔细分析提供的上下文以检查其与问题的相关性。
2. 严格使用以下JSON结构格式响应:
```json
{{"页面内容":<<与问题相关的文档页面内容>>,
"理由":<<选择该页面内容的原因>>,
"是否无关":<<如果页面内容不足以回答问题,请指定为'True';如果页面内容足以回答问题,请指定为'False'>>
}}
"""
messages =[ {"角色": "系统", "内容": system},
{"角色": "用户", "内容": prompt},
]
response = llm_relevancy.invoke(messages)
print(response.content)
formatted_response = relevancy_parser.parse(response.content)
result.append(formatted_response)
final_context = []
for items in result:
if (items['是否无关'] == False) or ( items['是否无关'] == 'false') or (items['是否无关'] == 'False'):
final_context.append(items['页面内容'])
return final_context
调用一下函数来找到相关的上下文信息
question = "什么是纤维肌痛综合征?"
final_context = 提取相关背景信息(docs, )
print(len(final_context))
帮助生成响应的函数
def generate_response(question, final_context):
prompt = PromptTemplate(template=rag_prompt,
input_variables=["问题", "上下文"],)
chain = prompt | llm
响应 = chain.invoke({"问题":question,"上下文":final_context})
print(响应.content.split("\n\n")[-1])
return 响应.content.split("\n\n")[-1]
生成响应
final_response = generate_response(问题, final_context)
final_response
#################### 回复 #################################
'纤维肌痛症是一种慢性疾病,以广泛的肌肉和骨骼疼痛、疲劳、睡眠障碍和认知困难(如“纤维脑雾”症状)为特征。这种疾病通常与神经系统处理疼痛的方式改变有关,导致对疼痛的敏感度增加。诊断主要依据长期疼痛、疲劳和睡眠问题,但没有发现炎症或损伤的迹象。'
问题二
question = "纤维肌痛的病因是什么?"
final_context = extract_relevant_context(question, docs)
final_response = generate_response(question, final_context)
##################################Response ############################
纤维肌痛可能由中枢痛觉调节机制失调引起,导致疼痛敏感度增加(痛觉过敏或痛觉异常)。可能的原因有下丘脑-垂体-肾上腺轴功能障碍、炎症、星形胶质细胞激活、小纤维神经病、感染如Epstein-Barr病毒或莱姆病,以及遗传因素。其他如感染或药物副作用等也可能引起类似症状。
问题三
question = "患有风湿性疾病的人是否可能患有纤维肌痛?"
final_context = extract_relevant_context(question, docs)
final_response = generate_response(question, final_context)
############################响应################################
是的,患有风湿性疾病的人,比如类风湿性关节炎或银屑性关节炎,也可能患有纤维肌痛。这是因为它们有重叠的症状,这使得诊断变得比较困难。
第4题
question = "纤维肌痛的非药物治疗有哪些?"
final_context = extract_relevant_context(question, docs)
final_response = generate_response(question, final_context)
#############################响应###########################
纤维肌痛的非药物治疗方法包括患者教育、运动和认知行为疗法(CBT)。
问题5:
question = "根据2016年美国风湿病学学会的纤维肌痛诊断标准,纤维肌痛的诊断标准是什么?"
final_context = extract_relevant_context(question,docs)
final_response = generate_response(question,final_context)
###############################回复#############################
根据2016年美国风湿病学会的诊断标准,纤维肌痛患者需要在至少四个身体部位出现广泛性疼痛感至少三个月。此外,患者还需要满足Widespread Pain Index (WPI) 评分≥7且Symptom Severity Scale (SSS) 评分≥5,或者WPI评分≥4且SSS评分≥9。还必须排除其他可能引起这些症状的疾病。
第6题
question = "阿米替林的起始剂量是多少?"
final_context = extract_relevant_context(question,docs)
final_response = generate_response(question,final_context)
#########################RESPONSE###########################
成人阿米替林的起始剂量通常是每天25到50毫克,通常从较低的剂量5到10毫克开始,晚上服用以最小化副作用,逐渐增加剂量。
第七题.
question = "关于2019年AAPT纤维肌痛诊断标准,提到了哪些内容?"
final_context = extract_relevant_context(question, docs)
final_response = generate_response(question, final_context)
#########################RESPONSE####################################
2019年AAPT的纤维肌痛标准包括至少六个指定区域出现多部位疼痛,中到重度的睡眠问题或疲劳症状,以及症状持续至少三个月。
第8题
question = "治疗纤维肌痛的药物和剂量有哪些?"
final_context = extract_relevant_context(question,docs)
print(final_context)
final_response = generate_response(question,final_context)
#######################Response##################################
['度洛西汀、米拉可普兰、普瑞巴林和阿米替林可能是治疗纤维肌痛的有效药物。而非甾体抗炎药和阿片类药物对纤维肌痛的疗效不佳,并且存在显著的限制。',
'阿米替林、环苯扎林、度洛西汀(Cymbalta)、米拉可普兰(Savella)和普瑞巴林(Lyrica)对纤维肌痛疼痛有效。',
'阿米替林(三环类抗抑郁药)- 每晚 5 至 10 毫克,每晚 20 至 30 毫克。环苯扎林(肌肉松弛剂;三环类衍生物)- 每晚 5 至 10 毫克,每日 1 至 3 次,每次 10 至 40 毫克。度洛西汀(Cymbalta;血清素和去甲肾上腺素再摄取抑制剂)- 每晨 20 至 30 毫克,每晨 60 毫克。米拉可普兰(Savella;血清素和去甲肾上腺素再摄取抑制剂)- 每晨 12.5 毫克,每日 2 次,每次 50 毫克。普瑞巴林(Lyrica;加巴喷丁类似物)- 每晚 25 至 50 毫克,每晚 150 至 450 毫克。',
'纤维肌痛通常用普瑞巴林(Lyrica)和度洛西汀(Cymbalta)等药物治疗。普瑞巴林可以从每天两次,每次 75 毫克起始,最大剂量为每天 450 毫克。度洛西汀可以从每天一次,每次 30 毫克起始,目标剂量为每天 60 毫克。',
'纤维肌痛通常用普瑞巴林(Lyrica)和度洛西汀(Cymbalta)等药物治疗。普瑞巴林可以从每天两次,每次 75 毫克起始,最大剂量为每天 450 毫克。度洛西汀可以从每天一次,每次 30 毫克起始,目标剂量为每天 60 毫克。']
最后的回复
print(final_response)
#############################响应############################
用于治疗纤维肌痛的常用药物包括:
-
阿米替林:一种三环类抗抑郁药,通常在晚上服用,剂量范围为5至30毫克。
-
环苯扎林:一种肌肉松弛剂和三环类衍生物,通常每天分次服用,每次不超过40毫克。
-
度洛西汀(欣米宁):一种血清素-去甲肾上腺素再摄取抑制剂,通常在早上服用,初始剂量为20至30毫克,如有必要可增加到60毫克。
-
米纳普林(萨维拉):另一种血清素-去甲肾上腺素再摄取抑制剂,初始剂量为早晨12.5毫克,必要时可增加到每天两次,每次50毫克。
-
普瑞巴林(乐瑞卡):一种加巴喷丁类似物,通常在晚上服用,初始剂量为每天早晚各75毫克,最大剂量为450毫克/天。
这些药物对于管理纤维肌痛相关的疼痛非常有效。重要的是需要注意,在医生指导下调整剂量,从低剂量开始并根据需要增加剂量。此外,非甾体抗炎药(NSAIDs)和阿片类药不建议用于治疗纤维肌痛,因为它们效果有限且可能带来副作用。
- 医学研究 🩺:从原始临床试验数据和期刊中综合提炼见解。
- 金融市场 📉:分析实时财报和SEC文件,制定实时的投资策略。
- 法律分析 ⚖️:解析复杂的判例法,识别先例之间的联系。
- 混合系统 🤝:使用RAG进行初始筛选,接着用ReAG进行深入分析,使ReAG更强大。
- 更便宜的模型 📉:开源LLM(如DeepSeek)和量化将节省成本。
- 更大的上下文窗口 🪟:未来的模型将处理数十亿字符的文档,使ReAG更强大。
ReAG并不是要取代RAG——它是为了重新思考AI与知识的互动方式。通过将检索看作一个推理任务,ReAG反映了人类的研究方式:全面、细致且上下文驱动。
参考文献与推荐阅读