Define a Pydantic model that validates the configuration for an LLM request, then confirm it accepts valid input and rejects invalid input with a clear error.
Generation parameters come from config files, environment variables, and user input, all of which can be wrong. A model with temperature = 5.0 or max_tokens = -10 fails at the API, often after you have already spent time and tokens building the request. Validating the config up front turns a late, confusing API error into an early, specific one.
LLMConfig model with these fields and rules:model: a non-empty string.temperature: a float between 0.0 and 2.0 inclusive, default 0.7.max_tokens: an integer between 1 and 128000 inclusive, default 1024.temperature = 5.0, catch the validation error, and print it.The valid config prints its fields. The invalid one raises a validation error that names the offending field and the rule it broke.
Field carries the constraints declaratively: ge and le set inclusive bounds, min_length rejects an empty model name, and default makes a field optional. Pydantic checks every rule when the model is constructed and raises a single error listing each field that failed, which is why the bad temperature is caught before the request is ever assembled.
Real request payloads are nested: a chat request holds a list of message objects, each with its own fields. Build a ChatRequest model that contains a list of Message models, and add a validator that rejects an empty message list or any message with blank content.
Nested models plus a field validator are how you enforce structure that a flat schema cannot, like "the list must be non-empty and every item well-formed." Catching this before the request leaves your service turns a confusing downstream API error into a clear local one.
Message model (role, content) and a ChatRequest model holding model and messages: list[Message].field_validator on messages that rejects an empty list and any message whose content is blank after stripping.The valid request prints its nested messages; the invalid one is rejected with a clear reason.
Declaring messages: list[Message] makes Pydantic validate and construct each item as a Message, so the nested structure is checked automatically. The field_validator adds the cross-item rules a type alone cannot express: non-empty list and no blank content. Together they guarantee that any ChatRequest your code builds is already well-formed, which is exactly the contract you want before serializing it to the API.