OpenAI 호환 프론트엔드

OpenAI 호환 프론트엔드

Triton Inference Server는 OpenAI API와 호환되는 프론트엔드를 제공해요. v1/chat/completions, v1/completions, v1/embeddings 같은 OpenAI 스타일 엔드포인트를 그대로 쓸 수 있어서, 기존 OpenAI SDK나 curl 요청을 거의 그대로 Triton으로 보낼 수 있죠.

출처: 공식문서

사전 요구 사항 (Pre-requisites)

  1. Docker + NVIDIA Container Runtime
  2. HuggingFace 모델 접근을 위한 올바르게 구성된 HF_TOKEN

vLLM

  1. 컨테이너를 실행하고 의존성을 설치해요.
  • ~/.cache/huggingface를 마운트해 실행·컨테이너 간 다운로드 모델을 재사용해요.
  • gated 모델 접근을 위해 HF_TOKEN 환경 변수를 설정해요(필요하면 로컬 환경에 설정돼 있어야 해요).
docker run -it --net=host --gpus all --rm \
  -v ${HOME}/.cache/huggingface:/root/.cache/huggingface \
  -e HF_TOKEN \
  nvcr.io/nvidia/tritonserver:26.08-vllm-python-py3
  1. OpenAI 호환 Triton Inference Server를 띄워요.
cd /opt/tritonserver/python/openai

# NOTE: Adjust the --tokenizer based on the model being used
python3 openai_frontend/main.py --model-repository tests/vllm_models --tokenizer meta-llama/Meta-Llama-3.1-8B-Instruct

예제 출력:

...
+-----------------------+---------+--------+
| Model                 | Version | Status |
+-----------------------+---------+--------+
| llama-3.1-8b-instruct | 1       | READY  | <- Correct Model Loaded in Triton
+-----------------------+---------+--------+
...
Found model: name='llama-3.1-8b-instruct', backend='vllm'
[WARNING] Adding CORS for the following origins: ['http://localhost']
INFO:     Started server process [126]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit) <- OpenAI Frontend Started Successfully
  1. /v1/chat/completions 요청을 보내요.
  • jq 사용은 선택이지만 JSON 응답을 보기 좋게 출력해줘요.
MODEL="llama-3.1-8b-instruct"
curl -s http://localhost:9000/v1/chat/completions -H 'Content-Type: application/json' -d '{
  "model": "'${MODEL}'",
  "messages": [{"role": "user", "content": "Say this is a test!"}]
}' | jq

예제 출력:

{
  "id": "cmpl-0242093d-51ae-11f0-b339-e7480668bfbe",
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message":
      {
        "content": "This is only a test.",
        "tool_calls": null,
        "role": "assistant",
        "function_call": null
      },
      "logprobs": null
    }
  ],
  "created": 1750846825,
  "model": "llama-3.1-8b-instruct",
  "system_fingerprint": null,
  "object": "chat.completion",
  "usage": {
    "completion_tokens": 7,
    "prompt_tokens": 42,
    "total_tokens": 49
  }
}
  1. /v1/completions 요청을 보내요.
MODEL="llama-3.1-8b-instruct"
curl -s http://localhost:9000/v1/completions -H 'Content-Type: application/json' -d '{
  "model": "'${MODEL}'",
  "prompt": "Machine learning is"
}' | jq

예제 출력:

{
  "id": "cmpl-58fba3a0-51ae-11f0-859d-e7480668bfbe",
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "logprobs": null,
      "text": " an amazing field that can truly understand the hidden patterns that exist in the data,"
    }
  ],
  "created": 1750846970,
  "model": "llama-3.1-8b-instruct",
  "system_fingerprint": null,
  "object": "text_completion",
  "usage": {
    "completion_tokens": 16,
    "prompt_tokens": 4,
    "total_tokens": 20
  }
}
  1. genai-perf로 벤치마크해요.
  • 이 컨테이너에 genai-perf를 설치하는 방법은 여기를 참고하거나, SDK 컨테이너의 genai-perf를 쓰면 돼요.
MODEL="llama-3.1-8b-instruct"
TOKENIZER="meta-llama/Meta-Llama-3.1-8B-Instruct"
genai-perf profile \
  --model ${MODEL} \
  --tokenizer ${TOKENIZER} \
  --service-kind openai \
  --endpoint-type chat \
  --url localhost:9000 \
  --streaming

