mirror of
https://github.com/hwchase17/langchain.git
synced 2025-06-27 17:08:47 +00:00
core: support Union
type args in strict mode of OpenAI function calling / structured output (#30971)
**Issue:**[ #309070](https://github.com/langchain-ai/langchain/issues/30970) **Cause** Arg type in python code ``` arg: Union[SubSchema1, SubSchema2] ``` is translated to `anyOf` in **json schema** ``` "anyOf" : [{sub schema 1 ...}, {sub schema 1 ...}] ``` The value of anyOf is a list sub schemas. The bug is caused since the sub schemas inside `anyOf` list is not taken care of. The location where the issue happens is `convert_to_openai_function` function -> `_recursive_set_additional_properties_false` function, that recursively adds `"additionalProperties": false` to json schema which is [required by OpenAI's strict function calling](https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses#additionalproperties-false-must-always-be-set-in-objects) **Solution:** This PR fixes this issue by iterating each sub schema inside `anyOf` list. A unit test is added. **Twitter handle:** shengboma If no one reviews your PR within a few days, please @-mention one of baskaryan, eyurtsev, ccurme, vbarda, hwchase17. --------- Co-authored-by: ccurme <chester.curme@gmail.com>
This commit is contained in:
parent
c982573f1e
commit
eb25d7472d
@ -788,9 +788,12 @@ def _recursive_set_additional_properties_false(
|
|||||||
schema["additionalProperties"] = False
|
schema["additionalProperties"] = False
|
||||||
|
|
||||||
# Recursively check 'properties' and 'items' if they exist
|
# Recursively check 'properties' and 'items' if they exist
|
||||||
|
if "anyOf" in schema:
|
||||||
|
for sub_schema in schema["anyOf"]:
|
||||||
|
_recursive_set_additional_properties_false(sub_schema)
|
||||||
if "properties" in schema:
|
if "properties" in schema:
|
||||||
for value in schema["properties"].values():
|
for sub_schema in schema["properties"].values():
|
||||||
_recursive_set_additional_properties_false(value)
|
_recursive_set_additional_properties_false(sub_schema)
|
||||||
if "items" in schema:
|
if "items" in schema:
|
||||||
_recursive_set_additional_properties_false(schema["items"])
|
_recursive_set_additional_properties_false(schema["items"])
|
||||||
|
|
||||||
|
@ -497,6 +497,61 @@ def test_convert_to_openai_function_nested_strict() -> None:
|
|||||||
assert actual == expected
|
assert actual == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_convert_to_openai_function_strict_union_of_objects_arg_type() -> None:
|
||||||
|
class NestedA(BaseModel):
|
||||||
|
foo: str
|
||||||
|
|
||||||
|
class NestedB(BaseModel):
|
||||||
|
bar: int
|
||||||
|
|
||||||
|
class NestedC(BaseModel):
|
||||||
|
baz: bool
|
||||||
|
|
||||||
|
def my_function(my_arg: Union[NestedA, NestedB, NestedC]) -> None:
|
||||||
|
"""Dummy function."""
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"name": "my_function",
|
||||||
|
"description": "Dummy function.",
|
||||||
|
"parameters": {
|
||||||
|
"properties": {
|
||||||
|
"my_arg": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"properties": {"foo": {"title": "Foo", "type": "string"}},
|
||||||
|
"required": ["foo"],
|
||||||
|
"title": "NestedA",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"properties": {"bar": {"title": "Bar", "type": "integer"}},
|
||||||
|
"required": ["bar"],
|
||||||
|
"title": "NestedB",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"properties": {"baz": {"title": "Baz", "type": "boolean"}},
|
||||||
|
"required": ["baz"],
|
||||||
|
"title": "NestedC",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": False,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["my_arg"],
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": False,
|
||||||
|
},
|
||||||
|
"strict": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
actual = convert_to_openai_function(my_function, strict=True)
|
||||||
|
assert actual == expected
|
||||||
|
|
||||||
|
|
||||||
json_schema_no_description_no_params = {
|
json_schema_no_description_no_params = {
|
||||||
"title": "dummy_function",
|
"title": "dummy_function",
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user