Flow Parameters (parameters.yaml)¶
Every flow can declare its tunable inputs in a parameters.yaml file. The
values are loaded automatically when the flow runs and exposed through the
context-aware params accessor — no manual passing, no global
state to thread through your task signatures.
# flows/my_flow/parameters.yaml
model_name: gpt-4o
batch_size: 32
temperature: 0.0
gates:
quality: 3.5
faithfulness: 4.0
from latent.prefect import flow, task, params, logger
@flow("my_flow")
async def my_flow():
logger.info(f"Scoring with {params.model_name} (batch={params.batch_size})")
threshold = params.gates["quality"]
...
Accessing parameters¶
Inside any @flow- or @task-decorated function, read parameters off params.
Three equivalent forms, plus a safe .get():
params.model_name # attribute access — raises if missing
params["model_name"] # item access — raises if missing
params.get("model_name") # returns None if missing
params.get("batch_size", 32) # returns 32 if missing (default)
Only inside a flow context
params resolves against the current flow. Reading it outside a
@flow/@task body raises RuntimeError ("No flow context available").
Attribute/item access on a missing key raises; use params.get(key, default)
when a parameter is optional.
The layering model¶
parameters.yaml is not read in isolation — the final config is merged from
several layers. Highest priority wins; nested dicts are deep-merged (so you can
override a single nested key without restating the whole block):
| Priority | Layer | Source |
|---|---|---|
| 1 (highest) | CLI flags | latent run <flow> --param value |
| 2 | Flow parameters | flows/<flow>/parameters.yaml |
| 3 | Global defaults | flows/global.yaml |
| 4 (lowest) | Bundled defaults | shipped inside a library flow's package |
After merging, ${VAR} / $VAR environment variables are substituted,
and finally — if the flow declares one — the result is validated against a
Pydantic schema.
global.yaml — shared defaults¶
Put values common to every flow in flows/global.yaml. Each flow's own
parameters.yaml overrides them:
# flows/global.yaml
mlflow_experiment: my-project
model_name: gpt-4o-mini # default model for all flows
# flows/my_flow/parameters.yaml
model_name: gpt-4o # this flow overrides the global default
batch_size: 64
At runtime params.model_name == "gpt-4o" and params.mlflow_experiment ==
"my-project".
Environment variables¶
Any string value may contain ${VAR_NAME} or $VAR_NAME; it is replaced with
the environment variable's value at load time. Substitution is recursive (works
inside nested dicts and lists). If the variable is unset, the placeholder is
left as-is and a warning is logged.
# flows/my_flow/parameters.yaml
api_base: ${OPENAI_API_BASE}
data_root: ${LATENT_WORKSPACE_ROOT}/data
prompt_version: $PROMPT_VERSION
Tip
latent run exports LATENT_WORKSPACE_ROOT before loading parameters, so
${LATENT_WORKSPACE_ROOT} is always resolvable when you run via the CLI.
Typed parameters¶
Pass a Pydantic model as config_schema to validate parameters and get typed,
auto-completing attribute access. Validation runs after merging and env
substitution; a bad config fails fast with a clear error.
from pydantic import BaseModel
from latent.prefect import flow, params
class MyConfig(BaseModel):
model_name: str
batch_size: int = 32
temperature: float = 0.0
@flow("my_flow", config_schema=MyConfig)
async def my_flow():
# params now proxies the validated MyConfig instance
reveal_type = params.batch_size # int, validated and coerced
With a schema, params.batch_size returns the validated/coerced value, and an
unknown or mistyped parameter raises a ValueError at flow start rather than
surfacing as a confusing failure deep inside a task.
Cross-flow parameters¶
Read a parameter from another flow's parameters.yaml with dot notation via
params.get(). This loads the other flow's merged config on demand:
# Reuse the judge model configured by the scoring flow
judge_model = params.get("scoring_flow.model_name", default="gpt-4o")
Cross-flow access works only through params.get("flow.param") — attribute
and item access (params.x) always target the current flow.
Overriding from the CLI¶
latent run forwards extra flags into the parameter system, overriding
parameters.yaml for that run. Underscores and hyphens are interchangeable:
latent run my_flow --model-name gpt-4o --batch-size 64
# inside the flow: params.model_name == "gpt-4o", params.batch_size == 64
Overrides are matched to the flow's declared parameters and made available
through params.get(...). See latent run.
See Also¶
- Data Catalog (
catalog.yaml) — the dataset half of flow config - Prefect Flows & Tasks — the
params/loggeraccessors and@flow/@task - Flow Building & Style — project layout and conventions
- CLI Tools —
latent run,latent list,latent check