dev.to

I Let AI Plan 170 Changes. It Made the Same 3 Mistakes Every Time.

AI에게 170개 변경 계획을 맡겨 봤습니다. 매번 똑같은 3가지 실수를 했습니다

170개 변경 계획을 대상으로 LLM 플래너와 비평기, 결정론적 검증 게이트를 결합한 PlannerCritic을 실험했습니다. 더 큰 모델도 구조적 결함을 고치지 못했으며, 의존성·순서·롤백을 코드로 검증하는 하이브리드 방식이 핵심 해법으로 나타났습니다.

AI 요약

작성자는 어떤 LLM이 계획을 가장 잘 세우는지 비교하는 대신, 계획 자체가 구조적으로 안전한지를 검증하기 위해 PlannerCritic이라는 작은 엔진을 만들었습니다. 이 엔진은 하나의 LLM이 구조화된 실행 계획을 작성하고, 결정론적 게이트(Deterministic Gate)가 하드 룰을 검사한 뒤, 또 다른 LLM이 게이트를 통과한 계획을 검토하는 구조입니다. 비평기(Critic)가 차단하면 플래너(Planner)가 계획을 수정하지만, 수정 횟수에는 상한을 두며 수렴하지 않으면 추측하지 않고 사람에게 에스컬레이션합니다. 작성자는 아이덴티티 관리(Identity Management), 멀티 에이전트 운영(Multi-agent Operations), SRE, 공급망 정책(Supply Chain Policy), FinOps 등 40개 도메인에서 실제 변경 계획 목표 170개를 실행했고, 전체 비용은 0.49달러였습니다.

■ 세 가지 구조적 결함

엄격한 목표에서 실패한 모든 사례는 무작위로 흩어지지 않고 세 가지 결함군으로 모였습니다. 첫째는 검증되지 않은 의존성(Unverified Dependencies)으로, 57개의 차단이 발생했습니다. 계획이 어떤 조건이 충족되어야 한다고 선언하면서도, 그 조건을 실제로 만족시키는 선행 작업을 포함하지 않은 경우입니다. 모델 서빙 마이그레이션 사례에서는 트래픽을 10%, 50% 단계로 전환한 뒤 안정성을 확인해야 했지만, 100% 트래픽 전환 작업이 앞선 단계의 정상 여부를 확인하지 않은 채 진행되도록 작성됐습니다.

둘째는 안전하지 않은 순서(Unsafe Sequencing)로 46개의 차단이 발생했습니다. 임베딩 인덱스 마이그레이션에서 품질 검증이 끝나기 전에 벡터 백필(Backfill)을 수행하도록 배치한 사례가 여기에 해당합니다. 필요한 선행 조건은 계획 안에 존재하더라도 실행 순서가 뒤집혀 있으면 안전한 계획으로 볼 수 없습니다. 셋째는 약한 롤백(Weak Rollback)으로 18개의 차단이 발생했습니다. 멀티테넌트 데이터베이스 분할 사례에서는 듀얼 라이트(Dual-write) 중 발생할 수 있는 데이터 불일치를 처리하지 않고 단일 쓰기 모드로만 되돌리는 롤백이 작성됐습니다. 세 결함은 총 132개 구체적 차단 중 121개를 차지했습니다. 작성자는 이를 ‘검증되지 않은 상태, 순서가 뒤섞인 작업, 복구할 수 없는 변경’으로 요약합니다.

■ 더 큰 모델로도 해결되지 않은 이유

작성자는 GPT-4o를 플래너로 사용하고 소형 모델을 비평기로 두는 구성과, GPT-4o를 플래너와 비평기 양쪽에 사용하는 구성을 모두 시험했습니다. 결과는 더 나은 문장과 표현을 제공했을 뿐, 같은 구조적 실수를 반복했습니다. 플래너는 필요한 작업을 알고 있었지만 의존성 그래프를 완성하거나 작업 순서를 강제하지 못했습니다. 따라서 문제는 모델의 파라미터 규모나 언어 표현 능력보다 다단계 계획 구조 자체에 있었습니다.

