Skip to content

Commit f92f1e1

Browse files
authored
fix(genai): update json_mode to json_schema for structured output methods (#1188)
1 parent c4d3c27 commit f92f1e1

File tree

3 files changed

+33
-10
lines changed

3 files changed

+33
-10
lines changed

libs/genai/langchain_google_genai/chat_models.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,8 +1219,8 @@ class Joke(BaseModel):
12191219
# Default method uses function calling
12201220
structured_llm = llm.with_structured_output(Joke)
12211221
1222-
# For more reliable output, use json_mode with native responseSchema
1223-
structured_llm_json = llm.with_structured_output(Joke, method="json_mode")
1222+
# For more reliable output, use json_schema with native responseSchema
1223+
structured_llm_json = llm.with_structured_output(Joke, method="json_schema")
12241224
structured_llm_json.invoke("Tell me a joke about cats")
12251225
12261226
.. code-block:: python
@@ -1235,12 +1235,13 @@ class Joke(BaseModel):
12351235
12361236
* ``method="function_calling"`` (default): Uses tool calling to extract
12371237
structured data. Compatible with all models.
1238-
* ``method="json_mode"``: Uses Gemini's native structured output with
1238+
* ``method="json_schema"``: Uses Gemini's native structured output with
12391239
responseSchema. More reliable but requires Gemini 1.5+ models.
1240+
``method="json_mode"`` also works for backwards compatibility but is a misnomer.
12401241
1241-
The ``json_mode`` method is recommended for better reliability as it constrains
1242-
the model's generation process directly rather than relying on post-processing
1243-
tool calls.
1242+
The ``json_schema`` method is recommended for better reliability as it
1243+
constrains the model's generation process directly rather than relying on
1244+
post-processing tool calls.
12441245
12451246
Image input:
12461247
.. code-block:: python
@@ -2103,7 +2104,9 @@ def get_num_tokens(self, text: str) -> int:
21032104
def with_structured_output(
21042105
self,
21052106
schema: Union[Dict, Type[BaseModel]],
2106-
method: Optional[Literal["function_calling", "json_mode"]] = "function_calling",
2107+
method: Optional[
2108+
Literal["function_calling", "json_mode", "json_schema"]
2109+
] = "function_calling",
21072110
*,
21082111
include_raw: bool = False,
21092112
**kwargs: Any,
@@ -2115,7 +2118,7 @@ def with_structured_output(
21152118

21162119
parser: OutputParserLike
21172120

2118-
if method == "json_mode":
2121+
if method in ("json_mode", "json_schema"): # `json_schema` preferred
21192122
if isinstance(schema, type) and is_basemodel_subclass(schema):
21202123
if issubclass(schema, BaseModelV1):
21212124
schema_json = schema.schema()

libs/genai/tests/integration_tests/test_chat_models.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -724,11 +724,12 @@ def my_tool(name: str, age: int, likes: list[str]) -> None:
724724
(_MODEL, None),
725725
(_MODEL, "function_calling"),
726726
(_MODEL, "json_mode"),
727+
(_MODEL, "json_schema"),
727728
],
728729
)
729730
def test_chat_google_genai_with_structured_output(
730731
model_name: str,
731-
method: Optional[Literal["function_calling", "json_mode"]],
732+
method: Optional[Literal["function_calling", "json_mode", "json_schema"]],
732733
) -> None:
733734
class MyModel(BaseModel):
734735
name: str
@@ -756,7 +757,8 @@ class MyModel(BaseModel):
756757
expected = {"name": "Erick", "age": 27}
757758
assert response == expected
758759

759-
if method is None: # This won't work with json_schema as it expects an OpenAPI dict
760+
# This won't work with json_schema/json_mode as it expects an OpenAPI dict
761+
if method is None:
760762
model = llm.with_structured_output(
761763
{
762764
"name": "MyModel",

libs/genai/tests/unit_tests/test_chat_models.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,3 +1114,21 @@ async def test_max_retries_parameter_handling(
11141114
assert call_kwargs_actual["max_retries"] == expected_max_retries
11151115
else:
11161116
assert "max_retries" not in call_kwargs_actual
1117+
1118+
1119+
def test_with_structured_output_json_schema_alias() -> None:
1120+
"""Test that json_schema method works as alias for json_mode."""
1121+
from pydantic import BaseModel
1122+
1123+
class TestModel(BaseModel):
1124+
name: str
1125+
age: int
1126+
1127+
llm = ChatGoogleGenerativeAI(model="gemini-pro", google_api_key="fake-key")
1128+
1129+
structured_llm = llm.with_structured_output(TestModel, method="json_schema")
1130+
assert structured_llm is not None
1131+
1132+
schema_dict = {"type": "object", "properties": {"name": {"type": "string"}}}
1133+
structured_llm_dict = llm.with_structured_output(schema_dict, method="json_schema")
1134+
assert structured_llm_dict is not None

0 commit comments

Comments
 (0)