AI에게 추측을 멈추라고 요구하지 마세요. 추측할 필요가 없는 시스템을 설계하세요.
요약
AI 에이전트 시스템 구축 시 발생하는 환각 문제를 프롬프팅이 아닌 아키텍처 설계 관점에서 해결해야 함을 강조합니다. 모델의 판단에 의존하기보다 시스템적으로 추측이 불가능하도록 설계하는 엔지니어링 원칙을 다룹니다.
핵심 포인트
- AI의 오류는 모델의 능력이 아닌 시스템 설계의 문제일 가능성이 높음
- 프롬프팅을 통한 주의력 강화는 근본적인 해결책이 될 수 없음
- 시스템 문제를 모델의 행동 문제로 치부하지 말고 아키텍처로 해결해야 함
- 데이터의 진실의 원천(Source of Truth)을 강제하는 설계가 필요함
추측을 설계 단계에서 제거하기.
통제된 AI 보조 생산 시스템(AI-assisted production systems)을 구축하며 얻은 엔지니어링 교훈에 관한 짧은 시리즈(3부작 중 1부)의 일부입니다. 각 글은 하나의 실제 실패 사례와 그로 인해 강제된 아키텍처(architectural) 아이디어를 다룹니다. 예시는 저희의 것이지만, 원칙은 다른 곳에도 적용 가능하도록 의도되었습니다.
우리는 역량을 공정하게 나타내는 것이 전체 작업인 도구에서, 실제로 존재하던 기능을 제거했습니다. 모델이 환각(hallucination)을 일으켰기 때문이 아닙니다. 우리의 아키텍처가 추측을 하는 것이 합리적인 선택이 되도록 만들었기 때문입니다.
모델은 주어진 입력값으로부터 올바르게 추론했습니다. 문제는 입력값이었고, 이를 어떻게 수정할지에 대한 우리의 첫 번째 본능 또한 문제였습니다. 이 글은 무엇이 실패했는지, 왜 명백한 해결책이 작동하지 않았는지, 그리고 우리가 최종적으로 도달한 패턴에 대한 기록입니다. 이 중 어느 것도 프롬프팅(prompting)에 관한 것이 아닙니다.
실패 사례
우리는 구매자를 위해 옵션들을 비교하고 가장 적합한 것을 추천하는 도구를 운영합니다. 이 도구는 중립적이어야 합니다. 이 도구의 입력값 중 하나는 각 옵션이 실제로 무엇을 할 수 있는지를 나타내는 '역량(capabilities)' 세트입니다.
유지보수 작업을 수행하던 자동화된 에이전트(automated agent)가 해당 역량 세트를 업데이트했습니다. 에이전트는 특정 역량이 중단되었다는 근거로 우리의 역량 중 하나를 제거했습니다. 에이전트가 인용한 출처는 이전 작업 세션의 인수인계 노트였는데, 거기에는 해당 역량이 "보류(parked)"되었다는 내용이 지나가는 말로 적혀 있었습니다.
해당 역량은 보류된 것이 아니었습니다. 그것은 라이브 상태였고, 게시되었으며, 활발히 사용 중이었습니다. 하지만 그 변경이 일어나는 동안, 중립적이어야 했던 도구는 조용히 '불공정'해졌습니다. 실제로 존재하는 무언가를 나타내는 것을 중단해 버린 것입니다.
에이전트는 부주의하지 않았습니다. 에이전트가 작업하던 노트를 읽었다면 당신도 똑같은 결론을 내렸을 것입니다. 노트가 틀렸던 것이며, 워크플로우(workflow) 내의 그 어떤 것도 실제 사실과 대조하도록 강제하지 않았습니다.
명백한 해결책이 작동하지 않는 이유
모두가 가장 먼저 떠올리는 명백한 해결책은 모델에게 더 주의를 기울이라고 말하는 것입니다. 지침을 추가하는 것이죠. "단언하기 전에 검증할 것." "요약에 의존하지 말 것." "진실의 원천(source of truth)을 확인할 것." 프롬프트(prompt)를 강화하는 방식입니다.
우리는 이런 방식들을 시도해 보았습니다. 이는 실패율을 이동시킬 뿐, 실패를 제거하지는 못합니다. 그리고 그 '이유(why)'를 깊이 고민해 보면 이 사실 또한 명백해집니다.
LLM(Large Language Model)은 자신에게 주어진 컨텍스트(context)를 바탕으로 추론합니다. 만약 현실에 대한 가장 가깝고 유창한 설명이 요약본이라면, 모델은 그 요약을 사용할 것입니다. 이는 모델이 게을러서가 아니라, 요약본이 '바로 그곳에' 있고 권위 있게 읽히기 때문입니다. "주의하세요"라는 명령은 명시되지 않은 대상을 향해 추가적인 노력을 기울이라는 지시입니다. 이는 컨텍스트 내의 다른 모든 지시 사항과 경쟁하게 되며, 긴 컨텍스트(long context), 시간 압박, 또는 자신감 넘치는 어조로 작성되었지만 오래된 서사(narrative)와 같이 정작 가장 필요할 때 성능을 저하시킵니다.
더 깊은 문제는 우리가 **시스템 문제(systems problem)**를 **행동 문제(behaviour problem)**로 취급했다는 점입니다. 우리에게는 두 가지 현실의 묘사 — 권위 있는 것(라이브 시스템 레코드, live system of record)과 편리한 것(산문, prose) — 가 있었고, 매번 올바른 것을 선택하는 일을 모델의 판단에 맡겨두었습니다. 그것은 우리가 모델에게 위임해서는 안 될 판단이었습니다. 모델에게는 추측의 문제가 없었습니다. 우리가 모델에게 추측할 이유를 제공했을 뿐입니다.
우리가 변경한 사항
우리는 모델이 소스(source) 사이에서 올바르게 선택하도록 만드는 시도를 중단했습니다. 대신, 권위 있는 소스를 사실에 도달하는 유일한 경로로 만들었습니다.
두 가지 아이디어가 이 작업을 수행했습니다.
첫째: 소스의 순위를 명시적으로 매기고, 모델이 아닌 순위(ranking)가 충돌을 해결하도록 합니다.
authoritative = resolve(
production, # 시스템 레코드 — 권위 있음
derived, # production으로부터 계산됨
...
assert의 목적은 방어적 코딩(defensive coding)이 아닙니다. 그것은 의도의 선언입니다. 즉, production에 답이 있다면 그 아래의 어떤 것도 투표권을 갖지 못한다는 것입니다. 산문(prose)은 production이 침묵하는 부분에 대해 정보를 제공할 수는 있지만, 시스템 레코드가 이미 보유하고 있는 사실을 결코 무시하거나 조용히 대신할 수 없습니다. 그리고 — 이 부분이 우리를 괴롭혔던 지점인데 — 부재(absence)는 요약본에서 언급되지 않았다고 해서 추론되는 것이 아니라, 반드시 권위 있는 소스로부터 증명되어야 합니다.
둘째: 사실을 단언(assert)하지 말고, 도출(derive)하십시오.
역량 세트(capability set)는 더 이상 인간이나 에이전트가 수동으로 편집하는 것이 아닙니다. 이는 빌드 타임(build time)에 라이브 기록 시스템(system of record)으로부터 _계산(computed)_됩니다.
capabilities = derive_from(system_of_record.published_items())
# 역량의 부재는 (system_of_record)에 그것이 존재하지 않음으로써 확립되며,
# 결코 문서에 그것이 존재하지 않음으로써 확립되지 않습니다.
역량이 도출(derive)되고 나면, 우리가 맞닥뜨리는 버그의 유형은 구조적으로 불가능해집니다. 노트를 편집한다고 해서 라이브 역량을 제거할 수는 없습니다. 왜냐하면 노트는 더 이상 경로(path)에 있지 않기 때문입니다. 기록 시스템(system of record)이 변경될 때마다 시스템은 스스로를 수정합니다. 동기화해야 할 별도의 설명(description) 자체가 존재하지 않으므로, 아무도 설명을 동기화하는 것을 기억할 필요가 없습니다.
우리가 의도적으로 자동화하지 않은 것
이 부분은 회의적인 독자들이 가장 주목해주었으면 하는 부분입니다. 왜냐하면 이곳이 영리함보다 절제가 더 중요했던 지점이기 때문입니다.
우리는 **진실의 원천(source of truth)**을 자동화했습니다. 우리는 **결정(decision)**을 자동화하지 않았습니다.
도출된 역량 세트와 누군가의 기대치가 일치하지 않을 때, 시스템은 아무런 소리 없이 무엇인가를 "수정"하지 않습니다. 대신 불일치를 드러내고 멈춥니다. 그 차이가 실제적인 변화인지, 실수인지, 아니면 의도된 예외인지는 인간이 결정합니다. 우리는 파이프라인에 세상에 대한 새로운 사실을 _단언(assert)_할 권한을 결코 부여하지 않았습니다. 오직 이미 사실을 보유하고 있는 시스템으로부터 사실을 _도출(derive)_하고, 무언가 잘못되어 보일 때 플래그(flag)를 표시할 권한만을 부여했습니다.
리졸버(resolver)를 구축하고 나면, 모든 것을 자동으로 해결(auto-resolve)하도록 내버려 두고 싶은 유혹에 빠지기 쉽습니다. 우리는 그렇게 하지 않았습니다. 왜냐하면 "존재하는 것"은 사실(도출 가능)이지만, "존재해야 하는 것"은 결정(도출 불가능)이기 때문입니다. 이 두 가지를 하나로 뭉뚱그리는 것이 바로 확신에 차서, 자동으로 틀린 결론을 내리는 시스템을 만드는 방법입니다.
이 모든 것의 밑바탕에는 명확한 선이 있습니다:
사실은 시스템에서 옵니다. 결정은 사람으로부터 옵니다. 파이프라인은 사실을 도출하고 충돌을 표시할 수는 있지만, 무엇이 진실인지 결코 결정할 수는 없습니다.
동작 / 증인 경계 (The behaviour / witness boundary)
우리는 여전히 동작(behaviour)에 의존합니다. 즉, 에이전트가 권위 있는 소스(authoritative source)로부터 추론할 것으로 기대합니다. 하지만 우리는 더 이상 동작을 유일한 방어선으로 신뢰하지 않습니다. 파이프라인 내에서 실행되는 하나의 작은 머신 체크(machine check)가 있습니다. 이 체크는 기록 시스템(system of record)으로부터 기능 세트(capability set)를 재계산하며, 우리가 배포하려는 내용이 소스가 실제로 노출하는 내용에서 벗어났을 경우 빌드를 실패 처리합니다.
그 체크가 모델의 동작을 제어하는 것은 아닙니다. 그것은 불변성(invariant)을 관찰 가능하게(observable) 만듭니다. 만약 동작이 조용히 퇴보한다면, 증인(witness)은 사용자에게 무엇인가가 도달하기 전에 명확하게 실패를 알립니다. 동작이 지배한다면, 체크는 불변성이 여전히 유지되고 있다는 증거입니다. 우리는 이 둘을 혼동하지 않도록 주의했습니다. 체크를 통과했다는 것이 훌륭한 판단력을 증명하는 것은 아니며, 단지 하나의 특정하고 결정 가능한(decidable) 속성이 온전하다는 증거일 뿐입니다.
다른 엔지니어링 팀을 위한 교훈
-
대부분의 "AI 신뢰성" 문제는 모호성 표면(ambiguity-surface) 문제입니다. 더 나은 프롬프트(prompt)를 찾기 전에, 모델이 추론할 수 있는 명확한 소스가 있었는지부터 자문하십시오. 만약 현실에 대한 두 가지 설명이 범위(scope) 안에 있다면, 당신은 이미 패배한 것입니다. 단지 언제 그 사실을 알게 될지 기다리고 있을 뿐입니다.
-
올바른 경로를 유일하게 쉬운 경로로 만드세요. "주의하십시오"라는 말은 모든 미래의 추론(inference)에 부과되는 세금입니다. 대안적인 소스를 제거하는 것은 일회성 구조적 변경입니다. 근면함(diligence)보다는 구조(structure)를 선호하십시오. 근면함은 확장(scale)되지 않으며 컨텍스트 압박(context pressure) 속에서 살아남지 못합니다.
-
기술(describe)하지 말고 유도(derive)하세요. 어딘가에 권위 있게 존재하는 모든 사실은 필사(transcription)되는 것이 아니라, 그곳으로부터 계산되어야 합니다. 모든 필사는 결국 원본과 일치하지 않게 될 복사본입니다.
-
필요해지기 전에 소스의 순위를 정하세요. 기록 시스템(system of record)과 편리한 요약(summary) 사이의 충돌은 생소한 것이 아닙니다. 이는 문서화가 존재하는 모든 시스템의 기본 조건입니다. 인간이나 모델이 그 순간에 이를 판결할 필요가 없도록, 코드 상에서 미리 우선순위를 결정해 두십시오.
-
이는 LLM (Large Language Models)을 훨씬 넘어 일반화될 수 있습니다. "에이전트 (agent)"를 "신입 엔지니어"나 "크론 잡 (cron job)"으로 바꾸어 보십시오. 동일한 해결책 — 단일 권위적 소스 (single authoritative source), 설명이 아닌 유도 (derived not described), 해결되지 않은 충돌 노출 (conflicts surfaced not resolved) — 이 동일한 유형의 오류를 제거합니다. LLM은 단지 잠재적인 설계 결함이 더 빠르고 눈에 띄게 실패하도록 만들었을 뿐입니다.
우리에게 중요했던 재정의(reframe)는 작지만 완전했습니다. 우리는 그동안 "어떻게 하면 모델이 추측을 멈추게 할 수 있을까?"라고 물어왔습니다. 더 나은 질문은 "왜 모델이 추측을 하는 것이 합리적인 상황에 놓여 있는가?"였습니다. 일단 그 원인을 제거하자, 해당 동작은 자연스럽게 해결되었습니다.
엔지니어링 원칙 (The Engineering Principle)
에이전트는 입력값에 추측의 여지가 있을 때 추측을 합니다. 에이전트에게 멈추라고 지시하지 마십시오. 모호함을 제거하십시오. 기록 시스템 (system of record)으로부터 사실을 유도하고, 산문 (prose)이 결코 진실보다 우선할 수 없도록 모든 소스의 순위를 매기며, 충돌을 자동으로 해결하는 대신 표면 위로 드러내십시오. AI에게 추측을 멈추라고 요구하지 마세요. 추측할 필요가 없는 시스템을 설계하세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기