콘텐츠로 이동

A/B 테스트와 반복 개선

Harness를 “설정 파일” 처럼 다루면 개선이 느려집니다. Harness는 소프트웨어이며, 버전 관리, 테스트, 배포 주기 가 필요합니다. Harness 변경 하나가 전체 에이전트 성능을 수 십 퍼센트 바꿀 수 있기 때문입니다.

Manus(AI 에이전트 플랫폼)는 harness 최적화에 SGD(Stochastic Gradient Descent) 에 비유한 접근법을 사용합니다. 수학적 SGD가 아니라, 철학적 유사성을 차용한 것입니다.

Manus SGD 접근법:
1. 현재 harness로 벤치마크 실행 → 기준 점수 측정
2. 실패한 케이스를 수동으로 분석 → 개선 가설 도출
3. 한 번에 하나의 harness 변수만 변경
4. 동일 벤치마크 재실행 → 점수 변화 측정
5. 개선되면 유지, 악화되면 롤백
6. 1로 돌아가 반복

핵심 원칙은 한 번에 하나의 변수만 변경 하는 것입니다. 여러 변경을 동시에 적용하면 어떤 변경이 성능을 개선하고 악화시켰는지 알 수 없습니다.

interface HarnessVersion {
id: string; // 예: 'v2.3.1'
description: string; // 이 버전의 변경 내용
config: HarnessConfig;
createdAt: string;
benchmarkResults?: BenchmarkResult[];
}
interface HarnessConfig {
systemPromptVersion: string; // 프롬프트 파일 해시
maxTurns: number;
compactionThreshold: number;
allowedTools: string[];
modelRoles: ModelRoles;
reminderRules: ReminderRule[];
fuzzyMatchPasses: number;
}
class HarnessVersionStore {
async save(version: HarnessVersion): Promise<void> {
const path = `.agent/versions/${version.id}.json`;
await fs.writeFile(path, JSON.stringify(version, null, 2), 'utf-8');
}
async load(id: string): Promise<HarnessVersion> {
const path = `.agent/versions/${id}.json`;
const raw = await fs.readFile(path, 'utf-8');
return JSON.parse(raw);
}
async list(): Promise<Pick<HarnessVersion, 'id' | 'description' | 'createdAt'>[]> {
// ...
}
}
interface Experiment {
id: string;
hypothesis: string; // "컨텍스트 리마인더를 5턴마다 추가하면 성공률이 높아진다"
controlVersion: string; // 기준 harness 버전 ID
treatmentVersion: string; // 실험 harness 버전 ID
taskSample: string[]; // 실험에 사용할 작업 ID 목록
primaryMetric: keyof HarnessMetrics; // 주요 측정 지표
minSampleSize: number; // 통계적 유의성을 위한 최소 샘플 수
}
async function runExperiment(experiment: Experiment): Promise<ExperimentResult> {
const [controlHarness, treatmentHarness] = await Promise.all([
buildHarness(experiment.controlVersion),
buildHarness(experiment.treatmentVersion),
]);
const controlMetrics = new MetricsCollector();
const treatmentMetrics = new MetricsCollector();
// 순서 편향 방지: 인터리빙 실행
for (let i = 0; i < experiment.taskSample.length; i++) {
const task = await loadTask(experiment.taskSample[i]);
if (i % 2 === 0) {
await runAndRecord(task, controlHarness, controlMetrics);
await runAndRecord(task, treatmentHarness, treatmentMetrics);
} else {
await runAndRecord(task, treatmentHarness, treatmentMetrics);
await runAndRecord(task, controlHarness, controlMetrics);
}
}
const control = controlMetrics.summarize();
const treatment = treatmentMetrics.summarize();
const diff = treatment[experiment.primaryMetric] - control[experiment.primaryMetric];
return {
experimentId: experiment.id,
hypothesis: experiment.hypothesis,
control,
treatment,
primaryMetricDiff: diff,
recommendation: diff > 0.02 ? 'adopt' : diff < -0.02 ? 'reject' : 'inconclusive',
};
}
개선 주기 (2주 스프린트 권장):
Week 1:
Day 1-2: 트레이스 데이터 분석 → 실패 패턴 발견
Day 3-4: 개선 가설 수립 → Harness 변경 구현
Day 5: 50개 샘플 빠른 실험 실행
Week 2:
Day 1: 실험 결과 분석 → 채택/거부 결정
Day 2-3: 채택된 경우: 200개 샘플 검증 실험
Day 4: 프로덕션 배포 또는 다음 가설로 전환
Day 5: 회고: 무엇을 배웠는가?

트레이스 데이터에서 개선 기회를 찾는 체계적 방법입니다.

async function analyzeFailures(traces: TraceEvent[][]): Promise<ImprovementOpportunity[]> {
const opportunities: ImprovementOpportunity[] = [];
// 패턴 1: 특정 툴에서 반복 실패
const toolFailures = groupBy(
traces.flatMap(t => t.filter(e => e.type === 'tool_result' && !e.success)),
e => (e as ToolResultEvent).toolName
);
for (const [toolName, failures] of Object.entries(toolFailures)) {
if (failures.length > 5) {
opportunities.push({
type: 'tool_reliability',
description: `${toolName} 툴이 ${failures.length}번 실패함`,
hypothesis: `${toolName} 의 에러 메시지를 더 명확하게 만들면 재시도 성공률이 높아진다`,
priority: failures.length,
});
}
}
// 패턴 2: maxTurns 직전에 실패하는 작업
const nearMaxTurns = traces.filter(t => {
const end = t.find(e => e.type === 'agent_end') as AgentEndEvent | undefined;
return end && !end.success && end.turns >= MAX_TURNS * 0.9;
});
if (nearMaxTurns.length > traces.length * 0.1) {
opportunities.push({
type: 'max_turns',
description: `${nearMaxTurns.length}개 작업이 maxTurns 근처에서 실패`,
hypothesis: `maxTurns를 현재 값의 1.5배로 늘리면 성공률이 개선된다`,
priority: nearMaxTurns.length,
});
}
return opportunities.sort((a, b) => b.priority - a.priority);
}
.agent/
versions/
v2.0.0.json # 기준 harness
v2.1.0.json # 컨텍스트 압축 임계값 조정
v2.2.0.json # 퍼지 매칭 9-pass 도입
v2.3.0.json # 이벤트 리마인더 추가
experiments/
exp-001.json # v2.0 vs v2.1: 성공률 +3.2pp
exp-002.json # v2.1 vs v2.2: 성공률 +4.8pp
exp-003.json # v2.2 vs v2.3: 성공률 +6.0pp (채택)
exp-004.json # v2.3 vs v2.3+리마인더: +1.1pp (inconclusive)

버전과 실험 이력을 관리하면 “왜 이 설계를 선택했는가” 를 나중에 추적할 수 있습니다. 팀 협업에서도 동일한 실험을 반복하는 낭비를 줄입니다.