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
相关产品推荐
相关产品推荐

