CriticNode class evaluates the output of a target node against a list of criteria. It is automatically added as a dependent of the target node so it always runs after the node it evaluates.
Constructor
from fibonacci import CriticNode
node = CriticNode(
id="evaluate_report",
name="Evaluate Report Quality",
target_node="generate_report",
criteria=["clarity", "completeness", "accuracy"]
)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
id | str | Required | Unique node identifier (lowercase letters, numbers, underscores, hyphens) |
name | str | Required | Human-readable node name |
target_node | str | Required | ID of the node whose output will be evaluated |
criteria | list[str] | ["quality", "correctness", "completeness"] | Evaluation criteria labels |
dependencies | list[str] | auto | target_node is automatically added; add extras here if needed |
enable_retry | bool | False | Retry the critic node on failure |
max_retries | int | 3 | Maximum retry attempts (used when enable_retry=True) |
retry_delay | float | 1.0 | Initial delay in seconds between retries |
The
target_node is automatically added to dependencies. You do not need to list it manually.Basic Usage
from fibonacci import Workflow, LLMNode, CriticNode
wf = Workflow(name="quality-assured")
# Content generator
writer = LLMNode(
id="writer",
name="Write Email",
instruction="Write a professional email about: {{input.topic}}"
)
# Quality evaluator
critic = CriticNode(
id="critic",
name="Evaluate Email Quality",
target_node="writer",
criteria=[
"professional tone throughout",
"clear and concise language",
"proper grammar and spelling",
"appropriate greeting and closing"
]
)
wf.add_nodes([writer, critic])
Default Criteria
When you omitcriteria, the node uses three built-in labels:
# These two are equivalent
critic_a = CriticNode(
id="critic_a",
name="Default Critic",
target_node="writer"
)
critic_b = CriticNode(
id="critic_b",
name="Explicit Critic",
target_node="writer",
criteria=["quality", "correctness", "completeness"]
)
Custom Criteria
Provide specific, measurable criteria for your use case:Content Writing
content_critic = CriticNode(
id="content_critic",
name="Content Quality Check",
target_node="blog_writer",
criteria=[
"engaging opening hook",
"clear value proposition",
"actionable takeaways",
"appropriate length for the audience"
]
)
Code Review
code_critic = CriticNode(
id="code_critic",
name="Code Review",
target_node="code_generator",
criteria=[
"syntactically correct",
"follows best practices",
"includes error handling",
"is well-documented"
]
)
Data Extraction
extraction_critic = CriticNode(
id="extraction_critic",
name="Extraction Accuracy Check",
target_node="extractor",
criteria=[
"all required fields extracted",
"values are in the correct format",
"no hallucinated information"
]
)
Writing Good Criteria
Be specific and measurable
Be specific and measurable
# ✅ Good — specific, observable
criteria=[
"response is between 100 and 200 words",
"includes at least one concrete example",
"no grammatical errors"
]
# ❌ Vague — hard to evaluate objectively
criteria=[
"good quality",
"sounds nice"
]
Match criteria to the task
Match criteria to the task
# For customer-facing content
criteria=[
"friendly and empathetic tone",
"directly addresses the user's question",
"offers a clear next step"
]
# For internal analysis
criteria=[
"cites data from the source",
"identifies at least 3 trends",
"recommends concrete actions"
]
Retry Configuration
critic = CriticNode(
id="critic",
name="Evaluator",
target_node="writer"
).with_retry(max_retries=3, delay=1.0)
YAML Configuration
nodes:
- id: quality_check
name: Quality Check
type: critic
target_node: writer
evaluation_criteria:
- professional tone
- clear language
- grammar and spelling
dependencies:
- writer
Complete Example
from fibonacci import Workflow, LLMNode, CriticNode
wf = Workflow(name="blog-writer")
# Generate blog post
writer = LLMNode(
id="writer",
name="Write Blog Post",
instruction="""
Write a blog post about {{input.topic}}.
Target audience: {{input.audience}}
Desired length: approximately {{input.word_count}} words
Tone: {{input.tone}}
""",
model="claude-sonnet-4-6"
)
# Evaluate quality
critic = CriticNode(
id="quality_check",
name="Editorial Quality Check",
target_node="writer",
criteria=[
"engaging from the first paragraph",
"well-researched and accurate",
"writing style matches the target audience",
"close to the requested word count",
"tone is consistent throughout",
"includes actionable takeaways",
"compelling conclusion"
]
)
wf.add_nodes([writer, critic])
result = wf.run(input_data={
"topic": "Introduction to Machine Learning",
"audience": "business professionals",
"word_count": 800,
"tone": "informative yet approachable"
})
print(result.output_data["quality_check"])