LlamaIndex ReActAgent 中 tool 和 tool_retriever 联系和区别

LlamaIndex ReActAgent 中 tool 和 tool_retriever 的联系和区别

在 LlamaIndex 的 ReActAgent 中,tooltool_retriever 都是重要组件,但它们在代理的工作流程中服务于不同的目的:

Tools(工具)

工具是代理可以执行的实际函数或操作。每个工具:

  • 具有定义明确的输入和输出的特定功能
  • 在被调用时执行具体的动作
  • 可被代理直接使用来完成任务

Tool Retriever(工具检索器)

工具检索器是一个帮助代理根据当前上下文或查询找到合适工具的组件。它:

  • 管理可用工具的集合
  • 选择可能对特定情况有帮助的适当工具
  • 充当代理与其可用工具集之间的中介

主要区别

  1. 功能

    • 工具执行动作
    • 工具检索器选择应该考虑使用哪些工具
  2. 在工作流程中的角色

    • 工具是执行动作的"手"
    • 工具检索器是决定考虑使用哪些工具的"头脑"
  3. 实现方式

    • 工具通常实现为具有明确签名的函数
    • 工具检索器实现为管理工具选择逻辑的类

它们如何协同工作

当 ReActAgent 处理查询时:

  1. 工具检索器评估查询和上下文
  2. 它从所有可用工具中选择相关工具的子集
  3. 代理随后决定实际使用这些工具中的哪一个
  4. 代理执行所选工具来完成任务

这种分离允许代理更高效地运行,尤其是当有许多潜在工具可用时。工具检索器防止代理在每次查询时都必须考虑每一个可能的工具。

如何创建 LlamaIndex 中的工具检索器(Tool Retriever)

基于搜索结果,我将详细介绍如何在 LlamaIndex 中创建工具检索器(Tool Retriever)。工具检索器是一个重要组件,可以帮助代理根据当前查询选择最合适的工具。

基本步骤

1. 创建索引和检索器

首先,需要创建基本的索引和检索器,这些将作为工具检索器的基础组件:

在 LlamaIndex 中,可以从各种索引(如 SummaryIndex、VectorIndex 或 KeywordIndex)创建检索器。例如:

# 创建基础索引
summary_index = SummaryIndex(nodes, storage_context=storage_context)
vector_index = VectorStoreIndex(nodes, storage_context=storage_context)
keyword_index = SimpleKeywordTableIndex(nodes, storage_context=storage_context)

# 从索引创建检索器
list_retriever = summary_index.as_retriever()
vector_retriever = vector_index.as_retriever()
keyword_retriever = keyword_index.as_retriever()

2. 将检索器包装为工具

接下来,将这些检索器转换为检索工具(RetrieverTool),这样它们就可以被工具检索器使用:

from llama_index.core.tools import RetrieverTool

list_tool = RetrieverTool.from_defaults(
    retriever=list_retriever,
    description=(
        "用于检索文档的所有上下文,适合需要完整背景信息的查询"
    ),
)

vector_tool = RetrieverTool.from_defaults(
    retriever=vector_retriever,
    description=(
        "用于检索文档中的特定上下文,适合具体问题"
    ),
)

keyword_tool = RetrieverTool.from_defaults(
    retriever=keyword_retriever,
    description=(
        "使用查询中提到的实体来检索文档中的特定上下文"
    ),
)

这里的描述非常重要,因为工具检索器将基于这些描述来选择合适的工具。

3. 创建选择器模块

选择器决定使用哪些检索工具。LlamaIndex 提供了几种选择器:

from llama_index.core.selectors import PydanticSingleSelector, PydanticMultiSelector
from llama_index.llms.openai import OpenAI

# 初始化LLM
llm = OpenAI(model="gpt-4")

# 创建单选择器(只选择一个工具)
single_selector = PydanticSingleSelector.from_defaults(llm=llm)

# 或者创建多选择器(可以选择多个工具)
multi_selector = PydanticMultiSelector.from_defaults(llm=llm)

