Skip to content
Blog

Golden Trajectories: Curating Human-Approved Agent Runs

Build golden trajectory datasets by curating human-approved agent runs. Use these validated paths to fine-tune agents, create evals, and improve reliability.

Published on September 8, 2026

AI Assistant

The gap between a working agent and a reliable agent is data. You need examples of agents succeeding — not just once, but consistently. Golden trajectories are human-approved agent runs that serve as ground truth: they define what “good” looks like, provide training data for fine-tuning, and form the backbone of regression test suites.

What Are Golden Trajectories

A golden trajectory is a complete record of an agent’s execution that has been reviewed and approved by a human expert. It captures:

  • The initial task and context
  • Every decision the agent made (tool calls, routing, reasoning)
  • The intermediate states and outputs
  • The final result
  • A human approval signal with optional corrections

Think of it as a “verified solution” for agent tasks — similar to how textbooks provide worked examples for students.

Why They Matter

For Evaluation

Golden trajectories give you deterministic benchmarks. Instead of asking “did the agent produce a good output?” you ask “did the agent follow the same path as the approved trajectory?”

For Fine-Tuning

Approved trajectories become training data. You can fine-tune models to replicate successful patterns without reinventing them from scratch.

For Debugging

When an agent fails, comparing its trajectory to a golden one shows exactly where it diverged — which decision was wrong, which tool call was unnecessary, where the reasoning broke down.

Building the Curation Pipeline

Step 1: Collect Agent Runs

Record every agent execution with full trace data:

from dataclasses import dataclass, field
from datetime import datetime
from typing import Any

@dataclass
class AgentStep:
    step_id: int
    action: str  # "tool_call", "reasoning", "routing"
    tool_name: str | None
    input_data: dict
    output_data: Any
    timestamp: datetime
    duration_ms: float

@dataclass
class AgentRun:
    run_id: str
    task: str
    steps: list[AgentStep]
    final_output: str
    total_duration_ms: float
    token_usage: dict
    status: str  # "completed", "failed", "timeout"

class TrajectoryCollector:
    def __init__(self):
        self.runs: list[AgentRun] = []
    
    def record_run(self, run: AgentRun):
        self.runs.append(run)
        
        # Store in database for curation
        self._persist(run)
    
    def _persist(self, run: AgentRun):
        # Save to database
        pass

Step 2: Human Review Interface

Build an interface for humans to review and approve trajectories:

@dataclass
class TrajectoryReview:
    run_id: str
    reviewer: str
    approved: bool
    rating: int  # 1-5 quality score
    corrections: list[dict]  # Manual fixes applied
    notes: str
    reviewed_at: datetime

class CurationPipeline:
    def __init__(self):
        self.pending_reviews: list[AgentRun] = []
        self.approved_trajectories: list[dict] = []
    
    def queue_for_review(self, run: AgentRun):
        self.pending_reviews.append(run)
    
    def submit_review(self, review: TrajectoryReview):
        run = self._get_run(review.run_id)
        
        if review.approved:
            trajectory = self._build_trajectory(run, review)
            self.approved_trajectories.append(trajectory)
            
            # Store for fine-tuning
            self._store_golden(trajectory)
        
        self._update_status(review.run_id, "reviewed")
    
    def _build_trajectory(self, run: AgentRun, review: TrajectoryReview) -> dict:
        return {
            "task": run.task,
            "trajectory": [
                {
                    "step": step.step_id,
                    "action": step.action,
                    "tool": step.tool_name,
                    "input": step.input_data,
                    "output": step.output_data,
                }
                for step in run.steps
            ],
            "final_output": run.final_output,
            "rating": review.rating,
            "corrections": review.corrections,
            "reviewer": review.reviewer,
        }

Step 3: Automatic Quality Filtering

Pre-filter runs before human review to save time:

class QualityFilter:
    def __init__(self):
        self.min_tool_success_rate = 0.8
        self.max_retries = 3
        self.min_output_quality = 0.6
    
    def should_review(self, run: AgentRun) -> tuple[bool, str]:
        # Check tool success rate
        tool_steps = [s for s in run.steps if s.action == "tool_call"]
        if tool_steps:
            success_rate = sum(
                1 for s in tool_steps 
                if not s.output_data.get("error")
            ) / len(tool_steps)
            
            if success_rate < self.min_tool_success_rate:
                return False, f"Low tool success rate: {success_rate:.2f}"
        
        # Check for excessive retries
        retry_count = sum(
            1 for s in run.steps 
            if s.action == "retry"
        )
        if retry_count > self.max_retries:
            return False, f"Too many retries: {retry_count}"
        
        # Check output quality (heuristic)
        output_length = len(run.final_output)
        if output_length < 50:
            return False, "Output too short"
        
        return True, "Passed quality filter"

