AIGC宇宙 AIGC宇宙

一日一技:如何快速生成大模型工具调用的JSON Schema

在使用大模型的工具调用时,我们需要编写JSON Schema,例如下图的tools字段的值:图片这个Schema写起来非常麻烦,括号太多了,看着眼花。 不信你肉眼看看,你需要几秒钟才能分清楚type: "object"跟哪个字段在同一层级? 这个Schema有没有什么办法自动生成呢?

在使用大模型的工具调用时,我们需要编写JSON Schema,例如下图的tools字段的值:

图片图片

这个Schema写起来非常麻烦,括号太多了,看着眼花。不信你肉眼看看,你需要几秒钟才能分清楚type: "object"跟哪个字段在同一层级?这个Schema有没有什么办法自动生成呢?

LangChain提供了一个@tool装饰器来简化工具调用的JSON Schema,直接装饰函数就能使用了。例如:

复制
import json
from langchain_core.tools.convert import tool


@tool(parse_docstring=True)
def parse_user_info(name: str, age: int, salary: float) -> bool:
    """
    保存用户的个人信息
 
    Args:
        name: 用户名
        age: 用户的年龄
        salary: 用户的工资
    """
    return True

然后,我们可以通过打印函数名的.args_schema.model_json_schema()来获取到类似于Tool Calling的JSON Schema,如下图所示:

图片图片

这种方式有两个问题:

1. Tool Calling需要的JSON Schema中,参数名对应的字段应该是name,但这里导出来的是title。

2. 函数的docstring使用的是Google Style,跟Python的不一样。

在Python里面,我们写docstring时,一般这样写::param 参数名: 参数解释,例如下面这样:

复制
import json
from langchain_core.tools.convert import tool


@tool
def parse_user_info(name: str, age: int, salary: float) -> bool:
    """
    保存用户的个人信息
 
    :param name: 用户名 
    :param age: 用户的年龄
    :param salary: 用户的工资
    :return: bool,成功返回True,失败返回False
    """
    return True

schema = parse_user_info.args_schema.model_json_schema()
print(json.dumps(schema, ensure_ascii=False, indent=2))

但使用这种方式定义的时候,@tool装饰器不能加参数parse_docstring=True,否则会报错。可如果不加,提取的信息里面,字段没有描述。效果如下图所示:

图片图片

这两个问题,其实有一个通用的解决办法,那就是直接使用`Pydantic`。实际上,LangChain本身使用的也是Pydantic。如下图所示:

图片图片

我之前写过一篇文章:一日一技:如何使用大模型提取结构化数据,介绍了一个第三方库,名叫`instructor`。它本质上就是把Pydantic定义的类转成Tool Calling需要的JSON Schema,然后通过大模型的Tool Calling来提取参数。使用使用它,我们可以非常容易的实现本文的目的。

使用Pydantic定义我们要提取的数据并转换为JSON Schema格式:

复制
import json
from pydantic import BaseModel, Field

class UserInfo(BaseModel):
    """
    用户个人信息
    """
    name: str = Field(..., descriptinotallow='用户的姓名')
    age: int = Field(default=None, descriptinotallow='用户的年龄')
    salary: float = Field(default=None, descriptinotallow='用户的工资')

schema = UserInfo.model_json_schema()
print(json.dumps(schema, indent=2, ensure_ascii=False))

Field的第一个参数如果是三个点...,表示这个字段是必填字段。如果想把一个字段设定为可选字段,那么Field加上参数default=None。

运行效果如下图所示:

图片图片

参数描述直接写到参数字段定义里面,根本不需要担心注释格式导致参数没有描述,管他是Google Style还是Python Style。

接下来,我们要把Pydantic输出的这个格式转换为Tool Calling需要的JSON Schema格式。我们来看一下Instructor的源代码:

图片图片

把他这个代码复制出来,用来处理刚刚Pydantic生成的JSON Schema:

复制
from docstring_parser import parse