4. 创建工具检索器

最后,使用选择器和检索工具创建工具检索器:

from llama_index.core.retrievers import RouterRetriever

# 创建只选择一个工具的检索器
single_retriever = RouterRetriever(
    selector=PydanticSingleSelector.from_defaults(llm=llm),
    retriever_tools=[list_tool, vector_tool, keyword_tool],
)

# 或者创建可以选择多个工具的检索器
multi_retriever = RouterRetriever(
    selector=PydanticMultiSelector.from_defaults(llm=llm),
    retriever_tools=[list_tool, vector_tool, keyword_tool],
)

自定义检索器示例

如果需要更高级的功能,还可以创建自定义检索器,例如混合搜索检索器:

from llama_index.core import QueryBundle
from llama_index.core.schema import NodeWithScore
from llama_index.core.retrievers import BaseRetriever
from typing import List

class CustomRetriever(BaseRetriever):
    """自定义混合检索器,可以结合向量检索和关键词检索"""
    
    def __init__(
        self, 
        vector_retriever, 
        keyword_retriever,
        mode: str = "AND"  # 可以设置为 "AND" 或 "OR"
    ) -> None:
        self._vector_retriever = vector_retriever
        self._keyword_retriever = keyword_retriever
        
        if mode not in ("AND", "OR"):
            raise ValueError("无效的模式,必须是 AND 或 OR")
        self._mode = mode
        super().__init__()
    
    def _retrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]:
        """根据查询检索节点"""
        # 获取两种检索器的结果
        vector_nodes = self._vector_retriever.retrieve(query_bundle)
        keyword_nodes = self._keyword_retriever.retrieve(query_bundle)
        
        # 获取节点ID
        vector_ids = {n.node.node_id for n in vector_nodes}
        keyword_ids = {n.node.node_id for n in keyword_nodes}
        
        # 合并结果
        combined_dict = {n.node.node_id: n for n in vector_nodes}
        combined_dict.update({n.node.node_id: n for n in keyword_nodes})
        
        # 根据模式选择结果
        if self._mode == "AND":
            # 两种检索器都检索到的节点
            retrieve_ids = vector_ids.intersection(keyword_ids)
        else:  # OR模式
            # 任一检索器检索到的节点
            retrieve_ids = vector_ids.union(keyword_ids)
            
        return [combined_dict[rid] for rid in retrieve_ids]

递归检索器

还可以创建递归检索器,它能够递归地检索和查询节点:

from llama_index.core.retrievers import RecursiveRetriever
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core import get_response_synthesizer

# 创建递归检索器
recursive_retriever = RecursiveRetriever(
    "vector",  # 指定根检索器的ID
    retriever_dict={"vector": vector_retriever},  # 映射 ID 到检索器
    query_engine_dict=query_engine_mapping,  # 映射 ID 到查询引擎
    verbose=True,
)

# 创建响应合成器
response_synthesizer = get_response_synthesizer(response_mode="compact")

# 创建查询引擎
query_engine = RetrieverQueryEngine.from_args(
    recursive_retriever,
    response_synthesizer=response_synthesizer
)

工具检索器的使用

创建完工具检索器后,可以直接使用它来检索节点:

# 使用检索器检索节点
nodes = retriever.retrieve("你的查询")

# 异步方式
nodes = await retriever.aretrieve("你的查询")

# 查看结果
for node in nodes:
    print(node.node.text)

工具检索器会根据查询自动选择最合适的检索工具,然后使用该工具检索相关节点。对于多选择器,它可能会选择多个工具并合并结果。

总结

创建工具检索器的关键步骤是:

  1. 创建基础索引和检索器
  2. 将检索器包装为检索工具(RetrieverTool)
  3. 创建选择器模块(单选择或多选择)
  4. 使用选择器和检索工具创建工具检索器(RouterRetriever)

这种方法使代理能够智能地选择最合适的检索工具,从而提高检索效率和准确性。

你可能感兴趣的:(java,前端,算法)