什么是Agentic RAG

经典RAG应用的范式与架构已经非常流行,你甚至可以在很短的时间内借助成熟框架开发一个简单能用的RAG应用:用户问题被输入RAG、应用执行检索、从被向量化的文档中检索相关知识块、送入到LLM(大语言模型)进行合成响应:

前排提示,文末有大模型AGI-CSDN独家资料包哦!

但是让我们考虑这样一个应用场景:企业中有大量不同来源与类型的文档(在实际中并不一定代表“文件”,也可以是某种非文件形态的信息,比如存放在RDBMS中的数据),现在需要在这些文档之上构建一个依赖于它们的、知识密集型的应用或工具。这些需求包括:

  • 基于全局的理解文档后回答问题。比如:对某知识内容进行总结摘要?

  • 跨文档与知识库的回答问题。比如:比较不同文档内容的区别?

  • 结合非知识工具的复合场景。比如:从文档提取产品介绍发送给xx客户?

这种复杂需求的场景如果使用经典RAG架构,通过chunks+向量+top_K检索来获得并插入上下文,直接让LLM来给出答案,显然是不现实的。经典RAG在回答文档相关的事实性问题时可以工作的不错,但是实际的知识应用并不总是这种类型! 当然你也可以借助一些改进的RAG范式来提高应用场景的适应性,比如RAPTOR(基于文档树的多级检索机制,有利于回答从细节到高层理解的多级问题),但在一些跨文档或者需要结合工具的场景仍然无法胜任。

这里介绍Agentic RAG方案:一种基于AI Agent的方法,借助Agent的任务规划与工具能力,来协调完成对多文档的、多类型的问答需求。 既能提供RAG的基础查询能力,也能提供基于RAG之上更多样与复杂任务能力。概念架构如下:

在这里的Agentic RAG架构中:

  • RAG应用(RAG引擎,即借助索引实现检索并合成响应)退化成一个Agent使用的知识工具。你可以针对一个文档/知识库构建多种不同的RAG引擎,比如使用向量索引来回答事实性问题;使用摘要索引来回答总结性问题;使用知识图谱索引来回答需要更多关联性的问题等

  • 在单个文档/知识库的多个RAG引擎之上设置一个ToolAgent,把RAG引擎作为该Agent的tools,并利用LLM的能力由ToolAgent在自己“负责”的文档内使用这些tools来回答问题

  • 设置一个总的顶级代理TopAgent来管理所有的低阶ToolAgent,将ToolAgent看作自己的tools,仍然利用LLM来规划、协调、执行用户问题的回答方案

    以下使用LlamaIndex来实现这个架构(如果你是LangChain用户,也完全可以读懂并参考实现)

02

HOT SUMMER

实现Agentic RAG

让我们来一步步实现简单的Agentic RAG。

【准备测试文档】

首先这里准备三个RAG相关的测试PDF文档,其名称与路径分别保存。当然,在实际应用中,这里文档数量可以扩展到非常大(后面会看到针对大量文档的一个优化方法):

names = ['c-rag','self-rag','kg-rag']  
files = ['../../data/c-rag.pdf','../../data/self-rag.pdf','../../data/kg-rag.pdf']

【准备创建Tool Agent的函数】

创建一个针对单个文档生成Tool Agent的函数,在这个函数中,将对一个文档创建两个索引与对应的RAG引擎:

  • 针对普通事实性问题的向量索引与RAG引擎

  • 针对更高层语义理解的总结类问题的摘要索引与RAG引擎

最后,我们把这两个引擎作为一个Agent可使用的两个tool,构建一个Tool Agent返回。

......省略import部分与准备llm部分......  
  
#采用chroma向量数据库  
chroma = chromadb.HttpClient(host="localhost", port=8000)  
collection = chroma.get_or_create_collection(name="agentic_rag")   
vector_store = ChromaVectorStore(chroma_collection=collection)  
  
