본문 바로가기
카테고리 없음

Microsoft.Extensions.AI 10.9에서 들어온 챗 클라이언트 라우팅과 장애 조치 API를 .NET 앱에 붙이는 순서

by Juelria 2026. 10. 23.
728x90
반응형
SMALL

Microsoft.Extensions.AI 10.9.0이 2026년 8월 12일에 나오면서 IChatClient 여러 개 중 하나를 골라 쓰는 라우팅 API와, 앞 클라이언트가 실패하면 다음 클라이언트로 넘기는 장애 조치 API가 들어왔습니다. 주 모델 호출이 막혔을 때 보조 모델로 돌리는 코드를 직접 짜 두었다면 바꿔 볼 만한 변경입니다. 다만 전부 실험 API라서 MEAI001 경고를 풀어야 쓸 수 있습니다. 10.11.0 소스의 ChatRouting 폴더에는 빌더 확장 메서드 파일이 보이지 않아 생성자를 직접 부르는 방식으로 씁니다.

10.9.0에서 들어온 것

릴리스 노트가 새 실험 API(MEAI001)로 꼽은 것은 PR #7662입니다. 제목은 Add extensible chat client routing이고 Microsoft.Extensions.AI.Abstractions 패키지에 추상 클래스 RoutingChatClient가 생겼습니다. 이 위에 Microsoft.Extensions.AI 패키지의 SemanticRoutingChatClient, 추상 FailoverChatClient, 구체 OrderedFailoverChatClient가 올라갑니다. 클라이언트를 어떻게 고를지는 SelectClientAsync 한 곳에서 정하고, 시도가 끝날 때마다 OnRoutingUpdateAsync가 결과를 알려 주는 구조입니다.

실험 표시는 모양이 바뀔 수 있다는 뜻입니다. 같은 라인의 10.11.0 릴리스 노트에는 실험 API였던 AddHttpLatencyTelemetry의 이름이 AddHttpServerLatencyTelemetry로 바뀌었다는 항목이 있습니다. 라우팅 쪽도 8월 7일 무렵 병합된 후속 PR #7685가 선택된 클라이언트에 넘기는 옵션을 RoutingContext.ChatOptions로 통일했으니, 업그레이드 때마다 릴리스 노트를 읽는 편이 안전합니다.

순서대로 장애 조치 붙이기

먼저 클라이언트를 각각 만듭니다. 소스 주석은 특정 경로에만 해당하는 옵션을 요청 옵션에 넣지 말고 그 클라이언트 쪽에 설정하라고 안내합니다. RoutingContext가 들고 있는 ChatOptions는 호출자 옵션의 복제본이고, 다음 후보에게도 같은 값이 넘어가기 때문입니다.

그다음 new OrderedFailoverChatClient([주, 보조])처럼 순서대로 묶습니다. 생성자는 IReadOnlyList와 leaveOpen을 받습니다. 빈 목록이나 null 요소는 ArgumentException이고, 같은 클라이언트를 여러 번 넣으면 자리마다 한 번씩 호출됩니다. leaveOpen 기본값이 false라서 이 객체를 폐기하면 안쪽 클라이언트도 같이 폐기됩니다. DI 컨테이너가 이미 수명을 관리하는 클라이언트라면 true를 주세요.

시도 횟수는 FailoverChatClient의 MaximumAttemptsPerRequest로 제한합니다. 기본값은 null이라 후보가 남아 있는 한 계속 넘어가고, 0 이하를 넣으면 예외가 납니다. 값은 요청이 시작될 때 읽히므로 진행 중인 요청에는 영향이 없습니다. 후보를 모두 소진하면 마지막 예외가 그대로 다시 던져집니다.

어떤 실패에서 넘어가는가

비스트리밍 경로의 소스를 보면 호출자가 취소하지 않은 예외는 종류를 가리지 않고 다음 후보로 이어집니다. 일시적인 서버 오류와 요청 자체가 잘못된 오류를 구분하지 않으니, 잘못된 요청까지 보조 모델에 보내고 싶지 않다면 FailoverChatClient를 직접 상속해야 합니다. OnRoutingUpdateAsync 안에서 예외를 던지면 라우팅이 거기서 멈추므로 attempt.Exception을 검사해 다시 던지는 방법이 있습니다. OrderedFailoverChatClient는 sealed라 상속할 수 없습니다.

스트리밍은 규칙이 더 까다롭습니다. 첫 업데이트가 호출자에게 나가기 전의 실패만 넘어가고, 일부 출력이 나간 뒤에 끊기면 그 예외가 그대로 전달됩니다. 중간에 읽기를 멈추고 열거자를 폐기하지 않으면 안쪽 열거자 정리와 마지막 라우팅 업데이트가 모두 빠진다고 소스에 적혀 있으니 await foreach로 돌리세요.

관측에는 FailoverChatClientAttempt를 씁니다. 호출된 Client, 걸린 Duration, 실패 Exception, 스트리밍 출력이 나갔는지 OutputCommitted, 응답이 끝났는지 ResponseCompleted, 첫 업데이트까지의 TimeToFirstUpdate가 들어 있습니다. 어느 모델에서 몇 번 실패했는지 로그로 남기려면 OnRoutingUpdateAsync를 재정의해 여기서 찍으면 됩니다.

의미 기반 라우팅

SemanticRoutingChatClient는 임베딩 생성기, 클라이언트별 예시 문장 목록, 기본 클라이언트, scoreThreshold를 받습니다. 마지막 사용자 메시지를 임베딩해 예시 문장과 코사인 유사도로 견주고, 기준에 못 미치면 기본 클라이언트로 보냅니다. 예시 문장의 임베딩은 처음 쓸 때 만들어 캐시합니다. topK 기본값은 1이고 점수를 합산할지 평균 낼지는 scoreAggregation으로 고릅니다. 예를 들어 코드 질문 예시를 한 클라이언트에, 일상 대화 예시를 다른 클라이언트에 묶어 둘 수 있습니다.

함께 확인할 버전

10.9.0 릴리스 노트에는 Microsoft.Extensions.AI.OpenAI가 OpenAI 패키지를 2.12.x로 묶어 둔다는 경고가 있습니다. 10.10.0(2026년 9월 14일)이 OpenAI 패키지를 2.13.0으로 올리면서 OpenAI Assistants API 지원을 제거했고, 10.11.0(2026년 10월 15일)에는 스트리밍 응답의 빈 모델 ID를 무시하는 수정이 들어갔습니다. 새로 시작한다면 10.11.0 이상에서 출발하고, OPENAI001 실험 API로 있던 Assistants 지원 코드는 10.10.0에서 사라졌다는 점부터 확인하세요.

참고한 자료

728x90
반응형
LIST