登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

AI 工具调用参数怎样用枚举收窄输入

来源:17golang原创

时间:2026-10-17 23:33:50 147浏览 收藏

如果一个工具参数实际只允许 summary、detail 两种模式,就不要把它声明成“任意字符串”。在 JSON Schema 中加入 enum,可以把允许值写进工具契约;但它只是输入约束,不能替代服务端在执行前的最终校验。模型仍可能返回格式错误、未知字段或不在集合中的值,分发器必须先拒绝,再决定是让调用方澄清还是重试。

官方参考入口:https://huggingface.co/docs/hugs/guides/function-calling。Hugging Face 的工具调用文档把工具参数表示为 JSON Schema,并展示了用 enum 约束温度单位的方式。

把枚举当作“可执行接口的白名单”,把校验放在工具真正执行之前;非法值返回结构化错误,暂时性下游故障才进入重试。

先把开放字符串收窄成工具契约

假设工具负责生成一份报告,mode 只允许摘要或详细两种模式。工具声明应同时表达对象类型、属性类型、枚举集合和必填字段。若调用方还需要禁止额外字段,可以配合 additionalProperties: false;是否支持严格模式则取决于具体模型和提供方,不能只因为字段写进 Schema 就假设所有服务都会替你拦截。

# 这是发送给模型的工具参数契约,不是报告生成函数本身。
report_tool = {
    "type": "function",
    "function": {
        "name": "create_report",
        "description": "按指定模式生成一份报告",
        "parameters": {
            "type": "object",
            "properties": {
                "topic": {"type": "string", "description": "报告主题"},
                "mode": {
                    "type": "string",
                    "enum": ["summary", "detail"],
                    "description": "只能选择摘要或详细模式"
                }
            },
            "required": ["topic", "mode"],
            "additionalProperties": False
        },
        # 是否开启严格工具调用,要按所用提供方的接口能力决定。
        "strict": True
    }
}

enum 的作用是让一个实例只能等于列出的值;它不会把 "Summary" 自动转成 "summary",也不会把中文“摘要”自动映射成内部值。建议把稳定的机器值放在枚举数组里,再用 description 解释给模型和开发者看。

工具定义、参数对象、枚举属性和执行前校验器的静态关系
图1:结构说明图,查看工具定义如何把参数对象、枚举属性、必填字段和校验器放进同一份接口契约;这不是运行截图。

枚举校验必须挡在真实工具之前

模型输出的工具参数通常还要经历 JSON 解析、Schema 校验和函数分发。任何一个环节失败,都不应直接把未确认的参数传给真实工具。下面的示例用 jsonschema 表达执行边界:解析失败、枚举不匹配和额外字段都返回结构化错误,只有校验通过才进入注册表。

import json
from jsonschema import Draft202012Validator

# 只保留业务允许的模式,避免把模型输出直接当成可信输入。
REPORT_SCHEMA = {
    "type": "object",
    "properties": {
        "topic": {"type": "string", "minLength": 1},
        "mode": {"type": "string", "enum": ["summary", "detail"]}
    },
    "required": ["topic", "mode"],
    "additionalProperties": False
}

def dispatch_report(arguments_text, create_report):
    # 工具调用参数常以 JSON 字符串到达,先解析再校验。
    try:
        arguments = json.loads(arguments_text)
    except json.JSONDecodeError:
        return {"ok": False, "kind": "invalid_json", "message": "工具参数不是合法 JSON"}

    # 第一道白名单检查:非法枚举值不会进入 create_report。
    errors = list(Draft202012Validator(REPORT_SCHEMA).iter_errors(arguments))
    if errors:
        return {
            "ok": False,
            "kind": "schema_rejected",
            "message": errors[0].message
        }

    # 只有完整通过 Schema 后,才把已知字段交给真实工具。
    return {"ok": True, "result": create_report(arguments["topic"], arguments["mode"])}

这里的关键不是使用某一个 Python 校验库,而是把“校验通过”作为分发前置条件。生产代码还应限制工具名、检查当前用户是否有权限,并对下游工具返回值做独立的错误处理。JSON Schema 只能约束结构和取值,不会替你完成授权、业务状态检查或敏感操作确认。

原始工具参数经过解析器和枚举校验后分成拒绝响应与工具处理器的静态关系
图2:边界说明图,查看原始参数、解析器、Schema 校验器、拒绝响应和工具处理器之间的职责分界;连线表示静态关系,不代表已执行结果。

拒绝、澄清和重试要使用不同错误模型

当 mode 收到 full 时,这是输入契约错误,不应把同一参数无限重试。可以把 kind 设为 schema_rejected,并告诉上层只接受哪些值;如果用户意图不明确,则让模型或用户重新选择。只有在枚举合法、工具已经开始执行之后出现网络超时、限流等暂时性故障,才适合按幂等策略重试。

情况处理动作是否重试原参数
JSON 无法解析返回 invalid_json,并记录原始调用 ID否,先修正输出
枚举值不在集合中返回 schema_rejected,给出允许值否,先澄清
枚举合法但下游超时返回 transient_error,使用幂等键可按策略重试
工具名不在注册表拒绝调用并告警配置漂移否

将错误类型分开后,调用方不会把“参数写错”误判成“服务暂时不可用”。日志里可以保留工具名、校验错误类型和调用 ID,但不要把口令、令牌或完整敏感参数原样写入日志。

枚举值是版本化接口的一部分

枚举并不是只影响提示词的装饰字段。删除或改名会让旧调用方失效;新增值虽然通常比删除更容易兼容,但旧版处理器可能仍然只认识原来的分支。对外接口可以使用稳定的机器值,例如 summary 和 detail,把展示文案放在描述或前端映射层,不要让中文显示名直接成为后端分支条件。

  • 新增枚举值前,先确认所有执行器遇到未知值时会安全拒绝。
  • 删除或改名时,保留一段兼容期,并在 Schema 和文档中同步标记。
  • 需要跨版本协商时,可增加独立的能力字段,不要偷偷改变原枚举的含义。
  • 测试至少覆盖每个合法值、一个非法值、缺失字段和额外字段。

两个容易混淆的问题

写了 enum,模型就一定不会返回非法值吗? 不一定。Schema 是模型可见的约束,也是本地校验的依据,但不同模型、模板和提供方对严格模式的支持不同。最终执行前仍要解析和校验。

enum 能代替业务规则吗? 不能。它适合表达有限集合,例如模式、单位和状态;库存是否足够、用户是否有权限、当前订单是否允许某动作,都需要在工具内部继续判断。

真正稳妥的做法是把枚举写进工具 Schema,把校验器放在分发器,把错误分成输入拒绝与下游暂时失败,再把枚举变更当成接口版本管理问题处理。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>