🎨(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:
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user