자기 수정 루프 역시 완전한 해결책이 되지 못했습니다. 비평기는 반복해서 같은 차단을 찾아냈지만, 플래너는 한 차단을 수정하면서 다른 차단을 만들곤 했습니다. 예를 들어 의존성 공백을 닫지 않은 채 작업 순서만 바꾸거나, 롤백을 추가하더라도 실제로 문제가 생기는 작업이 아닌 다른 작업에 붙였습니다. 중앙값 기준 두 번의 수정 이후에는 의미 있는 변화가 멈췄고, 수렴 감지기가 작동해 사람에게 넘겼습니다. 작성자는 이 동작이 엔진 설계대로 작동한 것이며, 플래너의 병목을 프롬프트만으로 해결할 수 없다고 설명합니다.

■ 결정론적 게이트가 담당한 역할

가장 효과가 컸던 변경은 플래너가 초안을 작성한 직후, 비평기가 실행되기 전에 동작하는 사전 조건 보완기(Precondition Closer)였습니다. 이 검증기는 모든 작업의 사전 조건이 앞선 작업에서 실제로 설정되는지를 검사합니다. 어떤 작업이 ‘replica_verified’를 요구한다면, 앞선 작업 중 해당 사실을 확립하는 작업이 반드시 존재해야 합니다. 이 한 번의 검증만으로도 132개 차단 중 64개, 즉 48%를 모델을 더 똑똑하게 만들지 않고 제거할 수 있다고 계산했습니다. 작성자는 이 수치를 실제 수정 후 측정값이 아니라 투영치(projection)라고 명시합니다.

