Creating Pipeline Templates
Templates are YAML definitions + seed files in lib/templates/. Auto-discovered on startup by TemplateRegistry (lib/templates/init.py).
- Template ID = filename without
.yaml
- Seed file:
seed<templateid>.json or seed<templateid>.md
Template YAML Format
name: Template Display Name
description: What this template generates
blocks:
- type: BlockClassName # must match class name exactly
config:
param1: value1 # must match __init__ parameter names exactly
user_prompt: "{{ var }}" # Jinja2 references to seed metadata
- type: AnotherBlock
config:
field_name: generated
Seed File Format
JSON (most templates):
[
{"repetitions": 3, "metadata": {"content": "input text here"}}
]
Markdown (only for MarkdownMultiplierBlock as first block):
- File:
seed<templateid>.md
- Registry auto-wraps as
[{"repetitions": 1, "metadata": {"file_content": "<content>"}}]
Available Blocks
| Block |
Category |
Key Outputs |
Notes |
TextGenerator |
generators |
assistant, system, user |
free-text via LLM |
StructuredGenerator |
generators |
generated |
JSON via LLM with schema |
SemanticInfiller |
generators |
dynamic |
complete skeleton records |
StructureSampler |
seeders |
skeletons, seedsamples |
multiplier, must be first |
MarkdownMultiplierBlock |
seeders |
content |
multiplier, must be first |
ValidatorBlock |
validators |
text, valid, assistant |
text rules |
JSONValidatorBlock |
validators |
valid, parsed_json |
JSON parse + validate |
DuplicateRemover |
validators |
generated_samples |
embedding similarity |
DiversityScore |
metrics |
diversity_score |
lexical diversity |
CoherenceScore |
metrics |
coherence_score |
text coherence |
RougeScore |
metrics |
rouge_score |
ROUGE comparison |
RagasMetrics |
metrics |
ragas_scores |
RAGAS QA evaluation |
FieldMapper |
utilities |
dynamic |
Jinja2 field expressions |
LangfuseBlock |
observability |
langfusetraceurl |
trace logging |
Common Pipeline Patterns
# simple generation + validation
StructuredGenerator → JSONValidatorBlock
# document processing (multiplier first)
MarkdownMultiplierBlock → TextGenerator → StructuredGenerator → JSONValidatorBlock
# data augmentation
StructureSampler → SemanticInfiller → DuplicateRemover
# generation + metrics
StructuredGenerator → FieldMapper → RagasMetrics
# generation + review-friendly output
StructuredGenerator → FieldMapper (flatten for review)
Adding a FieldMapper for Review
The Review page displays records from the last block's accumulatedstate. Only first-level keys are shown as primary/secondary fields. Nested objects (e.g. generated.confirmeddependencies) appear as raw JSON strings and can't be configured as separate review fields.
Always add a FieldMapper as the last block to surface the fields reviewers need at the top level.
Why it matters
Without a FieldMapper, the accumulated_state after a StructuredGenerator looks like:
{
"input_field": "...",
"generated": {
"question": "...",
"answer": "...",
"contexts": ["..."]
}
}
The review UI sees input_field and generated (a blob). Reviewers can't configure question or answer as primary fields.
How to add it
Add a FieldMapper as the last block (or last before metrics/observability blocks):
- type: FieldMapper
config:
mappings:
# Flatten nested fields to top level
question: "{{ generated.question }}"
answer: "{{ generated.answer }}"
# tojson is safe only for structured data (IDs, numbers, short labels)
# avoid tojson on arrays/objects with free-text — newlines/quotes break JSON parsing
context_count: "{{ generated.contexts | length }}"
# Carry forward useful seed metadata
source: "{{ source_document }}"
Rules
- Map every field the reviewer needs — if it's not a first-level key after the last block, it won't be configurable in the review field settings
- Use
| tojson for arrays/objects — FieldMapper auto-parses JSON strings back to objects, so the review UI can display them properly. Exception: tojson on arrays/objects whose values contain unescaped quotes or newlines (e.g. free-text descriptions) will break FieldMapper JSON parsing. In that case, map only scalar summaries (counts, IDs) and let the array flow through as an existing first-level key.
- Use
| length for counts — gives reviewers a quick numeric summary without expanding lists
- Use
| default('') for optional fields — prevents Jinja2 errors when a field is missing
- Don't map internal/noisy fields — skip
folderpath, usage, seedsamples etc. Only map what's useful for human review
- Order matters — FieldMapper outputs merge into accumulated_state, so its keys become the available fields in the Review "Configure Fields" modal
Step-by-Step Workflow
- Define use case — what data to generate, what fields in output, what seed input needed
- Choose blocks — pick from table above, wire outputs to inputs
- Write YAML —
lib/templates/<template_id>.yaml
- Write seed file — match
{{ variables }} in YAML to metadata keys
- Validate template loads:
``bash uv run python -c " from lib.templates import templateregistry for t in templateregistry.list_templates(): print(f'{t[\"id\"]}: {t[\"name\"]}') " ``
- Check block params (if unsure about config keys):
``bash uv run python -c " from lib.blocks.registry import BlockRegistry registry = BlockRegistry() for name, cls in registry.blocks.items(): schema = cls.getschema() print(f'{name}: {list(schema.get(\"config_schema\", {}).get(\"properties\", {}).keys())}') " ``
- Test single execution:
``bash # create pipeline from template curl -s -X POST http://localhost:8000/api/pipelines/fromtemplate/<templateid> | python -m json.tool # execute with seed curl -s -X POST http://localhost:8000/api/pipelines/<id>/execute \ -H 'Content-Type: application/json' \ -d '{"content": "test input"}' | python -m json.tool ``
Reference Templates
| Template |
File |
Pattern |
| JSON Generation |
json_generation.yaml |
StructuredGenerator → JSONValidator |
| Text Classification |
text_classification.yaml |
StructuredGenerator → JSONValidator |
| Q&A Generation |
qa_generation.yaml |
Multiplier → Text → Structured → JSONValidator |
| Data Augmentation |
data_augmentation.yaml |
Sampler → Infiller → DuplicateRemover |
| RAGAS Evaluation |
ragas_evaluation.yaml |
Structured → FieldMapper → RagasMetrics |
Common Mistakes
| Mistake |
Fix |
Block type doesn't match class name |
Check lib/blocks/builtin/ for exact class names |
Config key doesn't match init param |
Read block source, match parameter names |
| Missing seed variable referenced in prompt |
Add the variable to seed metadata |
| MarkdownMultiplierBlock not first |
Multiplier blocks must always be first |
Seed file not named seed<templateid>.* |
Template ID must match: foo.yaml → seed_foo.json |
| Nested fields not visible in Review UI |
Add a FieldMapper as last block to flatten nested outputs to top-level keys |
Review shows generated as a JSON blob |
Map individual sub-fields: question: "{{ generated.question }}" |
Checklist
Related Skills
implementing-datagenflow-blocks — creating new block types
debugging-pipelines — troubleshooting template execution
testing-pipeline-templates — thorough end-to-end testing