Erlo

如何构建大模型代理 LLM Agent?

2025-01-20 17:30:16 发布   16 浏览  
页面报错/反馈
收藏 点赞

file

什么是LLM Agent 大模型代理?

file

LLM Agent是一个程序,其执行逻辑由底层模型控制。与少样本提示(few-shot prompting)或固定工作流等方法相比,LLM Agent的特别之处在于它能够定义并适应执行用户查询所需的步骤。借助一组工具(如代码执行或网络搜索)的支持,代理可以决定使用哪个工具、如何使用该工具,并根据输出结果进行迭代。这种适应性使得系统能够以最小的配置处理多种使用场景。

file

LLM Agent架构存在一个从固定工作流的可靠性到自主代理灵活性的演进方向。例如:
• 固定流程:像检索增强生成(Retrieval-Augmented Generation, RAG)这样的固定流程可以通过加入自我反思环路(self-reflection loop)得到改进,从而使程序能够在初始响应不足时进行迭代。
• ReAct代理:ReAct代理可以将固定流程作为工具嵌入其中,从而在灵活性和结构化之间取得平衡。

架构的选择最终取决于具体使用场景,以及在可靠性和灵活性之间的权衡需求。

Step by step构建LLM Agent

第一步:选择合适的LLM

选择合适的模型对实现预期性能至关重要。在选择过程中,需要考虑多个因素,例如许可证要求、成本以及语言支持。然而,对于构建LLM代理而言,最重要的考量是模型在核心任务(如编码、工具调用和推理)上的性能。以下是用于评估模型的关键基准:
• Massive Multitask Language Understanding (MMLU):评估推理能力。 https://paperswithcode.com/sota/multi-task-language-understanding-on-mmlu
• Berkeley’s Function Calling Leaderboard:评估工具选择和工具调用能力。 https://gorilla.cs.berkeley.edu/leaderboard.html
• HumanEval 和 BigCodeBench:评估编程能力。 https://evalplus.github.io/leaderboard.htmlhttps://huggingface.co/spaces/bigcode/bigcode-models-leaderboard

另一个关键因素是模型的上下文窗口大小。代理式工作流可能会消耗大量的token,有时甚至超过10万。因此,较大的上下文窗口对于支持复杂任务非常有帮助。

模型推荐:
• 前沿模型:GPT-4o、Claude 3.5
• 开源模型:Llama 3.2、Qwen 2.5

通常而言,规模更大的模型往往性能更强,但可以在本地运行的小型模型仍然是一个可靠的选择。对于小型模型,使用场景可能局限于较为简单的任务,且通常只能将代理连接到一到两个基础工具。

第二步:定义代理的控制逻辑 Agent's Control Logic

file

简单的LLM与代理之间的主要区别在于系统提示(system prompt)。

常见的代理模式

以下是一些常见的代理行为模式,可以根据需要进行定制:

  1. 工具使用
    代理决定何时将查询路由到适当的工具处理,或依赖自身知识提供解答。
  2. 反思
    代理在响应用户之前审查并修正自己的答案。反思步骤可以嵌入到大多数LLM系统中。
  3. 推理后行动(Reason-then-Act, ReAct)
    代理通过迭代的方式推理如何解决查询,执行某个动作,观察结果,并决定是否采取进一步行动或直接提供响应。
  4. 计划后执行(Plan-then-Execute)
    代理预先计划,将任务分解为多个子步骤(如有必要),然后逐步执行每个步骤。

推荐模式

在构建通用型单一代理时,推理后行动(ReAct)和计划后执行(Plan-then-Execute)通常是最佳起点。
为了有效实现这些行为,您需要进行提示工程(prompt engineering)。此外,可以采用结构化生成技术,这意味着将LLM的输出格式化为特定的格式或结构,使代理的响应风格始终与目标通信风格保持一致。

file

示例