나머지 문제에는 두 가지 결정론적 장치를 추가했습니다. 위상 자동 수정(Topological Auto-repair, #130)은 선행 조건이 먼저 실행되도록 작업을 재배치하고, 의존성 그래프가 실제로 순환할 때만 차단을 노출합니다. 진동 감지(Oscillation Detection, #152)는 플래너가 두 가지 작업 순서를 반복해서 오가는 상황을 찾아내고, 수정 상한까지 불필요하게 호출을 소비하지 않은 채 루프를 조기에 종료합니다. v0.2.1 실험에서는 과거라면 수정 상한까지 반복했을 5개의 엄격한 목표에서 진동 감지가 작동했습니다. 그 결과 지연 시간과 LLM 호출 수를 줄이고, 어차피 사람이 검토해야 할 계획을 더 빠르게 에스컬레이션할 수 있었습니다.

■ 릴리스별 검증 결과와 비용

v0.1.0에서는 157개 목표를 0.30달러에 실행했고, 현장 테스트에서 10개 문제를 찾았으며 코드 리뷰에서 찾은 문제는 없었습니다. 이 단계는 진단 단계였습니다. 전통적인 실패는 하나였지만, 65개 assertion 파일 중 57개가 잘못된 형식이어서 하네스(Harness)가 오류 없이 0/0을 반환하는 문제가 있었습니다. 시스템이 충돌하지 않고 침묵한 것이 오히려 문제였습니다.

v0.2.0에서는 170개 목표를 0.40달러에 실행했습니다. 현장 테스트에서 새로 발견된 문제는 없었고, 코드 리뷰에서 31개 문제가 발견됐습니다. v0.2.1에서는 동일하게 170개 목표를 0.49달러에 실행했으며, 현장 테스트와 코드 리뷰에서 각각 0개와 10개가 기록됐습니다. v0.2.1의 전체 스윕은 게시된 기준선과 결과를 비교하는 순수 회귀 게이트(Regression Gate)로 동작했고, 30개의 판정 변화가 모두 원인 추적 가능했으며 설명되지 않은 변화는 없었습니다. 비용은 0.30달러에서 0.49달러로 늘었지만, 실험의 역할은 버그를 처음 발견하는 것에서 버그가 없음을 입증하는 것으로 바뀌었습니다.

v0.2.1의 주요 측정값은 승인된 계획의 p50 지연 시간 13.86초, 에스컬레이션된 계획의 p50 지연 시간 27.82초, 목표당 평균 차단 수 2.58개, 100개 목표당 에스컬레이션 결정 58.0회, 목표당 평균 LLM 호출 1.4회, 해결까지 필요한 수정 횟수 중앙값 1.0회였습니다. 결정론적 사전 조건 보완과 위상 자동 수정이 순서 관련 작업을 LLM 호출 없이 처리하기 때문에, 목표의 중앙값은 한 번의 수정으로 해결됐습니다. 반면 에스컬레이션된 계획은 승인된 계획보다 약 두 배 오래 걸렸으며, 작성자는 불확실성이 큰 작업에 시스템 시간이 집중되는 형태라고 설명합니다.

■ 비결정적인 비평기와 안전 경계

동일한 경계 사례 집합을 실제 비평기 모델에 다섯 번 입력하자, 비평기의 판정과 설명은 매번 달라졌습니다. label_flip_rate는 1.000, evidence_drift_rate도 1.000이었습니다. 그러나 미리 심어 둔 결함이 자문(advisory) 수준으로 잘못 낮춰진 family_migration_rate는 0.000이었고, 결함 있는 계획에서 차단을 하나도 찾지 못한 underclaim_approvals도 0이었습니다. 즉 비평기는 완전히 결정적이지 않았지만, 결함을 놓치는 방향으로 작동하지는 않았습니다.

안전 계약은 비평기가 항상 같은 답을 내는 데 의존하지 않습니다. 반드시 잡아야 하는 문제는 결정론적 게이트가 소유하고, 비평기는 새로운 발견을 추가할 수 있지만 게이트가 만든 차단을 억제할 수 없도록 구성했습니다. 심각도 규칙 역시 코드로 강제해 과잉 주장 방향을 통제했습니다. 이런 방식으로 모델을 신뢰할 수 있게 만드는 대신, 의사결정을 내리는 안전 경계를 모델 외부에 배치했습니다.

■ 적대적 입력과 설계의 한계

작성자는 손으로 만든 적대적 목표 3개를 모두 차단했고, SWE-bench에서 파생한 보안 오라클(Security Oracle)은 결함이 있는 변형 35개를 모두 차단하면서 올바른 계획 7개는 모두 통과시켰습니다. 생성된 인젝션 트랩은 21개였고, 적대적 목표 8개는 모두 에스컬레이션됐습니다. 이 결과를 바탕으로 LLM을 신뢰할 수 있게 만드는 방식이 아니라, 안전 판정을 수행하는 부분을 코드로 분리하는 방식이 중요하다고 설명합니다.

작성자는 자신의 시스템이 의존성 그래프를 안정적으로 닫는 플래너를 제공하는 것은 아니며, 실패를 감지하고 사람에게 넘기는 엔진을 제공한다고 선을 긋습니다. 또한 발견한 실패 유형이 모든 도메인에 적용된다고 증명한 것은 아니며, ‘검증되지 않음·순서가 잘못됨·복구 불가능함’이 전체 결함 목록이라는 보장도 없다고 밝힙니다. 결정론적 수리 방식이 영구적인 해답인지, 명시적인 그래프 상태 표현을 가진 플래너 모델이 이 간극을 줄일 수 있는지는 아직 답하지 않은 질문으로 남겨 두었습니다. 결론적으로 이 실험은 다단계 작업을 계획하는 에이전트에서 작은 데모보다 실제 코퍼스와 결함 유형별 측정이 중요하며, 자기 수정 루프를 신뢰하기 전에 결정론적 검증을 추가해야 한다는 방향을 제시합니다.

원문: dev.to / 번역·요약: Trawling