Using Golden Trajectories

Evaluation Suite

Compare new agent runs against golden trajectories:

class TrajectoryEvaluator:
    def __init__(self, golden_trajectories: list[dict]):
        self.golden = {t["task"]: t for t in golden_trajectories}
    
    def evaluate(self, agent_run: AgentRun) -> dict:
        golden = self.golden.get(agent_run.task)
        if not golden:
            return {"status": "no_golden_available"}
        
        # Compare tool call sequences
        tool_sequence_score = self._compare_tool_sequences(
            agent_run.steps,
            golden["trajectory"]
        )
        
        # Compare final output
        output_similarity = self._compare_outputs(
            agent_run.final_output,
            golden["final_output"]
        )
        
        # Check for unnecessary steps
        efficiency_score = self._calculate_efficiency(
            len(agent_run.steps),
            len(golden["trajectory"])
        )
        
        return {
            "tool_sequence_match": tool_sequence_score,
            "output_similarity": output_similarity,
            "efficiency": efficiency_score,
            "overall": (tool_sequence_score + output_similarity + efficiency_score) / 3,
        }
    
    def _compare_tool_sequences(self, actual_steps, golden_steps):
        actual_tools = [s.tool_name for s in actual_steps if s.action == "tool_call"]
        golden_tools = [s["tool"] for s in golden_steps if s["action"] == "tool_call"]
        
        # Longest common subsequence
        lcs_length = self._lcs_length(actual_tools, golden_tools)
        max_length = max(len(actual_tools), len(golden_tools))
        
        return lcs_length / max_length if max_length > 0 else 1.0

Fine-Tuning Data Generation

Convert golden trajectories into training data:

def trajectory_to_training_data(trajectory: dict) -> list[dict]:
    """Convert a golden trajectory into fine-tuning examples."""
    training_examples = []
    
    messages = [{"role": "system", "content": "You are a helpful assistant."}]
    
    for step in trajectory["trajectory"]:
        if step["action"] == "tool_call":
            # User message (context)
            messages.append({
                "role": "user",
                "content": f"Task: {trajectory['task']}"
            })
            
            # Assistant response (tool call)
            messages.append({
                "role": "assistant",
                "content": None,
                "tool_calls": [{
                    "function": {
                        "name": step["tool"],
                        "arguments": json.dumps(step["input"])
                    }
                }]
            })
            
            # Tool result
            messages.append({
                "role": "tool",
                "content": json.dumps(step["output"])
            })
    
    # Final response
    messages.append({
        "role": "assistant",
        "content": trajectory["final_output"]
    })
    
    training_examples.append({
        "messages": messages,
        "quality_score": trajectory["rating"],
    })
    
    return training_examples

Regression Testing

Run golden trajectories as regression tests:

import pytest

@pytest.fixture
def golden_suite():
    return load_golden_trajectories("trajectories/")

def test_trajectory_regression(golden_suite):
    evaluator = TrajectoryEvaluator(golden_suite)
    
    for task, golden in golden_suite.items():
        # Run agent on the same task
        agent_run = agent.execute(task)
        
        # Evaluate against golden
        result = evaluator.evaluate(agent_run)
        
        # Assert minimum quality
        assert result["overall"] >= 0.8, \
            f"Agent degraded on task '{task}': {result}"

Curation Best Practices

Diverse Coverage

Ensure golden trajectories cover:

  • Common tasks (80% of volume)
  • Edge cases (unusual inputs, ambiguous requests)
  • Error recovery (tool failures, timeouts)
  • Multi-step workflows (complex task chains)

Regular Refresh

Agent capabilities evolve. Refresh golden trajectories:

  • Monthly for fast-moving applications
  • When models or prompts change significantly
  • After major tool or API updates

Reviewer Calibration

Multiple reviewers should agree on trajectory quality:

def calculate_inter_reviewer_agreement(reviews: list[TrajectoryReview]) -> float:
    agreements = 0
    total = 0
    
    for i in range(len(reviews)):
        for j in range(i + 1, len(reviews)):
            if reviews[i].run_id == reviews[j].run_id:
                total += 1
                if reviews[i].approved == reviews[j].approved:
                    agreements += 1
    
    return agreements / total if total > 0 else 0.0

Conclusion

Golden trajectories bridge the gap between “it works” and “it works reliably.” By systematically collecting, reviewing, and storing approved agent runs, you build a foundation for evaluation, fine-tuning, and regression testing. Start with the most common tasks, invest in a clean review interface, and treat your golden trajectory dataset as a living asset that evolves with your agent.