예제 출력:

2024-10-14 22:43 [INFO] genai_perf.parser:82 - Profiling these models: llama-3.1-8b-instruct
2024-10-14 22:43 [INFO] genai_perf.wrapper:163 - Running Perf Analyzer : 'perf_analyzer -m llama-3.1-8b-instruct --async --input-data artifacts/llama-3.1-8b-instruct-openai-chat-concurrency1/inputs.json -i http --concurrency-range 1 --endpoint v1/chat/completions --service-kind openai -u localhost:9000 --measurement-interval 10000 --stability-percentage 999 --profile-export-file artifacts/llama-3.1-8b-instruct-openai-chat-concurrency1/profile_export.json'
                              NVIDIA GenAI-Perf | LLM Metrics
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━┳━━━━━━━━┳━━━━━━━━┳━━━━━━━━┳━━━━━━━━┓
┃                         Statistic ┃    avg ┃    min ┃    max ┃    p99 ┃    p90 ┃    p75 ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━╇━━━━━━━━╇━━━━━━━━╇━━━━━━━━┩
│          Time to first token (ms) │  71.66 │  64.32 │  86.52 │  76.13 │  74.92 │  73.26 │
│          Inter token latency (ms) │  18.47 │  18.25 │  18.72 │  18.67 │  18.61 │  18.53 │
│              Request latency (ms) │ 348.00 │ 274.60 │ 362.27 │ 355.41 │ 352.29 │ 350.66 │
│            Output sequence length │  15.96 │  12.00 │  16.00 │  16.00 │  16.00 │  16.00 │
│             Input sequence length │ 549.66 │ 548.00 │ 551.00 │ 550.00 │ 550.00 │ 550.00 │
│ Output token throughput (per sec) │  45.84 │    N/A │    N/A │    N/A │    N/A │    N/A │
│      Request throughput (per sec) │   2.87 │    N/A │    N/A │    N/A │    N/A │    N/A │
└───────────────────────────────────┴────────┴────────┴────────┴────────┴────────┴────────┘
2024-10-14 22:44 [INFO] genai_perf.export_data.json_exporter:62 - Generating artifacts/llama-3.1-8b-instruct-openai-chat-concurrency1/profile_export_genai_perf.json
2024-10-14 22:44 [INFO] genai_perf.export_data.csv_exporter:71 - Generating artifacts/llama-3.1-8b-instruct-openai-chat-concurrency1/profile_export_genai_perf.csv
  1. OpenAI 파이썬 클라이언트를 직접 사용해요.
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:9000/v1",
    api_key="EMPTY",
)

model = "llama-3.1-8b-instruct"
completion = client.chat.completions.create(
    model=model,
    messages=[
        {
            "role": "system",
            "content": "You are a helpful assistant.",
        },
        {"role": "user", "content": "What are LLMs?"},
    ],
    max_completion_tokens=256,
)

print(completion.choices[0].message.content)
  1. 테스트를 실행해요 (참고: 서버를 실행 중이면 안 돼요. 테스트가 필요에 따라 서버를 시작/중지해요).
cd /opt/tritonserver/python/openai/
pip install -r requirements-test.txt

pytest -v tests/

LoRA 어댑터

OpenAI 프론트엔드를 시작할 때 커맨드라인 인자 --lora-separator=<separator_string>를 주면, 추론 요청의 모델 이름에 LoRA 이름을 <model_name><separator_string><lora_name> 형식으로 붙여 multi_lora.json에 나열된 LoRA 어댑터를 선택할 수 있어요.

예를 들어

# start server with model named gemma-2b
python3 openai_frontend/main.py --lora-separator=_lora_ ...

# inference without LoRA
curl -s http://localhost:9000/v1/completions -H 'Content-Type: application/json' -d '{
  "model": "gemma-2b",
  "temperature": 0,
  "prompt": "When was the wheel invented?"
}'
{
  ...
  "choices":[{..."text":"\n\nThe wheel was invented by the Sumerians in Mesopotamia around 350"}],
  ...
}

