LlamaIndex中的Agent代理的使用模式讲解

Agent代理

在大型语言模型(LLM, Large Language Model)中,Agent代理通常指的是一个能够执行特定任务或操作的软件实体。这些任务可能包括但不限于信息检索、数据分析、文本生成、对话管理等。在不同的应用场景下,Agent的功能和设计会有所不同,但它们共同的目标是提高自动化水平、增强用户体验和效率。

Agent的主要特点

  1. 自主性:Agent能够在一定程度上独立运作,根据环境变化做出决策。
  2. 交互性:与用户或其他系统进行有效沟通,提供或请求必要的信息。
  3. 适应性:能够学习和适应新情况,改进自己的表现。
  4. 目标导向:每个Agent都有明确的任务或目标,围绕这些目标进行工作。

应用场景

  • 客户服务:作为虚拟助手回答常见问题,提供产品信息,处理客户投诉等。
  • 个人助理:帮助用户管理日程、提醒重要事项、搜索网络信息等。
  • 教育辅助:为学生提供个性化学习建议,辅导作业等。
  • 医疗健康:提供初步的健康咨询,帮助患者记录健康状况等。
  • 娱乐互动:开发游戏中的非玩家角色(NPC),增加游戏的真实感和趣味性。

技术实现

在技术层面,Agent的设计通常涉及到自然语言处理(NLP)、机器学习(ML)、知识表示与推理等多个领域。通过这些技术,Agent能够理解用户的意图,处理复杂的任务,并以人类可理解的方式交流反馈。

例如,在客服场景中,一个基于LLM的Agent需要能够准确地理解客户的查询或投诉,利用预先训练好的模型来分析问题,然后从数据库中检索相关信息或直接生成适当的响应。这一过程不仅要求模型具备强大的语言理解和生成能力,还需要有良好的逻辑推理能力和数据处理能力。

随着人工智能技术的发展,Agent代理的应用将更加广泛,功能也会越来越强大,为用户提供更加智能、便捷的服务。

入门

代理由一组工具初始化。以下是从一组工具实例化 ReAct 代理的示例。

from llama_index.core.tools import FunctionTool
from llama_index.llms.openai import OpenAI
from llama_index.core.agent import ReActAgent


# define sample Tool
def multiply(a: int, b: int) -> int:
    """将两个整数相乘并返回结果整数"""
    return a * b


multiply_tool = FunctionTool.from_defaults(fn=multiply)

# 初始化llm
llm = OpenAI(model="gpt-3.5-turbo-0613")

# 初始化ReAct代理
agent = ReActAgent.from_tools([multiply_tool], llm=llm, verbose=True)

代理支持chatquery端点,分别从我们的ChatEngine和继承QueryEngine

使用示例:

agent.chat("2123 * 215123等于多少")

要根据 LLM 自动选择最佳代理,您可以使用该from_llm方法生成代理。

from llama_index.core.agent import AgentRunner

agent = AgentRunner.from_llm([multiply_tool], llm=llm, verbose=True)

定义工具

查询引擎工具

将查询引擎包装为代理工具也很容易。只需执行以下操作:

from llama_index.core.agent import ReActAgent
from llama_index.core.tools import QueryEngineTool

# 注意:lyft_index和uber_index都是SimpleVectorIndex实例
lyft_engine = lyft_index.as_query_engine(similarity_top_k=3)
uber_engine = uber_index.as_query_engine(similarity_top_k=3)

query_engine_tools = [
    QueryEngineTool(
        query_engine=lyft_engine,
        metadata=ToolMetadata(
            name="lyft_10k",
            description="提供Lyft 2021年的财务信息。 "
            "使用一个详细的纯文本问题作为工具的输入。",
        ),
        return_direct=False,
    ),
    QueryEngineTool(
        query_engine=uber_engine,
        metadata=ToolMetadata(
            name="uber_10k",
            description="提供Uber 2021年的财务信息。 "
            "使用一个详细的纯文本问题作为工具的输入。",
        ),
        return_direct=False,
    ),
]

# 初始化ReAct代理
agent = ReActAgent.from_tools(query_engine_tools, llm=llm, verbose=True)

使用其他代理作为工具

我们的代理的一个巧妙特性是,由于它们继承自BaseQueryEngine,因此您可以轻松地通过我们的将其他代理定义为QueryEngineTool工具。

from llama_index.core.tools import QueryEngineTool

query_engine_tools = [
    QueryEngineTool(
        query_engine=sql_agent,
        metadata=ToolMetadata(
            name="sql_agent", description="可以执行SQL查询的代理。"
        ),
    ),
    QueryEngineTool(
        query_engine=gmail_agent,
        metadata=ToolMetadata(
            name="gmail_agent",
            description="可以在Gmail上发送电子邮件的工具。",
        ),
    ),
]

outer_agent = ReActAgent.from_tools(query_engine_tools, llm=llm, verbose=True)

有计划的代理

将初始任务分解为更容易理解的子任务是一种强大的模式。

LlamaIndex 提供了一个代理规划模块,可以完成以下任务:

from llama_index.agent.openai import OpenAIAgentWorker
from llama_index.core.agent import (
    StructuredPlannerAgent,
    FunctionCallingAgentWorker,
)

worker = FunctionCallingAgentWorker.from_tools(tools, llm=llm)
agent = StructuredPlannerAgent(worker)

