@generative decorator — functions with typed return values, docstring-driven
prompts, and consistent behaviour that you can reuse across a codebase.
By the end you will have covered:
- Defining
@generativefunctions with typed returns - Composing multiple generative functions into a pipeline
- Controlling behaviour via
ChatContextand context injection - Precondition and postcondition validation patterns
pip install mellea, Ollama running locally with granite4.1:3b downloaded.
Step 1: Your first @generative function
A@generative function uses its name, type annotation, and docstring as the
prompt. Call it by passing a MelleaSession as the first argument:
Sample output
Note: Output may vary — LLM responses depend on model and temperature.The return type annotation shapes the output. With
-> str, the model returns
free text. For constrained output, use Literal:
Step 2: Typed and structured returns
Generative functions support any JSON-serialisable return type —str, int,
bool, list, dict, and Pydantic models:
Sample output
Note: With a Pydantic return type,The return value is a validatedresultis a validatedFeedbackAnalysisinstance.result.sentimentwill always be one of"positive","negative", or"neutral".
FeedbackAnalysis instance. If the model output
doesn’t conform, Mellea retries.
Step 3: Compose generative functions
Because each@generative function is just a Python function, you compose them
the same way as any other code:
Sample output
Note: LLM output is non-deterministic. The response will be in French (or whichever target language you specify) and will vary in wording.Each function is an independent LLM call. The composition logic stays in ordinary Python.
Full example: docs/examples/generative_stubs/generate_with_context.py
Step 4: Steer all functions via context
A key advantage of@generative functions over direct instruct() calls: you can
change the behaviour of every function in a session by injecting context once.
Sample output
Note: LLM output is non-deterministic. Output will vary.
m.reset() clears injected context while keeping the session and backend alive.
Step 5: Pre- and postcondition validation
For production pipelines, validate inputs before the LLM call and outputs afterwards using plain Python:Sample output
Note: LLM output is non-deterministic. The letter will vary in wording but should be 50+ words and free of prohibited compliance language (The precondition check runs before the expensive letter generation. The postcondition check uses a second"guaranteed returns","no risk", etc.). If either check fails, you will seeValidation failed: ...instead.
@generative call as a lightweight verifier.
Full example: docs/examples/generative_stubs/investment_advice.py
What you built
A pattern for replacing ad-hocinstruct() calls with reusable, typed,
context-steerable generative functions:
See also: Generative Functions | The Requirements System | Write Custom Verifiers