Marvin (PrefectHQ)
AI functions and agentic workflow library by PrefectHQ. Provides decorator-based AI functions (marvin.fn, marvin.classify, marvin.extract, marvin.cast) and agent/task orchestration. v3.0 released 2024 — merged with ControlFlow, switched LLM backend from OpenAI-only to Pydantic AI (multi-provider). Current version: 3.2.7 (Mar 2026). WARNING: 'marvin' on PyPI is PrefectHQ's AI library — not the SDSS astronomy Marvin library (sdss-marvin on PyPI).
Warnings
- breaking marvin v2 was OpenAI-only. v3 uses Pydantic AI as backend supporting all providers. marvin.settings.openai.api_key configuration pattern from v2 is gone.
- breaking ControlFlow's @flow decorator removed in v3. ControlFlow merged into marvin. Use marvin.Thread() context manager instead.
- breaking Thread/message history storage changed to SQLite in v3. No database migrations available — expect data loss when updating during development.
- gotcha Name collision: 'marvin' PyPI package is PrefectHQ's AI library. 'sdss-marvin' is the SDSS astronomy toolkit. LLMs may conflate them. They are completely unrelated.
- gotcha Marvin defaults to OpenAI gpt-4o. No model specified = OpenAI API call. Fails silently with AuthenticationError if OPENAI_API_KEY not set.
- gotcha ai_fn decorator from very old v1 docs still appears in many tutorials. Renamed to marvin.fn in v2+.
Install
-
pip install marvin
Imports
- marvin.extract
import marvin result = marvin.extract( 'i found $30 on the ground and bought 5 bagels for $10', int, instructions='only USD amounts' ) print(result) # [30, 10] - marvin.fn decorator
import marvin @marvin.fn def sentiment(text: str) -> float: """Returns sentiment score from -1.0 (negative) to 1.0 (positive).""" score = sentiment('I love this product!') print(score) # ~0.9 - marvin.Thread (v3)
import marvin with marvin.Thread() as thread: marvin.run('What is quantum computing?') marvin.run('How does that relate to AI?')
Quickstart
# pip install marvin
import marvin
import os
# Set OPENAI_API_KEY env var — marvin uses OpenAI by default
# Structured extraction
numbers = marvin.extract(
'I paid $45 for lunch and $12 for coffee',
int,
instructions='USD amounts only'
)
print(numbers) # [45, 12]
# Classification
category = marvin.classify(
'The new iPhone has great camera features',
labels=['tech', 'sports', 'politics']
)
print(category) # 'tech'
# AI function
@marvin.fn
def translate(text: str, language: str) -> str:
"""Translates text to the given language."""
print(translate('Hello world', 'Spanish')) # 'Hola mundo'