工具描述与Schema设计:让AI精准理解工具能力

在大语言模型应用开发中,工具(Function)是我们赋予AI执行实际任务能力的关键载体。然而,AI能否正确理解并使用这些工具,很大程度上取决于我们如何描述工具、如何定义其参数Schema。本文将深入探讨工具描述的设计原则、Schema编写的最佳实践,以及如何避免常见的描述陷阱,帮助开发者构建可靠的工具调用系统。

在这里插入图片描述

一、为什么工具描述如此重要

在传统的API设计中,我们只需要考虑程序能否正确解析请求;但在LLM工具调用场景中,模型需要先“理解”工具的用途,再决定是否调用、如何调用。这其中存在一个关键的转化过程:将人类可读的工具文档转化为模型可理解的语义表示。

1.1 模型对工具的理解机制

现代大语言模型通过在海量文本数据中学习,积累了对各种工具、函数、概念的语义理解。当我们为模型提供工具描述时,模型会将其与训练时学到的知识进行关联,从而理解工具应该做什么、在什么场景下使用。

举例来说,当模型看到“天气查询工具”这样的描述时,它会结合训练数据中关于天气API的知识,理解这应该是一个获取特定地区天气信息的功能。但如果我们描述不够清晰或存在歧义,模型可能会产生错误的理解,导致调用了错误的工具或传递了错误的参数。

1.2 描述不当带来的典型问题

在实际开发中,工具描述不当会引发一系列问题。有些工具因为描述过于简略,模型无法判断应该在什么场景下调用它;有些工具因为描述与其他工具重叠,模型在选择时产生混淆;还有些工具的参数说明不清晰,导致模型传递了错误类型或格式的数据。这些问题都会直接影响应用的可靠性和用户体验。

二、工具描述的编写原则

2.1 描述的基本结构

一个完整的工具描述应该包含以下几个核心要素:工具名称、工具功能描述、适用场景说明、参数说明以及返回结果说明。让我们通过一个具体示例来展示如何编写高质量的描述。

{
  "name": "search_hotels",
  "description": "根据用户提供的目的地、入住日期和预算范围,搜索符合条件的酒店列表。该工具连接多个酒店预订平台,返回符合条件的所有可用选项。",
  "parameters": {
    "type": "object",
    "properties": {
      "destination": {
        "type": "string",
        "description": "目的地城市或具体地址,必须使用标准城市名称或详细地址"
      },
      "check_in_date": {
        "type": "string", 
        "description": "入住日期,格式为YYYY-MM-DD,必须是未来日期"
      },
      "check_out_date": {
        "type": "string",
        "description": "退房日期,格式为YYYY-MM-DD,必须晚于入住日期"
      },
      "budget_range": {
        "type": "object",
        "description": "预算范围,包含最低和最高价格",
        "properties": {
          "min": {"type": "number", "description": "每晚最低价格(元)"},
          "max": {"type": "number", "description": "每晚最高价格(元)"}
        }
      },
      "guests": {
        "type": "integer",
        "description": "入住人数,默认值为1"
      }
    },
    "required": ["destination", "check_in_date", "check_out_date"]
  }
}

2.2 描述语言的选择与风格

在编写工具描述时,语言的选择至关重要。首先,描述应该使用清晰、准确的简体中文,避免使用可能引起歧义的词汇。其次,描述应该保持客观、专业的风格,避免夸张或情感化的表达。第三,描述应该完整但不过度冗长,每个说明都应该有其存在的必要。

对于参数的描述,尤其需要注意使用模型能够准确理解的表述方式。例如,当参数是枚举类型时,应该明确列出所有可能的取值;当参数有特定格式要求时,应该给出具体的格式说明;当参数有取值范围限制时,应该说明合理的范围。

2.3 描述的层次与粒度

工具描述应该具有清晰的层次结构。从宏观到微观,依次是:工具的整体功能、每个参数的用途、每个参数内部属性的含义。这种层次结构帮助模型逐步理解工具的完整语义。

同时,描述的粒度也需要把握好平衡。过于简略的描述会让模型无法准确理解工具的能力;过于详细的描述则可能造成信息过载,反而影响模型的判断。一个好的原则是:描述应该包含模型正确使用工具所需的全部信息,但不应该包含与使用无关的细节。

三、Schema设计的最佳实践

3.1 参数类型的选择与定义

