JamJet

평가 하네스

JamJet eval로 출력 품질을 점수화하고, 회귀 테스트를 실행하며, CI를 제어하세요.

Eval Harness

JamJet은 출력 품질을 측정하고 보장하기 위한 내장 평가 시스템을 제공합니다 — 빠른 임시 검증부터 전체 CI 회귀 테스트 스위트까지 지원합니다.

평가가 중요한 이유

LLM 출력은 확률적입니다. 동일한 워크플로우가 대부분의 입력에서는 훌륭한 결과를 생성하지만 엣지 케이스에서는 실패할 수 있습니다. JamJet eval은 다음을 제공합니다:

  • LLM-as-judge — 별도의 모델이 평가 기준에 따라 출력 품질을 점수화
  • Assertions — 구조적 검사(길이, 필드 존재 여부, 형식)
  • 지연 시간 + 비용 게이트 — CI에서 SLA 적용
  • 회귀 테스트 스위트 — 프로덕션 배포 전 회귀 감지

인라인 평가(워크플로우)

워크플로우에 eval 노드를 추가하여 출력을 점수화하고 실패 시 재시도합니다:

nodes:
  check-quality:
    type: eval
    scorers:
      - type: llm_judge
        rubric: "답변이 정확하고 완전하며 200단어 이하인가?"
        min_score: 4          # 1-5 척도
        model: claude-haiku-4-5-20251001
      - type: assertion
        check: "len(output.answer) > 0"
      - type: latency
        max_ms: 5000
    on_fail: retry_with_feedback
    max_retries: 2
    next: end

on_fail: retry_with_feedback로 설정하면, 평가자의 피드백이 자동으로 다음 모델 호출의 프롬프트에 주입되어 자체 개선 루프가 생성됩니다.

데이터셋 평가(CLI)

배치 평가를 위해 JSONL 데이터셋을 생성합니다:

{"id": "q1", "input": {"query": "JamJet이 무엇인가요?"}, "expected": {"topic": "runtime"}}
{"id": "q2", "input": {"query": "어떻게 설치하나요?"}, "expected": {"topic": "install"}}
{"id": "q3", "input": {"query": "어떤 모델을 지원하나요?"}, "expected": {}}

실행:

jamjet eval run dataset.jsonl \
  --workflow workflow.yaml \
  --rubric "답변이 정확하고 유용한가?" \
  --min-score 4 \
  --assert "len(output.answer) >= 50" \
  --latency-ms 3000 \
  --concurrency 10 \
  --fail-below 0.9
Running 50 eval rows... ████████████████████ 50/50

┌─────────┬────────────┬───────┬──────────┬────────────────────┐
│ Row     │ Status     │ Score │ Latency  │ Note               │
├─────────┼────────────┼───────┼──────────┼────────────────────┤
│ q1      │ ✓ passed   │ 4.8   │  512ms   │                    │
│ q2      │ ✓ passed   │ 4.2   │  623ms   │                    │
│ q3      │ ✗ failed   │ 2.1   │  891ms   │ Answer too vague   │
└─────────┴────────────┴───────┴──────────┴────────────────────┘

Results: 49/50 passed (98.0%) — above threshold 90.0% ✓

종료 코드는 통과 시 0, 실패 시 1 — CI에서 바로 사용 가능합니다.

CI 통합

GitHub Actions 워크플로우에 추가하세요:

- name: Run eval suite
  run: |
    jamjet eval run evals/core.jsonl \
      --workflow workflow.yaml \
      --rubric "Is the answer accurate and complete?" \
      --fail-below 0.85
  env:
    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
    JAMJET_URL: http://localhost:7700

tip: CI 작업에서 평가를 실행하기 전에 JamJet 개발 런타임을 시작하세요: jamjet dev & 실행 후 sleep 2로 초기화 대기.

Python 평가 API

커스텀 평가 로직을 위해 Python 평가 패키지를 사용하세요:

import asyncio
from jamjet.eval import EvalDataset, EvalRunner
from jamjet.eval.scorers import LlmJudgeScorer, AssertionScorer, LatencyScorer

dataset = EvalDataset.from_file("evals/core.jsonl")

runner = EvalRunner(
    workflow_path="workflow.yaml",
    runtime_url="http://localhost:7700",
    scorers=[
        LlmJudgeScorer(
            rubric="Is the answer accurate and helpful?",
            model="claude-haiku-4-5-20251001",
            min_score=4,
        ),
        AssertionScorer(check="len(output['answer']) >= 50"),
        LatencyScorer(max_ms=3000),
    ],
    concurrency=10,
)

results = asyncio.run(runner.run(dataset))
runner.print_summary(results)

# 전체 통과율 확인

pass_rate = sum(1 for r in results if r.passed) / len(results)
assert pass_rate >= 0.9, f"Eval failed: {pass_rate:.0%} pass rate"

커스텀 스코어러

BaseScorer를 상속하여 직접 스코어러를 작성하세요:

from jamjet.eval.scorers import BaseScorer, ScorerResult

class ExactMatchScorer(BaseScorer):
    async def score(
        self,
        output: dict,
        *,
        expected: dict,
        duration_ms: float,
        cost_usd: float,
        input_data: dict,
    ) -> ScorerResult:
        answer = output.get("answer", "")
        expected_answer = expected.get("answer", "")
        passed = answer.strip().lower() == expected_answer.strip().lower()

        return ScorerResult(
            scorer="exact_match",
            passed=passed,
            score=1.0 if passed else 0.0,
            message=None if passed else f"Expected '{expected_answer}', got '{answer}'",
        )

스코어러 유형

LLM 평가자

별도 모델을 사용하여 1–5점 척도로 출력을 평가합니다:

- type: llm_judge
  rubric: "Is the answer accurate, complete, and under 200 words?"
  min_score: 4           # 1–5 (5 = 완벽)
  model: claude-haiku-4-5-20251001

평가자는 입력, 출력, 평가 기준을 받아 score (1–5)와 reason을 포함한 JSON 객체를 반환합니다.

어서션

outputexpected에 대해 평가되는 Python 표현식:

- type: assertion
  check: "len(output.answer) > 0"

# 다중 어서션

- type: assertion
  check: "'sources' in output"

- type: assertion
  check: "output.confidence >= 0.7"

지연 시간

실행이 시간 제한 내에 완료되었는지 확인합니다:

- type: latency
  max_ms: 3000

비용

실행이 비용 제한 내에 유지되었는지 확인합니다:

- type: cost
  max_usd: 0.05

출력 형식

추가 분석을 위해 결과를 파일로 저장합니다:

jamjet eval run dataset.jsonl \
  --workflow workflow.yaml \
  --output results.json
{
  "summary": {
    "total": 50,
    "passed": 47,
    "failed": 3,
    "pass_rate": 0.94,
    "avg_latency_ms": 612,
    "avg_cost_usd": 0.0003
  },
  "rows": [
    {
      "id": "q1",
      "passed": true,
      "scorers": [
        { "scorer": "llm_judge", "passed": true, "score": 4.8 }
      ],
      "duration_ms": 512,
      "cost_usd": 0.00023
    }
  ]
}

On this page