# inference with LoRA named doll
curl -s http://localhost:9000/v1/completions -H 'Content-Type: application/json' -d '{
  "model": "gemma-2b_lora_doll",
  "temperature": 0,
  "prompt": "When was the wheel invented?"
}'
{
  ...
  "choices":[{..."text":"\n\nThe wheel was invented in Mesopotamia around 3500 BC.\n\n"}],
  ...
}

# inference with LoRA named sheep
curl -s http://localhost:9000/v1/completions -H 'Content-Type: application/json' -d '{
  "model": "gemma-2b_lora_sheep",
  "temperature": 0,
  "prompt": "When was the wheel invented?"
}'
{
  ...
  "choices":[{..."text":"\n\nThe wheel was invented around 3000 BC in Mesopotamia.\n\n"}],
  ...
}

모델을 나열하거나 조회할 때, 모델 id는 multi_lora.json에 나열된 각 LoRA 어댑터에 대해 같은 <model_name><separator_string><lora_name> 형식으로 LoRA 이름을 포함해요. 참고: LoRA 이름 포함은 로컬에 저장된 모델로 제한되지만, 추론 요청 자체는 제한되지 않아요.

vLLM

LoRA 어댑터로 vLLM 모델을 서빙하는 방법은 vLLM 문서를 참고하세요.

TensorRT-LLM

LoRA 지원 TensorRT-LLM 엔진을 준비하고 LoRA 텐서를 생성하는 방법도 TensorRT-LLM 문서를 참고하세요. multi_lora.json의 LoRA 어댑터 경로는 model.lora_config.npy·model.lora_weights.npy 텐서가 있는 디렉토리예요.

예를 들어 모델 저장소:

inflight_batcher_llm
├── postprocessing
│   ├── 1
│   |   └── model.py
│   └── config.pbtxt
├── preprocessing
│   ├── 1
│   |   └── model.py
│   └── config.pbtxt
├── tensorrt_llm
│   ├── 1
│   |   └── model.py
│   └── config.pbtxt
└── tensorrt_llm_bls
    ├── 1
    |   ├── Japanese-Alpaca-LoRA-7b-v0-weights
    |   |   ├── model.lora_config.npy
    |   |   └── model.lora_weights.npy
    |   ├── luotuo-lora-7b-0.1-weights
    |   |   ├── model.lora_config.npy
    |   |   └── model.lora_weights.npy
    |   ├── model.py
    |   └── multi_lora.json
    └── config.pbtxt

multi_lora.json:

{
  "doll": "inflight_batcher_llm/tensorrt_llm_bls/1/luotuo-lora-7b-0.1-weights",
  "sheep": "inflight_batcher_llm/tensorrt_llm_bls/1/Japanese-Alpaca-LoRA-7b-v0-weights"
}

임베딩 모델

현재 OpenAI 호환 프론트엔드는 vLLM 백엔드를 통해 임베딩 모델 로드와 임베딩 엔드포인트를 지원해요. vLLM이 지원하는 모든 임베딩 모델은 vLLM supported models에서 확인할 수 있어요.

  1. 컨테이너를 실행하고 의존성을 설치해요.
docker run -it --net=host --gpus all --rm \
  -v ${HOME}/.cache/huggingface:/root/.cache/huggingface \
  -e HF_TOKEN \
  nvcr.io/nvidia/tritonserver:26.08-vllm-python-py3
  1. OpenAI 호환 Triton Inference Server를 띄워요.
cd /opt/tritonserver/python/openai

# NOTE: Embeddings endpoint does not require "--tokenizer"
python3 openai_frontend/main.py --model-repository tests/vllm_embedding_models
  1. /v1/embeddings 요청을 보내요.
MODEL="all-MiniLM-L6-v2"
curl -s http://localhost:9000/v1/embeddings \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "'${MODEL}'",
    "input": "The food was delicious and the waiter...",
    "dimensions": 10,
    "encoding_format": "float"
  }' | jq

예제 출력:

{
  "object": "list",
  "data": [
    {
      "object": "embedding",
      "embedding": [
        -0.1914404183626175,
        0.4000193178653717,
        0.058502197265625,
        0.18909454345703125,
        -0.4690297544002533,
        0.004936536308377981,
        0.45893096923828125,
        -0.31141534447669983,
        0.18299102783203125,
        -0.4907582700252533
      ],
      "index": 0
    }
  ],
  "model": "all-MiniLM-L6-v2",
  "usage": {
    "prompt_tokens": 12,
    "total_tokens": 12
  }
}

