veritas-kanban/docs/SOP-output-evaluation.md
2026-08-24 07:47:20 -05:00

6.9 KiB

SOP: Agent Output Evaluation & Scoring

Define scoring profiles and evaluate agent outputs for quality.


Overview

The Scoring Framework lets you define profiles with weighted criteria that evaluate agent outputs. Each evaluation runs the output through all scorers, combines scores using a composite method, and returns a per-scorer breakdown for diagnostics.

Scorer types:

Type What it checks
RegexMatch Whether bounded worker-isolated regex evaluation matches
KeywordContains Whether the output contains required keywords
NumericRange Whether a numeric field in the output falls within a range
OccurrenceRatio Literal occurrence density with optional numeric-path normalization

RegexMatch accepts patterns up to 256 characters and any valid JavaScript regex flag set supported by the active Node runtime. Evaluation uses a globally bounded four-worker pool outside the server event loop, a bounded wait queue, and a 100 ms limit. Output is limited to 100,000 characters, action text to 10,000 characters, and their combined scoring target to 110,001 characters.

OccurrenceRatio is the declarative replacement for legacy custom expressions. It accepts one to 32 literal needles and divides their occurrence count by either a fixed denominator or a numeric denominatorPath, optionally scaled with denominatorScale. wholeWord, caseSensitive, minimumDenominator, and invert provide bounded transformations without executing code.

Persisted profiles containing the removed CustomExpression scorer fail closed during evaluation. Replace those scorers through the profile API before retrying; the server never evaluates or silently converts the stored expression.

Composite methods:

Method Behavior
weightedAvg Weighted average of all scorer scores
minimum Score is the lowest individual scorer score
geometricMean Geometric mean — penalizes any single low scorer

Prerequisites

  • VK server running (v4.0+)
  • Know what "good" looks like for the outputs you want to evaluate

Step-by-Step Procedure

1. Create a Scoring Profile

curl -X POST http://localhost:3001/api/scoring/profiles \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Task Summary Quality",
    "description": "Evaluate quality of agent task completion summaries.",
    "compositeMethod": "weightedAvg",
    "scorers": [
      {
        "id": "has-action-items",
        "name": "Contains action items",
        "type": "KeywordContains",
        "weight": 0.4,
        "target": "output",
        "keywords": ["completed", "implemented", "fixed", "added"],
        "matchMode": "any",
        "caseSensitive": false
      },
      {
        "id": "length-check",
        "name": "Summary length",
        "type": "NumericRange",
        "weight": 0.3,
        "target": "output",
        "valuePath": "length",
        "min": 50,
        "max": 500
      },
      {
        "id": "no-apologies",
        "name": "No apology language",
        "type": "RegexMatch",
        "weight": 0.3,
        "target": "output",
        "pattern": "I apologize|I\\'m sorry|unfortunately|I cannot",
        "flags": "i",
        "scoreOnMatch": 0,
        "scoreOnMiss": 1,
        "invert": false
      }
    ]
  }'

Response: 201 with profile object including id.

2. List Available Profiles

curl http://localhost:3001/api/scoring/profiles

3. Evaluate an Output

curl -X POST http://localhost:3001/api/scoring/evaluate \
  -H "Content-Type: application/json" \
  -d '{
    "profileId": "prof_abc123",
    "output": "Implemented the OAuth login feature using Passport.js. Added Google and GitHub providers. Tests pass.",
    "action": "task-completion",
    "agent": "TARS",
    "taskId": "task_20260321_abc"
  }'

Response:

{
  "id": "eval_xyz789",
  "profileId": "prof_abc123",
  "score": 0.87,
  "passed": true,
  "breakdown": [
    { "scorerId": "has-action-items", "score": 1.0, "weight": 0.4, "weighted": 0.4 },
    { "scorerId": "length-check", "score": 0.85, "weight": 0.3, "weighted": 0.255 },
    { "scorerId": "no-apologies", "score": 1.0, "weight": 0.3, "weighted": 0.3 }
  ],
  "agent": "TARS",
  "taskId": "task_20260321_abc",
  "createdAt": "2026-03-21T14:00:00.000Z"
}

4. Review Evaluation History

# All history
curl http://localhost:3001/api/scoring/history

# Filter by profile and agent
curl "http://localhost:3001/api/scoring/history?profileId=prof_abc123&agent=TARS&limit=20"

5. Update a Profile

curl -X PUT http://localhost:3001/api/scoring/profiles/prof_abc123 \
  -H "Content-Type: application/json" \
  -d '{
    "compositeMethod": "minimum"
  }'

6. Delete a Profile

Built-in profiles cannot be deleted.

curl -X DELETE http://localhost:3001/api/scoring/profiles/prof_abc123

Response: 204 No Content.


API Endpoints

Method Path Description
GET /api/scoring/profiles List all scoring profiles
POST /api/scoring/profiles Create a scoring profile
GET /api/scoring/profiles/:id Get a specific profile
PUT /api/scoring/profiles/:id Update a profile
DELETE /api/scoring/profiles/:id Delete a profile (non-built-in only)
POST /api/scoring/evaluate Evaluate an output against a profile
GET /api/scoring/history List evaluation history

Common Issues

Cannot delete built-in profile: Built-in profiles ship with VK and cannot be removed. Create a custom profile instead.

Score unexpectedly low: Check the breakdown field in the evaluation response — it shows which scorer penalized the score.

NumericRange scorer always returns 0: Ensure valuePath correctly addresses a numeric property of the output object. For string length, use length.

KeywordContains with matchMode: "all" is too strict: Switch to "any" if you want partial credit, or use partialCredit: true to award fractional scores.