채팅 서버

채팅 서버 (Chat Server)

OpenAI 호환 Chat Completions API로 에이전트를 노출해서, 이미 OpenAI를 말하는 어떤 도구든 Docker Agent 에이전트를 구동하게 해요.

출처: 문서

본문

개요 (Overview)

docker agent serve chat 명령은 /v1/chat/completions 와 /v1/models 에서 OpenAI 호환 Chat Completions API로 하나 이상의 에이전트를 노출하는 HTTP 서버를 시작해요. 이미 OpenAI 프로토콜을 말하는 어떤 클라이언트 — 예: Open WebUI, curl, OpenAI Python SDK, LangChain — 도 커스텀 통합 없이 Docker Agent 에이전트를 구동할 수 있어요.

# Single agent — exposed as the model `root`
$ docker agent serve chat agent.yaml

# Multi-agent config — every agent in the team becomes a model
$ docker agent serve chat ./team.yaml

# Pick a specific agent from a multi-agent config
$ docker agent serve chat ./team.yaml --agent reviewer

# Run an agent straight from the registry
$ docker agent serve chat myorg/agent:tag --listen 127.0.0.1:9090

# Require a Bearer token, sourced from an env var
$ docker agent serve chat agent.yaml --api-key-env CHAT_BEARER_TOKEN

Tip 채팅 서버 vs API 서버 (When to use chat server vs. API server) Docker Agent를 기존 OpenAI 호환 도구(챗 UI, IDE 통합, OpenAI SDK 클라이언트)에 끼워 넣고 싶을 때 채팅 서버를 사용하세요. 세션, 에이전트 실행, 도구 호출 확인, 스트리밍 런타임 이벤트를 완전히 제어하고 싶을 때는 API 서버를 사용하세요.

엔드포인트 (Endpoints)

OpenAI 호환 엔드포인트는 OpenAI API 표면과 일치하도록 /v1 접두사 아래에 살아요. OpenAPI 사양은 인증 없이 발견될 수 있도록 최상위에 제공돼요.

Method Path Description
GET /v1/models 이 서버가 모델로 노출하는 에이전트 나열
POST /v1/chat/completions 메시지 보내고 완성 받기 (일반 또는 스트리밍)
GET /openapi.json 채팅 서버용 OpenAPI 사양

POST /v1/chat/completions 의 모델 식별자는 에이전트 이름 이에요. 단일 에이전트 구성에서는 보통 root; 다중 에이전트 구성에서는 각 이름 있는 에이전트가 자체 선택 가능한 모델이 돼요.

빠른 시작 (Quick Start)

# 1. Start the server
$ docker agent serve chat agent.yaml
Listening on 127.0.0.1:8083
OpenAI-compatible chat completions endpoint: http://127.0.0.1:8083/v1/chat/completions

# 2. List exposed agents (models)
$ curl http://127.0.0.1:8083/v1/models
{ "object": "list", "data": [{ "id": "root", "object": "model", "owned_by": "docker-agent" }]}

# 3. Send a chat request
$ curl http://127.0.0.1:8083/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
  "model": "root",
  "messages": [{"role": "user", "content": "Hello!"}]
}'

스트리밍 (Streaming)

요청 본문에 "stream": true 를 설정하면 OpenAI 형식 chat.completion.chunk 델타의 Server-Sent Events(SSE) 스트림을 받아요:

$ curl -N http://127.0.0.1:8083/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
  "model": "root",
  "stream": true,
  "messages": [{"role": "user", "content": "Stream a poem"}]
}'

OpenAI Python SDK에서 구동 (Drive it from the OpenAI Python SDK)

와이어 형식이 OpenAI 호환이므로, 어떤 OpenAI 클라이언트든 채팅 서버의 base_url 을 가리키고 에이전트 이름을 모델로 사용해요:

from openai import OpenAI

client = OpenAI(
    base_url="http://127.0.0.1:8083/v1",
    api_key="not-needed-when-no-api-key-flag", # required by the SDK, ignored if no auth
)

