From 6d58ccb0134e90d128c364a3cc4aaaec2d20fd5f Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Tue, 4 Feb 2025 18:01:24 -0800 Subject: [PATCH 1/5] standard-tests: model param test --- .../langchain_tests/unit_tests/chat_models.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/libs/standard-tests/langchain_tests/unit_tests/chat_models.py b/libs/standard-tests/langchain_tests/unit_tests/chat_models.py index e2b58d2f050..caba7f8d283 100644 --- a/libs/standard-tests/langchain_tests/unit_tests/chat_models.py +++ b/libs/standard-tests/langchain_tests/unit_tests/chat_models.py @@ -85,6 +85,10 @@ class ChatModelTests(BaseStandardTests): """Initialization parameters for the chat model.""" return {} + @property + def chat_model_model_param(self) -> dict: + return self.chat_model_params.get("model", "test-model-name") + @property def standard_chat_model_params(self) -> dict: """:private:""" @@ -521,6 +525,29 @@ class ChatModelUnitTests(ChatModelTests): ) assert model is not None + def test_model_param_name(self) -> None: + """Tests model initializatiokn with a model= parameter. This should pass for all + integrations. + + .. dropdown:: Troubleshooting + + If this test fails, ensure that the model can be initialized with a + ``model`` parameter, and that the model parameter can be accessed as + ``.model``. + """ + params = { + **self.standard_chat_model_params, + **self.chat_model_params, + } + if "model_name" in params: + params["model"] = params.pop("model_name") + else: + params["model"] = self.chat_model_model_param + + model = self.chat_model_class(**params) + assert model is not None + assert model.model == params["model"] + def test_init_from_env(self) -> None: """Test initialization from environment variables. Relies on the ``init_from_env_params`` property. Test is skipped if that property is not From 3b441f312a9911f60de8f182875ff86ffd4fd3c0 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Tue, 4 Feb 2025 18:16:10 -0800 Subject: [PATCH 2/5] x --- .../integration_template/chat_models.py | 10 +++++++--- .../tests/unit_tests/custom_chat_model.py | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/libs/cli/langchain_cli/integration_template/integration_template/chat_models.py b/libs/cli/langchain_cli/integration_template/integration_template/chat_models.py index 917feb2df0b..9939fe71f5d 100644 --- a/libs/cli/langchain_cli/integration_template/integration_template/chat_models.py +++ b/libs/cli/langchain_cli/integration_template/integration_template/chat_models.py @@ -13,7 +13,7 @@ from langchain_core.messages import ( ) from langchain_core.messages.ai import UsageMetadata from langchain_core.outputs import ChatGeneration, ChatGenerationChunk, ChatResult -from pydantic import Field +from pydantic import ConfigDict, Field class Chat__ModuleName__(BaseChatModel): @@ -266,7 +266,7 @@ class Chat__ModuleName__(BaseChatModel): """ # noqa: E501 - model_name: str = Field(alias="model") + model: str = Field(alias="model_name") """The name of the model""" parrot_buffer_length: int """The number of characters from the last message of the prompt to be echoed.""" @@ -276,6 +276,10 @@ class Chat__ModuleName__(BaseChatModel): stop: Optional[List[str]] = None max_retries: int = 2 + model_config = ConfigDict( + populate_by_name=True, + ) + @property def _llm_type(self) -> str: """Return type of chat model.""" @@ -293,7 +297,7 @@ class Chat__ModuleName__(BaseChatModel): # rules in LLM monitoring applications (e.g., in LangSmith users # can provide per token pricing for their model and monitor # costs for the given LLM.) - "model_name": self.model_name, + "model": self.model, } def _generate( diff --git a/libs/standard-tests/tests/unit_tests/custom_chat_model.py b/libs/standard-tests/tests/unit_tests/custom_chat_model.py index 1791138cf35..032d69b6406 100644 --- a/libs/standard-tests/tests/unit_tests/custom_chat_model.py +++ b/libs/standard-tests/tests/unit_tests/custom_chat_model.py @@ -11,7 +11,7 @@ from langchain_core.messages import ( ) from langchain_core.messages.ai import UsageMetadata from langchain_core.outputs import ChatGeneration, ChatGenerationChunk, ChatResult -from pydantic import Field +from pydantic import ConfigDict, Field class ChatParrotLink(BaseChatModel): @@ -33,7 +33,7 @@ class ChatParrotLink(BaseChatModel): [HumanMessage(content="world")]]) """ - model_name: str = Field(alias="model") + model: str = Field(alias="model_name") """The name of the model""" parrot_buffer_length: int """The number of characters from the last message of the prompt to be echoed.""" @@ -43,6 +43,10 @@ class ChatParrotLink(BaseChatModel): stop: Optional[List[str]] = None max_retries: int = 2 + model_config = ConfigDict( + populate_by_name=True, + ) + def _generate( self, messages: List[BaseMessage], @@ -163,5 +167,5 @@ class ChatParrotLink(BaseChatModel): # rules in LLM monitoring applications (e.g., in LangSmith users # can provide per token pricing for their model and monitor # costs for the given LLM.) - "model_name": self.model_name, + "model": self.model, } From 07b1ccb23011ac7cf1196c2834a6f4ca9a862a3b Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Tue, 4 Feb 2025 18:21:28 -0800 Subject: [PATCH 3/5] x --- .../openai/langchain_openai/chat_models/base.py | 6 +++++- .../langchain_tests/unit_tests/chat_models.py | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/libs/partners/openai/langchain_openai/chat_models/base.py b/libs/partners/openai/langchain_openai/chat_models/base.py index 5ac28a717ac..6e7b3455c7f 100644 --- a/libs/partners/openai/langchain_openai/chat_models/base.py +++ b/libs/partners/openai/langchain_openai/chat_models/base.py @@ -440,7 +440,7 @@ class BaseChatOpenAI(BaseChatModel): async_client: Any = Field(default=None, exclude=True) #: :meta private: root_client: Any = Field(default=None, exclude=True) #: :meta private: root_async_client: Any = Field(default=None, exclude=True) #: :meta private: - model_name: str = Field(default="gpt-3.5-turbo", alias="model") + model: str = Field(default="gpt-3.5-turbo", alias="model_name") """Model name to use.""" temperature: Optional[float] = None """What sampling temperature to use.""" @@ -545,6 +545,10 @@ class BaseChatOpenAI(BaseChatModel): model_config = ConfigDict(populate_by_name=True) + @property + def model_name(self) -> str: + return self.model + @model_validator(mode="before") @classmethod def build_extra(cls, values: Dict[str, Any]) -> Any: diff --git a/libs/standard-tests/langchain_tests/unit_tests/chat_models.py b/libs/standard-tests/langchain_tests/unit_tests/chat_models.py index caba7f8d283..08a2e1c3b55 100644 --- a/libs/standard-tests/langchain_tests/unit_tests/chat_models.py +++ b/libs/standard-tests/langchain_tests/unit_tests/chat_models.py @@ -534,6 +534,22 @@ class ChatModelUnitTests(ChatModelTests): If this test fails, ensure that the model can be initialized with a ``model`` parameter, and that the model parameter can be accessed as ``.model``. + + If not, the easiest way to configure this is likely to add + ``from pydantic import ConfigDict`` at the top of your file, and add a + ``model_config`` class attribute to your model class: + + .. code-block:: python + + class MyChatModel(BaseChatModel): + model: str = Field(alias="model_name") + model_config = ConfigDict(populate_by_name=True) + + # optional property for backwards-compatibility + # for folks accessing chat_model.model_name + @property + def model_name(self) -> str: + return self.model """ params = { **self.standard_chat_model_params, From d28db771d4f343cf0fa58af34a87db1d2993ebb4 Mon Sep 17 00:00:00 2001 From: Mason Daugherty Date: Wed, 16 Jul 2025 10:42:03 -0400 Subject: [PATCH 4/5] fix typo --- libs/standard-tests/langchain_tests/unit_tests/chat_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/standard-tests/langchain_tests/unit_tests/chat_models.py b/libs/standard-tests/langchain_tests/unit_tests/chat_models.py index c46973f7844..6466c8974fe 100644 --- a/libs/standard-tests/langchain_tests/unit_tests/chat_models.py +++ b/libs/standard-tests/langchain_tests/unit_tests/chat_models.py @@ -837,7 +837,7 @@ class ChatModelUnitTests(ChatModelTests): assert model is not None def test_model_param_name(self) -> None: - """Tests model initializatiokn with a model= parameter. This should pass for all + """Tests model initialization with a ``model=`` parameter. This should pass for all integrations. .. dropdown:: Troubleshooting From 8b40258e72fdb2fb6dd22d6e080e18c34f7b576c Mon Sep 17 00:00:00 2001 From: Mason Daugherty Date: Wed, 16 Jul 2025 11:03:32 -0400 Subject: [PATCH 5/5] fix: update `response_metadata` to use correct `model` attribute --- .../langchain_tests/unit_tests/chat_models.py | 8 ++++---- libs/standard-tests/tests/unit_tests/custom_chat_model.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/standard-tests/langchain_tests/unit_tests/chat_models.py b/libs/standard-tests/langchain_tests/unit_tests/chat_models.py index 6466c8974fe..b6c7e27e0f4 100644 --- a/libs/standard-tests/langchain_tests/unit_tests/chat_models.py +++ b/libs/standard-tests/langchain_tests/unit_tests/chat_models.py @@ -837,8 +837,8 @@ class ChatModelUnitTests(ChatModelTests): assert model is not None def test_model_param_name(self) -> None: - """Tests model initialization with a ``model=`` parameter. This should pass for all - integrations. + """Tests model initialization with a ``model=`` parameter. This should pass for + all integrations. .. dropdown:: Troubleshooting @@ -851,7 +851,7 @@ class ChatModelUnitTests(ChatModelTests): ``model_config`` class attribute to your model class: .. code-block:: python - + class MyChatModel(BaseChatModel): model: str = Field(alias="model_name") model_config = ConfigDict(populate_by_name=True) @@ -873,7 +873,7 @@ class ChatModelUnitTests(ChatModelTests): model = self.chat_model_class(**params) assert model is not None - assert model.model == params["model"] + assert model.model == params["model"] # type: ignore[attr-defined] def test_init_from_env(self) -> None: """Test initialization from environment variables. Relies on the diff --git a/libs/standard-tests/tests/unit_tests/custom_chat_model.py b/libs/standard-tests/tests/unit_tests/custom_chat_model.py index fb1a6f0d597..3a9475a60ef 100644 --- a/libs/standard-tests/tests/unit_tests/custom_chat_model.py +++ b/libs/standard-tests/tests/unit_tests/custom_chat_model.py @@ -81,7 +81,7 @@ class ChatParrotLink(BaseChatModel): additional_kwargs={}, # Used to add additional payload to the message response_metadata={ # Use for response metadata "time_in_seconds": 3, - "model_name": self.model_name, + "model_name": self.model, }, usage_metadata={ "input_tokens": ct_input_tokens, @@ -146,7 +146,7 @@ class ChatParrotLink(BaseChatModel): chunk = ChatGenerationChunk( message=AIMessageChunk( content="", - response_metadata={"time_in_sec": 3, "model_name": self.model_name}, + response_metadata={"time_in_sec": 3, "model_name": self.model}, ) ) if run_manager: