Skip to content

Commit

Permalink
Merge branch 'master' into html-simple-split
Browse files Browse the repository at this point in the history
  • Loading branch information
AhmedTammaa authored Jan 23, 2025
2 parents 03ffcef + 317fb86 commit 264fc8f
Show file tree
Hide file tree
Showing 7 changed files with 617 additions and 350 deletions.
2 changes: 1 addition & 1 deletion libs/partners/openai/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ test tests:
TIKTOKEN_CACHE_DIR=tiktoken_cache poetry run pytest --disable-socket --allow-unix-socket $(TEST_FILE)

integration_test integration_tests:
poetry run pytest $(TEST_FILE)
poetry run pytest -n auto $(TEST_FILE)

test_watch:
poetry run ptw --snapshot-update --now . -- -vv $(TEST_FILE)
Expand Down
40 changes: 27 additions & 13 deletions libs/partners/openai/langchain_openai/chat_models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1354,19 +1354,33 @@ def with_structured_output(
)
is_pydantic_schema = _is_pydantic_class(schema)

# Check for Pydantic BaseModel V1
if (
method == "json_schema"
and is_pydantic_schema
and issubclass(schema, BaseModelV1) # type: ignore[arg-type]
):
warnings.warn(
"Received a Pydantic BaseModel V1 schema. This is not supported by "
'method="json_schema". Please use method="function_calling" '
"or specify schema via JSON Schema or Pydantic V2 BaseModel. "
'Overriding to method="function_calling".'
)
method = "function_calling"
if method == "json_schema":
# Check for Pydantic BaseModel V1
if (
is_pydantic_schema and issubclass(schema, BaseModelV1) # type: ignore[arg-type]
):
warnings.warn(
"Received a Pydantic BaseModel V1 schema. This is not supported by "
'method="json_schema". Please use method="function_calling" '
"or specify schema via JSON Schema or Pydantic V2 BaseModel. "
'Overriding to method="function_calling".'
)
method = "function_calling"
# Check for incompatible model
if self.model_name and (
self.model_name.startswith("gpt-3")
or self.model_name.startswith("gpt-4-")
or self.model_name == "gpt-4"
):
warnings.warn(
f"Cannot use method='json_schema' with model {self.model_name} "
f"since it doesn't support OpenAI's Structured Output API. You can "
f"see supported models here: "
f"https://platform.openai.com/docs/guides/structured-outputs#supported-models. " # noqa: E501
"To fix this warning, set `method='function_calling'. "
"Overriding to method='function_calling'."
)
method = "function_calling"

if method == "function_calling":
if schema is None:
Expand Down
863 changes: 549 additions & 314 deletions libs/partners/openai/poetry.lock

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions libs/partners/openai/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "langchain-openai"
version = "0.3.1"
version = "0.3.2"
description = "An integration package connecting OpenAI and LangChain"
authors = []
readme = "README.md"
Expand All @@ -23,7 +23,7 @@ ignore_missing_imports = true

[tool.poetry.dependencies]
python = ">=3.9,<4.0"
langchain-core = "^0.3.30"
langchain-core = "^0.3.31"
openai = "^1.58.1"
tiktoken = ">=0.7,<1"

Expand Down Expand Up @@ -67,6 +67,7 @@ pytest-watcher = "^0.3.4"
pytest-asyncio = "^0.21.1"
pytest-cov = "^4.1.0"
pytest-socket = "^0.6.0"
pytest-xdist = "^3.6.1"
[[tool.poetry.group.test.dependencies.numpy]]
version = "^1"
python = "<3.12"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ def test_disable_parallel_tool_calling() -> None:
assert len(result.tool_calls) == 1


@pytest.mark.parametrize("model", ["gpt-4o-mini", "o1"])
@pytest.mark.parametrize("model", ["gpt-4o-mini", "o1", "gpt-4"])
def test_openai_structured_output(model: str) -> None:
class MyModel(BaseModel):
"""A Person"""
Expand All @@ -657,24 +657,6 @@ class MyModel(BaseModel):
assert result.age == 27


def test_structured_output_errors_with_legacy_models() -> None:
class MyModel(BaseModel):
"""A Person"""

name: str
age: int

llm = ChatOpenAI(model="gpt-4").with_structured_output(MyModel)

with pytest.warns(UserWarning, match="with_structured_output"):
with pytest.raises(openai.BadRequestError):
_ = llm.invoke("I'm a 27 year old named Erick")

with pytest.warns(UserWarning, match="with_structured_output"):
with pytest.raises(openai.BadRequestError):
_ = list(llm.stream("I'm a 27 year old named Erick"))


def test_openai_proxy() -> None:
"""Test ChatOpenAI with proxy."""
chat_openai = ChatOpenAI(openai_proxy="http://localhost:8080")
Expand Down
22 changes: 22 additions & 0 deletions libs/partners/openai/tests/unit_tests/chat_models/test_azure.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import os
from unittest import mock

import pytest
from typing_extensions import TypedDict

from langchain_openai import AzureChatOpenAI


Expand Down Expand Up @@ -59,3 +62,22 @@ def test_initialize_azure_openai_with_openai_api_base_set() -> None:
ls_params = llm._get_ls_params()
assert ls_params["ls_provider"] == "azure"
assert ls_params["ls_model_name"] == "35-turbo-dev"


def test_structured_output_old_model() -> None:
class Output(TypedDict):
"""output."""

foo: str

with pytest.warns(match="Cannot use method='json_schema'"):
llm = AzureChatOpenAI( # type: ignore[call-arg]
model="gpt-35-turbo",
azure_deployment="35-turbo-dev",
openai_api_version="2023-05-15",
azure_endpoint="my-base-url",
).with_structured_output(Output)

# assert tool calling was used instead of json_schema
assert "tools" in llm.steps[0].kwargs # type: ignore
assert "response_format" not in llm.steps[0].kwargs # type: ignore
15 changes: 14 additions & 1 deletion libs/partners/openai/tests/unit_tests/chat_models/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ class Foo(BaseModel):
def test_schema_from_with_structured_output(schema: Type) -> None:
"""Test schema from with_structured_output."""

llm = ChatOpenAI()
llm = ChatOpenAI(model="gpt-4o")

structured_llm = llm.with_structured_output(
schema, method="json_schema", strict=True
Expand Down Expand Up @@ -886,3 +886,16 @@ def test_init_o1() -> None:
with pytest.warns(None) as record: # type: ignore[call-overload]
ChatOpenAI(model="o1", reasoning_effort="medium")
assert len(record) == 0


def test_structured_output_old_model() -> None:
class Output(TypedDict):
"""output."""

foo: str

with pytest.warns(match="Cannot use method='json_schema'"):
llm = ChatOpenAI(model="gpt-4").with_structured_output(Output)
# assert tool calling was used instead of json_schema
assert "tools" in llm.steps[0].kwargs # type: ignore
assert "response_format" not in llm.steps[0].kwargs # type: ignore

0 comments on commit 264fc8f

Please sign in to comment.