resp = client.chat.completions.create(
    model="root",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(resp.choices[0].message.content)

서버 측 대화 캐싱 (Server-side Conversation Caching)

기본적으로 서버는 무상태(stateless)예요: 모든 요청은 OpenAI의 API와 정확히 같이 전체 메시지 기록을 포함해야 해요. --conversations-max 를 양수 값으로 설정해 서버 측 캐싱을 활성화한 뒤, 각 요청에 안정적인 X-Conversation-Id 헤더를 보내요:

$ docker agent serve chat agent.yaml --conversations-max 100 --conversation-ttl 30m
$ curl http://127.0.0.1:8083/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -H 'X-Conversation-Id: my-thread-1' \
  -d '{
  "model": "root",
  "messages": [{"role": "user", "content": "Remember my name is Alice"}]
}'

$ curl http://127.0.0.1:8083/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -H 'X-Conversation-Id: my-thread-1' \
  -d '{
  "model": "root",
  "messages": [{"role": "user", "content": "What is my name?"}]
}'

캐시된 대화는 --conversation-ttl 만큼 비활성 후, 또는 캐시가 --conversations-max 항목에 닿으면(가장 오래된 항목이 먼저 퇴출) 제거돼요.

실패 안전 캐싱 (Failure-safe caching)

요청이 실패하면 — 예를 들어 모델이 에러를 반환하거나 --request-timeout 이 만료되면 — 대화 캐시가 갱신되지 않아요. 서버는 각 요청을 처리하기 전에 캐시된 세션을 클론하고 턴이 성공적으로 완료될 때만 갱신된 세션을 커밋해요. 이는 다음을 의미해요:

  • 실패한 턴은 대화를 요청 전과 같은 상태로 둬요.
  • 클라이언트는 실패 후 같은 X-Conversation-Id 로 안전하게 재시도할 수 있어요.
  • 일시적 에러가 대화 기록을 손상시키지 않아요.

인증 (Authentication)

채팅 서버는 기본적으로 루프백 바인딩을 사용해요. 비루프백 --listen 주소는 --api-key, --api-key-env, 또는 명시적 --insecure-no-auth 재정의를 필요로 해요. --api-key-env 로 선택된 환경 변수는 설정되고 비어 있지 않아야 해요.

Bearer 토큰을 요구하려면 --api-key(리터럴 값) 또는 --api-key-env(값을 담는 환경 변수의 이름)를 전달해요:

$ docker agent serve chat agent.yaml --api-key-env CHAT_BEARER_TOKEN

그러면 클라이언트는 /v1/* 에 대한 모든 요청에 Authorization: Bearer *** 헤더를 보내야 해요. 키가 설정되면 /v1/models 와 /v1/chat/completions 모두 보호돼요.

Warning 공개 노출 (Public exposure) 기본 수신 주소는 127.0.0.1:8083 이에요. --api-key, --api-key-env, --insecure-no-auth 가 제공되지 않으면 비루프백 바인딩은 거부돼요. 인증되지 않은 재정의는 신뢰된 인증 경계 뒤에서만 사용하세요.

도구 안전 (Tool safety)

채팅 서버는 --safety, 에이전트 구성, 런타임 구성, restricted 순으로 안전 정책을 해결해요. 캐시된 대화는 이전 정책과 서버 정책 중 더 제한적인 것을 유지하므로, 서버 정책이 더 엄격해진 후에도 연속이 권한을 되찾을 수 없어요.

CORS

CORS는 기본적으로 비활성화돼요. 브라우저 기반 클라이언트가 서버를 호출하게 하려면 --cors-origin 을 허용되어야 하는 정확한 origin(스킴 + 호스트 + 포트)으로 설정해요:

$ docker agent serve chat agent.yaml --cors-origin https://my-ui.example.com

CLI 플래그 (CLI Flags)

docker agent serve chat <agent-file> | <registry-ref> [flags]
Flag Default Description
-a, --agent <name> (all agents) 노출할 에이전트 이름. 생략하면 구성의 모든 에이전트가 별개 모델로 노출.
-l, --listen <addr> 127.0.0.1:8083 수신 주소
--cors-origin <origin> (none) 허용된 CORS origin (예: https://example.com). 비어 있으면 CORS 비활성화.
--api-key <token> (none) 클라이언트가 제시해야 하는 필수 Bearer 토큰 (Authorization: Bearer ***). 비어 있으면 인증 비활성화.
--api-key-env <name> (none) 필수 API 키를 이 비어 있지 않은 환경 변수에서 읽기
--insecure-no-auth false 인증 없는 비루프백 바인딩 허용. 신뢰된 인증 경계 뒤에서만 사용.
--safety <policy> restricted 도구 안전 정책. CLI 값이 에이전트/런타임 구성을 재정의.
--max-request-size <bytes> 1048576 (1 MiB) 최대 요청 본문 크기(바이트). 본문이 이 한도를 넘는 요청은 HTTP 413(Request Entity Too Large)으로 거부 — 이걸 만나면 Troubleshooting: HTTP 413 참고.
--request-timeout <dur> 5m 요청별 타임아웃(모델 + 도구 호출 + 스트리밍 포함).
--conversations-max <n> 0 최대 N개 대화에 대해 서버 측 캐시, X-Conversation-Id 로 키 매김. 0이면 비활성화 — 클라이언트가 기록을 재전송해야 함.
--conversation-ttl <dur> 30m 캐시된 대화가 제거되는 유휴 TTL.
--max-idle-runtimes <n> 4 에이전트당 풀링되는 최대 유휴 런타임 수. 0이면 풀링 비활성화.

모든 런타임 구성 플래그(--working-dir, --env-from-file, --models-gateway, --hook-*, …)도 받아들여져요.

Note --max-request-size 의 범위 이것은 단일 직렬화된 인바운드 HTTP 요청 본문에 대한 유한하면서 프로세스 전체에 걸친 상한이에요 — 모델 컨텍스트 창 한도가 아니고, 올려도 제공자/모델이 받아들이는 것 또는 로컬 첨부 파일/프롬프트 파일이 얼마나 클 수 있는지를 늘리지 않아요. 더 큰 상한은 서버가 인증되지 않거나 악의적인 클라이언트로부터 요청당 더 많은 메모리를 버퍼링한다는 뜻이므로, 배포의 노출과 저울질하세요. 이 서버 앞에 역방향 프록시나 게이트웨이가 있으면 이 플래그와 무관하게 자체 더 낮은 상한을 강제할 수 있어요. 전체 진단은 Troubleshooting: HTTP 413 참고.

이미지 입력 (Image Inputs)

메시지는 텍스트 옆에 OpenAI 스타일 image_url 콘텐츠 부분을 포함할 수 있어요:

{ "type": "image_url", "image_url": { "url": "data:image/png;base64,..." }}

data: URL은 이미지 바이트를 JSON 본문에 직접 임베드하므로, base64 인코딩된 크기가 다른 요청 콘텐츠처럼 위의 --max-request-size 에 포함돼요. 원격 http(s):// URL은 채팅 서버 자체가 가져오는 대신 선택된 모델 제공자에게 전달돼요 — 동작 여부는 그 제공자와 모델에 달려 있어요: 일부는 원격 URL을 직접 받고, 다른 것들은 data: URL만 받으며, 이미지 지원이 없는 제공자/모델은 그 부분을 버려요. 원격 이미지 URL이 보편적으로 가져와지거나 렌더링될 거라고 가정하지 말고, 구성한 특정 제공자/모델에 대해 검증하세요.

Open WebUI 통합 (Open WebUI Integration)

Open WebUI는 어떤 OpenAI 호환 엔드포인트와도 통신할 수 있어요. Docker Agent를 연결하려면:

  • 채팅 서버를, 선택적으로 인증과 함께 시작해요:
$ docker agent serve chat agent.yaml \
  --listen 127.0.0.1:8083 \
  --cors-origin http://localhost:3000 \
  --api-key-env OPEN_WEBUI_TOKEN
  • Open WebUI에서 OpenAI 호환 연결을 추가해요:
    • API Base URL: http://127.0.0.1:8083/v1
    • API Key: OPEN_WEBUI_TOKEN 의 값
  • 구성의 각 에이전트가 선택 가능한 모델로 나타나요.

Note 참고 (See also) Docker Agent 네이티브 HTTP API(세션, 도구 호출 확인, 런타임 이벤트)는 API Server 참고. 전체 CLI 플래그 문서는 CLI Reference 참고.

더 알아보기 (Learn more)