JSON Schema是目前最广泛使用的参数定义格式,它提供了丰富的类型系统和验证能力。在为工具定义参数Schema时,首先需要选择正确的参数类型。

基本类型的选择相对直接:字符串用于文本内容,数字用于数值(整数用integer,浮点数用number),布尔值用于开关类型,数组用于列表数据,对象用于结构化数据。但有时候类型的选择并不那么显而易见,需要根据参数的实际用途来决定。

以一个搜索功能为例,搜索关键词可以是一个简单的字符串,但高级搜索选项可能需要一个对象来包含多个配置项。分页参数可以是一个整数(表示页码),也可以是一个字符串(表示游标),需要根据后端API的设计来决定。

3.2 必填参数与可选参数的区分

正确标记必填参数和可选参数,对于模型正确调用工具至关重要。必填参数应该放在Schema的required数组中,这会强制模型在调用工具前必须提供这些参数的值。

但需要注意的是,必填参数的选择应该经过仔细考量。过多的必填参数会增加模型调用的难度,因为模型需要获取所有这些信息才能成功调用;过少的必填参数则可能导致模型在信息不完整的情况下就尝试调用工具,最终导致调用失败。

一个好的实践是:只将那些真正必要、没有默认值就无法完成核心功能的参数设为必填。那些有默认值或者可以提供默认行为的参数,应该设为可选参数,并在描述中说明默认值是什么。

3.3 嵌套对象的处理

当工具参数包含嵌套的对象结构时,Schema的设计需要更加谨慎。嵌套层级不宜过深,一般建议控制在三层以内。过深的嵌套会增加模型理解的难度,也容易导致参数解析错误。

对于复杂的对象参数,可以考虑将其拆分为多个平级的参数,每个参数负责对象的一个方面。这样可以降低模型的理解难度,也使得参数的传递更加灵活。

{
  "type": "object",
  "properties": {
    "basic_info": {
      "type": "object",
      "description": "基本信息",
      "properties": {
        "name": {"type": "string", "description": "姓名"},
        "age": {"type": "integer", "description": "年龄"}
      }
    },
    "contact_info": {
      "type": "object", 
      "description": "联系方式",
      "properties": {
        "email": {"type": "string", "description": "电子邮箱"},
        "phone": {"type": "string", "description": "手机号码"}
      }
    }
  }
}

3.4 枚举值的使用

当参数的取值是固定的一组值时,使用枚举(enum)来定义是最佳实践。枚举不仅能够限制参数的取值范围,还能帮助模型理解参数的语义。

{
  "language": {
    "type": "string",
    "description": "返回结果的语言",
    "enum": ["zh-CN", "en-US", "ja-JP", "ko-KR"],
    "default": "zh-CN"
  }
}

在使用枚举时,需要确保枚举值的命名清晰易懂。如果是代码式的枚举值(如上面示例中的"zh-CN"),应该在描述中说明每个值代表什么含义。同时,如果某些枚举值的使用频率远高于其他值,可以考虑将其设为默认值,减少模型需要传递的参数数量。

四、工具描述的优化策略

4.1 场景化描述技巧

与其简单地说“搜索书籍”,不如描述“在什么情况下应该搜索书籍”。场景化的描述能够帮助模型更准确地判断何时应该使用这个工具。

{
  "name": "search_books",
  "description": "当用户想要查找特定主题、作者或书名的书籍时使用此工具。该工具在用户明确表达想要找书、询问某本书的详细信息、或者想要获得书籍推荐时调用。\n\n不适用于:用户只是想了解某个话题的相关信息(应使用search_web)、用户想要购买实体书(应使用search_products)。"
}

这种场景化的描述通过明确指出工具的适用场景和不适用的场景,帮助模型在多个工具中进行准确的选择。

4.2 工具之间的区分与边界

当一个系统包含多个功能相似的工具时,工具之间的区分就变得尤为重要。每个工具的描述应该突出其独特性,让模型能够根据具体需求选择最合适的工具。

举例来说,如果系统同时提供“搜索新闻”、“搜索图片”、“搜索视频”三个工具,每个工具的描述应该明确说明它们分别返回什么类型的内容,以及它们各自适合什么场景。

{
  "name": "search_news",
  "description": "搜索新闻文章和媒体报道,返回与查询相关的新闻内容,包括标题、来源、发布时间和摘要。适用于用户想要了解最新事件、行业动态或特定话题的报道时使用。"
}

4.3 利用description补充语义信息

