From 927ec20b6990eba2729e44ea625152f99d8676db Mon Sep 17 00:00:00 2001 From: ccurme Date: Mon, 24 Feb 2025 08:59:46 -0500 Subject: [PATCH] openai[patch]: update system role to developer for o-series models (#29785) Some o-series models will raise a 400 error for `"role": "system"` (`o1-mini` and `o1-preview` will raise, `o1` and `o3-mini` will not). Here we update `ChatOpenAI` to update the role to `"developer"` for all model names matching `^o\d`. We only make this change on the ChatOpenAI class (not BaseChatOpenAI). --- .../openai/langchain_openai/chat_models/base.py | 7 +++++++ .../tests/unit_tests/chat_models/test_base.py | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/libs/partners/openai/langchain_openai/chat_models/base.py b/libs/partners/openai/langchain_openai/chat_models/base.py index 2d580d08ccd..a264fdedba6 100644 --- a/libs/partners/openai/langchain_openai/chat_models/base.py +++ b/libs/partners/openai/langchain_openai/chat_models/base.py @@ -6,6 +6,7 @@ import base64 import json import logging import os +import re import sys import warnings from io import BytesIO @@ -2011,6 +2012,12 @@ class ChatOpenAI(BaseChatOpenAI): # type: ignore[override] # in September 2024 release if "max_tokens" in payload: payload["max_completion_tokens"] = payload.pop("max_tokens") + + # Mutate system message role to "developer" for o-series models + if self.model_name and re.match(r"^o\d", self.model_name): + for message in payload.get("messages", []): + if message["role"] == "system": + message["role"] = "developer" return payload def _should_stream_usage( diff --git a/libs/partners/openai/tests/unit_tests/chat_models/test_base.py b/libs/partners/openai/tests/unit_tests/chat_models/test_base.py index a7b3e5f102e..5f129ef8d37 100644 --- a/libs/partners/openai/tests/unit_tests/chat_models/test_base.py +++ b/libs/partners/openai/tests/unit_tests/chat_models/test_base.py @@ -881,6 +881,20 @@ def test__get_request_payload() -> None: payload = llm._get_request_payload(messages) assert payload == expected + # Test we coerce to developer role for o-series models + llm = ChatOpenAI(model="o3-mini") + payload = llm._get_request_payload(messages) + expected = { + "messages": [ + {"role": "developer", "content": "hello"}, + {"role": "developer", "content": "bye"}, + {"role": "user", "content": "how are you"}, + ], + "model": "o3-mini", + "stream": False, + } + assert payload == expected + def test_init_o1() -> None: with pytest.warns(None) as record: # type: ignore[call-overload]