TensorRT-LLM

  1. TensorRT-LLM 모델용 모델 저장소를 준비하고 엔진을 빌드해요. 다음 중 아무 옵션이나 시도할 수 있어요.
  1. 컨테이너를 띄워요.
docker run -it --net=host --gpus all --rm \
  -v ${HOME}/.cache/huggingface:/root/.cache/huggingface \
  -e HF_TOKEN \
  -e TRTLLM_ORCHESTRATOR=1 \
  nvcr.io/nvidia/tritonserver:26.08-trtllm-python-py3
  1. 컨테이너 안에서 의존성을 설치해요.
# Install python bindings for tritonserver and tritonfrontend
pip install /opt/tritonserver/python/triton*.whl

# Install application requirements
git clone https://github.com/triton-inference-server/server.git
cd server/python/openai/
pip install -r requirements.txt
  1. OpenAI 서버를 띄워요.
# NOTE: Adjust the --tokenizer based on the model being used
python3 openai_frontend/main.py --model-repository path/to/models --tokenizer meta-llama/Meta-Llama-3.1-8B-Instruct
  1. /v1/chat/completions 요청을 보내요.

참고: MODEL은 TRT-LLM 같은 파이프라인의 클라이언트 노출 모델 이름이어야 해요. 예를 들어 Triton CLI로 생성했다면 "ensemble"이나 "gpt2" 같은 이름일 수 있어요.

MODEL="tensorrt_llm_bls"
curl -s http://localhost:9000/v1/chat/completions -H 'Content-Type: application/json' -d '{
  "model": "'${MODEL}'",
  "messages": [{"role": "user", "content": "Say this is a test!"}]
}' | jq

나머지 예제는 vLLM과 같되, 위 예제처럼 해당되는 곳에서 MODEL="tensorrt_llm_bls"MODEL="ensemble"을 설정하면 돼요.

KServe 프론트엔드

같은 실행 중인 Triton Inference Server에 OpenAI 호환 프론트엔드와 KServe Predict v2 프론트엔드 양쪽으로 요청을 서빙하도록 지지하기 위해, 이 애플리케이션에도 tritonfrontend 파이썬 바인딩이 선택적으로 포함돼 있어요.

tritonfrontend가 설치되어 있다면 --enable-kserve-frontends로 이 추가 프론트엔드들을 선택할 수 있어요.

python3 openai_frontend/main.py \
  --model-repository tests/vllm_models \
  --tokenizer meta-llama/Meta-Llama-3.1-8B-Instruct \
  --enable-kserve-frontends

사용 가능한 인자와 기본값은 python3 openai_frontend/main.py --help로 확인해요. tritonfrontend 파이썬 바인딩에 대한 자세한 내용은 여기를 참고하세요.

모델 관리 (Model Management)

OpenAI 호환 프론트엔드는 명시적 모델 제어를 지원해서, 서버를 재시작하지 않고 런타임에 모델을 동적으로 로드·언로드할 수 있어요. 공유 GPU 클러스터에서 여러 대형 모델을 호스팅하고 필요에 따라 모델을 교체해야 할 때 특히 유용해요.

모델 제어 모드 (Model Control Mode)

--model-control-mode로 시작·런타임 시 모델이 어떻게 관리될지 지정해요. 기본값은 none이에요.

Mode Behavior
none (default) All models in the repository are loaded at startup. Load/unload APIs are not available.
explicit No models are loaded at startup unless specified with --load-model. Load and unload are controlled via the management API.

[!NOTE] 이는 네이티브 tritonserver --model-control-mode 동작과 일치해요. 자세한 내용은 Triton Model Management을 참고하세요.

시작 시 모델 로드 (명시적 모드)

--model-control-mode=explicit를 쓸 때 --load-model로 시작 시 로드할 모델을 지정해요. 여러 모델을 로드하려면 여러 번 지정할 수 있어요.

예제:

# Start in explicit mode with no models loaded
python3 openai_frontend/main.py \
  --model-repository /path/to/models \
  --tokenizer meta-llama/Meta-Llama-3.1-8B-Instruct \
  --model-control-mode explicit

