Goal Engineering
Turn vague objectives into structured, measurable goals — then verify agent output against them
Goal Engineering turns a vague objective into a structured, measurable goal, then verifies agent output against it.
Quick Start
- Engineer and verify a goal
Engineer a goal, run your agent against it, then verify the output:
Python
python from praisonaiagents import Agent, GoalEngineer agent = Agent(name="Summariser", instructions="Summarise the input") engineer = GoalEngineer() goal = engineer.engineer("Summarise the report in under 100 words") output = agent.start(goal.to_prompt()) result = engineer.verify(goal, output) print(result.score, result.achieved)TypeScript
typescript import { Agent, GoalEngineer } from 'praisonai'; const agent = new Agent({ name: 'Summariser', instructions: 'Summarise the input' }); const engineer = new GoalEngineer(); const goal = await engineer.engineer('Summarise the report in under 100 words'); const output = await agent.start(goal.toPrompt()); const result = await engineer.verify(goal, output); console.log(result.score, result.achieved); - Explicit criteria + constraints
Provide your own criteria and constraints to skip LLM decomposition:
python from praisonaiagents import GoalEngineer engineer = GoalEngineer(auto_decompose=False) goal = engineer.engineer( "Summarise the report", criteria=["Under 100 words", "Preserves key findings"], constraints=["No hallucinations"], ) - Full control with GoalConfig
Tune the model, criteria count, and pass threshold:
python from praisonaiagents import GoalEngineer, GoalConfig engineer = GoalEngineer(config=GoalConfig( model="gpt-4o", max_criteria=3, threshold=7.5, ))
How It Works
A statement is decomposed into criteria, the agent runs, and the output is scored by the same Judge used across evaluation.
| Step | What happens |
|---|---|
| engineer | Builds a Goal from a statement. Uses supplied criteria, or the LLM proposes measurable ones when auto_decompose=True. |
| to_prompt | Renders the goal, criteria, and constraints as an instruction block for any agent. |
| verify | Reuses the unified Judge to score the output. A score at/above threshold marks the goal achieved. |
A judge failure is inconclusive — criteria stay pending and achieved=False, never a real unmet. The result carries an independent snapshot of criteria, so mutating it never corrupts the goal.
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
model | Optional[str] | os.getenv("OPENAI_MODEL_NAME", "gpt-4o-mini") | LLM model used for decomposition/verification |
max_criteria | int | 5 | Maximum success criteria auto-generated |
threshold | float | 8.0 | Score (0–10) at/above which the goal is achieved |
auto_decompose | bool | True | Auto-generate criteria via the LLM |
verbose | bool | False | Enable verbose logging |
GoalConfig follows the PraisonAI convention: False = disabled, True = defaults, GoalConfig(...) = custom.
Full Python API for the praisonaiagents package, including the goal exports
Data Model
GoalEngineer works with three dataclasses, all importable from praisonaiagents.
SuccessCriterion
A single measurable condition that contributes to achieving a goal.
| Field | Type | Default | Description |
|---|---|---|---|
description | str | — | What must be true for this criterion to be met |
id | str | 8-char UUID | Unique identifier |
weight | float | 1.0 | Relative importance when scoring the goal |
status | Literal["pending", "met", "unmet"] | "pending" | Current status |
notes | str | "" | Notes from verification |
Methods: to_dict(), from_dict(data) (classmethod).
Goal
A goal exposes two computed properties in addition to its fields.
| Property | Type | Description |
|---|---|---|
progress | float | Weighted fraction of criteria whose status == "met", clamped to [0.0, 1.0]. Non-positive weights count as 0; when total weight is 0, criteria count equally. |
is_achieved | bool | True when there is at least one criterion and all criteria are met |
GoalVerificationResult
The result returned by verify().
| Field | Type | Description |
|---|---|---|
goal_id | str | The verified goal’s id |
score | float | Overall score in 0.0–10.0 |
achieved | bool | Whether the goal is considered achieved (score >= config.threshold) |
criteria | List[SuccessCriterion] | Independent snapshot of the goal’s criteria with updated statuses; mutating this list does not affect the original Goal |
reasoning | str | Judge explanation, or "Verification unavailable: …" when the judge fell through |
Method: to_dict().
Common Patterns
Weight criteria by importance and track weighted progress:
from praisonaiagents import GoalEngineer
engineer = GoalEngineer(auto_decompose=False)
goal = engineer.engineer("Ship the release notes")
goal.add_criterion("Covers every merged PR", weight=3.0)
goal.add_criterion("Reads clearly", weight=1.0)
print(goal.progress) # fraction of weighted criteria met, clamped to [0.0, 1.0]progress is the fraction of weighted criteria currently met, clamped to [0.0, 1.0]. Non-positive weights count as 0; when total weight is 0, criteria count equally.
Reuse one engineered goal across multiple agents via to_prompt():
from praisonaiagents import Agent, GoalEngineer
engineer = GoalEngineer()
goal = engineer.engineer("Draft a launch email under 150 words")
drafter = Agent(name="Drafter", instructions="Write marketing copy")
editor = Agent(name="Editor", instructions="Tighten and proofread")
draft = drafter.start(goal.to_prompt())
final = editor.start(goal.to_prompt() + f"\n\nDraft:\n{draft}")Persist a goal with to_dict() and restore it with from_dict():
import json
from praisonaiagents import Goal, GoalEngineer
goal = GoalEngineer().engineer("Summarise the report")
saved = json.dumps(goal.to_dict())
restored = Goal.from_dict(json.loads(saved))Best Practices
Prefer explicit criteria for tests
Pass your own criteria (with auto_decompose=False) when you need deterministic, repeatable checks. Let auto_decompose propose criteria while you explore a new goal.
Tune the threshold deliberately
threshold defaults to 8.0, which is strict. Lower it in GoalConfig when a goal tolerates partial success, and review the value the same way you review test assertions.
Use constraints for hard rules
Add constraints for safety and format rules that must never be violated. They render inside to_prompt(), so the agent sees them alongside the goal.
Treat pending as retry, not failure
A pending status in GoalVerificationResult means the judge was unavailable — retry the verification. It is not the same as an unmet criterion.