폴백 모델은 투명한 대체재가 아닙니다
요약
폴백(fallback) 모델을 사용할 때 구조적 유효성만으로는 충분하지 않으며, 기능적 실패를 놓칠 수 있습니다. 호출자는 폴백 결정의 신뢰도와 검토 필요 여부를 명시적으로 알아야 합니다. 따라서 전체 폴백 경로에 대한 철저한 검증과 버전 관리가 필수적입니다.
핵심 포인트
- 폴백 모델은 구조적 유효성만으로는 부족하며, 기능적 실패를 놓칠 수 있습니다.
- 호출자는 라우팅 결정이 승인되었는지, 검토가 필요한 제안인지 명시적으로 알아야 합니다.
- 모델 식별자 및 관련 설정을 기록하여 전체 폴백 경로를 철저히 검증해야 합니다.
폴백(fallback) 모델은 해당 기능의 승인 검사를 통과해야만 프로덕션 트래픽을 받을 수 있습니다. 주력 모델과 API를 공유하면 통합이 더 쉬워집니다. 하지만 여전히 그 모델이 작업을 수행할 수 있다는 증거가 필요합니다.
호출자(Callers)는 자신이 승인된 라우팅 결정(accepted routing decision)을 받았는지, 아니면 검토가 필요한 제안(suggestion that requires review)을 받았는지 알아야 합니다. 만약 폴백이 제안 모드만 지원한다면, 애플리케이션은 이 축소된 모드를 명시적으로 반환해야 합니다. 유효한 JSON만으로는 호출자에게 해당 기능이 어떤 약속을 지켰는지 알려주지 못합니다.
저는 폴백을 별도의 후보로 평가한 다음, 언제 애플리케이션이 이를 사용할지 결정할 것이라고 생각합니다. 장애가 발생했을 때 그것이 작동하는지 알아내는 것은 잘못된 결정을 수정할 여지를 거의 남기지 않습니다.
성공적인 응답이라도 계약을 위반할 수 있습니다
Billing, TechnicalSupport, 또는 AccountAccess를 선택하는 티켓 라우터(ticket router)를 고려해 봅시다. 이 라우터는 티켓이 모호할 경우 반드시 사람의 검토를 요청해야 합니다. 모델은 결정을 제안합니다. 애플리케이션 코드는 응답 구조와 도메인 제약 조건을 확인한 다음, 어떤 큐에 할당되기 전에 라우팅 정책을 적용합니다.
다음 티켓을 고려해 봅시다:
계정에 접속하여 인보이스를 다운로드할 수 없습니다. 로그인하는 것을 도와주세요.
후보 폴백 모델은 다음과 같이 반환할 수 있습니다:
{
"queue": "Billing",
"requiresHumanReview": false,
...
이 응답은 구조적 검사(structural checks)를 통과합니다: 유효한 JSON, 허용된 큐, 필수 필드, 그리고 길이 제한 내의 이유가 있습니다. 하지만 여전히 즉각적인 계정 접근 문제를 놓치고 있습니다. 이 예시에서 검토자는 예상되는 큐를 AccountAccess로 레이블링할 것입니다.
이것은 가상의 경우입니다. 특정 모델이 생성한 것은 아닙니다. 이는 폴백이 구조적 및 도메인 유효성 검사를 통과하면서도 티켓을 잘못 할당하거나 모호한 경우에 대한 검토를 생략하는 방법을 보여줍니다.
같은 문제가 답장 초안 작성(reply drafting)에서도 나타납니다. 모델은 정책 예외를 누락시키거나 지원되지 않는 약속을 하면서 응답 형태는 유지할 수 있습니다. 이는 HTTP 요청이 성공하더라도 기능적 실패입니다.
전체 폴백 경로를 검증하세요
In .NET에서 IChatClient는 채팅 요청 및 스트리밍을 위한 공유 추상화(shared abstraction)를 제공합니다. Microsoft.Extensions.AI.Abstractions는 또한 함수 호출(function calls) 및 결과에 대한 공통 콘텐츠 유형을 정의합니다. FunctionInvokingChatClient와 같은 파이프라인 구성 요소는 자동 도구 호출(automatic tool invocation) 기능을 추가합니다. 이러한 추상화들은 SDK 종속성(SDK dependencies)을 포함하는 데 도움을 줍니다. 하지만 모든 백엔드가 동일한 기능 계약(feature contract)을 만족하도록 만드는 것은 아닙니다.
실제로 배포할 조합을 명확히 하십시오. 모델 식별자(model identifier)를 기록하고, 백엔드에서 허용한다면 특정 버전이나 스냅샷에 고정하십시오. 해당 기록에는 배포(deployment), 제공업체 통합(provider integration), 프롬프트(prompt), 응답 스키마(response schema), 그리고 관련 설정(relevant settings)을 포함시키십시오. 폴백(fallback)이 다른 지침을 필요로 한다면, 그 지침의 버전도 함께 평가하십시오.
가변 모델 별칭(mutable model alias)은 서비스되는 모델이 변경되더라도 동일한 구성된 이름을 유지할 수 있게 합니다. 사용 가능한 경우 관찰된 모델 메타데이터(observed model metadata)를 기록하고, 상위 스트림(upstream)의 변경 사항이 어떻게 재자격화(requalification)를 유발하는지 결정하십시오. 귀하의 자격 증명(qualification evidence)은 테스트한 구성에 적용됩니다. 별칭 아래에서 변경이 발생하면 구식이 될 수 있습니다.
티켓 라우터(ticket router)의 경우, 자격 기록은 다음 질문들에 답해야 합니다:
| 고려 사항 (Concern) | 폴백 활성화 전 필요한 증거 (Evidence needed before enabling fallback) |
|---|---|
| 입력 및 컨텍스트 (Inputs and context) | 현실적인 티켓 길이와 지원되는 언어가 필수 정보를 누락하지 않고 적합하게 들어맞는지 여부 |
| ... |
각 비율 뒤에 있는 사례 수를 보고하고, 해당 사례들을 어떻게 선택했는지 설명하세요. 언어, 모호한 티켓, 계정 접근 요청 등 관련 그룹별로 결과를 세분화하세요. 작은 성공적인 집합을 프로덕션 동작의 증거로 취급하기 전에 샘플링 불확실성을 고려해야 합니다. 후보 모델이 평가에 쉬운 청구 티켓만 포함되어 있다는 이유만으로 통과해서는 안 됩니다.
폴백 경로가 실제로 우회할 수 있는 것이 무엇인지 확인하세요. 이는 동일한 엔드포인트 뒤의 다른 모델이나 배포, 다른 지역, 또는 다른 제공업체를 선택할 수 있습니다. 자격 증명(credentials), 네트워크 접근, 용량 제한을 포함하여 기본 경로와 공유하는 종속성을 매핑하세요. 동일한 실패 게이트웨이를 통해 모델을 전환한다고 해서 서비스가 복구되는 것은 아닙니다.
구조화된 출력 주장 유지하기 (Keep structured-output claims precise)
스키마 제약형 구조화된 출력(Schema-constrained structured output)과 모델에게 JSON 작성을 요청하는 것은 다른 메커니즘입니다. OpenAI의 구조화된 출력 문서에서는 JSON 모드와 스키마 준수(schema adherence)를 구분하고, 지원되는 JSON Schema 하위 집합을 문서화하며, 거부 처리 방식(refusal handling)을 설명합니다. 각 후보 모델에 대한 해당 문서를 확인하고 통합 동작을 점검하세요.
만약 기본 경로가 스키마 제약형 구조화된 출력을 사용하고 폴백이 프롬프트 기반 JSON을 사용하는 경우, 그 차이는 자격 기록(qualification record)에 포함되어야 합니다. 폴백은 애플리케이션 검증(application validation)을 통해 여전히 기능의 수용 기준을 충족할 수도 있습니다. 단일 성공적인 스모크 테스트만으로는 이를 확립할 수 없습니다.
모든 경로에서 필수 필드와 도메인 규칙을 검증하세요. 불완전한 응답이나 거부를 성공 DTO에 강제로 넣기보다는 정의된 결과로 취급해야 합니다. 스키마 준수는 응답 형태의 속성을 확립합니다. 평가는 라우팅 품질에 대한 증거를 제공하며, 신뢰할 수 있는 시스템 제어(trusted system controls)가 애플리케이션이 제안을 기반으로 행동할 수 있는지 여부를 결정합니다. 일반적인 검증 코드는 모델이 올바른 큐를 선택했음을 증명하지 못합니다.
실패 중 어떤 것이 전환을 허용하는지 정의하기 (Define which failures permit a switch)
모든 것을 처리하는 핸들러(catch-all handler)는 취소된 요청을 다른 모델로 보내거나 애플리케이션의 버그를 숨기는 데 사용될 수 있습니다. 이 두 경우 모두 추가적인 생성 시도를 요구하지 않습니다.
이 라우터에 대해서는 다음과 같은 좁은 정책으로 시작할 것입니다:
| 주요 결과 | 폴백 정책 |
|---|---|
| 임시 모델 서비스 이용 불가 | 요청에 여전히 충분한 예산이 있는 경우 자격 있는 대체재를 허용 (Permit one qualified alternate if the request still has enough budget) |
| ... | |
| 분기점 어댑터(provider adapter)에서 실패를 분류하고 애플리케이션에 안정적인 카테고리를 노출해야 합니다. 임의의 예외 텍스트와 일치시키는 것을 피하세요. 위의 표는 HTTP 상태 코드를 폴백으로 매핑하는 보편적인 것이 아니라 제안된 기능 정책입니다. |
자동 폴백은 필요한 증거(evidence)도 보존해야 합니다. 티켓 라우터가 계약에 필요한 컨텍스트를 얻을 수 없다면, 애플리케이션은 생성된 콘텐츠를 누락된 컨텍스트의 대체재로 취급해서는 안 됩니다. AI 기능을 위한 우아한 저하 (Graceful Degradation for AI Features)에서는 생성이 안전하게 계속될 수 없을 때 제품의 대안을 다룹니다.
요청 예산 내에 폴백 유지하기
폴백은 또 다른 모델 시도와 원래 실행 예산에서 더 많은 입력 토큰을 소모합니다. 주요 시도는 애플리케이션이 사용할 수 있는 응답을 받지 못했더라도 이미 비용이 발생했을 수 있습니다. 이러한 지출을 계산에 포함하세요. 타임아웃 후 사용량 데이터가 누락되는 것이 시도가 무료였다는 증거는 아닙니다.
8초의 마감 시간을 가진 요청을 가정해 봅시다. 주요 시도가 6초를 소모하면, 검증 및 결과 처리를 포함하여 폴백에는 최대 2초만 남습니다. 여기에 새로운 8초 타임아웃을 부여하면 해당 작업이 호출자의 마감 시간보다 오래 지속되게 할 수 있습니다.
각 시도 전에, 후보가 완료 작업까지 포함하여 남은 시간 및 지출 예산 내에 적합한지 확인해야 합니다. 입력, 구성된 출력 제한, 그리고 해당 경로의 다른 청구 가능한 작업을 포함한 적용 가능한 가격을 기반으로 지출을 추정합니다. 실제 완료 시간과 청구 사용량은 나중에 알 수 없을 수도 있습니다. 만약 후보가 입학 정책(admission policy)에 맞지 않는다면, 선택된 이용 불가 또는 검토 결과를 반환해야 합니다. 호출자(caller)의 취소 신호와 전체 마감 시간을 재사용합니다. 시도 시간 초과는 더 짧을 수 있습니다.
이 예시에서는 총 두 번의 아웃바운드 모델 시도를 허용합니다. 의도된 경로는 하나의 기본 시도 후, 필요할 경우 하나의 폴백(fallback) 시도로 이어집니다. SDK 재시도(retry)는 공유 마감 시간 및 시도 예산 외부에 추가 시도를 할 수 없도록 명시적으로 구성하거나 비활성화하거나 고려해야 합니다. 이 정책 하에서 제공업체 클라이언트가 두 번째 아웃바운드 모델 시도를 수행하면, 남은 슬롯을 소모합니다. 그러면 애플리케이션은 폴백을 시작할 수 없습니다. 별도로 자격을 갖춘 복구 호출(repair call) 역시 세 번째를 생성하는 대신 그 슬롯을 소모합니다. AI Systems Need Runtime Budgets에서 이를 더 자세히 설명합니다.
SDK 재시도 계층이 해당 회계에 참여할 수 없다면, 이 정책을 위해 비활성화해야 합니다. 또 다른 설계는 클라이언트 호출과 근본적인 전송 시도에 별도의 제한을 부여할 수 있지만, 두 가지를 모두 계산하고 동일한 실행 예산 내에 유지하는 것이 전제되어야 합니다. 이 정책은 이러한 단위를 명확히 해야 합니다. IChatClient에 대한 호출만 세는 것은 제공업체 클라이언트 내부의 반복 요청을 놓칠 수 있습니다.
폴백 역시 용량 제한이 필요합니다. 기본 서비스 중단 기간 동안 무한한 요청 스트림을 상속받아서는 안 됩니다. 만약 용량이 없다면, 중지하거나 다른 승인된 저하 모드(degradation mode)를 사용해야 합니다.
불확실한 부작용 및 부분 출력에서 중지하기
티켓 라우팅 모델 호출은 티켓을 할당하지 않고 결정을 제안하므로, 애플리케이션은 어떤 것도 확정하기 전에 생성을 반복할 수 있습니다. 도구 사용이 가능한 워크플로우는 더 엄격한 경계가 필요합니다.
만약 주 경로(primary path)가 초안을 저장하는 도구를 호출했다면, 시간 초과(timeout)가 저장이 실패했음을 증명하지 않습니다. 작업을 반복하기 전에 결과(outcome)를 확립하거나 **멱등성 쓰기 계약(idempotent write contract)**을 사용해야 합니다. 알려진 상태에서 재개하고 완료된 동작의 반복을 피하십시오. 권한 부여 및 승인 강제는 모델 외부, 신뢰할 수 있는 시스템 제어 장치에 양쪽 경로 모두에서 유지되어야 합니다. 아키텍처에 따라 이러한 제어 장치는 애플리케이션, 도구 서비스(tool service), 정책 엔진(policy engine) 또는 다운스트림 시스템에 존재할 수 있습니다.
스트리밍은 또 다른 경계를 만듭니다. 애플리케이션이 답변의 일부를 보여준 후, 폴백 모델(fallback model)의 연속 내용을 조용히 추가하는 것은 호환되지 않는 답변을 혼합시킬 수 있습니다. 이 정책에 따라 자동 전환은 가시적인 출력 전과 해결되지 않은 부수 효과(unresolved side effect)가 발생하기 전에만 허용됩니다. 그 경계 이후에는 중단된 결과(interrupted outcome)를 반환하거나 알려진 상태로 명시적 재시작을 제공해야 합니다.
.NET 폴백 API가 처리하는 내용
Microsoft.Extensions.AI 10.9.0 버전에서는 진단용 MEAI001 태그가 붙은 실험적인 라우팅 및 폴백(failover) API가 도입되었습니다. RoutingChatClient는 요청별로 클라이언트를 선택합니다. FailoverChatClient는 폴백 루프를 추가하며, OrderedFailoverChatClient는 구성된 순서대로 클라이언트를 시도합니다.
폴백 루프는 호출이 발생하기 전에 어떤 스트리밍 업데이트가 호출자에게 도달하지 못했을 때 다른 클라이언트를 선택할 수 있습니다. 업데이트가 노출된 후에는 실패가 전환 없이 전파됩니다. 요청 취소(Request cancellation) 또한 재선택을 중단시킵니다. MaximumAttemptsPerRequest는 클라이언트 호출 횟수를 제한합니다. 이는 프로바이더 SDK 내부에 숨겨진 재시도(retry) 횟수는 계산하지 않습니다. 해당 호출자 경계는 가시적인 UI 텍스트보다 더 빠를 수 있습니다. 스트리밍 업데이트가 페이지에 표시되기 전에 파이프라인 컴포넌트에 도달할 수도 있기 때문입니다.
FailoverChatClient는 호출 예외가 발생했을 때 실패 원인이 일시적인지 여부를 먼저 결정하지 않고 다른 클라이언트를 시도할 수 있습니다. 요청이 취소되지 않았고, 스트리밍 출력이 커밋되지 않았으며, 시도 제한을 허용하는 경우, 다른 선택이 이어질 수 있습니다. 따라서 유효하지 않은 자격 증명이나 지원되지 않는 옵션도 전환을 유발할 수 있습니다. OrderedFailoverChatClient는 순서를 제공합니다. 이 클라이언트는 앞선 표의 실패 범주를 구현하지 않습니다.
실패 범주가 부적격한 경우 다음 클라이언트 호출을 차단해야 합니다. 사용자 정의 FailoverChatClient는 시도 업데이트를 검사하고 요청에 대한 정책 상태를 유지하여 해당 규칙을 강제할 수 있습니다. 또는, 제공자 인식 애플리케이션 정책이 디스패치를 담당하여 대체 클라이언트를 아예 호출할지 여부를 결정할 수 있습니다. 또한, 디스패치 전에 남은 예산과 도구 상태도 확인해야 합니다. 애플리케이션은 후보가 작업을 수행할 수 있다는 증거와 대상지가 데이터를 받을 수 있을지에 대한 증거를 여전히 필요로 합니다. 배포하는 패키지 버전에 대해 실험적 API 동작을 확인하십시오.
파이프라인 배치 변경은 도구 동작을 바꿉니다: FunctionInvokingChatClient 주변으로 라우팅하는 것은 전체 도구 루프 시도에 대한 클라이언트를 선택하는 반면, 그 내부에서 라우팅하는 것은 개별 모델 턴(model turns)에 대해 선택합니다. 실제로 배포할 파이프라인 구성과 실패 복구 경계를 명확히 하십시오.
실제 모드를 가시화하기
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기