代理若要有效运用外部功能,不能仅仅知道工具存在;它必须对每个工具的作用、何时使用以及如何正确调用具备功能性理解。简单地给代理提供一份工具名称列表,如 search_web、calculate_price 或 query_database,不足以保证其可靠运行。代理需要结构化信息,以连接其内部推理或规划状态与使用工具的具体行动。阐述了描述工具的方法,以及代理为特定子任务选择最恰当工具所用的机制。精确工具描述的作用有效的工具使用取决于提供给代理核心LLM的描述质量。这些描述充当代理可用功能的操作“手册”。一份精心编写的描述理想情况下应包含:工具名称: 工具的独特标识符。用途/功能: 清晰、简洁地说明工具能实现什么以及何时适用。这应具有足够的描述性,以便LLM将其与其他工具区分开。输入参数: 必需和可选输入的详细规定,包括:参数名称。数据类型(例如,字符串、整数、布尔值、列表)。说明每个参数目的和预期格式的描述。输出规定: 工具成功执行后返回的数据或结果的描述。这有助于代理理解预期返回何种信息。潜在副作用: (可选但重要)关于工具除了返回值之外所做任何更改的信息(例如,保存数据、发送消息)。错误情况: (可选)关于工具可能返回的常见故障模式或错误的指导。这些领域中任何的歧义都可能导致工具选择错误、请求格式不正确或结果误解,最终使代理的计划偏离。工具规定的格式几种格式常用于向LLM传递工具信息,每种都有其取舍:自然语言描述: 使用普通英语句子描述工具。虽然人类易于编写,但这种方式容易产生歧义,并要求LLM进行更复杂的解读。它通常与更结构化的格式结合使用。函数签名和文档字符串: 运用编程语言惯例,尤其在基于Python的框架中很受欢迎。函数签名定义名称和参数(带类型提示),而文档字符串提供关于目的、参数和返回值的自然语言描述。def search_academic_papers(query: str, max_results: int = 5) -> list[dict]: """ 在学术论文数据库中搜索匹配查询的论文。 Args: query (str): 搜索关键词或短语。 max_results (int): 要返回的最大结果数量。默认为5。 Returns: list[dict]: 字典列表,每个字典包含论文详细信息 (标题、作者、摘要、出版年份)。 如果未找到匹配项,则返回空列表。 """ # ... 实现细节 ... pass结构化数据格式(JSON Schema, OpenAPI): 对于Web API或更复杂的工具,JSON Schema或OpenAPI规范等标准化格式提供高度结构化、机器可读的定义。这些格式严格定义输入和输出的数据结构,从而减少歧义。许多具有原生函数/工具调用能力的LLM都经过优化,可配合这些格式使用。{ "name": "get_stock_price", "description": "获取给定股票代码的当前股价。", "parameters": { "type": "object", "properties": { "ticker_symbol": { "type": "string", "description": "股票代码(例如,'GOOGL'、'MSFT')。" } }, "required": ["ticker_symbol"] } // 也可以在此处添加输出架构描述 }格式选择通常取决于工具的复杂度、所使用的代理框架以及底层LLM的能力(例如,基于结构化模式的原生函数调用支持)。将结构化定义与这些结构内清晰的自然语言描述结合起来,常能获得最佳效果。工具选择机制一旦工具得到充分描述,代理就需要一种机制,以在其计划中的恰当步骤选择正确的工具。基于LLM的推理最常见的方法依赖于LLM自身的推理能力。代理的提示包含当前目标或子任务、来自先前步骤的相关上下文(观察、记忆)以及所有可用工具的描述。LLM被指示分析情况,并确定接下来应执行哪个工具(如果有),以及从上下文中推导出的必要参数。提示片段示例:您是一名研究助理。您当前的目标是查找关于“Transformer架构进展”的近期论文。 您可以使用以下工具:工具:search_academic_papers 描述:搜索学术论文数据库... [完整描述如上]工具:summarize_text 描述:提供给定文本的简洁摘要...根据您的目标,您接下来应该使用哪个工具并提供什么参数?LLM理想情况下会通过选择 search_academic_papers 并将 query 参数指定为 'transformer architecture advancements' 来响应。现代LLM通常支持专用的“函数调用”或“工具使用”模式,模型会明确输出结构化请求,以使用特定参数调用特定工具,而不仅仅是生成描述该选择的文本。提示工程以实现选择基于LLM的选择的有效性很大程度上取决于工具在提示中如何呈现。重要的考量包括:清晰与简洁: 确保描述清晰,但避免过度冗长以占用宝贵的上下文窗口空间。格式化: 以结构化、易于解析的格式(如列表或代码块)呈现工具列表可以帮助LLM。指令: 明确指示LLM执行选择任务(例如,“从以下列表中选择最佳工具以实现当前目标...”)很重要。管理大量工具随着可用工具数量的增加,简单地在每个提示中列出所有描述会变得低效,并可能超出上下文限制。管理此情况的策略包括:语义工具检索: 避免包含所有工具,而是使用基于嵌入的检索来根据当前任务描述找到最相关的工具子集,并仅将它们包含在提示中。分层工具组织: 按类别(例如,“数据分析工具”、“通信工具”)对工具进行分组,并可能让LLM首先选择一个类别,然后在该类别中选择一个特定工具。工具路由器: 在某些情况下,一个初步的、更简单的模型或基于规则的系统(“工具路由器”)可以在调用主LLM之前预先选择一个可能的工具子集,从而减少主要模型的认知负担。这灵活性较低,但对于定义明确的工作流而言可能高效。例如,简单的关键词匹配可能会将包含“天气”的查询路由到天气API工具描述。为专门化进行微调对于具有固定工具集的高度专门化应用,专门针对工具选择和参数生成任务微调一个较小的LLM,可能是一种可行的优化策略,与每次选择都使用大型通用模型相比,可能提高准确性并降低推理成本。下图说明了代理推理循环中典型的LLM驱动工具选择流程:digraph ToolSelection { rankdir=LR; node [shape=box, style=rounded, fontname="sans-serif", color="#495057", fontcolor="#495057"]; edge [color="#adb5bd", fontcolor="#495057"]; Goal [label="当前目标 / 子任务", shape=ellipse, style=filled, fillcolor="#a5d8ff"]; Context [label="代理状态与记忆", shape=cylinder, style=filled, fillcolor="#bac8ff"]; ToolDesc [label="可用工具描述", shape=note, style=filled, fillcolor="#ffec99"]; LLM [label="LLM推理\n(提示包含目标、上下文、工具)", shape=hexagon, style=filled, fillcolor="#b2f2bb"]; Select [label="选择工具与参数", shape=cds, style=filled, fillcolor="#fcc2d7"]; Execute [label="执行工具", shape=ellipse, style=filled, fillcolor="#ffc9c9"]; NoTool [label="无合适工具 / 继续推理", shape=ellipse, style=filled, fillcolor="#ced4da"]; Goal -> LLM; Context -> LLM; ToolDesc -> LLM; LLM -> Select [label=" 找到工具 "]; LLM -> NoTool [label=" 无需工具 "]; Select -> Execute; }代理接收一个目标并访问其当前状态/记忆以及可用工具的描述。LLM处理此信息以判断是否需要工具。如果需要,它选择工具并制定所需参数,进而执行。如果不需要,代理则继续其他推理步骤。最终,工具选择需要将清晰定义的工具约定(描述)与智能机制(主要基于LLM的推理,可能通过检索或路由增强)相结合,以使任务要求与可用能力相匹配。这是使代理能够与外部系统进行有意义交互并完成复杂目标的重要一步。