diff --git a/libs/partners/openai/langchain_openai/chat_models/base.py b/libs/partners/openai/langchain_openai/chat_models/base.py index 03d9eb4b4a..dc51c95c03 100644 --- a/libs/partners/openai/langchain_openai/chat_models/base.py +++ b/libs/partners/openai/langchain_openai/chat_models/base.py @@ -2158,7 +2158,7 @@ class BaseChatOpenAI(BaseChatModel): tokens_per_message = 4 # if there's a name, the role is omitted tokens_per_name = -1 - elif model.startswith(("gpt-3.5-turbo", "gpt-4", "gpt-5")): + elif model.startswith(("gpt-3.5-turbo", "gpt-4", "gpt-5", "o1", "o3", "o4")): tokens_per_message = 3 tokens_per_name = 1 else: 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 887e31d739..eb990b208d 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 @@ -1099,6 +1099,26 @@ def test_get_num_tokens_from_messages() -> None: assert actual +@pytest.mark.parametrize( + "model", ["o1", "o1-preview", "o1-mini", "o3", "o3-mini", "o4-mini"] +) +def test_get_num_tokens_from_messages_o_series(model: str) -> None: + """o-series models use the same message token format as gpt-4/gpt-5. + + Regression test: these raised NotImplementedError. + """ + llm = ChatOpenAI(model=model) + messages = [ + SystemMessage("you're a good assistant"), + HumanMessage("how are you"), + ] + actual = llm.get_num_tokens_from_messages(messages) + expected = ChatOpenAI(model=OPENAI_TEST_MODEL).get_num_tokens_from_messages( + messages + ) + assert actual == expected + + class Foo(BaseModel): bar: int