函数调用(Function Calling)是大模型应用中的一项重要能力,它允许模型根据用户意图生成结构化的参数来调用预定义的函数。然而,仅仅让模型输出JSON格式的内容并不足够,如果缺少严格的参数约束,模型很容易产生类型错误、字段缺失或多余字段,导致后端解析失败。本篇文章将深入探讨如何通过JSON Schema来规范模型输出,以及如何优雅地处理参数解析过程中的各种错误。

JSON Schema在函数调用中的角色
大模型生成函数参数时,本质上是根据提示词和上下文预测文本。尽管主流模型已经在输出JSON格式方面做了大量优化,但依然无法保证每次生成的JSON都完全符合预期。例如,一个查询天气的函数需要城市名称和日期两个参数,模型可能输出{"city": "北京", "date": "2024-01-01"},也可能输出{"city": "北京", "date": 20240101},后者将日期写成了数字,导致后端解析失败。
JSON Schema正是为了解决这种不确定性而引入的契约。它以声明方式描述JSON数据的结构、类型、约束和必填字段,使得大模型在生成参数时有了明确的目标格式,同时后端可以利用Schema对模型输出进行自动校验。在函数调用实践中,开发者通常将JSON Schema作为函数定义的一部分提供给大模型,模型会根据Schema生成符合约束的参数。这种机制大幅提高了参数生成的可靠性,但前提是Schema本身设计得足够严谨。
下面是一个简单的JSON Schema示例,用于定义一个天气查询函数的参数:
{
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
},
"date": {
"type": "string",
"format": "date",
"description": "查询日期,格式为YYYY-MM-DD"
}
},
"required": ["city", "date"],
"additionalProperties": false
}这个Schema规定了参数必须是一个对象,包含字符串类型的city和符合日期格式的date,两者都是必填字段,并且不允许出现额外的属性。大模型在生成参数时会倾向于遵循这些约束,而后端则可以利用该Schema进行严格校验。
设计健壮的JSON Schema的实践要点
编写一个能用的JSON Schema并不困难,但要编写一个健壮的、能应对大模型各种奇怪输出的Schema则需要仔细考虑。首先,尽量避免使用宽泛的类型,例如将某个字段定义为any或仅使用object而不指定内部结构。类型越具体,模型生成错误数据的概率越低。如果某个参数只能是几个固定值中的一个,使用enum来限制;如果参数是数组,明确数组元素的类型和最小/最大长度。
其次,必填字段和默认值需要谨慎设置。将所有关键参数标记为required可以防止模型遗漏重要信息,但也要注意模型可能会因为无法确定某个可选参数而编造值。对于可选参数,可以在后端设置默认值,或者在Schema中使用default关键字。另外,additionalProperties通常设置为false,以避免模型添加无用字段,但某些场景下允许额外属性可能更宽容,需要根据业务需求权衡。
对于嵌套对象和数组,Schema的复杂度会显著增加。例如一个创建订单的函数可能需要客户信息、商品列表和配送地址。此时需要定义嵌套的properties,并对数组元素使用items约束。下面是一个更复杂的示例:
{
"type": "object",
"properties": {
"customer": {
"type": "object",
"properties": {
"name": { "type": "string" },
"phone": { "type": "string", "pattern": "^1[3-9]\\d{9}$" }
},
"required": ["name", "phone"],
"additionalProperties": false
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"product_id": { "type": "string" },
"quantity": { "type": "integer", "minimum": 1 }
},
"required": ["product_id", "quantity"]
},
"minItems": 1
},
"shipping_address": {
"type": "string"
}
},
"required": ["customer", "items", "shipping_address"],
"additionalProperties": false
}这个Schema使用了正则表达式校验手机号格式,用minimum限制数量至少为1,并要求商品列表至少包含一项。这些约束能有效防止模型生成不合逻辑的参数。
参数解析错误处理策略
即使有了完善的JSON Schema,大模型偶尔还是会输出无法解析的JSON或不符合约束的数据。此时需要在后端建立兜底机制。参数解析错误大致可以分为三类:JSON格式错误(例如缺少引号、括号不匹配)、Schema校验失败(类型不匹配、缺少必填字段等)以及业务逻辑错误(虽然通过了Schema校验,但数值不符合实际业务规则)。对于第一类错误,直接使用JSON.parse会抛出异常;对于第二类错误,需要使用JSON Schema校验库(如Python的jsonschema)来捕获;第三类错误则需要开发者自行编写验证逻辑。
在实际实现中,可以将错误信息结构化并返回给大模型,让模型根据错误提示重新生成参数。这种做法通常被称为“自我修正”或“重试机制”,能显著提高函数调用的成功率。下面以Python为例,展示如何结合jsonschema库进行校验和错误处理:
import json
from jsonschema import validate, ValidationError
def parse_and_validate(raw_output: str, schema: dict):
"""解析模型输出并校验,返回(参数, 错误信息)"""
try:
params = json.loads(raw_output)
except json.JSONDecodeError as e:
return None, f"JSON解析失败: {e.msg}"
try:
validate(instance=params, schema=schema)
except ValidationError as e:
# 提取路径和错误信息,方便模型理解
path = ".".join(str(p) for p in e.absolute_path)
return None, f"参数校验失败: 字段 '{path}' {e.message}"
return params, None
# 假设模型输出的原始文本
model_output = '{"city": "北京", "date": 20240101}'
schema = {
"type": "object",
"properties": {
"city": {"type": "string"},
"date": {"type": "string", "format": "date"}
},
"required": ["city", "date"],
"additionalProperties": False
}
params, error = parse_and_validate(model_output, schema)
if error:
# 将错误信息返回给模型,提示重新生成
retry_prompt = f"你之前生成的参数有误:{error}。请严格按照JSON Schema重新生成。"
# 这里调用大模型重新生成,略去具体实现
print(retry_prompt)
else:
print("参数合法:", params)
上面的代码首先尝试将原始输出解析为JSON,如果失败则返回格式错误信息;如果解析成功但校验不通过,则提取字段路径和错误描述,这些信息可以反馈给模型进行针对性修正。实际的函数调用流程通常会将错误信息拼接进下一次请求的提示词中,并设置最大重试次数以避免无限循环。
除了重试机制,还可以对常见错误进行预处理。例如,模型输出的JSON前后可能带有额外的反引号或说明文字,可以通过正则表达式提取出纯JSON部分;对于类型不匹配,可以尝试将字符串转换为数字或布尔值;对于多余字段,可以在校验前删除additionalProperties之外的键。这些预处理操作能进一步提高容错性,但也要注意避免过度修改导致语义改变。
最后,建议在日志中记录每次解析失败的原因和模型原始输出,以便后续分析模型的常见错误模式,针对性地优化提示词或调整Schema。参数解析错误处理不是一次性的工作,而是需要在实际使用中不断迭代和完善的环节。
函数调用JSON Schema参数解析错误修改时间:2026-10-05 07:02:57