채팅 기록에 실패한 코드 시도를 남기는 것이 코딩 에이전트에 미치는 영향: 오류 추적 제거(Error-Trace Pruning) vs. 누적
요약
본 벤치마크는 격리된 Proxmox VM 환경에서 AI 코딩 에이전트의 성능을 테스트하며, 실패한 코드 시도와 오류 스택 추적 기록을 대화 기록에 누적하는 방식(Mode A)과 이를 가지치기하고 구조화된 교훈만 남기는 방식(Mode B)을 비교했습니다. Mode B는 재시도 횟수를 줄이고 최종 입력 토큰을 크게 압축하여 효율성을 높이는 결과를 보여주었습니다.
핵심 포인트
- 실패 기록 누적은 LLM에게 '자기 조건화 편향'을 유발할 수 있습니다.
- 오류 추적 제거(Pruning)는 재시도 횟수를 줄이고 입력 토큰을 대폭 압축했습니다.
- 두 모드 모두 모든 숨겨진 테스트 케이스를 통과하는 성능을 보였습니다 (100%).
- 벤치마크는 Proxmox 격리 VM 환경에서 진행되었습니다.
💡 AI Labo Benchmark Series — Experiment
E19(41개 패턴 중 순위 #4)
본 게시물은 네트워크가 격리된 Proxmox VM 환경에서 숨겨진 20개 케이스의 채점 스위트(grading suite)를 대상으로 AI 코딩 에이전트 하네스 패턴을 테스트하는 경험적 벤치마크 시리즈의 일부입니다.
메타데이터 및 실험 식별자
- 실험 ID:
E19(백로그 후보C015) - 실행 ID:
e19-20261028-vm223-01 - 샌드박스 환경: Proxmox 격리 VM
VM223(ai-e19-223, 0 NICs,virtio-serialQGA relay,systemdUID 분리) - 모델:
gemini-3.8-flash(thinkingLevel: LOW) - 테스트 패턴: 컨텍스트 오염 방지 — "오류 추적 제거(Error-Trace Pruning) (실패 시도 롤백) vs. 누적된 실패 기록"
1. 요약 (TL;DR)
코딩 에이전트가 다중 파일 수정(multi-file fix)을 시도하고 첫 번째 패치가 테스트에 실패할 경우, 표준 에이전트 루프는 단순히 **실패한 코드 차이(failed code diff) (역할: "모델")**와 **상세 오류 스택 추적(verbose error stack trace) (역할: "사용자")**을 대화 기록(messages[])에 추가하고 LLM에게 다시 시도하도록 요청합니다.
이는 자기 조건화 편향 (Self-Conditioning Bias), 즉 Context Poisoning을 생성합니다. LLM은 컨텍스트 창에서 자신들이 이전에 생성한 코드에 강하게 고정됩니다. 에이전트는 모듈 간 아키텍처를 재고하기보다는, 오류 스택 추적이 턴(turn)마다 쌓이는 동안 실패했던 첫 번째 시도 위에 좁은 증분적 수정만을 계속해서 하게 됩니다.
대안인 **오류 추적 제거 (Error-Trace Pruning) (실패 시도 롤백)**을 테스트하기 위해, 우리는 격리된 Proxmox VM VM223 내에서 3개 모듈로 구성된 결제 정산 파이프라인(validator.py, settlement.py, statement.py)을 두 가지 모드에 걸쳐 벤치마크했습니다:
- Mode A (
AccumulatedFailedHistoryRunner): 재시도 과정 전반에 걸쳐 실패한 부분 패치와 전체 오류 스택 트레이스(Turn 1에서36,606 chars; Turn 2에서36,264 chars)를 대화 기록에 보존합니다. - Mode B (
PrunedFailedAttemptRunner): 테스트 실패 시 작업 공간을 즉시 되돌리고(git checkout),messages[]에서 실패한 모델 출력과 원시 스택 트레이스를 가지치기(prune)하며, 깨끗한 초기 프롬프트에 오직927-character(+392-token)의 구조화된 부정적 교훈만을 추가합니다.
주요 결과 (Key Result)
두 모드 모두 결국 모든 20 / 20 (100%) 숨겨진 테스트 케이스를 통과했지만, Mode B에서 실패한 턴을 가지치기함으로써 두 번째 실패 재시도(3 호출 → 2 호출)가 제거되었고, 최종 턴 입력 토큰이 -94.0% (38,134 → 2,301 tokens) 압축되었으며, 누적 입력 토큰을 -93.0% (59,944 → 4,210 tokens, 효율성 14.24배 증가) 절감했고, API 비용을 -80.3% ($0.0558 → $0.0110) 줄였으며, 처리 시간을 1.57x 더 빠르게 완료했습니다.
| 지표 (Metric) | Mode A: 누적 실패 기록 (AccumulatedHistory) | Mode B: 오류 스택 가지치기 (PrunedFailedAttempt) | 변화량 / 개선 정도 (Delta / Improvement) |
|---|---|---|---|
| 숨겨진 채점 세트 점수 (20 케이스) | 20 / 20 (100%) | 20 / 20 (100%) | 두 모드 모두 20개 케이스 통과 |
| ... |
2. 실험 아키텍처 및 롤백-가지치기 워크플로우 (Experiment Architecture & Rollback-Prune Workflow)
+-------------------------------------------------------------------------+
| Proxmox Isolated VM223 (0 NICs, virtio-serial QGA, systemd UID split) |
| 대상 작업: 3개 모듈 정산 파이프라인 버그 수정 (Target Task: 3-Module Settlement Pipeline Bugfix)
...
3. 턴별 토큰 진행 및 프롬프트 비교 (Turn-by-Turn Token Progression & Prompt Comparison)
3.1 턴별 토큰 및 비용 분석 (usage.json)
| Seq | Mode | Node ID | Input Tokens | Output Tokens | API Cost (micro-USD) | Action & Outcome |
|---|---|---|---|---|---|---|
0 | Mode A | accumulated_history_turn_1 | 1,898 | 497 | 3,288 | attempt_patch (validator.py만 ➔ 실패; 기록에 유지) |
| ... |
3.2 Mode A가 기록으로 남긴 것 (input-01.json / input-02.json)
Mode A는 Turn 1에서 validator.py만 패치한 후에도, 필터링되지 않은(unpruned) diff 프레임과 로컬 변수 덤프(MSG[2]) 36,606 문자를 추가하고, 또 다른 실패한 부분적 시도(MSG[3]), 그리고 추적 기록(traces) 36,264 문자를 남겼다 (MSG[4]):
=== 실패한 시도 #1 전체 diff 및 트레이스백 덤프 (필터링되지 않음) ===
Status: FAILED (3 invariants broken)
[FAILED_PATCH_CONTEXT_FRAME_001] attempt=1 rejected_hunk_sha256=0000...0001 locals={'merchant_id': 'M-1', 'currency': 'USD', 'bps': 300, 'tier': 'ENTERPRISE'}
...
3.3 Mode B가 필터링 후 주입한 것 (input-04.json)
Mode B는 Turn 1이 실패하자마자 error_trace_pruner_v1을 사용하여 작업 공간(workspace)을 복원하고, messages[]에서 MSG[1] (실패한 부분적 패치)과 MSG[2] (36,606 문자 추적 기록)를 삭제했다. 그리고 원래 프롬프트에 이 927자 (+392 토큰)의 구조화된 교훈만을 추가했다:
{
"concise_lessons_learned": [
"Lesson 1 (validator.py): Partial patch failed because `settlement.py` and `statement.py` were not updated together; in `validator.py` use `ALLOWED_CURRENCIES=('USD','EUR','JPY')`, reject empty list & `bool`, allow `unit_cents>=0` & `0<=chargeback_bps<=1000`, and return a new 5-key dict.",
...
깨끗하게 정리되어 실패한 첫 시도에서 확보된 2,301 토큰의 컨텍스트를 바탕으로, Mode B는 Turn 2에서 즉시 완전하고 통합된 3개 모듈 패치를 생성했다.
4. 실질적인 구현 레시피: 20줄 되돌리기 및 필터링 루프
Python에서 사용자 지정 코딩 에이전트 루프를 유지하는 경우, 실패한 턴을 messages에 추가하는 대신 git checkout과 lesson_log 리스트를 결합하여 20줄 만에 오류 추적 제거(Error-Trace Pruning)를 구현할 수 있습니다:
import subprocess
def run_step_with_error_pruning(messages: list[dict], lesson_log: list[str], call_llm, run_tests) -> bool:
...
🔗 시리즈 계속 읽기
- 🚀 Master Benchmark Hub (모든 41가지 패턴 순위): Isolated VM에서 벤치마킹한 41가지 AI 에이전트 하네스 패턴: 정확도를 잃지 않으면서 토큰을 90% 절감하는 방법
- 🛡️ 방법론 및 샌드박스 아키텍처: 평가 부정행위나 API 키 누출 없이 AI 에이전트를 벤치마킹하는 방법: Proxmox 및 systemd 샌드박스 설계
- 🥇 순위 #1 심층 분석 (
E20): 코딩 에이전트가 같은 랙을 두 번 밟는 것을 막으세요: 콜드 스타트 탐색 대 5개 항목의MEMORY.md - 🥈 순위 #2 심층 분석 (
E21): 코딩 에이전트에 전체 의존성 파일을 공급하는 것이 정확도를 떨어뜨리는 이유: 전체 소스 대 Tree-sitter 인터페이스 스켈레톤 - 🥉 순위 #3 심층 분석 (
E16): 원시 Pytest 로그를 코딩 에이전트에 덤프하는 것을 멈추세요: 구조화된 JSON 테스트 필터가 입력 토큰을 94.1% 절감하는 방법
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기