배치 API 가드레일

배치 API 가드레일 (Batch API Guardrails)

배치 입력 파일 안의 레코드를 가드해요. 그래서 배치 작업이 /chat/completions에서 같은 콘텐츠를 차단했을 가드레일을 지나 콘텐츠를 옮기지 못하게 해요.

출처: 문서

본문

동작 방식 (How it works)

배치 작업은 두 단계로 제출돼요. purpose=batch.jsonl 파일을 /v1/files에 업로드하고, 파일 id에 대해 작업을 만들어요. 레코드는 제공자에서만 실행되므로, 업로드가 LiteLLM이 그 콘텐츠를 보유하는 유일한 순간이에요.

그것이 가드레일이 실행되는 곳이에요. 각 레코드는 자체적으로, 그 url이 명명하는 호출 유형 아래에서 스캔돼요. /v1/chat/completions를 대상으로 하는 레코드는 동등한 채팅 요청이 받을 것과 정확히 동일하게 검사해요:

POST /v1/files  (purpose=batch)
        │
        ▼
┌──────────────────────┐
│    LiteLLM Proxy     │  scans every record against your pre_call guardrails
└──────────┬───────────┘
           │
           │  record 1  clean          -> submitted unchanged
           │  record 2  guardrail masks -> submitted with the mask applied
           │  record 3  guardrail blocks -> left out of the file
           │
           ▼
      Provider receives the remaining records

하나의 위반 레코드가 파일을 거부하지 않아요. 배치 작업은 흔히 수천 행을 보유하므로, 하나 때문에 전부 거부하는 것은 원하는 것이 거의 아니에요.

설정 (Setup)

켤 것이 없어요. pre_call에서 실행되는 어떤 가드레일이든 배치 업로드에 적용돼요:

model_list:
  - model_name: gpt-5.6-luna
    litellm_params:
      model: openai/gpt-5.6-luna
      api_key: os.environ/OPENAI_API_KEY
guardrails:
  - guardrail_name: pii-guard
    litellm_params:
      guardrail: presidio
      mode: pre_call
      default_on: true
files_settings:
  - custom_llm_provider: openai
    api_key: os.environ/OPENAI_API_KEY

각 레코드에 일어나는 것 (What happens to each record)

콘텐츠를 다시 쓰는 가드레일(예: PII 마스킹)은 그 재작성이 적용되고 레코드는 그 형태로 제출돼요. 차단하는 가드레일은 그 레코드가 제공자에 도달하는 파일에서 빠지고, 작업의 나머지는 계속돼요.

가드레일이 이의를 제기하지 않은 레코드는 바이트 단위로 그대로 전달되므로, 가드레일을 활성화해도 파일의 나머지를 다시 포맷하지 않아요.

업로드 응답 (The upload response)

응답은 가드레일이 무언가를 바꿨을 때만 존재하는 추가 필드 litellm_batch_guardrail이 있는 평소 파일 객체예요:

curl -sS http://localhost:4000/v1/files \
  -H "Authorization: Bearer ***" \
  -F purpose=batch \
  -F file=@batch_input.jsonl
{
  "id": "file-Cr85eqBTg1WiNb1S4ystvR",
  "object": "file",
  "purpose": "batch",
  "bytes": 594,
  "status": "processed",
  "litellm_batch_guardrail": {
    "submitted_records": 3,
    "modified_records": [
      {"line": 2, "custom_id": "row-2", "action": "redacted", "guardrail": null},
      {"line": 3, "custom_id": "row-3", "action": "dropped", "guardrail": "pii-guard"}
    ]
  }
}

submitted_records는 제공자에 도달한 수예요. modified_records의 각 항목은 custom_id와 업로드한 파일의 1부터 시작하는 줄 번호로 레코드를 식별하므로, 어느 쪽으로든 소스와 대조할 수 있어요.

action은 레코드가 가드레일의 재작성을 적용해 제출됐을 때 redacted, 빠졌을 때 dropped예요.

guardrail은 자기 자신을 식별했을 때 레코드를 버린 가드레일을 명명해요. 이는 의도적으로 이유가 아니라 가드레일을 보고해요. 콘텐츠를 거부하는 가드레일과 fail-closed 기본값에서 도달할 수 없는 가드레일이 같은 방식으로 발생하므로, 이 시점에서 둘을 구분할 수 없어요. 이름은 무엇을 가서 확인할지 알려줘요.

같은 결과가 프록시 로그와 로깅 콜백이 읽는 요청 메타데이터에 기록되므로, 버려진 레코드는 서버 측에서 그리고 호출자에게만이 아니라 보여요.

업로드가 거부될 때 (When the upload is refused)

레코드를 버리는 대신 전체 업로드를 실패시키는 네 가지 경우가 있어요.

  1. 모든 레코드가 차단되면 제출할 것이 없으므로, 업로드는 빈 작업을 만드는 대신 400을 반환해요.
  2. 가드레일에 도달할 수 없거나, 콘텐츠에 대한 결정이 아닌 방식으로 실패하면 업로드는 그 가드레일 자체의 상태를 담은 400을 반환해요. 실제로 검사되지 않은 레코드를 버리면 데이터를 조용히 잃게 되므로 파일이 대신 거부돼요. 이는 백엔드가 다운된 fail-closed 구성의 가드레일을 다루며, 많은 통합이 둘 다 같은 방식으로 보고하므로 정책 블록으로 오인하기 쉬워요.
  3. 가드레일이 민감한 콘텐츠를 다른 모델로 라우팅하도록 구성되어 있으면, 그것을 발동시키는 레코드는 그 줄을 명명하는 400을 반환해요. 배치 파일의 모든 레코드는 한 제공자에 제출되므로, 그 하나의 레코드를 다른 곳으로 보낼 방법이 없어요. 배치 밖에서 보내세요.
  4. 레코드 본문이 객체가 아니거나, messages, prompt, input이 없으면 가드레일이 읽을 것이 없어 업로드가 그 줄을 명명하는 400을 반환해요. 레코드는 그 전에 평소 배치 파일 요구사항에 대해서도 확인되므로, 파싱되지 않거나 custom_id, method, url, body가 없는 줄은 자체 메시지와 함께 더 일찍 거부돼요.

한도 (Limits)

  • pre_call에서 실행되는 가드레일만 배치 레코드를 봐요. post_call만으로 구성된 가드레일은 업로드 시점에 검사할 응답이 없으므로 참여하지 않아요.
  • 레코드 자체 본문의 guardrails 키는 무엇을 실행할지 선택할 때 무시되므로, 레코드가 키나 팀이 선택한 것을 옵트아웃할 수 없어요. 그것은 제공자에 도달하는 레코드에 보존돼요.
  • litellm_params를 통해 특정 배포에 붙은 가드레일은 라우팅 후에 적용되는데, 배치 업로드는 라우팅을 거치지 않으므로 배치 레코드에는 적용되지 않아요.
  • 레코드는 한꺼번에가 아니라 제한된 배치로 스캔되며, 네트워크 백엔드 가드레일이 있는 매우 큰 파일은 업로드에 그만큼 더 오래 걸려요. 스캔될 레코드 수에 대한 캡은 없어요.