您仅以指令行的形式进行交流。格式为:"指令: 预期输出"。您只能使用这些指令行,不得在指令行之间插入空行或其他内容。
当不需要调用函数时,必须跳过以下指令行:Function Name、Function Input 和 Function Output。
指令行定义
• Message: 用户的消息。您永远不使用此指令行。
• Thought: 用单行说明如何回答用户的消息。必须紧接着是Final Answer。
• Thought: 用单行逐步说明如何回答用户的消息。可以使用上面定义的可用函数。此指令行必须紧接着是Function Name(如果需要调用某个已定义的可用函数),或是Final Answer。此处不得直接提供答案。
• Function Name: 函数的名称。此指令行必须紧接着是Function Input。
• Function Input: 函数参数。空对象也是有效参数。
• Function Output: 函数的输出,采用JSON格式。
• Thought: 继续思考过程。
• Final Answer: 回答用户或要求提供更多信息或澄清。此行必须始终由Thought引导。

示例
Message: Can you translate "How are you" into French?
Thought: The user wants to translate a text into French. I can do that.
Final Answer: Comment vas-tu?

通过这种方式,可以确保代理具备灵活的推理能力,同时输出结果保持逻辑一致性和目标导向。

第三步:定义代理的核心指令Instructions

我们通常认为LLM开箱即用地具备许多功能。有些功能非常实用,但另一些可能并不完全符合需求。为了实现所期望的性能,必须在系统提示中明确指出您需要的所有功能——以及不需要的功能。

核心指令可能包括:

  1. 代理名称与角色:定义代理的名称以及它的用途。
  2. 语气与简洁性:决定响应的正式或非正式语气,以及回答的简洁程度。
  3. 工具的使用时机:明确何时依赖外部工具,何时使用模型本身的知识。
  4. 错误处理:指明当工具或过程出错时,代理应采取的措施。

示例

Instructions

  • 用户只能看到Final Answer,所有答案必须在Final Answer中提供。
  • 您必须始终使用上述定义的通信结构和指令。请记住,Thought必须是单行,并且紧接着是Final Answer。
  • 您必须始终使用上述定义的通信结构和指令。请记住,Thought必须是单行,并且紧接着是Function Name或Final Answer。
  • 必须使用函数检索事实性或历史性信息来回答消息。
  • 如果用户建议使用不可用的函数,请回答该函数不可用,并在适当情况下建议替代方案。
  • 如果消息不明确或需要更多用户信息,请在Final Answer中询问。

Your capabilities

  • 优先使用以下能力而非函数:
    • 您理解以下语言:英语、西班牙语、法语。
    • 您可以翻译和总结,即使是长文档。

Notes

  • 如果您不知道答案,请直接说不知道。
  • 当前的时间和日期以ISO格式显示在最后一条消息中。
  • 在回答用户时,请以友好的格式提供时间和日期。
  • 使用Markdown语法格式化代码片段、链接、JSON、表格、图片和文件。
  • 有时事情可能不会按计划进行。函数在初次尝试时可能无法提供有用的信息。在宣布问题无法解决之前,您应尝试多种不同方法。
  • 当函数没有提供预期结果时,您必须尝试使用其他函数或调整函数输入。
    • 在使用搜索引擎时,您应尝试不同的查询表达方式,甚至可以尝试使用其他语言。
  • 您无法在不使用函数的情况下完成复杂计算、运算或数据处理。

通过清晰的核心指令,可以确保代理的行为和输出符合需求并具备可靠性。

第四步:定义并优化核心工具Tools

工具赋予代理“超级能力”。通过一组范围狭窄但定义明确的工具,可以实现广泛的功能。关键工具通常包括代码执行、网络搜索、文件读取和数据分析。

每个工具需要定义的要素

在系统提示中,需要明确每个工具的以下内容:

  1. 工具名称(Tool Name)
    提供一个唯一且具有描述性的名称,用以标识该工具的功能。
  2. 工具描述(Tool Description)
    明确工具的功能及其适用场景。这有助于代理判断何时使用该工具。
  3. 工具输入模式(Tool Input Schema)
    定义工具所需和可选参数的模式,包括参数类型及其限制条件。代理根据用户的查询填充所需的输入。
  4. 工具运行方式(Pointer to Execution)
    指明工具运行的位置或方式(例如,通过API调用、本地执行等)。

示例

假设我们要定义一个用于执行Python代码的工具,示例如下:

Tool Name: Python Code Executor
Tool Description: Executes Python code snippets and returns the output. Use this tool when users ask for code execution or debugging.
Tool Input Schema:

  • required:
    • code (string): The Python code to be executed.
  • optional:
    • timeout (integer): Maximum time (in seconds) to wait for code execution. Default is 10 seconds.
      Pointer to Execution: Local Python runtime environment with restricted access.

通过这种方法,可以确保代理明确了解每个工具的用途、使用场景以及操作细节,同时为用户查询提供准确高效的支持。

第五步:确定记忆Memory处理策略

LLM受到其上下文窗口限制,即它一次能“记住”的token数量。在多轮对话、冗长的工具输出或额外上下文中,这些token可能很快就被填满。因此,制定一个可靠的记忆处理策略至关重要。

在代理的上下文中,记忆指的是系统存储、回忆和利用过去交互信息的能力。这种能力使代理能够:
• 长期维护上下文。
• 根据以往交流改进响应质量。
• 提供更加个性化的体验。

常见的记忆处理策略

  1. 滑动记忆(Sliding Memory)
    仅保留最近的k轮对话,丢弃较早的交互内容。
  2. Token记忆(Token Memory)
    仅保留最近的n个token,丢弃其余内容。
  3. 总结记忆(Summarized Memory)
    使用LLM在每轮对话中生成对话摘要,随后丢弃单独的消息。

此外,可以让LLM检测对话中的关键时刻,并将其存储到长期记忆中。这使代理能够“记住”用户的重要信息,从而提供更加个性化的体验。

示例

假设我们在这一阶段通过LLM处理一个用户查询,可能的交互如下:

用户消息:从这个数据集中提取关键见解。
文件:bill-of-materials.csv

Thought: 首先,我需要检查数据集的列并提供基本数据统计。
Function Name: Python
Function Input: {
"language": "python",
"code": "import pandas as pdnndataset = pd.read_csv('bill-of-materials.csv')nnprint(dataset.columns)nprint(dataset.describe())",
"inputFiles": ["bill-of-materials.csv"]
}
Function Output: ...

通过以上五个步骤,我们已经为构建代理打下了坚实基础。代理可以逐步学习如何高效处理用户请求,同时维护上下文,实现动态响应和更好的用户体验。
file

第六步:解析代理的原始输出

解析器(Parser)是一个将原始数据转换为应用程序可以理解和使用的格式(如带有属性的对象)的函数。

对于我们正在构建的代理,解析器需要识别第二步中定义的通信结构,并将其转化为结构化输出(如JSON)。这样可以简化应用程序处理和执行代理下一步的过程。

注意,某些模型提供商(如OpenAI)默认支持可解析的输出。而对于其他模型,特别是开源模型,则需要手动配置这种能力。

第七步:协调代理的下一步操作

最后一步是设置协调逻辑,用来决定LLM生成结果后的处理方式。根据输出内容,您需要采取以下操作之一:
1. 执行工具调用
如果代理输出表明需要调用某个工具,则执行该工具,并将工具的输出作为输入返回给LLM(作为其工作记忆的一部分)。
2. 返回答案
输出可以是用户查询的最终答案,或者是针对不明确请求的进一步澄清需求。

file

当工具调用被触发时,其输出会反馈回LLM。LLM根据新信息决定下一步操作:
• 再次调用工具,或者
• 将最终答案返回给用户。

示例

以下是一个整合解析和协调逻辑的示例:
1. 用户输入:“分析这份数据并提取主要趋势。”
2. 代理输出:

Thought: 用户希望对数据进行统计分析以提取主要趋势。我需要调用统计工具。
Function Name: Python
Function Input: {
"language": "python",
"code": "import pandas as pdnn# 加载数据n...",
"inputFiles": ["dataset.csv"]
}

  1. 解析器
    将上述通信结构解析为JSON格式,供应用程序进一步处理。
  2. 协调逻辑
    • 执行工具调用,生成分析结果。
    • 将结果返回给LLM。
    • 根据新信息,LLM决定是否继续工具调用,或者向用户输出最终结果。

通过解析和协调,代理能够以模块化方式动态应对复杂任务,确保响应的准确性和可靠性。

本文由博客一文多发平台 OpenWrite 发布!

登录查看全部

参与评论

评论留言

还没有评论留言,赶紧来抢楼吧~~

手机查看

返回顶部

给这篇文章打个标签吧~

棒极了 糟糕透顶 好文章 PHP JAVA JS 小程序 Python SEO MySql 确认