모든 단계가 통과되었습니다. 프로세스의 책임은 누구에게 있었을까요?
요약
개별 검증 단계는 모두 통과했음에도 불구하고, 워크플로 내 문서 간의 버전 불일치로 인해 발생하는 인수인계(handoff) 실패 사례를 분석합니다. 로컬 검증기가 현재 문서의 유효성만 확인하고 전체 시스템의 정합성을 보장하지 못할 때 발생하는 위험을 다룹니다.
핵심 포인트
- 개별 단계의 검증 통과가 전체 프로세스의 성공을 보장하지 않음
- 로컬 검증기는 문서 간의 버전 불일치나 맥락적 정합성을 놓칠 수 있음
- 단순한 체크리스트 강화보다 시스템 전체의 상태 동기화가 중요함
- 수정 사항 발생 시 연관된 모든 산출물의 버전 관리가 필수적임
두 번째 파트에서 저는 공식 검증(formal validation)을 통과했고 완벽해 보였지만, 결국 취약한 인수인계(handoff)로 드러난 패키지에 대해 작성했습니다. 그 문제는 설명하기가 비교적 쉬웠습니다. 우리의 검증기(validators)는 섹션이 존재하는지는 확인했지만, 다음 담당자가 실제로 작업을 수행할 수 있는지 여부는 확인하지 않았습니다. 자연스러운 대응책은 더 많은 체크 항목을 추가하고, 스키마(schema)를 강화하며, 체크리스트를 보강하여 통제권이 회복되었다고 가정하는 것이었습니다. 우리는 정확히 그렇게 했고 — 그리고 거의 즉시, 문제가 더 이상 문서의 품질에 있지 않은 더 심각한 사례에 직면했습니다.
모든 단계가 완료되었습니다
PREFERENCE_CHANNEL_CHANGED 이벤트가 포함된 동일한 변형 도메인을 사용해 보겠습니다. 워크플로(workflow)는 올바른 순서로 모든 단계를 완료했습니다. 각 로컬 검증기(local validator)는 해당 문서를 승인했습니다. 담당자가 주요 결정을 확인했으며, 최종 패키지에는 필요한 모든 산출물(artifact)이 포함되어 있었습니다. 원래 요구사항은 간단했습니다: profile.notificationChannel이 email에서 sms로 변경될 때, 시스템은 하나의 이벤트를 방출하고 감사 로그(audit log)에 이전 값과 새로운 값을 기록해야 합니다. 프로세스는 여러 단계로 구성되었습니다: 요구사항 명확화, 기술 사양(technical spec) 작성, Jira 준비, QA 시나리오 생성, 승인 획득, 그리고 최종 인수인계(handoff) 조립. 오케스트레이션(orchestration) 수준에서는 모든 것이 완전히 정확해 보였습니다:
workflow:
- define_requirement
- generate_technical_spec
...
워크플로 (workflow)는 아무것도 건너뛰지 않았으며 의도된 순서를 유지했습니다. 기술 명세서 (technical spec)는 검증기 (validator)를 통과했고, Jira는 자체 검증을 통과했으며, QA 또한 또 다른 검증을 통과했습니다. 승인 (approval) 역시 기록되었습니다. 그 후 사용자가 작은 수정을 요청했습니다: 이벤트가 더 이상 email -> sms 전환에 대해서만 발생해서는 안 되며, 새로운 값이 sms와 일치하는 모든 변경 사항에 대해 발생해야 한다는 것이었습니다. 기술 명세서 (technical spec)는 업데이트되었고, 다시 검증을 통과했으며, 프로세스는 멈췄던 지점부터 다시 계속되었습니다. 개별 작업 수준에서는 모든 것이 여전히 논리적으로 보였습니다: 수정 사항이 적용되었고, 업데이트된 문서는 유효하며, 승인이 이미 존재하고, 모든 단계가 완료된 상태였습니다. 우리는 검증 (validation) 과정에서는 실수를 발견하지 못했습니다. 우리는 구현자 (implementer)가 Jira를 바탕으로 작업을 시작하면서, 티켓의 트리거 (trigger)가 왜 기술 명세서 (technical spec)와 일치하지 않는지 질문했을 때에야 비로소 실수를 발견했습니다. 처음에는 Jira의 결함을 찾았고, 그다음에는 검증기 (validator)를 조사했으며, 여러 번의 반복적인 확인을 거친 후에야 문서들이 개별적으로는 유효하지만 서로 다른 버전의 결정 사항에 속해 있다는 사실이 명확해졌습니다. 그 불일치를 풀어내는 작업은 수정 자체를 수행하는 것보다 더 오래 걸렸습니다. Jira와 QA는 여전히 이전 규칙을 기반으로 하고 있었던 반면, 승인 (approval)은 기술 명세서 (technical spec)의 이전 버전을 참조하고 있었습니다.
로컬 기술 명세서 검증기 (technical-spec validator)는 현재의 문서만을 보았습니다:
technical_spec_validator:
required:
- event_name
...
Jira 검증기 (Jira validator)는 티켓에 수락 기준 (acceptance criteria), 구현 노트 (implementation notes), 그리고 테스트 기대 사항 (test expectations)이 포함되어 있음을 확인했습니다:
jira_validator:
required_sections:
- acceptance_criteria
...
QA 검증기 (QA validator) 역시 자신의 산출물 (artifact)을 거부할 명백한 이유가 없었습니다:
qa_validator:
every_case_has:
- setup
...
이 결과들은 각각 국소적으로(locally)는 정확했습니다. 기술 사양(technical spec)은 정말로 유효했습니다. Jira에는 정말로 필요한 섹션들이 포함되어 있었습니다. QA 시나리오들도 정말로 독립적으로 완결되어 있었습니다. 문제는 검증기(validator) 중 하나가 "업무를 제대로 수행하지 못한" 것이 아니었습니다. 문제는 그들 중 어느 것도 다른 질문에 답하지 않았다는 점이었습니다: 이 모든 산출물(artifacts)이 동일한 결정 버전(version of the decision)에 속해 있는가?
상태(State)가 사라진 지점
수정 후에는 전체적인 그림이 대략 다음과 같아야 했습니다:
process_state:
canonical_requirement:
version: 4
...
하지만 실제로는, 프로세스가 각각의 성공적인 결과물만을 별도로 저장했습니다: 기술 사양 유효, Jira 유효, QA 유효, 승인 존재. 어떤 버전의 표준 요구사항(canonical requirement)이 각 산출물을 생성했는지, 승인이 어떤 버전에 적용되었는지, 그리고 수정 후에 어떤 의존성(dependencies)이 무효화되었는지를 기록하는 단일한 장소가 없었습니다. 결과적으로 시스템은 올바른 국소적 사실들을 결합하여 잘못된 전역적 결론(global conclusion)을 도출했습니다:
completion_check:
technical_spec_valid: true
jira_valid: true
...
이 체크 과정에서 명백하게 틀린 진술은 없습니다. 네 가지 값 모두 동시에 참(true)일 수 있습니다. 다만 이 값들은 버전, 인과적 의존성(causal dependencies), 그리고 무효화(invalidation)를 무시하기 때문에 complete를 정당화하기에는 불충분할 뿐입니다. 이 차이는 매우 중요합니다. 때때로 AI 프로세스가 잘못 종료되는 이유는 환각(hallucination) 때문도 아니고, 단계가 누락되었기 때문도 아니며, 심지어 출력이 좋지 않기 때문도 아닙니다. 시스템이 국소적으로 정확한 결과들을 올바른 프로세스 상태(process state)로 결합하지 못하기 때문에 실패하는 것입니다.
워크플로(Workflow)는 프로세스 제어(Process Control)와 같지 않다
워크플로(Workflow)는 “다음에 무엇을 실행해야 하는가?”라는 질문에 답하는 데 능숙합니다. 워크플로는 순서, 재시도(retries), 타임아웃(timeouts), 분기(branches), 심지어 이전 단계로의 복귀를 강제할 수 있습니다. 하지만 단계들의 시퀀스(sequence) 그 자체만으로는, 변경 사항이 발생한 후 모든 의존 객체(dependent object)가 최신 상태로 유지되는지를 증명하지 못합니다. 우리의 예시에서 워크플로는 generate_jira, 그 다음 generate_qa, 그 다음 request_approval을 올바르게 실행했습니다. 수정 사항이 발생한 후에도, 워크플로는 generate_technical_spec을 다시 올바르게 실행했습니다. 만약 모델에 “표준 요구사항(canonical requirement)의 변경은 Jira, QA, 그리고 승인(approval)을 무효화한다”라는 규칙이 포함되어 있지 않다면, 워크플로는 그것들을 다시 실행할 이유가 없습니다. 워크플로의 관점에서 이는 실패가 아닙니다. 규칙이 누락된 것입니다.
최소한의 오케스트레이션(orchestration) 조각은 다음과 같을 수 있습니다:
on_correction:
rerun:
- generate_technical_spec
하지만 실제 프로세스에는 더 강력한 무언가가 필요합니다:
on_correction:
invalidate:
- technical_spec_approval
...
이 두 블록의 차이는 문구의 품질이나 모델의 “지능(intelligence)” 차이가 아닙니다. 두 번째 사례에서는 프로세스 의존성(process dependencies)이 명시적(explicit)입니다. 첫 번째 사례에서는 의존성이 가정(assumptions)으로 남겨져 있습니다. 모델이 이를 추론(infer)할 수도 있고, 그렇지 않을 수도 있습니다. 설령 모델이 아홉 번 연속으로 이를 올바르게 추론한다 하더라도, 열 번째 실행이 결정론적(deterministic)이 되는 것은 아닙니다.
검증기(Validator)는 프로세스 제어(Process Control)와 같지 않다
검증기(Validator)는 “이 객체가 특정 규칙을 충족하는가?”라는 질문에 답합니다. 이는 강력하고 필수적인 메커니즘이지만, 그 범위는 대개 국소적(local)입니다. 검증기는 스키마(schema), 비즈니스 제약 조건(business constraints), 완전성(completeness), 문서 내의 일관성(consistency)을 확인할 수 있으며, 심지어 두 아티팩트(artifacts)를 비교할 수도 있습니다. 하지만 검증기에 현재의 표준 버전(canonical version), 이전 승인 내역, 그리고 의존성 그래프(dependency graph)가 주어지지 않는다면, 전체 프로세스의 맥락에서 문서가 최신 상태인지 여부를 판단할 수 없습니다.
예를 들어, 이 검증기는 기술 명세서(technical spec)를 기준으로 Jira를 확인합니다:
jira_consistency:
compare:
- jira.acceptance_criteria
...
이것은 현재의 기술 사양 (technical spec)을 전달받을 때만 작동합니다. 만약 오케스트레이션 레이어 (orchestration layer)가 캐시된 버전 3을 전달한다면, 정식 요구사항 (canonical requirement)이 이미 버전 4에 도달했음에도 불구하고 Jira 버전 3은 기술 사양 버전 3에 대해 성공적으로 검증을 통과할 것입니다. 로컬 일관성 (local consistency)은 유지되지만, 글로벌 정확성 (global correctness)은 유지되지 않습니다. 이것이 바로 "검증기 (validator)를 하나 더 추가하자"는 해결책이 항상 문제를 해결하지 못하는 이유입니다. 우선, 검증기가 어떤 상태를 보아야 하는지, 그리고 왜 그 상태가 최신(current)이라고 간주되는지를 정의해야 합니다.
평가자 (Evaluator) 또한 프로세스를 소유하지 않습니다
평가자 (evaluator)는 보통 결과물의 품질, 즉 완결성 (completeness), 명확성 (clarity), 기준과의 정렬 (alignment with criteria), 리스크 (risks), 그리고 때로는 종합 점수를 매깁니다. 이는 특히 규칙을 엄격한 스키마 (strict schema)를 통해 완전히 표현할 수 없을 때 유용합니다. 하지만 평가자는 주어진 패키지(package)를 바탕으로 작업합니다. 만약 패키지에 서로 일관되지만 오래된(stale) Jira 및 QA 산출물 (artifacts)이 포함되어 있다면, 평가자는 이들에게 매우 높은 점수를 줄 수 있습니다. 평가자에게는 수정 사항이 존재했다는 사실이나, 그 수정 사항이 해당 산출물들을 무효화했어야 한다는 사실을 알 의무가 없습니다.
evaluation:
clarity: 0.92
completeness: 0.88
...
그 점수는 정직할 수 있지만, 여전히 핵심 질문인 "이것이 현재의 의사결정을 위한 최종 패키지인가?"에 대한 답을 내놓지 못할 수 있습니다. 품질 평가 (quality evaluation)가 출처 (provenance), 버전 추적 (version tracking), 또는 프로세스 불변량 (process invariants)을 대체할 수는 없습니다.
여기서 "예측 가능한 동작 (Predictable Behavior)"이란 무엇을 의미하는가?
사람들이 AI 모델을 결정론적 (Deterministic)으로 만든다고 말할 때, 때로는 동일한 프롬프트에 대해 말 그대로 완전히 동일한 응답을 얻는 것을 의미하기도 합니다. 하지만 제가 여기서 사용하는 엄격한 의미는 그것이 아닙니다. 생성 모델 (Generative models)의 경우, 완전한 텍스트 결정론 (Textual determinism)은 비현실적일 때가 많으며 특별히 유용하지도 않습니다. 문구는 바뀔 수 있고, 인자 (Arguments)의 순서가 달라질 수 있으며, 동일한 아이디어가 다른 방식으로 표현될 수도 있기 때문입니다. 장기적으로 실행되는 작업 프로세스 (Work process)의 경우, 또 다른 형태의 예측 가능성이 더 중요합니다. 우리는 동일한 텍스트를 필요로 하는 것이 아니라, 프로세스 불변량 (Process invariants)의 일관된 강제가 필요합니다. 즉, 수정이 발생하면 이전의 승인들은 무효화되어야 하며, 오래된 아티팩트 (Stale artifacts)가 최종 패키지에 포함되어서는 안 되고, 필수적인 사실 정보가 누락되면 프로세스가 중단되어야 하며, 모든 최종 아티팩트는 알려진 출처 (Provenance)를 가져야 하고, 모든 의존성 (Dependencies)이 최신 상태일 때만 완료가 허용되어야 합니다.
process_invariants:
- correction_invalidates_dependent_artifacts
- approval_applies_to_exact_version
...
이러한 시스템은 모델을 수학적 의미에서 결정론적으로 만드는 것이 아닙니다. 대신 허용 가능한 동작의 경계를 예측 가능하게 만듭니다. 모델은 여전히 다른 문구를 제안하거나, 다른 문서 구조를 선택하거나, 추가 질문을 던질 수 있습니다. 하지만 오래된 승인이나 인지되지 않은 아티팩트 버전을 가지고 프로세스를 완료할 수는 없어야 합니다.
전체 그림을 볼 수 있어야 하는 주체는 누구인가?
실무적으로는 단일 문서나 단일 단계를 소유하는 것이 아니라, 프로세스 전체의 상태 (State)를 소유하는 계층이 필요합니다. 이 계층은 프로세스 엔진 (Process engine), 상태 머신 (State machine), 실행 컨트롤러 (Execution controller), 프로토콜 런타임 (Protocol runtime), 또는 단순히 명시적 제어 계층 (Explicit control layer)이라고 불릴 수 있습니다. 이름보다는 책임이 더 중요합니다. 이 계층은 다음 사항들을 파악해야 합니다:
- 정규 값 (Canonical values) 및 그 버전;
- 모든 아티팩트의 출처 (Provenance);
- 의존성 그래프 (Dependency graph);
- 승인의 유효성;
- 허용된 전이 (Transitions);
- 무효화 규칙 (Invalidation rules);
- 강제 중단 (Hard stops);
- 완료 조건 (Completion conditions).
워크플로 (Workflow)는 이 상태를 사용할 수 있고, 검증기 (Validators)는 이를 읽을 수 있으며, 평가자 (Evaluator)는 해당 컨텍스트 내에서 패키지에 점수를 매길 수 있고, 모델은 판단이 많이 필요한 개별 작업들을 처리할 수 있습니다. 하지만 “프로세스가 진정으로 완료되었다”는 결론이 모든 로컬 컴포넌트가 독립적으로 pass를 반환함에 따라 발생하는 부수 효과 (Side effect)로 나타나서는 안 됩니다.
이것이 모든 AI 프로세스가 복잡한 엔진이 되어야 한다는 의미는 아닙니다. 짧은 창의적 작업의 경우, 그 정도 수준의 제어는 과도할 것입니다. 하지만 프로세스가 길고, 분기 (Branches), 승인 (Approvals), 수정 (Corrections), 여러 개의 종속 문서 (Dependent documents), 그리고 재현성 (Repeatability)에 대한 요구사항을 포함한다면, 우리가 이를 명시하든 그렇지 않든 전역 상태 (Global state)는 이미 존재합니다. 만약 이를 명시적으로 만들지 못한다면, 상태는 프롬프트 (Prompt), 채팅 기록 (Chat history), 사용자 메모리 (User memory), 그리고 모델의 가정 (Assumptions) 속에 흩어진 채로 남게 됩니다.
실질적인 점검 사항
AI 프로세스가 제어되고 있다고 판단하기 전에, 저는 몇 가지 사항을 점검할 것입니다:
- 모든 산출물 (Artifact)이 생성된 소스의 버전을 기록하고 있는가?
- 수정 (Correction)이 모든 종속 문서와 승인을 무효화 (Invalidate)하는가?
- 검증기 (Validator)가 현재 버전을 확인하고 있는지 판단할 수 있는가?
valid(유효),current(현재),approved(승인됨) 사이에 명시적인 구분이 있는가?- 오래된 산출물 (Stale artifact)이 최종 완료를 차단하는가?
- 재시도 (Retries) 및 백트래킹 (Backtracking) 이후에도 출처 (Provenance)가 보존되는가?
- 완료 (Completion)가 단순히 마지막 단계가 끝났다는 사실이 아니라, 별도의 규칙으로 존재하는가?
- 하나의 계층 (Layer)이 프로세스가 왜 현재 상태에 있는지 설명할 수 있는가?
만약 이러한 질문들에 명확한 답이 없다면, 그 프로세스는 잘 오케스트레이션 (Orchestrated)되어 있고, 검증이 잘 이루어지며, 심지어 고품질의 출력을 생성할 수도 있지만, 그렇다고 해서 제어되고 있다는 의미는 아닙니다.
만약 어떤 계층도 프로세스의 전체 상태를 볼 수 없다면, 우리는 AI 모델의 동작을 제어하고 있는 것일까요 — 아니면 그저 모델의 로컬하게 올바른 결정들이 우연히 합쳐져 올바른 결과로 이어지기를 바라고 있는 것일까요?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기