빠른 LLM이 가르쳐준 가정(Assumptions)에 관한 교훈
요약
빠른 LLM을 활용한 복잡한 작업 수행 시, 명시적인 '산출물(deliverables)'을 계획에 포함하는 것이 모델의 성능과 검증 가능성을 어떻게 변화시키는지 분석합니다. 산출물은 단순히 정확도를 높이는 것이 아니라, 작업의 검토 및 검증 가능성을 높이는 도구로 작용합니다.
핵심 포인트
- 명시적 산출물은 모델의 정확도보다 검토 및 검증 가능성을 높이는 데 효과적임
- 약한 모델에게 산출물은 성능을 보완하는 버팀목 역할을 수행함
- 강력한 모델에서도 산출물은 결합된 작업의 경계를 명확히 하는 도구로 작용함
- 계약(Contract)을 통해 에이전트의 문서화 및 증거 남기기 수준을 조절 가능함
우리의 대부분의 도구는 한 종류의 오류를 위해 구축되었습니다. 하지만 진짜 비용이 많이 드는 것은 다른 종류의 오류입니다.
저렴하고 빠른 모델이 결합된(coupled) 작업을 한 시간 넘게 수행하면서도 무너지지 않고 작동했는데, 이는 제가 이 모델들에 대해 알고 있던 지식과 일치하지 않았습니다. 이 모델들은 긴 작업에서 게으른 경향이 있으며, 그 평판은 근거가 있습니다. 한 시간짜리 작업을 맡기면 절반만 수행하거나, 흐름을 놓치거나(drifts), 조기에 승리를 선언하고는 완료된 것처럼 보이지만 실제로는 그렇지 않은 결과를 남깁니다. 이번에는 제가 이미 사용 중인 동일한 규율 있는 워크플로우(workflow) 내에서 실행되었음에도 평소와 같은 일이 일어나지 않았습니다. 그리고 그 작업은 쉬운 것도 아니었습니다. 인터페이스까지 전체 파이프라인을 관통해야 하는 진행 상황 콜백(progress callback)이었는데, 이는 콜백이 처음부터 끝까지 모든 것을 가로질러야만 진행 상황을 보여주는 것이 작동하기 때문에 독립적인 조각으로 나눌 수 없는 종류의 작업이었습니다. 제가 이 모델들이 포기하는 것을 지켜봤던 때와 유일한 차이점은, 계획에 '산출물(deliverables)' 목록이 추가되었다는 점이었습니다. 즉, 작업이 완료될 때까지 반드시 존재해야 하는 구체적인 상태(concrete states)들 말입니다.
쉽게 내릴 수 있는 추론은 약한 모델에는 목록이 필요하다는 것이었습니다. 저는 어떤 의구심 때문이라기보다, 확인하지 않은 설명을 그대로 두지 않는 습관에 따라 누군가 명시적인 산출물(explicit deliverables)의 효과를 이미 측정했는지 찾아보았습니다. 그리고 그 검색 과정이 저의 설명들을 하나씩 무너뜨리기 시작했습니다.
가장 먼저 무너진 것은 이 이득이 정확성(correctness)에 있다는 생각이었습니다. 위임 계약(delegation contracts)에 관한 Vincent Schmalbach의 연구에 따르면, 작고 잘 정의된 작업에서는 정확성이 포화 상태에 이릅니다. 즉, 계약이 있든 없든 에이전트(agent)는 똑같이 정확하게 수행했습니다. 계약이 변화시킨 것은 검토 가능성(reviewability)이었습니다. 에이전트들은 자신이 수행한 내용을 문서화하고 증거를 남기기 시작했으며, 이는 오직 계약이 요구할 때만 수행되었습니다. 증거의 양은 작업 자체에 무엇이 필요한지와 상관없이 계약이 요구하는 수준에 맞춰 확장되었습니다. 산출물(deliverables)의 보상은 검증 가능성(verifiability)에 있었으며, 저는 검증 가능성을 마치 정확성과 같은 것인 양 혼동하고 있었습니다.
그 시점까지 정확히 동일한 것을 예측했던 두 가지 설명 사이에는 여전히 간극이 존재했습니다. "산출물(Deliverables)은 약한 모델을 위한 버팀목(crutch)이다"라는 설명과 "산출물은 결합된 작업(coupled work)을 위한 도구이다"라는 설명은, 모델이 약하고 작업이 결합되어 있을 때는 동일한 의미를 갖습니다. 왜냐하면 두 설명 모두 그 상황에서 산출물이 도움이 된다는 점에 동의하기 때문입니다. 이 둘을 구분할 수 있는 사례는 그 반대의 경우, 즉 동일하게 결합된 작업에서 강력한 모델(strong model)을 사용하는 경우입니다. 만약 산출물이 약함을 보완하기 위한 버팀목이라면, 강력한 모델은 그것을 필요로 하지 않아야 합니다. 만약 그것이 결합을 위한 도구라면, 강력한 모델 역시 동일한 고통을 겪어야 합니다. 단지 더 나중에, 더 높은 비용을 치를 뿐입니다. 왜냐하면 강력한 모델은 과정 중에 더 잘 기록(document)하긴 하지만, 단지 더 똑똑하다는 이유만으로 실제 경계(boundary)를 더 정확하게 깎아내지는 않기 때문입니다.
두 번째로 무너진 추론은 산출물이 약한 모델을 위한 버팀목이라는 것이었습니다. 이 효과는 두 단계(tiers) 모두에서 나타나지만, 강력한 단계에서는 그 크기가 줄어들 뿐입니다. 그 이유는 계약(contract)이 강력한 모델이 이미 스스로 수행하는 경향이 있는 보고 규율(reporting discipline)을 수동으로 코딩(hand-codes)하기 때문입니다. 제 직관에 따르면, 강력한 모델은 계약을 덜 필요로 하지만, 그 이유는 잘못되었습니다. 모델이 더 똑똑하고 더 많은 것을 맞히기 때문에 덜 필요로 하는 것이 아닙니다. 모델이 이미 자신이 무엇을 했는지 기록(document)하고 있기 때문에 덜 필요로 하는 것입니다. 양쪽 모두 여전히 검토 가능성(reviewability)에 관한 문제였으며, 정확성(correctness)은 결코 그 논의에 포함된 적이 없었습니다.
두 가지 가정(assumptions)이 모두 무너진 상황에서 남은 것은 논문이 답하지 못한 질문이었습니다. 왜냐하면 그것은 논문이 측정한 대상이 아니었기 때문입니다. 논문의 작업(tasks)은 그 자체로 정확성(correctness)이 포화되는 작은 규모였던 반면, 전체 파이프라인을 가로지르는 저의 콜백(callback)은 그렇지 않았습니다. 결합된 작업(coupled work)에서 계획(plan)과 산출물 목록(deliverables list)은 서로 다른 역할을 수행하며, 작업이 중간에 잘못되었을 때 살아남는 것은 오직 하나뿐입니다. 계획은 시작할 때 추측한 분해(decomposition)를 바탕으로 구축된 단계들의 시퀀스(sequence)이며, 작업이 크고 결합되어 있을 때 그 분해는 바로 틀릴 수 있는 부분이 되는 경향이 있습니다. 즉, 시스템에는 존재하지 않는 경계(boundary)를 당신이 설정하면, 모델은 규율 있게 그 계획을 따르며 정확히 '잘못된 것'을 만들어냅니다. 반면 산출물 목록은 다른 수준에서 존재합니다. 그것은 작업이 끝났을 때 시스템이 도달해야 하는 상태를 설명합니다. 콜백이 엔드포인트(endpoint)에 도달하는 것, 기존 인터페이스가 여전히 작동하는 것, 테스트가 전환(transition)을 커버하는 것, 이 모든 것이 동시에 유지되는 상태 말입니다. 만약 모델이 경계를 잘못 설정하여 제가 전혀 예상하지 못한 경로로 작업을 재수행한다면, 산출물은 변하지 않습니다. 왜냐하면 산출물은 경로에 대해 말한 적이 없기 때문입니다. 계획은 폐기 가능한 것이 됩니다. 결합된 작업에서 경로는 추측일 뿐이며, 목적지만이 당신이 실제로 아는 유일한 것입니다.
각 조각을 별도의 하위 에이전트(subagent)에게 전달하는 SDD 프레임워크들은 다른 각도에서 이 문제에 접근하지만, 격리(isolation)는 부분 간의 경계가 이미 존재할 때만 도움이 됩니다. 경계를 설정하는 것이 어려운 부분일 때, 각 조각은 자신의 영역 안에서는 결점 없이 완벽하게 나오지만 시스템 전체 관점에서는 틀리게 됩니다.
그리고 이 주의 사항은 구현 세부 사항(implementation detail)이 아니라, 바로 핵심입니다. 실제 소프트웨어 개발은 거의 항상 작고 격리된 단위에 관한 것이 아니었습니다. 모듈(Modules), 인터페이스(interfaces), 경계가 있는 컨텍스트(bounded contexts): 이 모든 것은 경계가 허용하는 것보다 내부적으로 더 결합되어 있는 시스템에서 경계를 꾸며낼 수 있다는 도박입니다. 이는 엔지니어링이 수십 년 동안 걸어온 도박입니다. 왜냐하면 그 대안인, 매번 전체 시스템을 머릿속에 담아두는 방식은 그 누구에게도 확장 가능(scale)하지 않기 때문입니다.
그렇다면 왜 LLM에게는 이것이 작동할까요? 서브에이전트(subagent)를 격리하는 것은 사람이 아닌 AI가 수행할 뿐, 기존의 똑같은 도박입니다. 그리고 그 도박이 성공하지 못할 때 — 즉, 실제 경계(boundary)가 그려진 경계와 일치하지 않을 때 — 누가 그 경계를 나누었는지는 중요하지 않습니다. 오류는 정확히 아무도 보지 않는 곳에 존재하기 때문입니다. 모두가 각자의 조각만을 보고 있었기 때문입니다.
하나의 작업에는 두 종류의 오류가 섞여 있습니다.
실행 오류 (execution error) — 잘못 찍힌 쉼표, 오프 바이 원 (off-by-one), 잊어버린 엣지 케이스 (edge case) 등 — 는 큰 소란 없이 구조에 의해 해결됩니다. 테스트가 잡아내고, 린팅 (linting)이 잡아내며, 리뷰가 잡아냅니다. 더 많은 규율을 투입할수록 이러한 오류는 덜 나타납니다. 반면 가정 오류 (assumption error)는 전혀 다른 차원의 문제입니다. 잘못된 위치에 설정된 결합 경계 (coupling boundary), 수행해야 할 작업에 대한 왜곡된 해석 같은 것들입니다. 프로세스(process)는 이 오류 또한 줄여주지만, 리뷰어들이 동일한 사각지대를 공유하지 않게 되는 지점까지만 유효합니다. 그리고 모두가 함께 잘못 가정하고 있는 바로 그 지점은, 그 누구도 잡아내지 못하는 지점이 됩니다. 두 오류는 동일한 작업 내에 공존하며, 실질적인 차이는 한계치(ceiling)에 있습니다. 실행 오류의 경우 프로세스를 늘릴수록 계속 도움이 되지만, 가정 오류의 경우 프로세스는 조기에 정체됩니다.
그리고 가정 오류가 고집스러운 데에는 우아한 해결책이 없는 이유가 있습니다. 잘못된 가정을 잡아낼 수 있는 것은 그것이 맞는지에 대한 인간의 판단 (human judgment)인데, 그 판단이야말로 애초에 오류를 통과시켜 버린 바로 그 실패의 원인이기 때문입니다. 잘못된 가정을 잡아내기 위해 리뷰를 할 때, 저는 이전에 오류를 놓치게 만들었던 것과 동일한 판단 과정을 한 번 더 반복하고 있는 셈입니다. 인원을 추가하고, 눈을 늘리고, 검토 횟수를 늘릴 수 있으며 이는 도움이 되지만, 근본적인 탈출은 불가능합니다. 오류를 수정해야 할 계층(layer) 자체가 오류를 범한 것과 동일한 성질로 구성되어 있기 때문입니다. 우리는 리뷰할 때 실패하며, 리뷰에서 실패하지 않으려고 노력할 때조차 실패합니다.
이 시점에서 당연히 드는 반응은 "실력 문제다, 더 열심히 리뷰해라"일 것입니다. 이 말이 틀린 것은 아니지만, 이는 규율(discipline)과는 전혀 상관없는 한계점에 부딪히게 됩니다. 진정으로 결합된(coupled) 작업은 자신의 머릿속이든 모델의 컨텍스트(context)든, 전체 가정을 검토할 수 있는 그 어떤 단일한 관점에서도 온전히 들어맞지 않는 경우가 많습니다. 따라서 리뷰를 더 많이 한다고 해서 확률이 낮아질 수는 있지만, 결코 0으로 만들 수는 없습니다.
만약 확률을 0으로 만드는 것이 불가능하다면, 남은 것은 조기에 탐지하는 것입니다. 프로덕션(production) 환경에서 시스템을 운영해 본 사람이라면 이미 이 문제와 함께 살아가고 있으며, 이를 지칭하는 약어까지 있습니다. 바로 MTTD, 평균 탐지 시간(mean time to detect) — 즉, 무언가 고장 났음을 누군가 알아차리기까지 걸리는 평균 시간입니다. 모든 사고를 방지할 수는 없기에, 우리는 알아차리는 데 걸리는 시간을 측정하고 단축합니다. 잘못된 가정(wrong assumption)의 경우도 동일한 논리가 적용되지만, 바로 이 지점에서 저는 막혔습니다. 왜냐하면 코딩 에이전트(coding agents) 분야에서는 아무도 이 수치를 측정하지 않기 때문입니다.
벤치마크(Benchmarks)는 정답을 맞힐 확률 — 성공률(success rate), 즉 이진적(binary)이고 사후적인 결과 — 을 측정합니다. 우리는 모델이 얼마나 자주 정답에 도달하는지를 보고 축하하지만, 잘못된 가정이 누군가에게 발견되기 전까지 얼마나 오래 생존하는지에 대해서는 거의 어떠한 어휘도 가지고 있지 않습니다. 현재 존재하는 가장 유사한 방식은 사후적인 것입니다. 즉, 실행이 이미 실패한 후에 에이전트가 어느 단계에서 틀렸는지를 지적하는 방식입니다. 제가 관심을 갖는 것은 그 반대입니다. 잘못된 가정이 실제 상황에서 포착되기 전까지 얼마나 오랫동안 전파(propagate)되는가 하는 점입니다.
그리고 차마 하고 싶지 않은 고백을 하나 하자면, 탐지 시간(time-to-detect)을 측정한다고 해서 문제가 해결되는 것은 아니며, 단지 그 크기를 줄일 뿐이라는 사실입니다. 체크포인트(checkpoint)를 확인하는 사람은 결국 그 가정을 통과시켜 버린 것과 동일한 판단 계층(layer of judgment)이기 때문에, TTD는 피로한 리뷰어, 서두르는 리뷰어, 혹은 가정을 작성한 사람과 동일한 사각지대(blind spot)를 가진 리뷰어로부터 자유로울 수 없습니다. 이를 통해 얻는 것은 보장이 아니라, 더 작은 패배입니다. 오류가 발생할 가능성은 여전히 남아 있지만, 똑같이 불완전한 누군가가 제때 확인했을 때 이를 되돌리는 비용이 더 저렴해질 뿐입니다. 이것은 해결책이 아닙니다. 해결책이 존재하지 않는다는 사실을 받아들였을 때 마주하게 되는 문제의 크기일 뿐입니다.
그리고 이 상황을 단순한 디테일에서 문제로 바꾸는 것은 바로 속도입니다.
속도가 변화시킨 것은 바로 실수를 저지르는 시점과 그것을 알아차리는 시점 사이의 간극이기 때문입니다. 가정을 틀릴 확률은 AI와 함께 낮아지지 않았습니다. 그 부분은 인간의 영역이며, 여전히 그대로 남아 있습니다. 줄어든 것은 그 편차(drift)를 누군가 발견할 기회를 갖기 전까지의 시간입니다. 이전에는 잘못된 가정이 방대한 코드로 변하기까지 시간이 걸렸고, 그 느린 속도는 의도치 않게 검토를 위한 창(window) 역할을 했습니다. 하지만 이제 모델은 당신이 알아차리기도 전에 삐뚤어진 가정 위에 3시간 분량의 유능한 작업물을 쌓아 올립니다.
그리고 여기에 역설적인 부분이 있습니다. 모델이 더 유능할수록 당신은 모델을 더 멀리 내버려 두게 됩니다. 왜냐하면 체크할 때마다 모델이 잘 해내고 있는 것처럼 보이기 때문이며, 검증을 위해 멈추는 것이 마치 무엇을 해야 할지 명확히 알고 있는 모델을 낭비하는 것처럼 느껴지기 시작하기 때문입니다. 하지만 오류가 가정(assumption)의 문제일 때, 매번 체크할 때마다 괜찮아 보이는 것과 실제로 괜찮은 것은 별개의 문제입니다. 잘못된 가정은 유능하게 실행되는 동안 경고등을 깜빡이지 않기 때문입니다. 체크 사이의 간격은 확신에 밀려 스스로 늘어나며, 3시간째에 발견된 잘못된 가정은 1시간째에 발견했을 때보다 세 배의 비용이 듭니다. 되돌려야 할 유능한 작업량이 세 배이기 때문입니다. 모델의 능력은 당신에게 멈춰야 할 구체적인 이유를 전혀 주지 않으면서 그 간격을 부풀리며, 바로 그 '이유의 부재'가 위험 요소입니다.
여기서 속도 그 자체가 악당은 아닙니다. 이것이 바로 초기에 사용한 저렴한 모델이 무너지지 않았던 정확한 이유입니다. 체크포인트(checkpoints)를 동일한 속도로 유지하면서 빠르다는 것은, 각 검토 주기(review cycle)가 더 저렴하고 더 자주 반복되기 때문에 실제 작업 시간(wall-clock work) 시간당 잘못된 가정(crooked assumption)을 포착할 기회가 더 많아짐을 의미합니다. 위험은 속도가 자신감을 살 때, 그리고 그 자신감이 더 많은 주기를 돌리는 대신 더 긴 간격에 그 속도를 소비할 때 나타납니다. 즉, 검토할 기회를 제공하는 대신 검토 없이 동일한 빠른 모델이 작업을 쌓아 올릴 때가 바로 그때입니다. 능력(Capability)이 문제가 아닙니다. 그 속도가 확보해 준 시간을 당신이 어떻게 사용하는지가 문제입니다.
이 모든 것에 대한 업계의 해답은 더 많은 프로세스를 추가하는 것이었습니다.
더 많은 사양(spec), 더 많은 계획(plan), 더 많은 단계(phases) — 그리고 유행하게 된 SDD(Software Design Document)는 결국 우리가 수년간 도망쳐 왔던 바로 그 폭포수(waterfall) 모델처럼 변해버렸습니다. 모델은 당신에게 도달하기 전까지 더 멀리 실행하도록 밀어붙이는 시대에, 검증(verification)이 마지막의 단 한 지점에 모두 몰려 있는 형태가 된 것입니다. 중간에 수정하는 살아있는 계획(living plan)을 가진 현대적인 버전조차도 유지 관리해야 할 계층을 하나 더 추가할 뿐입니다. 이는 오버헤드(overhead) 위에 오버헤드를 얹는 격이며, 정작 중요한 한 가지, 즉 작업이 쌓이기 전에 그 가정이 맞았는지에 대한 판단에는 아무런 영향을 주지 못합니다.
이것은 가정 오류(assumption error)에 대해 엄격함(rigor)으로 포장하여 던져진 실행 오류(execution-error)용 도구입니다.
남은 것은 레시피(recipe)가 아닌 관찰(observation)입니다. 제가 발견한 한 연구는 계약(contract)이 성능이 낮은 모델에서 거의 두 배 가까이 도움이 된다는 것을 보여주지만, 그것은 검토 가능성(reviewability)을 측정할 뿐입니다. 제가 알고 싶은 것은 다른 것입니다. 이 성능이 낮고 더 빠른 모델이 목표에 얼마나 더 빨리 도달했는지, 그리고 잘못된 가정으로부터 회복하는 데 비용이 얼마나 들었는지입니다. 아무도 그 축을 측정하지 않았기에, 우리는 더 높은 지능(intelligence)이 올바른 병목 현상(bottleneck)을 해결하는지 여부를 어둠 속에서 결정하고 있습니다.
제 생각에는 그렇지 않을 것입니다. 즉, 환원 불가능한 인간의 판단(human judgment) 영역에 확률적 지능(probabilistic intelligence)을 쏟아붓는 것은 속도만을 얻을 뿐 그 이상의 것은 얻지 못한다는 것입니다. 그리고 방지하지 못한 오류 위에서의 속도는, 그 누구도 확인하지 않은 가정(assumption) 위에 더 유능하게 수행된 작업이 쌓여 있는 것에 불과합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기