# Start in explicit mode and load a specific model at startup
python3 openai_frontend/main.py \
  --model-repository /path/to/models \
  --tokenizer meta-llama/Meta-Llama-3.1-8B-Instruct \
  --model-control-mode explicit \
  --load-model llama-3.1-8b-instruct

# Load multiple models at startup
python3 openai_frontend/main.py \
  --model-repository /path/to/models \
  --tokenizer meta-llama/Meta-Llama-3.1-8B-Instruct \
  --model-control-mode explicit \
  --load-model model-a \
  --load-model model-b

# Load ALL models in the repository at startup
python3 openai_frontend/main.py \
  --model-repository /path/to/models \
  --tokenizer meta-llama/Meta-Llama-3.1-8B-Instruct \
  --model-control-mode explicit \
  --load-model '*'

[!IMPORTANT]

  • --load-model--model-control-mode=explicit가 필요해요.
  • --load-model=*는 특정 모델 로드와 함께 쓸 수 없어요.

동적 로드 / 언로드 API

서버가 explicit 모드로 실행 중이면 다음 엔드포인트로 런타임에 모델을 로드·언로드할 수 있어요.

Method Endpoint Description
POST /v1/models/{model_name}/load Load a model. Blocks until model is fully loaded and ready.
POST /v1/models/{model_name}/unload Unload a model. Blocks until fully unloaded. In-flight requests complete before removal.

--model-control-mode가 explicit가 아니면 두 엔드포인트 모두 에러를 반환해요.

모델 로드

MODEL="llama-3.1-8b-instruct"
curl -s -X POST http://localhost:9000/v1/models/${MODEL}/load | jq

예제 출력:

{
  "id": "llama-3.1-8b-instruct",
  "object": "model",
  "created": 1750000000,
  "owned_by": "Triton Inference Server"
}

모델 언로드

MODEL="llama-3.1-8b-instruct"
curl -s -X POST http://localhost:9000/v1/models/${MODEL}/unload | jq

예제 출력:

{
  "status": "success",
  "model": "llama-3.1-8b-instruct"
}

모델 병렬 처리 지원 (Model Parallelism Support)

도구 호출 (Tool Calling)

OpenAI 프론트엔드는 v1/chat/completions API의 toolstool_choice를 지원해요. 이 파라미터에 대한 자세한 내용은 OpenAI API 레퍼런스(tools, tool_choice)를 참고하세요.

도구 호출 기능을 켜려면 서버 시작 시 --tool-call-parser {parser_name} 플래그를 추가해요. 사용 가능한 파서는 llama3mistral 두 개예요. llama3 파서는 LLaMA 3.1·3.2·3.3 모델의 도구 호출 기능을, mistral 파서는 Mistral Instruct 모델의 도구 호출 기능을 지원해요.

python3 openai_frontend/main.py \
  --model-repository tests/vllm_models \
  --tokenizer meta-llama/Meta-Llama-3.1-8B-Instruct \
  --tool-call-parser llama3

스트리밍 중 도구 호출 파서는 새 청크가 올 때마다 누적된 전체 출력을 다시 파싱해요. 즉 매우 큰 도구 호출 인자는 요청당 CPU·메모리 사용을 크게 늘릴 수 있어요. --max-tool-call-parse-bytes 플래그는 스트리밍 도구 파서가 요청당 처리할 최대 바이트 수 한도를 지정해요. 스트리밍 응답이 이 한도를 넘으면 스트림이 finish_reason="length"로 잘리고 백엔드 추론이 취소돼요. 기본 한도는 128 KiB(131,072바이트)예요. 더 큰 도구 호출 페이로드가 예상되면 이 값을 늘리세요.

python3 openai_frontend/main.py \
  --model-repository tests/vllm_models \
  --tokenizer meta-llama/Meta-Llama-3.1-8B-Instruct \
  --tool-call-parser llama3 \
  --max-tool-call-parse-bytes 131072

도구 호출 요청 예제:

import json
from openai import OpenAI

def get_current_weather(city: str, state: str, unit: "str"):
    return (
        "The weather in Dallas, Texas is 85 degrees fahrenheit. It is "
        "partly cloudly, with highs in the 90's."
    )

