고객 / 최종 사용자

고객 / 최종 사용자 (Customers / End-Users)

고객의 지출을 추적하고 예산과 권한을 설정해요.

출처: 문서

본문

고객 지출 + 권한 추적 (Tracking Customer Spend + Permissions)

1. 고객 ID로 LLM API 호출하기

LiteLLM은 다음 순서로 고객/최종 사용자 ID를 확인해요 (첫 매치가 이김):

우선순위 방법 위치 참고
1 x-litellm-customer-id 헤더 요청 헤더 표준 헤더, 항상 확인
2 x-litellm-end-user-id 헤더 요청 헤더 표준 헤더, 항상 확인
3 user_header_mappings의 커스텀 헤더 요청 헤더 general_settings에서 구성
4 user_header_name의 커스텀 헤더 요청 헤더 Deprecated — user_header_mappings 사용
5 user 필드 요청 본문 표준 OpenAI 필드
6 litellm_metadata.user 필드 요청 본문 Anthropic 스타일 메타데이터
7 metadata.user_id 필드 요청 본문 일반 메타데이터 패턴
8 safety_identifier 필드 요청 본문 Responses API

JWT 인증이 우선합니다 (JWT auth takes precedence)

JWT 인증이 end_user_id_jwt_field로 활성화되면 검증된 JWT 클레임의 고객 ID가 위의 모든 헤더와 본문 필드보다 우선해요. 요청에서 공급된 필드는 JWT가 최종 사용자 ID를 산출하지 않을 때만 사용돼요. 클레임이 LiteLLM이 이미 검증한 토큰에서 오므로, 호출자는 x-litellm-end-user-id, metadata.user_id 등으로 재정의할 수 없어요.

옵션 1: 표준 헤더 (권장, 요청 본문 수정 불필요)

curl -X POST 'http://0.0.0.0:4000/chat/completions' \
        --header 'Content-Type: application/json' \
        --header "Authorization: Bearer ***" \
        --header 'x-litellm-end-user-id: ishaan3' \
        --data '{
        "model": "azure-gpt-3.5",
        "messages": [{"role": "user", "content": "what time is it"}]
        }'

x-litellm-customer-idx-litellm-end-user-id 둘 다 지원되며 구성 없이 항상 확인돼요.

옵션 2: 요청 본문의 user 필드 (OpenAI 호환)

curl -X POST 'http://0.0.0.0:4000/chat/completions' \
        --header 'Content-Type: application/json' \
        --header "Authorization: Bearer ***" \
        --data '{
        "model": "azure-gpt-3.5",
        "user": "ishaan3",
        "messages": [{"role": "user", "content": "what time is it"}]
        }'

옵션 3: user_header_mappings의 커스텀 헤더 (구성 가능)

config.yaml:

general_settings:
  user_header_mappings:
    - header_name: "x-my-app-user-id"
      litellm_user_role: "customer"
curl -X POST 'http://0.0.0.0:4000/chat/completions' \
        --header 'Content-Type: application/json' \
        --header "Authorization: Bearer ***" \
        --header 'x-my-app-user-id: ishaan3' \
        --data '{
        "model": "azure-gpt-3.5",
        "messages": [{"role": "user", "content": "what time is it"}]
        }'

옵션 4: litellm_metadata.user (Anthropic 스타일)

curl -X POST 'http://0.0.0.0:4000/chat/completions' \
        --header 'Content-Type: application/json' \
        --header "Authorization: Bearer ***" \
        --data '{
        "model": "claude-sonnet-5",
        "messages": [{"role": "user", "content": "what time is it"}],
        "litellm_metadata": {"user": "ishaan3"}
        }'

옵션 5: metadata.user_id

curl -X POST 'http://0.0.0.0:4000/chat/completions' \
        --header 'Content-Type: application/json' \
        --header "Authorization: Bearer ***" \
        --data '{
        "model": "azure-gpt-3.5",
        "messages": [{"role": "user", "content": "what time is it"}],
        "metadata": {"user_id": "ishaan3"}
        }'

customer_id는 새 지출과 함께 DB에 upsert돼요. 이미 존재하면 지출이 증가해요.

2. 고객 지출 가져오기

