AlgoMaster Logo

Exercise: Type Hints and Pydantic

4 min readUpdated June 22, 2026
Listen to this chapter
Unlock Audio

Exercise 1: Validate an LLM Config with Pydantic

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.

Requirements

  • Define an 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.
  • Construct a valid config and print it.
  • Attempt to construct a config with temperature = 5.0, catch the validation error, and print it.
main.py
Loading...

Expected Output

The valid config prints its fields. The invalid one raises a validation error that names the offending field and the rule it broke.

Solution

main.py
Loading...

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.

Exercise 2: Validate a Nested Chat Request

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.

Requirements

  • Define a Message model (role, content) and a ChatRequest model holding model and messages: list[Message].
  • Add a field_validator on messages that rejects an empty list and any message whose content is blank after stripping.
  • Build a valid request and print it, then build an invalid one and print the validation error.
main.py
Loading...

Expected Output

The valid request prints its nested messages; the invalid one is rejected with a clear reason.

Solution

main.py
Loading...

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.