JSON Schema的description字段是传递额外语义信息的主要渠道。除了说明参数是什么之外,description还应该说明参数从哪里来、有什么用、有什么限制。

{
  "max_results": {
    "type": "integer",
    "description": "返回结果的最大数量,范围1-50,默认值为10。该参数用于控制返回结果的数量,如果设置为超过50的值,将被自动调整为50。"
  }
}

这种详细的描述能够帮助模型理解参数的完整语义,包括其取值范围、默认值、以及超出范围时的处理方式。

五、常见问题与解决方案

5.1 模型不调用工具

如果模型在应该调用工具的情况下没有调用工具,首先要检查工具的描述是否足够清晰,模型是否理解工具的用途。其次,可以检查是否在提示词中明确指定了工具可用的场景。最后,还可以尝试在系统提示词中增加关于工具使用时机的说明。

5.2 模型调用了错误的工具

当模型在多个相似工具中选择了错误的那个时,需要强化工具之间的区分描述。可以通过在描述中增加对比说明,明确指出这个工具与其他工具的区别所在。

5.3 参数传递不完整或不正确

参数传递问题通常源于参数描述不够清晰或者必填参数设置不合理。解决方案包括:为每个参数提供更详细的描述,确保模型理解参数的要求;检查必填参数列表,确保只有真正必要的参数才被设为必填;对于复杂的参数结构,考虑简化为更扁平的结构。

5.4 描述过长导致信息分散

有时候开发者会倾向于提供非常详细的描述,但这反而可能导致模型无法抓住重点。解决方法是保持描述简洁明了,只包含必要的信息;将详细的说明文档放在外部资源中,通过description提供链接;使用结构化的描述格式,让重要信息更容易被识别。

六、实战案例:重构工具描述

让我们通过一个实际的案例来展示如何优化工具描述。以下是一个优化前的搜索工具描述:

{
  "name": "search",
  "description": "搜索功能",
  "parameters": {
    "type": "object",
    "properties": {
      "query": {"type": "string"},
      "type": {"type": "string"},
      "limit": {"type": "integer"}
    }
  }
}

这个描述存在太多问题:工具名称没有描述性,描述过于简略,参数没有任何说明,缺少必填参数标记。优化后的版本如下:

{
  "name": "search_knowledge_base",
  "description": "在企业知识库中搜索相关文档和技术资料。当用户提出技术问题、查询产品文档、寻找解决方案或需要了解特定功能的使用方法时使用此工具。该工具不对接外部互联网搜索。\n\n适用场景:\n- 用户询问某个功能如何使用\n- 用户需要查找产品文档或技术规格\n- 用户在解决某个具体问题需要参考文档\n\n不适用场景:\n- 用户想要了解实时新闻或最新事件(应使用search_news)\n- 用户想要查找某个图片或视频内容(应使用search_media)",
  "parameters": {
    "type": "object",
    "properties": {
      "query": {
        "type": "string",
        "description": "搜索关键词,应使用简洁的技术术语或问题描述。避免使用口语化的表达,例如将'怎么设置'改为'设置方法'。"
      },
      "category": {
        "type": "string",
        "description": "搜索结果的分类筛选,可选值:all(全部)、product_docs(产品文档)、api_docs(API文档)、faq(常见问题)、tutorials(教程)。默认为all。",
        "enum": ["all", "product_docs", "api_docs", "faq", "tutorials"],
        "default": "all"
      },
      "limit": {
        "type": "integer",
        "description": "返回结果的数量限制,范围1-20,默认值为5。"
      }
    },
    "required": ["query"]
  }
}

优化后的描述不仅包含了工具的基本功能,还详细说明了使用场景、不适用场景、参数的具体要求和格式要求,以及各个参数的默认值。这些信息能够帮助模型更准确地理解工具并在合适的场景下正确调用。

七、总结

工具描述与Schema设计是大语言模型应用开发中的关键技术点。好的工具描述应该具备以下特征:清晰准确的功能说明、明确的适用场景说明、详细的参数定义、合理必填参数设置、以及工具之间的清晰边界。

在实际开发中,我们需要根据具体的应用场景和模型能力,不断迭代和优化工具描述。最初的设计可能并不完美,但通过观察模型的实际调用行为,持续改进描述内容,最终可以建立起一套可靠的工具调用系统。

随着对模型能力的深入理解和对业务场景的把握,开发者应该建立起适合自己项目的工具描述规范和最佳实践,这将大大提高应用开发的效率和质量。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