一般来说,与基本AgentRunner类相比,该代理可能需要更长的时间来响应,但输出通常会更完整。另一个需要考虑的权衡是,规划通常需要非常有能力的 LLM(对于上下文,gpt-3.5-turbo有时规划不稳定,而表现gpt-4-turbo要好得多。)

完整指南中提供更多信息

底层 API

OpenAIAgent ReActAgent 是与 交互的简单包装AgentRunnerAgentWorker

所有代理都可以以这种方式定义。例如对于 OpenAIAgent

from llama_index.core.agent import AgentRunner
from llama_index.agent.openai import OpenAIAgentWorker

# 从工具中构造OpenAIAgent
openai_step_engine = OpenAIAgentWorker.from_tools(tools, llm=llm, verbose=True)
agent = AgentRunner(openai_step_engine)

这也是定制代理的首选格式。

请查看下级代理指南以了解更多详细信息。

自定义您的代理

如果您希望定义自定义代理,最简单的方法就是定义一个状态函数FnAgentWorker并用 包装它。

传入和传出函数的变量state可以包含任何您想要的内容,无论是工具还是任意变量。它还包含任务和输出对象。

## 这个例子展示了一个简单的函数,每次将输入的数字乘以2。
## 把这个交给代理人
def multiply_agent_fn(state: dict) -> Tuple[Dict[str, Any], bool]:
    """Mock agent input function."""
    if "max_count" not in state:
        raise ValueError("max_count must be specified.")

    # __output__ is 是一个特殊的键表示代理的最终输出
    # __task__ 是一个特殊的键,表示代理传递给函数的Task对象。
    # `task.input` 是传递的输入字符串
    if "__output__" not in state:
        state["__output__"] = int(state["__task__"].input)
        state["count"] = 0
    else:
        state["__output__"] = state["__output__"] * 2
        state["count"] += 1

    is_done = state["count"] >= state["max_count"]

    # 这个函数的输出应该是状态变量和is_done的元组
    return state, is_done


from llama_index.core.agent import FnAgentWorker

agent = FnAgentWorker(
    fn=multiply_agent_fn, initial_state={
    
    "max_count": 5}
).as_agent()
agent.query("5")

请参阅我们的“定制代理笔记本指南”以了解更多详细信息。

高级概念(针对OpenAIAgent,测试版)

您还可以在更高级的设置中使用代理。例如,能够在查询时从索引中检索工具,并能够对现有的一组工具执行查询规划。

OpenAIAgent这些主要通过我们的类(依赖于 OpenAI 函数 API)实现。ReActAgent我们正在积极研究对更通用的支持。

注意:这些概念大部分仍处于测试阶段。随着时间的推移,抽象概念可能会发生变化,并变得更加通用。

功能检索代理

如果工具集非常大,您可以创建一个ObjectIndex来索引工具,然后ObjectRetriever在查询时将一个传递给代理,首先动态检索相关工具,然后让代理从候选工具中进行选择。

我们首先构建一套ObjectIndex现有的工具。

# define an "object" index over these tools
from llama_index.core import VectorStoreIndex
from llama_index.core.objects import ObjectIndex

obj_index = ObjectIndex.from_objects(
    all_tools,
    index_cls=VectorStoreIndex,
)

然后我们定义OpenAIAgent

from llama_index.agent.openai import OpenAIAgent

agent = OpenAIAgent.from_tools(
    tool_retriever=obj_index.as_retriever(similarity_top_k=2), verbose=True
)

您可以在完整指南中找到有关对象索引的更多详细信息。

上下文检索代理

我们的上下文增强型 OpenAI 代理在调用任何工具之前总是会执行检索。

这有助于提供额外的背景信息,帮助代理更好地选择工具,而不是仅仅试图在没有任何背景信息的情况下做出决定。

from llama_index.core import Document
from llama_index.agent.openai_legacy import ContextRetrieverOpenAIAgent


# 示例索引-存储缩写列表
texts = [
    "Abbreviation: X = Revenue",
    "Abbreviation: YZ = Risk Factors",
    "Abbreviation: Z = Costs",
]
docs = [Document(text=t) for t in texts]
context_index = VectorStoreIndex.from_documents(docs)

# add context agent
context_agent = ContextRetrieverOpenAIAgent.from_tools_and_retriever(
    query_engine_tools,
    context_index.as_retriever(similarity_top_k=1),
    verbose=True,
)
response = context_agent.chat("2022年3月的YZ是多少?")

查询规划

OpenAI 函数代理能够进行高级查询规划。诀窍是为代理提供一个QueryPlanTool-如果代理调用 QueryPlanTool,它将被迫推断出一个完整的 Pydantic 模式,该模式表示一组子工具上的查询计划。

# define query plan tool
from llama_index.core.tools import QueryPlanTool
from llama_index.core import get_response_synthesizer

response_synthesizer = get_response_synthesizer(
    service_context=service_context
)
query_plan_tool = QueryPlanTool.from_defaults(
    query_engine_tools=[query_tool_sept, query_tool_june, query_tool_march],
    response_synthesizer=response_synthesizer,
)

# initialize agent
agent = OpenAIAgent.from_tools(
    [query_plan_tool],
    max_function_calls=10,
    llm=OpenAI(temperature=0, model="gpt-4-0613"),
    verbose=True,
)

# 是否应该输出查询计划来调用3月、6月和9月的工具
response = agent.query(
    "分析Uber在3月、6月和9月的收入增长情况"
)

参看相关文章《LlamaIndex中的Tools工具概念和使用》

猜你喜欢

转载自blog.csdn.net/weixin_40986713/article/details/143181268