콘텐츠로 이동

Harness 성능 측정

Harness가 성능을 결정한다는 증거

섹션 제목: “Harness가 성능을 결정한다는 증거”

가장 인상적인 증거는 두 가지 사례에서 나왔습니다.

첫 번째 사례: SWE-bench 리더보드에서 동일한 기반 모델을 사용하더라도 harness 설계에 따라 점수가 30~40%p 이상 차이나는 것이 반복적으로 관찰됩니다. 이 격차의 원인은 순전히 harness입니다.

두 번째 사례: LangChain은 Terminal Bench 2.0에서 52.8% → 66.5% 향상을 달성했습니다. 모델은 바꾸지 않고 harness만 수정했습니다. 순위는 Top 30에서 Top 5로 올랐습니다.

이 수치들이 의미하는 바는 명확합니다. 모델 업그레이드보다 harness 개선이 더 빠르고 저렴하게 성능을 높일 수 있습니다.

interface HarnessMetrics {
// 효과성
successRate: number; // 작업 성공률 (0~1)
partialSuccessRate: number; // 부분 성공률 (보조 지표)
// 효율성
avgCostPerTask: number; // 작업당 평균 비용 (USD)
avgTokensPerTask: number; // 작업당 평균 토큰 수
avgLatencyMs: number; // 평균 완료 시간 (ms)
// 안정성
retryRate: number; // 재시도 발생률 (0~1)
errorRate: number; // 복구 불가 오류율 (0~1)
maxTurnsHitRate: number; // maxTurns 초과 비율 (0~1)
// 품질
avgTurnsPerTask: number; // 작업당 평균 턴 수
compactionRate: number; // 컨텍스트 압축 발생률
}
class MetricsCollector {
private records: TaskRecord[] = [];
startTask(taskId: string, task: string): TaskTracker {
const startTime = Date.now();
const startTokens = 0;
return {
complete: (result: AgentResult, tokensUsed: number, costUsd: number) => {
this.records.push({
taskId,
task,
success: result.success,
turns: result.turns,
tokensUsed,
costUsd,
latencyMs: Date.now() - startTime,
hitMaxTurns: result.turns >= MAX_TURNS,
compacted: result.wasCompacted ?? false,
});
},
};
}
summarize(): HarnessMetrics {
const n = this.records.length;
if (n === 0) throw new Error('측정 데이터 없음');
const sum = <K extends keyof TaskRecord>(key: K): number =>
this.records.reduce((acc, r) => acc + Number(r[key]), 0);
return {
successRate: sum('success') / n,
partialSuccessRate: 0, // 별도 측정 필요
avgCostPerTask: sum('costUsd') / n,
avgTokensPerTask: sum('tokensUsed') / n,
avgLatencyMs: sum('latencyMs') / n,
retryRate: this.records.filter(r => r.retried).length / n,
errorRate: this.records.filter(r => !r.success && !r.hitMaxTurns).length / n,
maxTurnsHitRate: sum('hitMaxTurns') / n,
avgTurnsPerTask: sum('turns') / n,
compactionRate: sum('compacted') / n,
};
}
}

같은 작업셋을 두 가지 harness로 실행해 차이를 측정합니다.

실험 설계:
┌──────────────────┬────────────────────┐
│ 변수 │ 값 │
├──────────────────┼────────────────────┤
│ 작업셋 │ 동일 (예: SWE-bench Verified 100개) │
│ 기반 모델 │ 동일 (claude-sonnet-4-5) │
│ 온도 │ 동일 (0) │
│ 변경 요소 │ Harness A vs B │
└──────────────────┴────────────────────┘
async function compareHarnesses(
tasks: Task[],
harnessA: MainAgent,
harnessB: MainAgent,
): Promise<ComparisonResult> {
const metricsA = new MetricsCollector();
const metricsB = new MetricsCollector();
// 동일 순서로 실행 (순서 편향 방지를 위해 무작위화 고려)
for (const task of tasks) {
const trackerA = metricsA.startTask(task.id, task.description);
const resultA = await harnessA.run(task.description);
trackerA.complete(resultA, resultA.tokensUsed, resultA.costUsd);
const trackerB = metricsB.startTask(task.id, task.description);
const resultB = await harnessB.run(task.description);
trackerB.complete(resultB, resultB.tokensUsed, resultB.costUsd);
}
return {
a: metricsA.summarize(),
b: metricsB.summarize(),
successRateDiff: metricsB.summarize().successRate - metricsA.summarize().successRate,
costDiff: metricsB.summarize().avgCostPerTask - metricsA.summarize().avgCostPerTask,
};
}

Harness 변경이 지표에 미치는 영향 패턴

섹션 제목: “Harness 변경이 지표에 미치는 영향 패턴”
Harness 변경예상 영향 지표방향
시스템 프롬프트 명확화successRate, avgTurnsPerTask↑, ↓
컨텍스트 압축 활성화maxTurnsHitRate, avgCostPerTask↓, ↓
이벤트 리마인더 추가successRate (장기 작업)
퍼지 편집 매칭 개선errorRate (파일 편집 작업)
fallback 모델 추가errorRate, retryRate↓, ↓
maxTurns 증가successRate, avgCostPerTask↑, ↑
SubAgentSpec allowedTools 정밀화successRate, avgTurnsPerTask↑, ↓
Harness v2.3 vs v2.2 비교 (SWE-bench Verified 100개 샘플)
═══════════════════════════════════════════════════════
지표 v2.2 v2.3 변화
─────────────────────────────────────────────────────
성공률 61.0% 67.0% +6.0pp ✓
평균 비용/작업 $0.42 $0.38 -$0.04 ✓
평균 레이턴시 142s 128s -14s ✓
재시도율 8.3% 5.1% -3.2pp ✓
maxTurns 초과율 12.0% 9.0% -3.0pp ✓
평균 턴 수 18.2 15.7 -2.5 ✓
개선 원인: 이벤트 리마인더 + 퍼지 편집 매칭 개선