전체 지출 (All-up spend)

/customer/info를 호출해 고객의 전체 지출을 얻어요:

# end_user_id: 👈 CUSTOMER ID
# Authorization: *** YOUR PROXY KEY
curl -X GET 'http://0.0.0.0:4000/customer/info?end_user_id=ishaan3' \
        -H "Authorization: Bearer ***"

예상 응답:

{
    "user_id": "ishaan3",
    "blocked": false,
    "alias": null,
    "spend": 0.001413,
    "allowed_model_region": null,
    "default_model": null,
    "litellm_budget_table": null
}

이벤트 웹훅

클라이언트 측 DB에서 지출을 업데이트하려면 프록시를 웹훅으로 지정하세요. 예를 들어 서버가 https://webhook.site이고 6ab090e8-c55f-4a23-b075-3209f5c57906에서 수신 중이라면:

export WEBHOOK_URL="https://webhook.site/6ab090e8-c55f-4a23-b075-3209f5c57906"

config.yaml에 'webhook' 추가:

general_settings:
  alerting: ["webhook"] # 👈 KEY CHANGE

테스트!

curl -X POST 'http://localhost:4000/chat/completions' \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer ***" \
-D '{
    "model": "mistral",
    "messages": [
        {
        "role": "user",
        "content": "What's the weather like in Boston today?"
        }
    ],
    "user": "krrish12"
}'

예상 응답 (웹훅 이벤트 페이로드):

{
  "spend": 0.0011120000000000001, # 👈 SPEND
  "max_budget": null,
  "token": "example-api-key-123",
  "customer_id": "krrish12",  # 👈 CUSTOMER ID
  "user_id": null,
  "team_id": null,
  "user_email": null,
  "key_alias": null,
  "projected_exceeded_date": null,
  "projected_spend": null,
  "event": "spend_tracked",
  "event_group": "customer",
  "event_message": "Customer spend tracked. Customer=krrish12, spend=0.0011120000000000001"
}

Webhook Spec 참고.

어떤 ID가 고객이 되는지 제한하기 (Restricting Which IDs Become Customers)

LiteLLM이 보는 모든 고유 고객 ID는 customer 테이블에 upsert돼요. 이는 클라이언트가 세션별 식별자를 보낼 때 문제가 돼요. 예를 들어 Claude Code는 metadata.user_id에 JSON blob을 넣어요:

{"device_id": "4ec41ed1...", "account_uuid": "...", "session_id": "..."}

그러면 각 세션이 Usage -> Customer Usage에서 자체 고객으로 들어가고, 기본 고객 예산을 구성했다면 각 세션이 그 예산의 자체 사본을 얻게 돼요. 실제 고객을 위한 월별 캡이 그 트래픽에 세션별 캡이 되는 거예요.

그 ID들을 제외하려면 validate_end_user_id_in_db를 설정하세요. v1.87.0 이상에서 사용 가능해요.

config.yaml:

litellm_settings:
  validate_end_user_id_in_db: true

그러면 ID는 기존 고객의 user_id, 내부 사용자의 user_id, 내부 사용자의 이메일과 일치할 때만 수락돼요. JSON 객체나 배열 형태의 ID는 데이터베이스 조회 전에 버려지는데, 그것은 진짜 고객 식별자가 아니기 때문이에요. 버리는 것은 오류가 아니에요. 요청은 여전히 성공하고, 단지 고객이 없을 뿐이며, 지출은 평소처럼 가상 키, 팀, 내부 사용자에 귀속돼요. 조회는 ID가 해석되면 5분, 아니면 1분 동안 캐시되므로, 새로 만든 고객을 인식하는 데 최대 1분이 걸릴 수 있어요.

미등록 고객용 기본 예산 유지하기 (Keeping a default budget for unregistered customers)

그 자체로 validate_end_user_id_in_db는 일치하는 행이 없는 모든 ID를 버려요. 이는 명시적으로 만들지 않은 고객을 캡하려고 max_end_user_budget_id에 의존하는 경우와 상충돼요. 둘 다 설정하면 협력해요. JSON 형태 ID는 여전히 버려지고, 행이 없는 일반 문자열 ID는 기본 예산이 여전히 적용되도록 보존돼요.

