본문 바로가기
C.W.K.
Stream
Lesson 06 of 07 · published

내장 OpenAI-호환 서버

~14 min · server, openai-compatible, api

Level 0호기심
0 XP0/51 lessons0/15 achievements
0/100 XP to next level100 XP to go0% complete

OpenAI 방식 서버가 이미 들어 있어

mlx-lm에는 OpenAI API와 같은 요청·응답 모양으로 /v1/chat/completions를 제공하는 HTTP 서버가 있어. OpenAI 프로토콜을 아는 공식 openai Python SDK, LangChain, LlamaIndex, 셸 별칭을 로컬 mlx-lm 서버로 돌리면 그대로 동작해.

MLX 모델 하나를 가장 적은 노력으로 배포하는 방법이야. 명령 하나로 안정된 HTTP 엔드포인트를 열고, 이미 OpenAI를 아는 도구에서 곧바로 말을 걸 수 있어. 동시 요청, 대기열, 여러 모델처럼 운영에서 중요한 문제는 prod.lesson1에서 다루고 여기서는 단순한 경우에 집중해.

서버를 시작해

준비는 두 줄이야. 모델은 시작할 때 한 번 불러온 뒤 요청 사이에도 메모리에 남아 있어. 다음 요청부터는 추론 비용만 내.

openai-python으로 호출해

OpenAI 클라이언트의 주소를 기본 포트인 http://localhost:8080/v1로 바꿔. 포트는 설정할 수 있어. API 키에는 비어 있지 않은 아무 문자열이나 넣어. 로컬 서버는 인증하지 않아. 그다음은 OpenAI를 호출하듯 쓰면 돼.

되는 것과 안 되는 것

  • 돼: chat-completions 엔드포인트, 스트리밍 SSE 응답, 모델 이름에 따른 분기, temperature·top_p·max_tokens 같은 기본 샘플링 값이 동작해. 여러 포트에 인스턴스를 띄우면 여러 모델도 서빙할 수 있어.
  • 안 돼: mlx-lm은 텍스트 생성 서버라 embeddings를 제공하지 않아. 함수 호출은 모델과 템플릿에 달려 있어 OpenAI의 정확한 JSON 스키마를 늘 지원하지는 않아. 파인튜닝 엔드포인트도 없고 트랙 5의 자체 LoRA 흐름을 써야 해.
  • 프로세스 하나야: 내장 서버는 단일 프로세스로 돌아. 대기열과 여러 작업자를 쓰는 진짜 동시 서빙은 prod.lesson1에서 mlx-lm을 얇은 FastAPI 계층으로 감싸 해결할 거야.

어디까지 내장 서버로 충분할까

로컬 개발, 사용자 한 명짜리 시연, 나와 팀원 한 명 정도만 쓰는 내부 도구라면 충분해. 외부 사용자가 있거나 동시 요청, 인증, 호출 제한이 필요하다면 FastAPI 계층으로 넘어가. 기준은 MLX 자체가 아니라 트래픽과 운영 요구야.

Code

서버 시작 (한 터미널에서)·bash
# In a terminal with the `mlx` env activated:
conda activate mlx

# Start mlx-lm's built-in OpenAI-compatible HTTP server.
# Default port is 8080. The model is loaded once at startup.
python -m mlx_lm server \
  --model mlx-community/Llama-3.2-1B-Instruct-4bit

# You'll see startup logs ending with something like:
#   Starting httpd at 127.0.0.1:8080
#
# Leave this terminal running; the next code block talks to it from a second terminal.
openai-python으로 호출하기 — 두 번째 터미널·python
# In a separate terminal with openai-python installed:
#   pip install openai
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8080/v1",
    api_key="not-used-but-required",     # any non-empty string is fine
)

resp = client.chat.completions.create(
    model="mlx-community/Llama-3.2-1B-Instruct-4bit",
    messages=[
        {"role": "system", "content": "You are a terse assistant."},
        {"role": "user",   "content": "Capital of France?"},
    ],
    max_tokens=20,
    temperature=0.7,
)
print(resp.choices[0].message.content)
# → "Paris." (or close to it)
같은 클라이언트로 스트리밍 응답·python
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8080/v1", api_key="x")

stream = client.chat.completions.create(
    model="mlx-community/Llama-3.2-1B-Instruct-4bit",
    messages=[{"role": "user", "content": "Count 1 to 5:"}],
    max_tokens=30,
    stream=True,
)

for chunk in stream:
    delta = chunk.choices[0].delta.content
    if delta:
        print(delta, end="", flush=True)
print()

External links

Exercise

한 터미널에서 서버를 시작하고 두 번째 터미널에서 openai-python 클라이언트로 단일 응답과 스트리밍 응답을 모두 호출해. 이어서 Cursor나 이미 쓰는 OpenAI 호환 클라이언트를 같은 모델 이름과 http://localhost:8080/v1로 설정해. 실제 채팅이 처음부터 끝까지 동작하는지 확인해. 클라이언트마다 설정 하나만 바꾸면 mlx-lm이 별도 번역 계층 없이 OpenAI 생태계 자리에 들어간다는 걸 느껴봐.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.