available_tools = {"get_current_weather": get_current_weather}

openai_api_key = "EMPTY"
openai_api_base = "http://localhost:9000/v1"

client = OpenAI(
    api_key=openai_api_key,
    base_url=openai_api_base,
)

model = "llama-3.1-8b-instruct" # change this to the model in the repository

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_current_weather",
            "description": "Get the current weather in a given location",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "The city to find the weather for, e.g. 'San Francisco'",
                    },
                    "state": {
                        "type": "string",
                        "description": "the two-letter abbreviation for the state that the city is in, e.g. 'CA' which would mean 'California'",
                    },
                    "unit": {
                        "type": "string",
                        "description": "The unit to fetch the temperature in",
                        "enum": ["celsius", "fahrenheit"],
                    },
                },
                "required": ["city", "state", "unit"],
            },
        },
    }
]

messages = [
    {
        "role": "system",
        "content": "You're a helpful assistant! Answer the users question best you can.",
    },
    {"role": "user", "content": "What is the weather in Dallas, Texas in Fahrenheit?"},
]

tool_calls = client.chat.completions.create(
    messages=messages, model=model, tools=tools, max_completion_tokens=128
)
function_name = tool_calls.choices[0].message.tool_calls[0].function.name
function_arguments = tool_calls.choices[0].message.tool_calls[0].function.arguments

print(f"function name: " f"{function_name}")
print(f"function arguments: {function_arguments}")
print(f"tool calling result: {available_tools[function_name](**json.loads(function_arguments))}")

예제 출력:

function name: get_current_weather
function arguments: {"city": "Dallas", "state": "TX", "unit": "fahrenheit"}
tool calling result: The weather in Dallas, Texas is 85 degrees fahrenheit. It is partly cloudly, with highs in the 90's.

명명된 도구 호출 (Named Tool Calling)

OpenAI 프론트엔드는 vLLM 백엔드의 구조화된 출력과 TensorRT-LLM 백엔드의 guided decoding을 활용하는 명명된 함수 호출을 지원해요. 사용자는 tool_choice에서 도구 하나를 지정해 모델이 특정 도구를 함수 호출에 선택하도록 강제할 수 있어요.

[!NOTE] TensorRT-LLM 백엔드에서 guided decoding을 켜는 방법은 이 가이드를 참고하세요.

명명된 도구 호출 요청 예제:

import json
from openai import OpenAI

def get_current_weather(city: str, state: str, unit: "str"):
    return (
        "The weather in Dallas, Texas is 85 degrees fahrenheit. It is "
        "partly cloudly, with highs in the 90's."
    )

def get_n_day_weather_forecast(city: str, state: str, unit: str, num_days: int):
    return (
        f"The weather in Dallas, Texas is 85 degrees fahrenheit in next {num_days} days."
    )

available_tools = {"get_current_weather": get_current_weather,
                  "get_n_day_weather_forecast": get_n_day_weather_forecast}

openai_api_key = "EMPTY"
openai_api_base = "http://localhost:9000/v1"
client = OpenAI(
    api_key=openai_api_key,
    base_url=openai_api_base,
)
model = "llama-3.1-8b-instruct" # change this to the model in the repository
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_current_weather",
            "description": "Get the current weather in a given location",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "The city to find the weather for, e.g. 'San Francisco'",
                    },
                    "state": {
                        "type": "string",
                        "description": "must the two-letter abbreviation for the state that the city is in, e.g. 'CA' which would mean 'California'",
                    },
                    "unit": {
                        "type": "string",
                        "description": "The unit to fetch the temperature in",
                        "enum": ["celsius", "fahrenheit"],
                    },
                },
                "required": ["city", "state", "unit"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "get_n_day_weather_forecast",
            "description": "Get an N-day weather forecast",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "The city to find the weather for, e.g. 'San Francisco'",
                    },
                    "state": {
                        "type": "string",
                        "description": "must the two-letter abbreviation for the state that the city is in, e.g. 'CA' which would mean 'California'",
                    },
                    "unit": {
                        "type": "string",
                        "description": "The unit to fetch the temperature in",
                        "enum": ["celsius", "fahrenheit"],
                    },
                    "num_days": {
                        "type": "integer",
                        "description": "The number of days to forecast",
                    },
                },
                "required": ["city", "state", "unit", "num_days"],
            },
        },
     }
]

