当前位置:首页 > 文章列表 > 科技周边 > 人工智能 > Tool calling校验工具参数并区分模型与业务错误的实现方法

Tool calling校验工具参数并区分模型与业务错误的实现方法

来源:17golang原创 2026-09-15 20:23:53 0浏览 收藏

我在第一次把工单查询接入 tool calling 时,最容易混淆的是“模型给错参数”和“工具执行失败”。前者属于调用契约问题,应该拒绝或让模型修正;后者属于业务结果,应该把可解释的失败回传给模型,而不是让模型继续猜参数。比较稳妥的实现是:工具声明负责约束形状,应用服务负责二次校验和白名单路由,业务函数只返回稳定的成功或失败结果。

官方文档:https://developers.openai.com/api/docs/guides/function-calling

要点速览
  • strict: true 能收紧函数参数契约,但不替代库存、权限、状态等业务校验。
  • 模型侧错误包括未知工具、JSON 解码失败和 schema 不匹配;业务侧错误包括订单不存在、无权访问和状态不允许。
  • 回传 function_call_output 时保留 call_id,让日志、重试和最终回答能对应同一次调用。

先把工具调用拆成两条责任边界

OpenAI 的 function calling 本质上是一个多轮交互:应用带着工具定义请求模型,模型返回工具调用,应用执行函数,再把工具结果发回模型。对我来说,最重要的设计决定不是“要不要加重试”,而是先给这条数据流划线:模型产生的调用对象到达业务函数之前,全部按模型错误处理;业务函数已经拿到合法参数后发生的失败,才算业务错误。

Tool calling 从模型调用对象到参数校验、业务工具和结果回传的边界结构图
图1:Tool calling 边界说明图,展示调用对象、schema 校验、业务工具与结果回传之间的责任关系,不是运行截图。

工具声明也要尽量具体。官方文档把函数输入定义为 JSON Schema,并建议开启严格模式;严格模式下,对象需要设置 additionalProperties: false,属性通常都应列入 required,可选值可以用可空类型表达。这些规则解决的是“字段长什么样”,不是“这个订单此刻能不能查”。

用 schema 拦截形状错误,再做一次应用层判断

下面这个示例把两层错误显式分开。示例使用 Python 标准库解析 JSON;生产项目可以把同一份契约交给 JSON Schema 校验器,但不要因为模型开启了 strict 就跳过应用侧校验。模型输出仍需要经过工具名白名单、解码、字段范围和权限上下文检查。

import json

def classify_tool_call(tool_call):
    # 先限制工具名,防止模型请求未注册的业务能力。
    if tool_call.get("name") != "lookup_order":
        return {"kind": "model_error", "code": "unknown_tool"}

    try:
        args = json.loads(tool_call.get("arguments", "{}"))
    except json.JSONDecodeError:
        # JSON 无法解析时,业务函数还没有被调用。
        return {"kind": "model_error", "code": "invalid_arguments_json"}

    if not isinstance(args, dict) or not isinstance(args.get("order_id"), str):
        # 这是参数形状错误,不应进入订单查询重试。
        return {"kind": "model_error", "code": "schema_mismatch"}

    if not args["order_id"].startswith("ORD-"):
        # 形状合法但业务字段格式不接受,仍在边界层拦截。
        return {"kind": "business_error", "code": "invalid_order_id"}

    return {"kind": "validated", "args": args}

这里的 invalid_order_id 也可以归入领域校验,关键是团队要固定分类并写进日志。不要有时把它当模型错误,有时又当订单服务错误,否则重试器很难判断是否应该再次请求模型。

现象归属处理动作
工具名不在注册表模型错误拒绝调用并记录原始 call_id
arguments 不是合法 JSON模型错误让模型修正调用,避免触发业务重试
订单不存在或无权限业务错误返回稳定错误码,由模型组织用户可读答复
订单已关闭,不能执行动作业务错误回传状态和下一步建议,不伪装成成功

业务函数只接收已验证参数,结果也要可回传

验证通过后再走白名单路由。业务函数不要把 Python 异常、数据库堆栈或内部字段直接塞进模型上下文;可观测信息写日志,给模型的结果保持短小、结构稳定。成功返回订单摘要,失败返回 ok=false、错误码和可行动的提示即可。

def execute_lookup(validated, current_user):
    # 通过验证后才读取业务数据,权限仍以当前用户为准。
    order_id = validated["args"]["order_id"]
    order = find_order(order_id)
    if order is None:
        return {"ok": False, "error_code": "ORDER_NOT_FOUND",
                "message": "订单不存在,请核对订单号"}
    if order["owner_id"] != current_user["id"]:
        # 不泄露订单是否存在,权限失败统一返回可解释结果。
        return {"ok": False, "error_code": "ORDER_FORBIDDEN",
                "message": "当前账号无权查看该订单"}
    return {"ok": True, "order_id": order_id,
            "status": order["status"]}

def to_function_output(call_id, result):
    # call_id 必须原样保留,便于把结果对应回这次工具调用。
    return {"type": "function_call_output", "call_id": call_id,
            "output": json.dumps(result, ensure_ascii=False)}
Tool calling 错误分类表展示模型错误、边界校验错误与业务错误的结果对象关系
图2:错误结果结构说明图,比较模型侧错误与业务侧错误的返回字段和后续处理边界,不是执行证据。

官方文档允许把工具结果作为字符串传回,字符串内部可以是 JSON、错误码或普通文本。我的取舍是统一使用 JSON,因为监控可以按 okerror_code 聚合,模型也能稳定理解;但内部异常细节不放进去,避免把实现信息暴露给下一轮上下文。

重试只对症下药,别把业务失败变成参数修复

模型错误可以有限次重试,例如只针对 JSON 解码或 schema 不匹配重新请求;未知工具应直接报警,因为它更像注册表漂移。业务错误通常不该自动重试:订单不存在不是换个参数就一定能解决,无权限也不能靠模型多调用几次绕过。若同时开启并行工具调用,日志还要按每个 call_id 独立记录结果,不能把一条失败污染同轮其他合法调用。

我会把以下字段放进结构化日志:调用名、call_id、schema 校验结果、业务错误码、用户上下文摘要、耗时和最终是否重试。这样排查时先看错误层级,再决定修提示词、修工具契约还是修业务服务,不会从一条模糊的“tool failed”开始猜。

常见问题

开启 strict 后还需要应用层校验吗?

需要。strict 主要约束模型生成的参数形状,订单存在性、权限、状态和数据一致性仍必须由应用服务判断。

模型错误要不要把原始异常回传?

不建议。给模型稳定的错误码和修正方向即可;原始 JSON、堆栈和内部字段留在受控日志中。

业务错误应该让模型重新调用工具吗?

只有错误信息明确提示可修正输入时才考虑一次重试,例如订单号格式不对;不存在、无权限和状态冲突通常直接生成解释性答复。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go HTTP 超时回收空闲连接避免资源占满的排查指南Go HTTP 超时回收空闲连接避免资源占满的排查指南
上一篇
Go HTTP 超时回收空闲连接避免资源占满的排查指南
Go io合并多个输入流并处理错误的实践方案
下一篇
Go io合并多个输入流并处理错误的实践方案
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    43次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    138次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    74次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    39次使用
  • CMMLU中文大模型评估基准:功能、使用教程与应用场景解析
    CMMLU
    深入了解CMMLU中文评估基准,涵盖67个学科主题,提供数据集下载、Zero-shot/Five-shot评估方法及排行榜,助力优化中文语言模型性能。
    26次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码