#创建针对某个文档的tool_agent  
def create_tool_agent(file,name):  
  
    #文档拆分  
    print(f'Starting to create tool agent for 【{name}】...\n')  
    docs =SimpleDirectoryReader(input_files = [file]).load_data()  
    splitter = SentenceSplitter(chunk_size=500,chunk_overlap=50)  
    nodes = splitter.get_nodes_from_documents(docs)  
      
    #创建向量索引,并做持久保存  
    if not os.path.exists(f"./storage/{name}"):  
        print('Creating vector index...\n')  
        storage_context = StorageContext.from_defaults(vector_store=vector_store)  
        vector_index = VectorStoreIndex(nodes,storage_context=storage_context)  
        vector_index.storage_context.persist(persist_dir=f"./storage/{name}")  
    else:  
        print('Loading vector index...\n')  
        storage_context = StorageContext.from_defaults(persist_dir=f"./storage/{name}",vector_store=vector_store)  
        vector_index = load_index_from_storage(storage_context=storage_context)  
  
    #创建基于向量的查询引擎  
    query_engine = vector_index.as_query_engine(similarity_top_k=5)  
  
    #创建摘要索引与对应的查询引擎  
    summary_index = SummaryIndex(nodes)  
    summary_engine = summary_index.as_query_engine(response_mode="tree_summarize")  
  
    #将RAG引擎转化为两个tool  
    query_tool = QueryEngineTool.from_defaults(query_engine=query_engine,name=f'query_tool',description=f'Use if you want to query details about {name}')  
    summary_tool = QueryEngineTool.from_defaults(query_engine=summary_engine,name=f'summary_tool',description=f'Use ONLY IF you want to get a holistic summary of the documents. DO NOT USE if you want to query some details about {name}.')  
  
    #创建一个tool agent  
    tool_agent = **ReActAgent**.from_tools(**[query_tool,summary_tool]**,verbose=True,  
                                  system_prompt=f"""  
                                                          You are a specialized agent designed to answer queries about {name}.You must ALWAYS use at least one of the tools provided when answering a question; DO NOT rely on prior knowledge. DO NOT fabricate answer.  
                                                            """)  
    return tool_agent

这部分代码主要目的就是把两个查询的RAG引擎包装成工具(一个是query_tool,用于回答事实性问题;一个是summary_tool用于回答总结性问题,当然你还可以构建更多类型的引擎),最后构建一个ReAct思考范式的AI Agent,并把构建的RAG tools插入。

如果你了解LlamaIndex,可能会使用路由RouteQueryEngine来代替这里的Agent,实现接近的功能。但是要注意,Router与Agent是有区别的,路由仅仅是起到一个“选择”工具与“转发”的作用,并不会做多次迭代;而Agent则会观察工具返回的结果,且有可能会使用多个工具通过迭代来完成任务。

【批量创建Tool Agent】

有了上面的函数后,就可以批量创建好这些文档的Tool Agent。这里把每一个文档名字和对应的Agent保存在一个dict中:

#创建不同文档的agent  
print('===============================================\n')  
print('Creating tool agents for different documents...\n')  
tool_agents_dict = {}  
for name, file in zip(names, files):  
    tool_agent = create_tool_agent(file, name)  
    tool_agents_dict[name] = tool_agent

【创建Top Agent】

最后,我们需要创建一个顶层的Top Agent,这个Agent的作用是接收客户的请求问题,然后规划这个问题的查询计划,并使用工具来完成,而这里的工具就是上面创建好的多个Tool Agent:

#首先将Tool Agent进行“工具化”  
print('===============================================\n')  
print('Creating tools from tool agents...\n')  
all_tools = []  
  
for name in names:  
    agent_tool = QueryEngineTool.from_defaults(  
            #注意,Agent本身也是一种Query Engine,所以直接转为tool  
           query_engine=tool_agents_dict[name],  
  
            #这个工具的名字  
            name=f"tool_{name.replace("-", "")}",  
  
            #描述这个工具的作用和使用方法  
            description=f"Use this tool if you want to answer any questions about {name}."  
    )  
  
    all_tools.append(agent_tool)  
  
#创建Top Agent  
print('Creating top agent...\n')  
top_agent = **OpenAIAgent.**from_tools(**tools=all_tools**,verbose=True,system_prompt="""You are an agent designed to answer queries over a set of given papers.Please always use the tools provided to answer a question.Do not rely on prior knowledge.DO NOT fabricate answer""" )

注意这里我们创建的Top Agent使用了OpenAIAgent,而不是ReActAgent,这也展示了这种架构的灵活性:不同Agent可以按需使用不同的推理范式。

【测试】

现在来简单测试这个Top Agent,并观察其执行的过程:

top_agent.chat_repl()

输入一个问题:Please introduce Retrieval Evaluator in C-RAG pattern?

注意观察这里红线与绿色部分内容,可以看出Agent的“思考”过程:

1.在TopAgent这一层,由于我们使用了OpenAIAgent,其是通过OpenAI的function calling来实现,因此这里显示LLM要求进行函数调用,需要调用tool_crag,输入参数为"Retrieval Evaluator in C-RAG pattern"。而这里的函数名tool_crag,也就是后端Tool Agent的名称。

