🎨(pydantic-ai) use the proper profile setting

The strict attribute for "tools" can now be removed with a specific
parameter for the model profile. Let's use it.
This commit is contained in:
Quentin BEY
2025-10-02 22:59:39 +02:00
parent 99c4b6ba29
commit bc65d646e5
4 changed files with 57 additions and 31 deletions
+15 -5
View File
@@ -82,13 +82,23 @@ def prepare_custom_model(configuration: "chat.llm_configuration.LLModel"):
from pydantic_ai.profiles.openai import OpenAIModelProfile # noqa: PLC0415
from pydantic_ai.providers.openai import OpenAIProvider # noqa: PLC0415
if configuration.profile and (
_config_profile := configuration.profile.dict(exclude_unset=True)
):
# set some defaults if not provided, see openai_model_profile which
# defines them for known models
_model_profile_params = {
"supports_json_schema_output": True,
"supports_json_object_output": True,
}
_model_profile_params.update(_config_profile)
profile = OpenAIModelProfile(**_model_profile_params)
else:
profile = None
return OpenAIChatModel(
model_name=configuration.model_name,
profile=(
OpenAIModelProfile(**configuration.profile.dict(exclude_unset=True))
if configuration.profile
else None
),
profile=profile,
provider=OpenAIProvider(
base_url=configuration.provider.base_url,
api_key=configuration.provider.api_key,
@@ -1,24 +0,0 @@
"""Custom JSON schema transformers."""
import logging
from dataclasses import dataclass
from pydantic_ai.profiles._json_schema import JsonSchema
from pydantic_ai.profiles.openai import OpenAIJsonSchemaTransformer
logger = logging.getLogger(__name__)
@dataclass
class MistralVllmJsonSchemaTransformer(OpenAIJsonSchemaTransformer):
"""
Custom JsonSchema transformer for Mistral models deployed using vLLM.
vLLM's OpenAI-compatible endpoint does not support the `function_strict` setting.
See discussion:
https://discuss.vllm.ai/t/the-openai-endpoint-doesnt-support-function-strict-setting/959
"""
def __init__(self, schema: JsonSchema, *, strict: bool | None = None):
super().__init__(schema, strict=None)
self.is_strict_compatible = None # Remove strict from generated schema
+10 -1
View File
@@ -2,7 +2,7 @@
import os
from functools import lru_cache
from typing import Annotated, Any, Literal, Optional, Self
from typing import Annotated, Any, Literal, Optional, Self, Sequence
from pydantic import (
AfterValidator,
@@ -69,6 +69,15 @@ class LLMProfile(BaseModel):
thinking_tags: tuple[str, str] | None = None
ignore_streamed_leading_whitespace: bool | None = None
# openai specific settings: should find a way to auto declare these
# based on OpenAIModelProfile.
openai_supports_strict_tool_definition: bool | None = None
openai_unsupported_model_settings: Sequence[str] | None = None
openai_supports_tool_choice_required: bool | None = None
openai_system_prompt_role: str | None = None
openai_chat_supports_web_search: bool | None = None
openai_supports_encrypted_reasoning_content: bool | None = None
@field_validator("json_schema_transformer", mode="after")
@classmethod
def validate_json_schema_transformer(
@@ -5,7 +5,7 @@ from pydantic_ai.models.mistral import MistralModel
from pydantic_ai.models.openai import OpenAIChatModel
from chat.agents.base import BaseAgent
from chat.llm_configuration import LLModel, LLMProvider
from chat.llm_configuration import LLModel, LLMProfile, LLMProvider
def test_not_custom_model(monkeypatch, settings):
@@ -79,3 +79,34 @@ def test_custom_model_mistral(settings):
import pydantic_ai.models.mistral as mistral_models # noqa: PLC0415 # pylint: disable=import-outside-toplevel
assert mistral_models.__safe_map_patched__ is True # pylint: disable=protected-access
def test_custom_model_openai_profile(settings):
"""Test that a custom OpenAI model with profile is initialized correctly."""
settings.LLM_CONFIGURATIONS = {
"openai-model": LLModel(
hrid="openai-model",
model_name="some-openai-model",
human_readable_name="Some OpenAI Model",
profile=LLMProfile(
supports_json_schema_output=False,
openai_supports_strict_tool_definition=False,
),
provider=LLMProvider(
hrid="openai",
kind="openai",
base_url="https://test.vllm/v1",
api_key="testkey",
),
is_active=True,
system_prompt="direct",
tools=[],
),
}
agent = BaseAgent(model_hrid="openai-model")
assert isinstance(agent._model, OpenAIChatModel)
assert agent._model.profile.supports_tools is True
assert agent._model.profile.supports_json_schema_output is False
assert agent._model.profile.supports_json_object_output is True