config.yaml:

litellm_settings:
  validate_end_user_id_in_db: true
  max_end_user_budget_id: "your_default_budget_id"

내부 트래픽을 한 고객 아래로 버킷팅 (Bucketing internal traffic under one customer)

그 트래픽을 버리는 대신 라벨링하고 싶다면 클라이언트가 x-litellm-customer-id를 보내게 하세요. 헤더는 본문 필드보다 먼저 확인되므로 헤더가 클라이언트가 metadata.user_id에 넣는 것보다 이겨요. Claude Code는 다른 변경 없이 ANTHROPIC_CUSTOM_HEADERS로 설정할 수 있어요. Claude Code granular cost tracking 참고.

그 고객을 자체 예산으로 /customer/new를 통해 만드세요. 이는 validate_end_user_id_in_db를 충족하고, 명시적 고객 예산이 기본 예산보다 우선하므로 내부 트래픽이 실제 고객과 다른 한도를 가질 수 있어요.

고객 객체 권한 설정 (Setting Customer Object Permissions)

고객이 액세스할 수 있는 리소스(MCP 서버, 벡터 스토어, 에이전트)를 제어해요.

객체 권한이란? (What are Object Permissions?)

객체 권한은 고객 액세스를 특정 리소스로 제한할 수 있게 해줘요:

  • MCP Servers: 고객이 호출할 수 있는 MCP 서버 제한
  • MCP Access Groups: 고객을 미리 정의된 MCP 서버 그룹에 할당
  • MCP Tool Permissions: 고객이 사용할 수 있는 MCP 서버 내 도구의 세분화된 제어
  • Vector Stores: 고객이 쿼리할 수 있는 벡터 스토어 제어
  • Agents: 고객이 상호작용할 수 있는 에이전트 제한
  • Agent Access Groups: 고객을 미리 정의된 에이전트 그룹에 할당

객체 권한으로 고객 생성:

curl -L -X POST 'http://localhost:4000/customer/new' \
-H "Authorization: Bearer ***" \
-H 'Content-Type: application/json' \
-d '{
    "user_id": "user_1",
    "object_permission": {
      "mcp_servers": ["server_1", "server_2"],
      "mcp_access_groups": ["public_group"],
      "mcp_tool_permissions": {
        "server_1": ["tool_a", "tool_b"]
      },
      "vector_stores": ["vector_store_1"],
      "agents": ["agent_1"],
      "agent_access_groups": ["basic_agents"]
    }
  }'

파라미터:

  • mcp_servers (선택, List[str]): 허용된 MCP 서버 ID 목록
  • mcp_access_groups (선택, List[str]): MCP 액세스 그룹 이름 목록
  • mcp_tool_permissions (선택, Dict[str, List[str]]): 서버 ID에서 허용 도구 이름으로의 매핑
  • vector_stores (선택, List[str]): 허용된 벡터 스토어 ID 목록
  • agents (선택, List[str]): 허용된 에이전트 ID 목록
  • agent_access_groups (선택, List[str]): 에이전트 액세스 그룹 이름 목록

참고: object_permission이 null 또는 {}이면 고객에게 객체 수준 제한이 없어요.

고객 객체 권한 업데이트:

기존 고객의 객체 권한을 업데이트할 수 있어요:

curl -L -X POST 'http://localhost:4000/customer/update' \
-H "Authorization: Bearer ***" \
-H 'Content-Type: application/json' \
-d '{
    "user_id": "user_1",
    "object_permission": {
      "mcp_servers": ["server_3"],
      "vector_stores": ["vector_store_2", "vector_store_3"]
    }
  }'

고객 객체 권한 보기:

고객 정보를 조회하면 객체 권한이 응답에 포함돼요:

curl -X GET 'http://0.0.0.0:4000/customer/info?end_user_id=user_1' \
    -H "Authorization: Bearer ***"

응답:

{
  "user_id": "user_1",
  "blocked": false,
  "alias": "John Doe",
  "spend": 0.0,
  "object_permission": {
    "object_permission_id": "perm_abc123",
    "mcp_servers": ["server_1", "server_2"],
    "mcp_access_groups": ["public_group"],
    "mcp_tool_permissions": {
      "server_1": ["tool_a", "tool_b"]
    },
    "vector_stores": ["vector_store_1"],
    "agents": ["agent_1"],
    "agent_access_groups": ["basic_agents"]
  },
  "litellm_budget_table": null
}

사용 사례 (Use Cases)

1. 계층형 액세스 제어 (Tiered Access Control)

고객을 위한 서로 다른 권한 티어 만들기:

무료 티어 고객:

# Free tier - limited access
curl -L -X POST 'http://localhost:4000/customer/new' \
-H "Authorization: Bearer ***" \
-H 'Content-Type: application/json' \
-d '{
    "user_id": "free_user",
    "budget_id": "free_tier",
    "object_permission": {
      "mcp_access_groups": ["public_group"],
      "agent_access_groups": ["basic_agents"]
    }
  }'

프리미엄 티어 고객:

# Premium tier - full access
curl -L -X POST 'http://localhost:4000/customer/new' \
-H "Authorization: Bearer ***" \
-H 'Content-Type: application/json' \
-d '{
    "user_id": "premium_user",
    "budget_id": "premium_tier",
    "object_permission": {
      "mcp_servers": ["server_1", "server_2", "server_3"],
      "vector_stores": ["vector_store_1", "vector_store_2"],
      "agents": ["agent_1", "agent_2", "agent_3"]
    }
  }'

2. 부서별 액세스 (Department-Specific Access)

고객을 부서 관련 리소스로 제한:

curl -L -X POST 'http://localhost:4000/customer/new' \
-H "Authorization: Bearer ***" \
-H 'Content-Type: application/json' \
-d '{
    "user_id": "sales_user",
    "object_permission": {
      "mcp_servers": ["crm_server", "email_server"],
      "agents": ["sales_assistant"],
      "vector_stores": ["sales_knowledge_base"]
    }
  }'

3. 도구 수준 제한 (Tool-Level Restrictions)

MCP 서버 내 특정 도구에만 액세스 부여:

curl -L -X POST 'http://localhost:4000/customer/new' \
-H "Authorization: Bearer ***" \
-H 'Content-Type: application/json' \
-d '{
    "user_id": "restricted_user",
    "object_permission": {
      "mcp_servers": ["database_server"],
      "mcp_tool_permissions": {
        "database_server": ["read_only_query", "get_table_schema"]
      }
    }
  }'

고객 예산 설정 (Setting Customer Budgets)

LiteLLM 프록시에서 고객 예산(예: 월별 예산, tpm/rpm 한도)을 설정해요.

모든 고객의 기본 예산 (Default Budget for All Customers)

명시적 예산이 없는 모든 고객에게 예산 한도를 적용해요. 모든 최종 사용자에 대한 요율 제한과 지출 제어에 유용해요.

1단계: 기본 예산 만들기

curl -X POST 'http://localhost:4000/budget/new' \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer ***" \
-d '{
    "max_budget": 10,
    "rpm_limit": 2,
    "tpm_limit": 1000
}'

2단계: 기본 예산 ID 구성

config.yaml:

litellm_settings:
  max_end_user_budget_id: "budget_id_from_step_1"

3단계: 테스트

curl -X POST 'http://localhost:4000/chat/completions' \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer ***" \
-d '{
    "model": "gpt-5.6-luna",
    "messages": [{"role": "user", "content": "Hello"}],
    "user": "my-customer-id"
}'

고객은 기본 예산 한도(RPM, TPM, $ 예산)의 적용을 받아요. 명시적 예산이 있는 고객은 영향을 받지 않으며, 기본은 아직 데이터베이스에 없는 고객에게도 적용돼요. LiteLLM은 예산 객체를 60초 동안 캐시하므로, 편집이 적용되는 데 최대 1분이 걸려요.

float 설정 max_end_user_budget은 더 이상 강제되지 않아요. 콘피그에 있다면 위처럼 max_end_user_budget_id로 교체하세요.

기본은 고객 추적으로 도달하는 모든 ID에 적용되며, 에이전트 클라이언트가 보내는 세션별 ID도 포함해요. 실제 고객이 기본 예산을 유지하면서 그 ID들을 customer 테이블 밖에 두고 싶다면 Restricting Which IDs Become Customers를 보세요.

