From 9d1a3ab3d4ae56d5a23f0f5f50714366a0befd15 Mon Sep 17 00:00:00 2001 From: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:40:40 +0100 Subject: [PATCH] chore(llm): remove deprecated llm_params module --- nemoguardrails/llm/params.py | 132 -------------- tests/test_llm_params.py | 321 ----------------------------------- 2 files changed, 453 deletions(-) delete mode 100644 nemoguardrails/llm/params.py delete mode 100644 tests/test_llm_params.py diff --git a/nemoguardrails/llm/params.py b/nemoguardrails/llm/params.py deleted file mode 100644 index 3cdf948c0..000000000 --- a/nemoguardrails/llm/params.py +++ /dev/null @@ -1,132 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -Module for providing a context manager to temporarily adjust parameters of a language model. - -Also allows registration of custom parameter managers for different language model types. - -.. deprecated:: 0.17.0 - This module is deprecated and will be removed in version 0.19.0. - Instead of using the context manager approach, pass parameters directly to `llm_call()` - using the `llm_params` argument: - - Old way (deprecated): - from nemoguardrails.llm.params import llm_params - with llm_params(llm, temperature=0.7): - result = await llm_call(llm, prompt) - - New way (recommended): - result = await llm_call(llm, prompt, llm_params={"temperature": 0.7}) - - See: https://github.com/NVIDIA/NeMo-Guardrails/issues/1387 -""" - -import logging -import warnings -from typing import Any, Dict, Type - -from langchain.base_language import BaseLanguageModel - -log = logging.getLogger(__name__) - -_DEPRECATION_MESSAGE = ( - "The nemoguardrails.llm.params module is deprecated and will be removed in version 0.19.0. " - "Instead of using llm_params context manager, pass parameters directly to llm_call() " - "using the llm_params argument. " - "See: https://github.com/NVIDIA/NeMo-Guardrails/issues/1387" -) - - -class LLMParams: - """Context manager to temporarily modify the parameters of a language model. - - .. deprecated:: 0.17.0 - Use llm_call() with llm_params argument instead. - """ - - def __init__(self, llm: BaseLanguageModel, **kwargs): - warnings.warn(_DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=2) - self.llm = llm - self.altered_params = kwargs - self.original_params: dict[str, Any] = {} - - def __enter__(self): - # Here we can access and modify the global language model parameters. - for param, value in self.altered_params.items(): - if hasattr(self.llm, param): - self.original_params[param] = getattr(self.llm, param) - setattr(self.llm, param, value) - - elif hasattr(self.llm, "model_kwargs"): - model_kwargs = getattr(self.llm, "model_kwargs", {}) - if param not in model_kwargs: - log.warning( - "Parameter %s does not exist for %s. Passing to model_kwargs", - param, - self.llm.__class__.__name__, - ) - - self.original_params[param] = None - else: - self.original_params[param] = model_kwargs[param] - - model_kwargs[param] = value - setattr(self.llm, "model_kwargs", model_kwargs) - - else: - log.warning( - "Parameter %s does not exist for %s", - param, - self.llm.__class__.__name__, - ) - - def __exit__(self, exc_type, value, traceback): - # Restore original parameters when exiting the context - for param, value in self.original_params.items(): - if hasattr(self.llm, param): - setattr(self.llm, param, value) - elif hasattr(self.llm, "model_kwargs"): - model_kwargs = getattr(self.llm, "model_kwargs", {}) - if param in model_kwargs: - model_kwargs[param] = value - setattr(self.llm, "model_kwargs", model_kwargs) - - -# The list of registered param managers. This will allow us to override the param manager -# for a new LLM. -_param_managers: Dict[Type[BaseLanguageModel], Type[LLMParams]] = {} - - -def register_param_manager(llm_type: Type[BaseLanguageModel], manager: Type[LLMParams]): - """Register a parameter manager. - - .. deprecated:: 0.17.0 - This function is deprecated and will be removed in version 0.19.0. - """ - warnings.warn(_DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=2) - _param_managers[llm_type] = manager - - -def llm_params(llm: BaseLanguageModel, **kwargs): - """Returns a parameter manager for the given language model. - - .. deprecated:: 0.17.0 - Use llm_call() with llm_params argument instead. - """ - warnings.warn(_DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=2) - _llm_params = _param_managers.get(llm.__class__, LLMParams) - - return _llm_params(llm, **kwargs) diff --git a/tests/test_llm_params.py b/tests/test_llm_params.py deleted file mode 100644 index 87aceaf13..000000000 --- a/tests/test_llm_params.py +++ /dev/null @@ -1,321 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import unittest -import warnings -from typing import Any, Dict -from unittest.mock import AsyncMock, MagicMock - -import pytest -from pydantic import BaseModel - -from nemoguardrails.actions.llm.utils import llm_call -from nemoguardrails.llm.params import LLMParams, llm_params, register_param_manager - - -class FakeLLM(BaseModel): - """Fake LLM wrapper for testing purposes.""" - - model_kwargs: Dict[str, Any] = {} - param3: str = "" - - -class FakeLLM2(BaseModel): - param3: str = "" - - -class TestLLMParams(unittest.TestCase): - def setUp(self): - self.llm = FakeLLM( - param3="value3", model_kwargs={"param1": "value1", "param2": "value2"} - ) - self.llm_params = LLMParams( - self.llm, param1="new_value1", param2="new_value2", param3="new_value3" - ) - - def test_init(self): - self.assertEqual(self.llm_params.llm, self.llm) - self.assertEqual( - self.llm_params.altered_params, - {"param1": "new_value1", "param2": "new_value2", "param3": "new_value3"}, - ) - self.assertEqual(self.llm_params.original_params, {}) - - def test_enter(self): - llm = self.llm - with llm_params( - llm, param1="new_value1", param2="new_value2", param3="new_value3" - ): - self.assertEqual(self.llm.param3, "new_value3") - self.assertEqual(self.llm.model_kwargs["param1"], "new_value1") - - def test_exit(self): - with self.llm_params: - pass - self.assertEqual(self.llm.model_kwargs["param1"], "value1") - self.assertEqual(self.llm.param3, "value3") - - def test_enter_with_nonexistent_param(self): - """Test that entering the context manager with a nonexistent parameter logs a warning.""" - - with self.assertLogs(level="WARNING") as cm: - with llm_params(self.llm, nonexistent_param="value"): - pass - self.assertIn( - "Parameter nonexistent_param does not exist for FakeLLM", cm.output[0] - ) - - def test_exit_with_nonexistent_param(self): - """Test that exiting the context manager with a nonexistent parameter does not raise an error.""" - - llm_params = LLMParams(self.llm, nonexistent_param="value") - llm_params.original_params = {"nonexistent_param": "original_value"} - try: - with llm_params: - pass - except Exception as e: - self.fail(f"Exiting the context manager raised an exception: {e}") - - -class TestLLMParamsWithEmptyModelKwargs(unittest.TestCase): - def setUp(self): - self.llm = FakeLLM(param3="value3", model_kwargs={}) - self.llm_params = LLMParams( - self.llm, param1="new_value1", param2="new_value2", param3="new_value3" - ) - - def test_init(self): - self.assertEqual(self.llm_params.llm, self.llm) - self.assertEqual( - self.llm_params.altered_params, - {"param1": "new_value1", "param2": "new_value2", "param3": "new_value3"}, - ) - self.assertEqual(self.llm_params.original_params, {}) - - def test_enter(self): - llm = self.llm - with llm_params( - llm, param1="new_value1", param2="new_value2", param3="new_value3" - ): - self.assertEqual(self.llm.param3, "new_value3") - self.assertEqual(self.llm.model_kwargs["param1"], "new_value1") - self.assertEqual(self.llm.model_kwargs["param2"], "new_value2") - - def test_exit(self): - with self.llm_params: - pass - self.assertEqual(self.llm.model_kwargs["param1"], None) - self.assertEqual(self.llm.param3, "value3") - - def test_enter_with_empty_model_kwargs(self): - """Test that entering the context manager with empty model_kwargs logs a warning.""" - warning_message = f"Parameter param1 does not exist for {self.llm.__class__.__name__}. Passing to model_kwargs" - - with self.assertLogs(level="WARNING") as cm: - with llm_params(self.llm, param1="new_value1"): - pass - self.assertIn( - warning_message, - cm.output[0], - ) - - def test_exit_with_empty_model_kwargs(self): - """Test that exiting the context manager with empty model_kwargs does not raise an error.""" - - llm_params = LLMParams(self.llm, param1="new_value1") - llm_params.original_params = {"param1": "original_value"} - try: - with llm_params: - pass - except Exception as e: - self.fail(f"Exiting the context manager raised an exception: {e}") - - -class TestLLMParamsWithoutModelKwargs(unittest.TestCase): - def setUp(self): - self.llm = FakeLLM2(param3="value3") - self.llm_params = LLMParams( - self.llm, param1="new_value1", param2="new_value2", param3="new_value3" - ) - - def test_init(self): - self.assertEqual(self.llm_params.llm, self.llm) - self.assertEqual( - self.llm_params.altered_params, - {"param1": "new_value1", "param2": "new_value2", "param3": "new_value3"}, - ) - self.assertEqual(self.llm_params.original_params, {}) - - def test_enter(self): - llm = self.llm - with llm_params( - llm, param1="new_value1", param2="new_value2", param3="new_value3" - ): - self.assertEqual(self.llm.param3, "new_value3") - - def test_exit(self): - with self.llm_params: - pass - self.assertEqual(self.llm.param3, "value3") - - def test_enter_with_empty_model_kwargs(self): - """Test that entering the context manager with empty model_kwargs logs a warning.""" - warning_message = ( - f"Parameter param1 does not exist for {self.llm.__class__.__name__}" - ) - with self.assertLogs(level="WARNING") as cm: - with llm_params(self.llm, param1="new_value1"): - pass - self.assertIn( - warning_message, - cm.output[0], - ) - - def test_exit_with_empty_model_kwargs(self): - """Test that exiting the context manager with empty model_kwargs does not raise an error.""" - - llm_params = LLMParams(self.llm, param1="new_value1") - llm_params.original_params = {"param1": "original_value"} - try: - with llm_params: - pass - except Exception as e: - self.fail(f"Exiting the context manager raised an exception: {e}") - - -class TestRegisterParamManager(unittest.TestCase): - def test_register_param_manager(self): - """Test that a custom parameter manager can be registered and retrieved.""" - - class CustomLLMParams(LLMParams): - pass - - register_param_manager(FakeLLM, CustomLLMParams) - self.assertEqual(llm_params(FakeLLM()).__class__, CustomLLMParams) - - -class TestLLMParamsFunction(unittest.TestCase): - def test_llm_params_with_registered_manager(self): - """Test that llm_params returns the registered manager for a given LLM type.""" - - class CustomLLMParams(LLMParams): - pass - - register_param_manager(FakeLLM, CustomLLMParams) - self.assertIsInstance(llm_params(FakeLLM()), CustomLLMParams) - - def test_llm_params_with_unregistered_manager(self): - """Test that llm_params returns the default manager for an unregistered LLM type.""" - - class UnregisteredLLM(BaseModel): - pass - - self.assertIsInstance(llm_params(UnregisteredLLM()), LLMParams) - - -class TestLLMParamsDeprecation(unittest.TestCase): - """Test deprecation warnings for llm_params module.""" - - def test_llm_params_function_raises_deprecation_warning(self): - """Test that llm_params function raises DeprecationWarning.""" - llm = FakeLLM(param3="value3", model_kwargs={"param1": "value1"}) - - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - with llm_params(llm, param1="new_value1"): - pass - - self.assertGreaterEqual(len(w), 1) - self.assertTrue( - any(issubclass(warning.category, DeprecationWarning) for warning in w) - ) - self.assertTrue( - any( - "0.19.0" in str(warning.message) - and "llm_call()" in str(warning.message) - for warning in w - ) - ) - - def test_llm_params_class_raises_deprecation_warning(self): - """Test that LLMParams class raises DeprecationWarning.""" - llm = FakeLLM(param3="value3", model_kwargs={"param1": "value1"}) - - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - params = LLMParams(llm, param1="new_value1") - - self.assertGreaterEqual(len(w), 1) - self.assertTrue(issubclass(w[0].category, DeprecationWarning)) - self.assertIn("0.19.0", str(w[0].message)) - - def test_register_param_manager_raises_deprecation_warning(self): - """Test that register_param_manager function raises DeprecationWarning.""" - - class CustomLLMParams(LLMParams): - pass - - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - register_param_manager(FakeLLM, CustomLLMParams) - - self.assertGreaterEqual(len(w), 1) - self.assertTrue(issubclass(w[0].category, DeprecationWarning)) - self.assertIn("0.19.0", str(w[0].message)) - - -class TestLLMParamsMigration(unittest.TestCase): - """Test migration from context manager to direct parameter passing.""" - - def test_context_manager_equivalent_to_direct_params(self): - """Test that context manager behavior matches direct parameter passing.""" - llm = FakeLLM(param3="original", model_kwargs={"temperature": 0.5}) - - with llm_params(llm, temperature=0.8, param3="modified"): - context_temp = llm.model_kwargs.get("temperature") - context_param3 = llm.param3 - - assert context_temp == 0.8 - assert context_param3 == "modified" - assert llm.model_kwargs.get("temperature") == 0.5 - assert llm.param3 == "original" - - @pytest.mark.asyncio - async def test_llm_call_params_vs_context_manager(self): - """Test that llm_call with params produces similar results to context manager approach.""" - mock_llm = AsyncMock() - mock_bound_llm = AsyncMock() - mock_response = MagicMock() - mock_response.content = "Response content" - - mock_llm.bind.return_value = mock_bound_llm - mock_bound_llm.ainvoke.return_value = mock_response - - params = {"temperature": 0.7, "max_tokens": 100} - - result = await llm_call(mock_llm, "Test prompt", llm_params=params) - - assert result == "Response content" - mock_llm.bind.assert_called_once_with(**params) - mock_bound_llm.ainvoke.assert_called_once() - - def test_parameter_isolation_after_migration(self): - """Test that parameter changes don't persist after llm_call completes.""" - llm = FakeLLM(param3="original", model_kwargs={"temperature": 0.5}) - original_temp = llm.model_kwargs.get("temperature") - original_param3 = llm.param3 - - assert original_temp == 0.5 - assert original_param3 == "original"