Skip to content

Commit 46c02bd

Browse files
authored
feat: implement validation to forbid dialog rails with reasoning traces (#1137)
* feat(validation): enforce reasoning traces strip with dialog rails Added a root validator in `RailsConfig` to ensure that reasoning traces cannot be enabled when dialog rails are present, either explicitly or implicitly. This includes checks for user messages, bot messages, and flows. Also added comprehensive test cases to validate this behavior: - Explicit dialog rails - Implicit dialog rails via user/bot messages or flows - Scenarios without dialog rails to ensure reasoning traces work as expected. * fix: improve reasoning traces validation for dialog rails - Fix validation to properly handle both dictionary and Model object cases - Add proper handling of cases where some dialog rail tasks have dedicated models and others fall back to main model - Improve error messages to be more user-friendly: * Specify which model has the issue (main model or specific task model) * Reference config.yml in error messages * Provide clear YAML configuration instructions * Include specific task name when relevant - Update test cases to match new error messages and validation logic - Add proper handling of implicit dialog rails activation through user/bot messages and flows This change ensures that reasoning traces are properly disabled when dialog rails are present, regardless of whether they are explicitly configured or implicitly activated through user/bot messages or flows. The improved error messages make it easier for users to understand and fix configuration issues in their YAML files. * tests to show the expected behavior of dialog rails and dialog tasks * remove generate bot message task from dialog rails tasks * fix: for OpenAI it is already removed
1 parent 17f68cc commit 46c02bd

File tree

3 files changed

+795
-1
lines changed

3 files changed

+795
-1
lines changed

nemoguardrails/rails/llm/config.py

+68-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from nemoguardrails.colang import parse_colang_file, parse_flow_elements
3636
from nemoguardrails.colang.v2_x.lang.utils import format_colang_parsing_error_message
3737
from nemoguardrails.colang.v2_x.runtime.errors import ColangParsingError
38+
from nemoguardrails.llm.types import Task
3839

3940
log = logging.getLogger(__name__)
4041

@@ -71,7 +72,7 @@ class ReasoningModelConfig(BaseModel):
7172

7273
remove_thinking_traces: Optional[bool] = Field(
7374
default=True,
74-
description="For reasoning models (e.g. OpenAI o1, DeepSeek-r1), if the output parser should remove thinking traces.",
75+
description="For reasoning models (e.g. DeepSeek-r1), if the output parser should remove thinking traces.",
7576
)
7677
start_token: Optional[str] = Field(
7778
default="<think>",
@@ -1181,6 +1182,72 @@ class RailsConfig(BaseModel):
11811182
description="Configuration for tracing.",
11821183
)
11831184

1185+
@root_validator(pre=True, allow_reuse=True)
1186+
def check_reasoning_traces_with_dialog_rails(cls, values):
1187+
"""Check that reasoning traces are not enabled when dialog rails are present."""
1188+
1189+
models = values.get("models", [])
1190+
rails = values.get("rails", {})
1191+
dialog_rails = rails.get("dialog", {})
1192+
1193+
# dialog rail tasks that should not have reasoning traces
1194+
dialog_rail_tasks = [
1195+
# Task.GENERATE_BOT_MESSAGE,
1196+
Task.GENERATE_USER_INTENT,
1197+
Task.GENERATE_NEXT_STEPS,
1198+
Task.GENERATE_INTENT_STEPS_MESSAGE,
1199+
]
1200+
1201+
# dialog rails are activated (explicitly or implicitly)
1202+
has_dialog_rails = (
1203+
bool(dialog_rails)
1204+
or bool(values.get("user_messages"))
1205+
or bool(values.get("bot_messages"))
1206+
or bool(values.get("flows"))
1207+
)
1208+
1209+
if has_dialog_rails:
1210+
main_model = next(
1211+
(model for model in models if model.get("type") == "main"), None
1212+
)
1213+
1214+
violations = []
1215+
1216+
for task in dialog_rail_tasks:
1217+
task_model = next(
1218+
(model for model in models if model.get("type") == task.value), None
1219+
)
1220+
1221+
if task_model:
1222+
reasoning_config = (
1223+
task_model.reasoning_config
1224+
if hasattr(task_model, "reasoning_config")
1225+
else task_model.get("reasoning_config", {})
1226+
)
1227+
if not reasoning_config.get("remove_thinking_traces", True):
1228+
violations.append(
1229+
f"Model '{task_model.get('type')}' has reasoning traces enabled in config.yml. "
1230+
f"Reasoning traces must be disabled for dialog rail tasks. "
1231+
f"Please update your config.yml to set 'remove_thinking_traces: true' under reasoning_config for this model."
1232+
)
1233+
elif main_model:
1234+
reasoning_config = (
1235+
main_model.reasoning_config
1236+
if hasattr(main_model, "reasoning_config")
1237+
else main_model.get("reasoning_config", {})
1238+
)
1239+
if not reasoning_config.get("remove_thinking_traces", True):
1240+
violations.append(
1241+
f"Main model has reasoning traces enabled in config.yml and is being used for dialog rail task '{task.value}'. "
1242+
f"Reasoning traces must be disabled when dialog rails are present. "
1243+
f"Please update your config.yml to set 'remove_thinking_traces: true' under reasoning_config for the main model."
1244+
)
1245+
1246+
if violations:
1247+
raise ValueError("\n".join(violations))
1248+
1249+
return values
1250+
11841251
@root_validator(pre=True, allow_reuse=True)
11851252
def check_prompt_exist_for_self_check_rails(cls, values):
11861253
rails = values.get("rails", {})

0 commit comments

Comments
 (0)