You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Langchain传递Enum类型工具报错:ModelMetaclass无法JSON序列化

解决Langchain中IntEnum类型工具参数的JSON序列化错误

问题背景

在Langchain 0.3.0 + langchain-openai 0.2.0环境下,尝试定义接收IntEnum类型参数的掷骰子工具时,运行出现以下错误:

TypeError: Object of type ModelMetaclass is not JSON serializable

推测是工具参数序列化环节失败,原代码如下:

import random
from enum import IntEnum

from dotenv import load_dotenv
from langchain.tools import Tool, tool
from langchain_openai import AzureChatOpenAI
from pydantic import BaseModel, Field

load_dotenv()


class Dice(IntEnum):
    """
    Roll a D&D dice. A d4 dice has 4 sides and thus
    rolling a d4 dice will return a value from 1 through 4.
    """

    d4 = 4
    d6 = 6
    d8 = 8
    d10 = 10
    d12 = 12
    d20 = 20
    d100 = 100


def roll_dice(dice: Dice) -> int:
    """
    Simulates rolling a dice with a specified number of sides.

    Parameters:
    dice (Dice): A dice to roll.

    Returns:
    int: The result of the dice roll.
    """
    return random.randint(1, dice.value)


class RollDiceInput(BaseModel):
    dice: Dice


def get_function_description(func):
    """Extract docstrings from the functions"""
    return func.__doc__.strip()


# Define the tool with the input schema
roll_dice_tool = Tool(
    name="roll_dice",
    description=get_function_description(roll_dice),
    args_schema=RollDiceInput,
    func=roll_dice,
)

# Define the prompt
prompt = """
Roll a dice in Dungeons and Dragons.
"""

client = AzureChatOpenAI()

# Call the GPT-4 API with descriptions extracted from docstrings
response = client.invoke(
    model="gpt-4o",
    input=prompt,
    tools=[roll_dice_tool],
    tool_choice={
        "type": "function",
        "function": {"name": "roll_dice"},
    },  # forces the model to call the `roll_dice` function
)

错误原因

Langchain在将工具参数schema序列化为JSON格式传递给OpenAI API时,无法直接处理IntEnum类型,导致序列化流程失败。需要调整参数定义方式,让schema能被正确序列化,同时兼容模型返回的字符串参数。

解决方案

提供两种可行的修改方式:

方式一:用Literal限定可选值,函数内部转换为IntEnum

修改输入schema为Literal枚举所有可选骰子类型字符串,在工具函数内部将字符串转换为Dice枚举实例:

import random
from enum import IntEnum
from typing import Literal

from dotenv import load_dotenv
from langchain.tools import Tool
from langchain_openai import AzureChatOpenAI
from pydantic import BaseModel

load_dotenv()


class Dice(IntEnum):
    d4 = 4
    d6 = 6
    d8 = 8
    d10 = 10
    d12 = 12
    d20 = 20
    d100 = 100


def roll_dice(dice: str) -> int:
    """
    Simulates rolling a dice with a specified number of sides.

    Parameters:
    dice (str): A dice to roll, options are d4, d6, d8, d10, d12, d20, d100.

    Returns:
    int: The result of the dice roll.
    """
    dice_enum = Dice[dice]
    return random.randint(1, dice_enum.value)


class RollDiceInput(BaseModel):
    dice: Literal["d4", "d6", "d8", "d10", "d12", "d20", "d100"]


roll_dice_tool = Tool(
    name="roll_dice",
    description=roll_dice.__doc__.strip(),
    args_schema=RollDiceInput,
    func=roll_dice,
)

prompt = """Roll a dice in Dungeons and Dragons."""

client = AzureChatOpenAI()

response = client.invoke(
    model="gpt-4o",
    input=prompt,
    tools=[roll_dice_tool],
    tool_choice={
        "type": "function",
        "function": {"name": "roll_dice"},
    },
)

# 处理工具调用结果
if hasattr(response, 'tool_calls'):
    tool_call = response.tool_calls[0]
    result = roll_dice(**tool_call['args'])
    print(f"骰子结果:{result}")

方式二:使用@tool装饰器自动生成schema

利用Langchain的@tool装饰器,直接在函数参数中使用Literal,让装饰器自动生成正确的schema,代码更简洁:

import random
from enum import IntEnum
from typing import Literal

from dotenv import load_dotenv
from langchain.tools import tool
from langchain_openai import AzureChatOpenAI

load_dotenv()


class Dice(IntEnum):
    d4 = 4
    d6 = 6
    d8 = 8
    d10 = 10
    d12 = 12
    d20 = 20
    d100 = 100


@tool
def roll_dice(dice: Literal["d4", "d6", "d8", "d10", "d12", "d20", "d100"]) -> int:
    """
    Simulates rolling a dice with a specified number of sides.

    Parameters:
    dice: A dice to roll, options are d4, d6, d8, d10, d12, d20, d100.

    Returns:
    int: The result of the dice roll.
    """
    dice_enum = Dice[dice]
    return random.randint(1, dice_enum.value)


prompt = """Roll a dice in Dungeons and Dragons."""

client = AzureChatOpenAI()

response = client.invoke(
    model="gpt-4o",
    input=prompt,
    tools=[roll_dice],
    tool_choice={
        "type": "function",
        "function": {"name": "roll_dice"},
    },
)

# 处理工具调用结果
if hasattr(response, 'tool_calls'):
    tool_call = response.tool_calls[0]
    result = roll_dice(**tool_call['args'])
    print(f"骰子结果:{result}")

关键说明

  • 核心是将IntEnum类型转换为JSON可序列化的Literal字符串集合,确保Langchain能正确生成工具的JSON schema传递给OpenAI API。
  • 在工具函数内部,将模型返回的字符串参数转换为IntEnum实例后再执行业务逻辑。
  • 模型返回工具调用指令后,需手动提取参数并执行工具函数获取结果。

内容的提问来源于stack exchange,提问作者tsorn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 05:35:23