빠른 시작 (Quick Start)

예산으로 고객 생성/업데이트:

예산으로 새 고객 만들기:

curl -X POST 'http://0.0.0.0:4000/customer/new' \
             -H "Authorization: Bearer ***" \
             -H 'Content-Type: application/json' \
             -d '{
        "user_id" : "my-customer-id",
        "max_budget": 10
    }'

/customer/new는 인라인 예산 필드를 받아요: max_budget, soft_budget, budget_duration, tpm_limit, rpm_limit, max_parallel_requests, model_max_budget. max_budget 또는 budget_id 중 하나만 설정하세요. 둘 다 전달하면 거부돼요. 고객 tpm_limit과 rpm_limit은 예산 객체에 저장되므로, 고객이 예산에 연결되어 있을 때만 적용돼요. 위처럼 인라인으로 또는 budget_id를 통해.

/customer/update는 더 좁은 필드 세트를 받아요: user_id, alias, blocked, max_budget, budget_id, allowed_model_region, default_model, object_permission. 다른 것(tpm_limit, rpm_limit, budget_duration 포함)은 조용히 버려져요. 그것들을 바꾸려면 대신 /budget/update로 예산 객체를 업데이트하세요.

고객 예산은 배포당 전역이에요. 지출은 고객 id 단독으로 추적되므로, 같은 고객이 모든 가상 키와 팀에서 하나의 예산을 공유하며, 고객 예산을 단일 키나 팀에 범위 지정할 수 없어요.

테스트!

curl -X POST 'http://localhost:4000/chat/completions' \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer ***" \
-D '{
    "model": "mistral",
    "messages": [
        {
        "role": "user",
        "content": "What's the weather like in Boston today?"
        }
    ],
    "user": "ishaan-jaff-48"
}'

가격 티어 할당 (Assign Pricing Tiers)

가격 티어를 만들고 고객을 할당해요.

1. 예산 만들기

UI의 'Budgets' 탭으로 가서 '+ Create Budget'을 클릭하고 가격 티어(예: 예산 $4인 'my-free-tier')를 만드세요. 이는 이 가격 티어의 각 사용자가 최대 예산 $4를 갖게 됨을 의미해요.

API 호출:

curl -X POST 'http://localhost:4000/budget/new' \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer ***" \
-D '{
    "budget_id": "my-free-tier",
    "max_budget": 4
}

info

tpm_limit과 rpm_limit은 예산에서 선택이에요. 설정하지 않으면 null로 저장되며, 그 예산의 고객에 대해 LiteLLM이 고객별 TPM/RPM 한도를 강제하지 않아요. 제공자 자체 요율 제한만 적용돼요. LiteLLM이 고객을 캡하게 하려고 할 때만 설정하세요.

curl -X POST 'http://localhost:4000/budget/info' \
  -H 'Authorization: Bearer ***' \
  -H 'Content-Type: application/json' \
  -d '{"budgets": ["my-free-tier"]}'

LiteLLM 한도가 설정되지 않으면 tpm_limit과 rpm_limit은 null로 돌아와요.

2. 고객에게 예산 할당

애플리케이션 코드에서 새 고객을 만들 때 예산을 할당해요. 예산을 만들 때 사용한 budget_id를 사용하세요. 예시에서는 my-free-tier예요.

curl -X POST 'http://localhost:4000/customer/new' \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer ***" \
-D '{
    "user_id": "my-customer-id",
    "budget_id": "my-free-tier" # 👈 KEY CHANGE
}

3. 테스트!

curl:

curl -X POST 'http://localhost:4000/customer/new' \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer ***" \
-D '{
    "user_id": "my-customer-id",
    "budget_id": "my-free-tier" # 👈 KEY CHANGE
}

OpenAI SDK:

from openai import OpenAI

client = OpenAI(
  base_url="<your_proxy_base_url>",
  api_key="<your_proxy_key>")

completion = client.chat.completions.create(
  model="gpt-5.6-luna",
  messages=[
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Hello!"}
  ],
  user="my-customer-id")
print(completion.choices[0].message)