2.然后来到Tool Agent层,Tool Agent收到请求后,通过ReAct范式的思考过程,决定需要调用query_tool工具,也就是通过向量索引进行响应的RAG引擎。在调用这个引擎后,获得了返回内容(observation的内容)。收到返回后Tool Agent通过观察与推理,认为可以回答这个问题,因此Tool Agent运行结束,并返回结果给Top Agent

3.Top Agent收到函数调用的结果后,认为无需再次进行其他函数调用,因此直接输出了结果,整个迭代过程结束。

当然,你也可以自行测试更复杂的文档任务,比如:要求对比两个文档中某个知识点的区别等。

03

HOT SUMMER

进一步优化Agentic RAG

上面我们只用了三个文档,构建了针对他们的Tool Agent。那么如果这里的文档数量是几十或者几百,过多的Tool Agent作为Tools塞给Top Agent进行推理选择时会带来一些问题:

  • LLM产生困惑并推理错误的概率会提高

  • 过多的Tools信息导致上下文过大,成本与延迟增加

一种可行的方法是:利用RAG的思想对Tools进行检索,即只把本次输入问题语义相关的Tools(即这里的多个ToolAgent)交给Top Agent使用。 这里借助LlamaIndex中的Object Index来实现:Object Index可以对任意Python对象构建向量化的索引,并通过输入问题来检索出相关的Objects。

现在可以对上面的代码做简单的改造,给Top Agent在推理时增加tools检索功能,从而能够缩小tools选择的范围。只需要在创建Top Agent之前针对tools创建一个Object Index的检索器用来根据输入问题检索相关的tools:

#创建工具检索器  
print('===============================================\n')  
print('Creating tool retrieve index...\n')  
obj_index = ObjectIndex.from_objects(all_tools,index_cls=VectorStoreIndex,)  
tool_retriever = obj_index.as_retriever(similarity_top_k=5,verbose=True)

然后将创建Top Agent的代码做简单的修改,不再传入all_tools,而是传入tools检索器:

......  
top_agent = OpenAIAgent.from_tools(**tool_retriever=tool_retriever,**                                   verbose=True,  
                                   system_prompt="""You are an agent designed to answer queries over a set of given papers.Please always use the tools provided to answer a question.Do not rely on prior knowledge.""")  
.......

现在如果你继续测试这个Agent,会发现仍然可以达到相同的效果。当然,如果你需要验证这里检索出来的tools正确性,可以直接对tool_retriever调用检索方法来观察(输入相同的自然语言问题)输出的tools信息:

tools_needed = tool_retriever.retrieve("What is the Adaptive retrieval in the c-RAG?")  
print('Tools needed to answer the question:')  
for tool in tools_needed:  
    print(tool.metadata.name)

04

HOT SUMMER

Agentic RAG总结

相对于更适用于对几个文档进行简单查询的经典RAG应用,Agentic RAG的方法通过更具有自主能力的AI Agent来对其进行增强,具备了极大的灵活性与扩展性,几乎可以完成任意基于知识的复杂任务:

  • 基于RAG之上的Tool Agent将不再局限于简单的回答事实性的问题,通过扩展更多的后端RAG引擎,可以完成更多的知识型任务。比如:整理、摘要生成、数据分析、甚至借助API访问外部系统等

  • Top Agent管理与协调下的多个Tool Agent可以通过协作完成联合型的任务。 比如对两个不同文档中的知识做对比与汇总,这也是经典问答型的RAG无法完成的任务类型。

读者福利:如果大家对大模型感兴趣,这套大模型学习资料一定对你有用

对于0基础小白入门:

如果你是零基础小白,想快速入门大模型是可以考虑的。

一方面是学习时间相对较短,学习内容更全面更集中。
二方面是可以根据这些资料规划好学习计划和方向。

包括:大模型学习线路汇总、学习阶段,大模型实战案例,大模型学习视频,人工智能、机器学习、大模型书籍PDF。带你从零基础系统性的学好大模型!
在这里插入图片描述

😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓

👉AI大模型学习路线汇总👈

大模型学习路线图,整体分为7个大的阶段:(全套教程文末领取哈)

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

👉大模型实战案例👈

光学理论是没用的,要学会跟着一起做,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

在这里插入图片描述

👉大模型视频和PDF合集👈

观看零基础学习书籍和视频,看书籍和视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
在这里插入图片描述
在这里插入图片描述

👉学会后的收获:👈

• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

👉获取方式:

😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