콘텐츠로 이동

Middle-Out 메시지 변환

이 문서는 POST /v1/chat/completions에서 실행되는 자동 컨텍스트 피팅을 기록합니다. OpenRouter의 middle-out 변환과 같은 동작입니다(이슈 #2415).

활성화 조건

변환에는 운영자 스위치와 클라이언트의 opt-in이 모두 필요합니다. 둘 중 하나라도 없으면 요청은 그대로 전달되고, 컨텍스트 윈도우를 넘는 입력에는 백엔드의 context-length 오류가 반환됩니다.

  • 운영자 스위치: proxy.middle_out.enabled, 기본값 false입니다. 이 블록은 요청 시점의 설정 스냅샷에서 읽으므로, 리로드는 다음 요청부터 적용됩니다.
  • 클라이언트 opt-in: 요청 본문 최상위의 "transforms": ["middle-out"] 배열입니다. 대소문자는 ASCII 기준으로 구분하지 않으며, transforms 값이 배열이 아니면 무시합니다.

변환이 메시지를 실제로 제거하면 transforms에서 사용한 middle-out 항목을 제거하고, 배열이 비면 키 자체를 제거합니다. 따라서 백엔드는 라우터가 이미 처리한 지시를 다시 받지 않습니다. 다른 변환 이름은 그대로 남습니다. 변환이 실행되지 않으면 페이로드는 바이트 단위로 동일하게 전달됩니다.

피팅 규칙

목표 크기는 모델의 유효 컨텍스트 윈도우에서 출력 예산을 뺀 값입니다.

  • 윈도우는 기본 컨텍스트 윈도우 입장 검사와 같은 캐시된 제한 스냅샷에서 가져오며, 요청의 후보 허용 목록을 적용해 서빙 백엔드별로 해석합니다. 백엔드 I/O는 발생하지 않습니다.
  • 출력 예산은 max_completion_tokens가 null이 아니면 그 값, 아니면 null이 아닌 max_tokens, 둘 다 없으면 proxy.middle_out.default_output_reserve입니다(기본값 1024, 범위 0..=1000000). 0은 유효하며 출력 예약이 없음을 뜻합니다.
  • 입력 추정치는 src/core/prompt_estimate.rs의 공용 typical 추정치로, fallback 예산 계획과 smart routing이 읽는 값과 같습니다.

변환은 추정치가 목표를 초과할 때만 실행됩니다. 컨텍스트 윈도우나 목표를 알 수 없거나 0이면 요청을 건너뜁니다.

제거 알고리즘

  • 선두의 system 또는 developer 메시지 연속 구간은 고정되며 제거되지 않습니다.
  • tool_calls 배열이 비어 있지 않은 assistant 메시지(또는 레거시 function_call이 null이 아닌 메시지)는 뒤따르는 연속된 tool 또는 레거시 function 결과와 하나의 단위를 이룹니다. 나머지 메시지는 각각 하나의 단위이며, 단위는 절대 나뉘지 않습니다.
  • 마지막 user 메시지를 포함하는 단위와 그 뒤의 모든 단위는 보호되므로, 현재 턴은 통째로 유지됩니다. user 메시지가 없으면 마지막 단위를 보호합니다.
  • 고정되지 않은 영역의 앞에서부터 오래된 단위를 하나씩 제거해 추정치가 목표 안에 들어올 때까지 반복합니다. 제거 대상은 연속된 접두 구간이므로, 가장 오래된 중간 기록이 먼저 빠지고 최근 턴이 남습니다.

보호되지 않은 단위를 모두 제거해도 목표를 넘으면 변환은 요청을 피팅하지 않습니다. 페이로드는 그대로 두고, 요청은 변환이 없을 때와 같이 진행됩니다. 즉 설정된 경우 컨텍스트 윈도우 fallback을 타고, 그렇지 않으면 백엔드의 context-length 오류를 반환합니다.

응답 신호

피팅된 응답에는 x-continuum-middle-out 헤더가 붙으며 값은 dropped=<n>;estimated_input_tokens=<n>;target_input_tokens=<n>;context_window=<n>입니다. 버퍼링, 스트리밍, 조기 거부 응답 모두에 적용됩니다. 응답 본문은 평소 형태를 유지합니다. 라우터는 라우팅된 모델, 제거 수, 피팅 후 추정치, 목표, 컨텍스트 윈도우를 담은 info 로그 이벤트도 남깁니다.

폴백과 과금

  • 피팅은 입장 검사와 같은 제한 스냅샷을 사용해 디스패치 전에 실행되므로, 피팅된 요청은 입장 검사를 통과하며 컨텍스트 윈도우 fallback hop(이슈 #2307)을 추가로 타지 않습니다.
  • 백엔드가 받는 입력은 피팅된 페이로드이며, 사용량 정산은 백엔드가 보고한 사용량을 기준으로 하므로 완료된 요청에는 피팅된 입력이 과금됩니다.
  • 토큰 예산의 입장 예약은 변환이 실행되기 전에 레이트 리밋 미들웨어가 원본 클라이언트 본문으로 계산합니다. 따라서 컨텍스트를 초과한 요청은 정산 시점까지 피팅 전 추정치를 예약합니다.

적용 범위

변환은 POST /v1/chat/completions에만 적용됩니다. 이 경로 뒤의 Responses 브리지는 피팅된 페이로드를 그대로 사용하며, 그 밖의 인그레스는 변경 없이 전달됩니다.