def generate_tool_calling_schema(cls):
    schema = cls.model_json_schema()
    docstring = parse(cls.__doc__ or'')
    parameters = {
        k: v for k, v in schema.items() if k notin ("title", "description")
    }
    for param in docstring.params:
        if (name := param.arg_name) in parameters["properties"] and (
            description := param.description
        ):
            if"description"notin parameters["properties"][name]:
                parameters["properties"][name]["description"] = description
    
    parameters["required"] = sorted(
        k for k, v in parameters["properties"].items() if"default"notin v
    )
    
    if"description"notin schema:
        if docstring.short_description:
            schema["description"] = docstring.short_description
        else:
            schema["description"] = (
                f"Correctly extracted `{cls.__name__}` with all "
                f"the required parameters with correct types"
            )
    
    return {
        "name": schema["title"],
        "description": schema["description"],
        "parameters": parameters,
    }

这里依赖一个第三方库,叫做docstring_parser,这个库的原理非常简单,就是正则表达处理docstring而已。大家甚至可以看一下他的源代码然后自己实现。

运行以后效果如下图所示。

图片图片

注意在参数信息里面,会有'default': null和title字段,这两个字段即使传给大模型也没有关系,它会自动忽略。如果大家觉得他们比较碍眼,也可以改动一下代码,实现跟Tool Calling 的JSON Schema完全一样:

复制
from docstring_parser import parse


def generate_tool_calling_schema(cls):
    schema = cls.model_json_schema()
    docstring = parse(cls.__doc__ or'')
    parameters = {
        k: v for k, v in schema.items() if k notin ("title", "description")
    }
    for param in docstring.params:
        if (name := param.arg_name) in parameters["properties"] and (
            description := param.description
        ):
            if"description"notin parameters["properties"][name]:
                parameters["properties"][name]["description"] = description

    parameters["required"] = sorted(
        k for k, v in parameters["properties"].items() if"default"notin v
    )

    for prop_name, prop_schema in parameters["properties"].items():
        prop_schema.pop("default", None)
        prop_schema.pop('title', None)

    if"description"notin schema:
        if docstring.short_description:
            schema["description"] = docstring.short_description
        else:
            schema["description"] = (
                f"Correctly extracted `{cls.__name__}` with all "
                f"the required parameters with correct types"
            )

    # 按 Tool Calling 规范封装:
    return {
        "type": "function",
        "function": {
            "name": schema["title"],
            "description": schema["description"],
            "parameters": parameters,
        }
    }

运行效果如下图所示:

图片图片

最后给大家出个思考题:如果函数的参数包含嵌套参数,应该怎么处理?

相关资讯

腾讯云上线DeepSeek全系API接口并打通联网搜索

腾讯云宣布完成对深度求索(DeepSeek)大模型的深度整合——正式上线DeepSeek-R1和V3原版模型的API接口,并创新性接入自研大模型知识引擎,同步开放联网搜索能力。 凭借腾讯云在推理并发和生成速率等方面的优化,用户可以获得更加稳定、安全、低门槛的使用体验。 开发者只需在云上简单三步即可实现API接口调用,并通过大模型知识引擎提供的文档解析、拆分、embedding、多轮改写等能力,灵活构建专属的AI服务。
2/8/2025 2:09:00 PM
AI在线

微信搜索接入DeepSeek大模型 称AI不会使用朋友圈聊天等信息

近日,微信宣布其搜索功能接入 DeepSeek-R1模型,目前处于灰度测试阶段。 部分用户在微信搜索框选择 AI 搜索时,可体验到 DeepSeek-R1提供的深度思考功能。 微信方面表示,引入大模型旨在提升搜索的智能化和精准度,更好地理解用户搜索意图,分析处理复杂查询。
2/19/2025 11:18:00 AM
AI在线

DeepSeek-R1 登顶 Hugging Face:以10000 赞力压 150 万个模型

今日凌晨,全球最大开源平台之一 Hugging Face 的首席执行官 Clement Delangue 在社交平台发文宣布,DeepSeek-R1在 Hugging Face 上获得了超过10000个赞,成为该平台近150万个模型中最受欢迎的大模型。 这一里程碑式的成就标志着 DeepSeek-R1在全球 AI 社区中的广泛认可与影响力。 DeepSeek-R1的崛起速度令人瞩目。
2/24/2025 9:30:00 AM
AI在线
testab