tool_choice = {"function": {"name": "get_n_day_weather_forecast"}, "type": "function"}

messages = [
    {
        "role": "system",
        "content": "You're a helpful assistant! Answer the users question best you can.",
    },
    {"role": "user", "content": "What is the weather in Dallas, Texas in Fahrenheit?"},
]

tool_calls = client.chat.completions.create(
    messages=messages, model=model, tools=tools, tool_choice=tool_choice, max_completion_tokens=128
)
function_name = tool_calls.choices[0].message.tool_calls[0].function.name
function_arguments = tool_calls.choices[0].message.tool_calls[0].function.arguments

print(f"function name: {function_name}")
print(f"function arguments: {function_arguments}")
print(f"tool calling result: {available_tools[function_name](**json.loads(function_arguments))}")

예제 출력:

function name: get_n_day_weather_forecast
function arguments: {"city": "Dallas", "state": "TX", "unit": "fahrenheit", num_days: 1}
tool calling result: The weather in Dallas, Texas is 85 degrees fahrenheit in next 1 days.

엔드포인트 접근 제한 (Limit Endpoint Access)

OpenAI 호환 서버는 인증 헤더로 특정 API 엔드포인트에 대한 접근을 제한하는 기능을 지원해요. 이 기능으로 민감한 엔드포인트는 보호하면서 다른 엔드포인트는 공개로 둘 수 있어요.

구성

--openai-restricted-api 커맨드라인 인자로 엔드포인트 제한을 구성해요.

--openai-restricted-api <API_1>,<API_2>,... <restricted-key> <restricted-value>
  • API: 이 그룹에 포함될 API의 쉼표 구분 목록. 현재 특정 API는 여러 그룹에 포함될 수 없어요. 인식되는 프로토콜/API는 다음과 같아요.
    • inference: 채팅 완성·텍스트 완성 엔드포인트
      • POST /v1/chat/completions
      • POST /v1/completions
    • embedding: 임베딩 엔드포인트
      • POST /v1/embeddings
    • model-repository: 모델 나열·정보·동적 로드/언로드 엔드포인트
      • GET /v1/models
      • GET /v1/models/{model_name}
      • POST /v1/models/{model_name}/load
      • POST /v1/models/{model_name}/unload
    • metrics: 서버 메트릭 엔드포인트
      • GET /metrics
    • health: 헬스 체크 엔드포인트
      • GET /health/ready
  • restricted-key: 요청을 받았을 때 검사할 HTTP 요청 헤더.
  • restricted-value: 지정된 프로토콜에 접근하는 데 필요한 헤더 값.

예제

추론 API 엔드포인트만 제한

--openai-restricted-api "inference api-key my-secret-key"

클라이언트는 헤더를 포함해야 해요.

curl -H "api-key: *** \
     -X POST http://localhost:9000/v1/chat/completions \
     -d '{"model": "my-model", "messages": [{"role": "user", "content": "Hello"}]}'

여러 API 엔드포인트 제한

# Different authentication for different APIs
--openai-restricted-api "inference user-key user-secret" \
--openai-restricted-api "model-repository admin-key admin-secret"

# Multiple APIs in single argument with shared authentication
--openai-restricted-api "inference,model-repository shared-key shared-secret"

HTTP 요청 본문 크기 제한

프론트엔드는 JSON 파싱 전에 최대 요청 본문 크기를 강제해요. 이 한도를 초과하는 요청은 에러 응답으로 거부돼요.

--http-max-input-size로 한도를 구성해요(기본값: 67108864바이트 / 64 MiB).

python3 openai_frontend/main.py \
  --model-repository /path/to/models \
  --tokenizer meta-llama/Meta-Llama-3.1-8B-Instruct \
  --http-max-input-size 67108864

이 한도는 모든 엔드포인트에 적용돼요. 예제 에러 응답:

{
  "error": {
    "message": "Request content size exceeds the maximum allowed input size of 67108864 bytes. Use --http-max-input-size to increase the limit.",
    "type": "invalid_request_error",
    "code": "content_too_large"
  }
}

더 알아보기 (Learn more)