tests[patch]: update API ref for chat models (#28594)

This commit is contained in:
ccurme 2024-12-06 19:00:14 -05:00 committed by GitHub
parent 0eb7ab65f1
commit 80a88f8f04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 52 additions and 35 deletions

View File

@ -230,7 +230,9 @@
"\n", "\n",
"Tests for \"optional\" capabilities are controlled via a set of properties that can be overridden on the test model subclass.\n", "Tests for \"optional\" capabilities are controlled via a set of properties that can be overridden on the test model subclass.\n",
"\n", "\n",
"You can see the entire list of properties in the API reference [here](https://python.langchain.com/api_reference/standard_tests/unit_tests/langchain_tests.unit_tests.chat_models.ChatModelTests.html). These properties are shared by both unit and integration tests.\n", "You can see the entire list of properties in the API references for\n",
"[unit tests](https://python.langchain.com/api_reference/standard_tests/unit_tests/langchain_tests.unit_tests.chat_models.ChatModelUnitTests.html)\n",
"and [integration tests](https://python.langchain.com/api_reference/standard_tests/integration_tests/langchain_tests.integration_tests.chat_models.ChatModelIntegrationTests.html).\n",
"\n", "\n",
"For example, to enable integration tests for image inputs, we can implement\n", "For example, to enable integration tests for image inputs, we can implement\n",
"\n", "\n",

View File

@ -145,6 +145,14 @@ class ChatModelIntegrationTests(ChatModelTests):
By default, this is determined by whether the chat model's `bind_tools` method By default, this is determined by whether the chat model's `bind_tools` method
is overridden. It typically does not need to be overridden on the test class. is overridden. It typically does not need to be overridden on the test class.
Example override:
.. code-block:: python
@property
def has_tool_calling(self) -> bool:
return True
.. dropdown:: tool_choice_value .. dropdown:: tool_choice_value
Value to use for tool choice when used in tests. Value to use for tool choice when used in tests.
@ -308,7 +316,7 @@ class ChatModelIntegrationTests(ChatModelTests):
@property @property
def standard_chat_model_params(self) -> dict: def standard_chat_model_params(self) -> dict:
""":meta private:""" """:private:"""
return {} return {}
def test_invoke(self, model: BaseChatModel) -> None: def test_invoke(self, model: BaseChatModel) -> None:
@ -1323,8 +1331,8 @@ class ChatModelIntegrationTests(ChatModelTests):
.. code-block:: python .. code-block:: python
@pytest.mark.xfail(reason=("Not implemented.")) @pytest.mark.xfail(reason=("Not implemented."))
def test_tool_message_histories_string_content(self, model: BaseChatModel) -> None: def test_tool_message_histories_string_content(self, *args: Any) -> None:
super().test_tool_message_histories_string_content(model) super().test_tool_message_histories_string_content(*args)
""" # noqa: E501 """ # noqa: E501
if not self.has_tool_calling: if not self.has_tool_calling:
pytest.skip("Test requires tool calling.") pytest.skip("Test requires tool calling.")
@ -1407,8 +1415,8 @@ class ChatModelIntegrationTests(ChatModelTests):
.. code-block:: python .. code-block:: python
@pytest.mark.xfail(reason=("Not implemented.")) @pytest.mark.xfail(reason=("Not implemented."))
def test_tool_message_histories_list_content(self, model: BaseChatModel) -> None: def test_tool_message_histories_list_content(self, *args: Any) -> None:
super().test_tool_message_histories_list_content(model) super().test_tool_message_histories_list_content(*args)
""" # noqa: E501 """ # noqa: E501
if not self.has_tool_calling: if not self.has_tool_calling:
pytest.skip("Test requires tool calling.") pytest.skip("Test requires tool calling.")
@ -1489,8 +1497,8 @@ class ChatModelIntegrationTests(ChatModelTests):
.. code-block:: python .. code-block:: python
@pytest.mark.xfail(reason=("Not implemented.")) @pytest.mark.xfail(reason=("Not implemented."))
def test_structured_few_shot_examples(self, model: BaseChatModel) -> None: def test_structured_few_shot_examples(self, *args: Any) -> None:
super().test_structured_few_shot_examples(model) super().test_structured_few_shot_examples(*args)
""" # noqa: E501 """ # noqa: E501
if not self.has_tool_calling: if not self.has_tool_calling:
pytest.skip("Test requires tool calling.") pytest.skip("Test requires tool calling.")
@ -1852,16 +1860,21 @@ class ChatModelIntegrationTests(ChatModelTests):
assert len(result.content) > 0 assert len(result.content) > 0
def invoke_with_audio_input(self, *, stream: bool = False) -> AIMessage: def invoke_with_audio_input(self, *, stream: bool = False) -> AIMessage:
""":private:"""
raise NotImplementedError() raise NotImplementedError()
def invoke_with_audio_output(self, *, stream: bool = False) -> AIMessage: def invoke_with_audio_output(self, *, stream: bool = False) -> AIMessage:
""":private:"""
raise NotImplementedError() raise NotImplementedError()
def invoke_with_reasoning_output(self, *, stream: bool = False) -> AIMessage: def invoke_with_reasoning_output(self, *, stream: bool = False) -> AIMessage:
""":private:"""
raise NotImplementedError() raise NotImplementedError()
def invoke_with_cache_read_input(self, *, stream: bool = False) -> AIMessage: def invoke_with_cache_read_input(self, *, stream: bool = False) -> AIMessage:
""":private:"""
raise NotImplementedError() raise NotImplementedError()
def invoke_with_cache_creation_input(self, *, stream: bool = False) -> AIMessage: def invoke_with_cache_creation_input(self, *, stream: bool = False) -> AIMessage:
""":private:"""
raise NotImplementedError() raise NotImplementedError()

View File

@ -77,17 +77,17 @@ class ChatModelTests(BaseStandardTests):
@property @property
@abstractmethod @abstractmethod
def chat_model_class(self) -> Type[BaseChatModel]: def chat_model_class(self) -> Type[BaseChatModel]:
"""The chat model class to test, e.g., `ChatParrotLink`.""" """The chat model class to test, e.g., ``ChatParrotLink``."""
... ...
@property @property
def chat_model_params(self) -> dict: def chat_model_params(self) -> dict:
"""Initialization parameters for the chat mobdel.""" """Initialization parameters for the chat model."""
return {} return {}
@property @property
def standard_chat_model_params(self) -> dict: def standard_chat_model_params(self) -> dict:
""":meta private:""" """:private:"""
return { return {
"temperature": 0, "temperature": 0,
"max_tokens": 100, "max_tokens": 100,
@ -98,8 +98,7 @@ class ChatModelTests(BaseStandardTests):
@pytest.fixture @pytest.fixture
def model(self) -> BaseChatModel: def model(self) -> BaseChatModel:
"""Fixture that returns an instance of the chat model. Should not be """:private:"""
overridden."""
return self.chat_model_class( return self.chat_model_class(
**{**self.standard_chat_model_params, **self.chat_model_params} **{**self.standard_chat_model_params, **self.chat_model_params}
) )
@ -115,18 +114,17 @@ class ChatModelTests(BaseStandardTests):
@property @property
def has_tool_calling(self) -> bool: def has_tool_calling(self) -> bool:
"""Boolean property indicating whether the model supports tool calling.""" """(bool) whether the model supports tool calling."""
return self.chat_model_class.bind_tools is not BaseChatModel.bind_tools return self.chat_model_class.bind_tools is not BaseChatModel.bind_tools
@property @property
def tool_choice_value(self) -> Optional[str]: def tool_choice_value(self) -> Optional[str]:
"""Value to use for tool choice when used in tests.""" """(None or str) to use for tool choice when used in tests."""
return None return None
@property @property
def has_structured_output(self) -> bool: def has_structured_output(self) -> bool:
"""Boolean property indicating whether the chat model supports structured """(bool) whether the chat model supports structured output."""
output."""
return ( return (
self.chat_model_class.with_structured_output self.chat_model_class.with_structured_output
is not BaseChatModel.with_structured_output is not BaseChatModel.with_structured_output
@ -134,32 +132,31 @@ class ChatModelTests(BaseStandardTests):
@property @property
def supports_image_inputs(self) -> bool: def supports_image_inputs(self) -> bool:
"""Boolean property indicating whether the chat model supports image inputs. """(bool) whether the chat model supports image inputs, defaults to
Defaults to ``False``.""" ``False``."""
return False return False
@property @property
def supports_video_inputs(self) -> bool: def supports_video_inputs(self) -> bool:
"""Boolean property indicating whether the chat model supports image inputs. """(bool) whether the chat model supports video inputs, efaults to ``False``.
Defaults to ``False``. No current tests are written for this feature.""" No current tests are written for this feature."""
return False return False
@property @property
def returns_usage_metadata(self) -> bool: def returns_usage_metadata(self) -> bool:
"""Boolean property indicating whether the chat model returns usage metadata """(bool) whether the chat model returns usage metadata on invoke and streaming
on invoke and streaming responses.""" responses."""
return True return True
@property @property
def supports_anthropic_inputs(self) -> bool: def supports_anthropic_inputs(self) -> bool:
"""Boolean property indicating whether the chat model supports Anthropic-style """(bool) whether the chat model supports Anthropic-style inputs."""
inputs."""
return False return False
@property @property
def supports_image_tool_message(self) -> bool: def supports_image_tool_message(self) -> bool:
"""Boolean property indicating whether the chat model supports ToolMessages """(bool) whether the chat model supports ToolMessages that include image
that include image content.""" content."""
return False return False
@property @property
@ -177,9 +174,8 @@ class ChatModelTests(BaseStandardTests):
] ]
], ],
]: ]:
"""Property controlling what usage metadata details are emitted in both invoke """(dict) what usage metadata details are emitted in invoke and stream. Only
and stream. Only needs to be overridden if these details are returned by the needs to be overridden if these details are returned by the model."""
model."""
return {"invoke": [], "stream": []} return {"invoke": [], "stream": []}
@ -250,6 +246,14 @@ class ChatModelUnitTests(ChatModelTests):
By default, this is determined by whether the chat model's `bind_tools` method By default, this is determined by whether the chat model's `bind_tools` method
is overridden. It typically does not need to be overridden on the test class. is overridden. It typically does not need to be overridden on the test class.
Example override:
.. code-block:: python
@property
def has_tool_calling(self) -> bool:
return True
.. dropdown:: tool_choice_value .. dropdown:: tool_choice_value
Value to use for tool choice when used in tests. Value to use for tool choice when used in tests.
@ -445,17 +449,15 @@ class ChatModelUnitTests(ChatModelTests):
@property @property
def standard_chat_model_params(self) -> dict: def standard_chat_model_params(self) -> dict:
""":meta private:""" """:private:"""
params = super().standard_chat_model_params params = super().standard_chat_model_params
params["api_key"] = "test" params["api_key"] = "test"
return params return params
@property @property
def init_from_env_params(self) -> Tuple[dict, dict, dict]: def init_from_env_params(self) -> Tuple[dict, dict, dict]:
"""This property is used in unit tests to test initialization from environment """(tuple) environment variables, additional initialization args, and expected
variables. It should return a tuple of three dictionaries that specify the instance attributes for testing initialization from environment variables."""
environment variables, additional initialization args, and expected instance
attributes to check."""
return {}, {}, {} return {}, {}, {}
def test_init(self) -> None: def test_init(self) -> None: