LLM Agent是一个程序,其执行逻辑由底层模型控制。与少样本提示(few-shot prompting)或固定工作流等方法相比,LLM Agent的特别之处在于它能够定义并适应执行用户查询所需的步骤。借助一组工具(如代码执行或网络搜索)的支持,代理可以决定使用哪个工具、如何使用该工具,并根据输出结果进行迭代。这种适应性使得系统能够以最小的配置处理多种使用场景。
LLM Agent架构存在一个从固定工作流的可靠性到自主代理灵活性的演进方向。例如:
• 固定流程:像检索增强生成(Retrieval-Augmented Generation, RAG)这样的固定流程可以通过加入自我反思环路(self-reflection loop)得到改进,从而使程序能够在初始响应不足时进行迭代。
• ReAct代理:ReAct代理可以将固定流程作为工具嵌入其中,从而在灵活性和结构化之间取得平衡。
架构的选择最终取决于具体使用场景,以及在可靠性和灵活性之间的权衡需求。
选择合适的模型对实现预期性能至关重要。在选择过程中,需要考虑多个因素,例如许可证要求、成本以及语言支持。然而,对于构建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.html ,https://huggingface.co/spaces/bigcode/bigcode-models-leaderboard
另一个关键因素是模型的上下文窗口大小。代理式工作流可能会消耗大量的token,有时甚至超过10万。因此,较大的上下文窗口对于支持复杂任务非常有帮助。
模型推荐:
• 前沿模型:GPT-4o、Claude 3.5
• 开源模型:Llama 3.2、Qwen 2.5
通常而言,规模更大的模型往往性能更强,但可以在本地运行的小型模型仍然是一个可靠的选择。对于小型模型,使用场景可能局限于较为简单的任务,且通常只能将代理连接到一到两个基础工具。
简单的LLM与代理之间的主要区别在于系统提示(system prompt)。
以下是一些常见的代理行为模式,可以根据需要进行定制:
在构建通用型单一代理时,推理后行动(ReAct)和计划后执行(Plan-then-Execute)通常是最佳起点。
为了有效实现这些行为,您需要进行提示工程(prompt engineering)。此外,可以采用结构化生成技术,这意味着将LLM的输出格式化为特定的格式或结构,使代理的响应风格始终与目标通信风格保持一致。
您仅以指令行的形式进行交流。格式为:"指令: 预期输出"。您只能使用这些指令行,不得在指令行之间插入空行或其他内容。
当不需要调用函数时,必须跳过以下指令行: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?
通过这种方式,可以确保代理具备灵活的推理能力,同时输出结果保持逻辑一致性和目标导向。
我们通常认为LLM开箱即用地具备许多功能。有些功能非常实用,但另一些可能并不完全符合需求。为了实现所期望的性能,必须在系统提示中明确指出您需要的所有功能——以及不需要的功能。
Instructions
Your capabilities
Notes
通过清晰的核心指令,可以确保代理的行为和输出符合需求并具备可靠性。
工具赋予代理“超级能力”。通过一组范围狭窄但定义明确的工具,可以实现广泛的功能。关键工具通常包括代码执行、网络搜索、文件读取和数据分析。
在系统提示中,需要明确每个工具的以下内容:
假设我们要定义一个用于执行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:
通过这种方法,可以确保代理明确了解每个工具的用途、使用场景以及操作细节,同时为用户查询提供准确高效的支持。
LLM受到其上下文窗口限制,即它一次能“记住”的token数量。在多轮对话、冗长的工具输出或额外上下文中,这些token可能很快就被填满。因此,制定一个可靠的记忆处理策略至关重要。
在代理的上下文中,记忆指的是系统存储、回忆和利用过去交互信息的能力。这种能力使代理能够:
• 长期维护上下文。
• 根据以往交流改进响应质量。
• 提供更加个性化的体验。
此外,可以让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: ...
通过以上五个步骤,我们已经为构建代理打下了坚实基础。代理可以逐步学习如何高效处理用户请求,同时维护上下文,实现动态响应和更好的用户体验。
解析器(Parser)是一个将原始数据转换为应用程序可以理解和使用的格式(如带有属性的对象)的函数。
对于我们正在构建的代理,解析器需要识别第二步中定义的通信结构,并将其转化为结构化输出(如JSON)。这样可以简化应用程序处理和执行代理下一步的过程。
注意,某些模型提供商(如OpenAI)默认支持可解析的输出。而对于其他模型,特别是开源模型,则需要手动配置这种能力。
最后一步是设置协调逻辑,用来决定LLM生成结果后的处理方式。根据输出内容,您需要采取以下操作之一:
1. 执行工具调用
如果代理输出表明需要调用某个工具,则执行该工具,并将工具的输出作为输入返回给LLM(作为其工作记忆的一部分)。
2. 返回答案
输出可以是用户查询的最终答案,或者是针对不明确请求的进一步澄清需求。
当工具调用被触发时,其输出会反馈回LLM。LLM根据新信息决定下一步操作:
• 再次调用工具,或者
• 将最终答案返回给用户。
以下是一个整合解析和协调逻辑的示例:
1. 用户输入:“分析这份数据并提取主要趋势。”
2. 代理输出:
Thought: 用户希望对数据进行统计分析以提取主要趋势。我需要调用统计工具。
Function Name: Python
Function Input: {
"language": "python",
"code": "import pandas as pdnn# 加载数据n...",
"inputFiles": ["dataset.csv"]
}
通过解析和协调,代理能够以模块化方式动态应对复杂任务,确保响应的准确性和可靠性。
本文由博客一文多发平台 OpenWrite 发布!
参与评论
手机查看
返回顶部