从此不再只是召回生成! 披上Agent盔甲的RAG
嘿,大家好!这里是一个专一于AI智能体的频道!
当天我要和大家聊聊一些实战关系的内容。大模型在实践的工业场景下最经常出现的2个场景区分为运行助手(copilot), 文档/常识库问答(RAG)。理想上后者也逐渐在往更复杂的Agentic方向开展了,当天咱们来看以下如何搭建一个可控的RAG Agent。
RAG Agent外围是它的“大脑”,一个复杂确实定性图,它能让AI启动复杂的推理。而且,这个系统普通还能防止“幻觉”。确保一切答案都基于提供的数据,而不是凭空构想。
那咱们要成功的这个系统须要具有哪些方面的才干呢?
大体的框架图如下:
它是怎样上班的呢?便捷来说,就是先把PDF文档加载出去,而后启动文本预处置,生成每个章节的摘要,再把这些内容编码到向量库中。当有人问疑问时,AI会先对疑问脱敏,生成一个布局,而后再依据这个布局启动细化出执行义务,最后生成最终答案。详细步骤如下:
S1:构建adavanced RAG
数据预备,召回的retriever,可以了解为给文档建设出索引,用户后续的召回。当然在S1的搭建初级RAG中,咱们只有要分段的即可。
接上去,可以构建规范的adavanced RAG的流程,召回块 -> 保管与query关系的块 -> 依据能否关系来选择能否须要改写 -> 答案假设可用则完结了 (这里的很多函数都可以在langgraph的官网examples中找到)
S2:从adavanced RAG 到 Agent
关于更复杂的义务,仅经过基于语义相似性检索消息不可回答疑问,须要更复杂的pipeline。为了成功这一指标,咱们先遗记adavanced rag的流程。咱们须要定义出Agent的工具,普通RAG的tool就是S1中的retriever(召回)。(为了更复杂一些,咱们在S1数据预备中,预备了3个retriever(文档块、摘要、援用)独自作为不同的tool)
可以获取3个子图:
有了工具,那接上去就是Agent的外围,planning局部了。
方案制订
首先须要制订方案->方案细化到工具上。
制订方案
方案细化
示例:
question = {"question": "客人公是如何战败反动的?"}my_plan = planner.invoke(question) # Generate a plan to answer the questionprint(my_plan)refined_plan = break_down_plan_chain.invoke(my_plan.steps) # Refine the planprint(refined_plan)#### outputsteps1 = ['识别故事中的客人公和反动。','找到客人公和反动之间的高潮或最终对决。','剖析客人公在这次对决中采取的执行。','确定造成反动失败的详细执行或战略。','总结发现,回答客人公是如何战败反动的。']steps2 = ['经过从书籍块的向量存储、章节摘要或书籍援用中检索关系消息来识别故事中的客人公和反动。','经过从书籍块的向量存储、章节摘要或书籍援用中检索关系消息来定位客人公和反动之间的高潮或最终对决。','经过从书籍块的向量存储、章节摘要或书籍援用中检索关系消息来剖析客人公在这次对决中采取的执行。','经过从书籍块的向量存储、章节摘要或书籍援用中检索关系消息来确定造成反动失败的详细执行或战略。','经过依据给定高低文回答疑问来总结发现,回答客人公是如何战败反动的。']
方案降级
给定原始疑问、方案、过去的步骤以及迄今为止汇总的消息,降级方案 (这个相似于一个迭代用到的,一次性方案不可成功义务,经过屡次搜集消息迭代)
义务处置
定义义务处置程序 - 选择是经常使用哪个工具来处置方案中的每个义务
疑问脱敏
脱敏
为了生成一个总体方案,不带任何基于任何先验常识的成见LLM,咱们首先对输入疑问启动匿名化,并将称号实体映射到变量中
恢复
下面的串联起来:
# 用户疑问state1 = {'question': "how did the harry beat quirrell? \n"}print(f'question: {state1["question"]}')# 脱敏anonymized_question_output = anonymize_question_chain.invoke(state1)## 脱敏后的疑问和脱敏字段anonymized_question = anonymized_question_output["anonymized_question"]mapping = anonymized_question_output["mapping"]print(f'anonimized_querry: {anonymized_question} \n')print(f'mapping: {mapping} \n')# 制订方案plan = planner.invoke({"question": anonymized_question})print(text_wrap(f'plan: {plan.steps}'))print("")# 方案的脱敏消息恢复deanonimzed_plan = de_anonymize_plan_chain.invoke({"plan": plan.steps, "mapping": mapping})## 恢复后的方案print(text_wrap(f'deanonimized_plan: {deanonimzed_plan.plan}'))# outputquestion:harry是如何战败Quirrell的?anonimized_querry:X是如何战败Y的?mapping:{'X': 'harry', 'Y': 'Quirrell'}plan:['确定查问的高低文或畛域(例如,体育、竞赛、游戏等)。','搜集X和Y加入的事情或竞赛的消息。','找到X与Y竞争的特定实例或较量。','查找那个特定实例或较量的结果。','剖析较量的细节,以了解X是如何设法战败Y的。','总结解释X如何战败Y的关键点。']deanonimized_plan:['确定查问的高低文或畛域(例如,体育、竞赛、游戏等)。','搜集harry和Quirrell加入的事情或竞赛的消息。','找到harry与Quirrell竞争的特定实例或较量。','查找那个特定实例或较量的结果。','剖析较量的细节,以了解harry是如何设法战败Quirrell的。','总结解释harry如何战败Quirrell的关键点。']
最后在加一个判别,确定能否能依据消息推出答案。
全体的流程图如下:
本文转载自,作者: