Guide · 1 of 4
가이드 · 1 / 4
Run and configure the server
서버 실행과 설정
Choose a model, set keys, and know how the engine runs it.
모델을 고르고, 키를 설정하고, 엔진이 모델을 어떻게 돌리는지 알아봅니다.
Host and port
호스트와 포트
uv run --extra torch python -m api run server [host] [port] [--reload] # defaults: 127.0.0.1 23100
GEMSTONE_HOST=0.0.0.0:11434 uv run --extra torch python -m api run server # host[:port], like OLLAMA_HOST
The server listens on loopback only. GEMSTONE_HOST overrides the address; the host and port arguments win over it. It reloads on code changes only with --reload or GEMSTONE_DEV=1, and keeps WebSockets alive for 300 seconds of silence, so that a slow first token does not drop the connection.
서버는 loopback 에서만 듣습니다. GEMSTONE_HOST 로 주소를 바꾸며, host·port 인자가 우선합니다. 코드가 바뀔 때의 재시작은 --reload 또는 GEMSTONE_DEV=1 일 때만 하고, WebSocket 을 300초 침묵까지 유지합니다. 첫 토큰이 늦어도 연결이 끊기지 않게 하기 위해서입니다.
Origins and API key
Origin 과 API 키
Browsers may call the server from localhost, 127.0.0.1, [::1] (any port) and the server's own origin. Add others with GEMSTONE_ORIGINS (comma-separated, * allowed). A foreign origin gets no CORS headers, a state-changing request from it is answered 403, and its WebSocket is refused. Requests without an Origin header (the Ollama CLI, the SDKs) always pass.
브라우저는 localhost, 127.0.0.1, [::1] (모든 포트)과 서버 자신의 origin 에서 서버를 부를 수 있습니다. 다른 origin 은 GEMSTONE_ORIGINS (쉼표로 구분, * 허용)로 더합니다. 외부 origin 에는 CORS 헤더가 붙지 않고, 상태를 바꾸는 요청은 403, WebSocket 은 거절됩니다. Origin 헤더가 없는 요청(Ollama CLI, SDK)은 항상 통과합니다.
GEMSTONE_API_KEY=s3cret uv run --extra torch python -m api run server
curl -H "Authorization: Bearer s3cret" http://127.0.0.1:23100/api/models
With GEMSTONE_API_KEY set, every route needs Authorization: Bearer <key>; a WebSocket may instead pass ?api_key=<key>. The web assets, HEAD / and GET /api/version stay open. Without a key on a non-loopback bind the server logs one warning at start-up and still serves, for Ollama compatibility.
API 키를 설정하면 모든 경로에 Authorization: Bearer <key> 가 필요하며, WebSocket 은 대신 ?api_key=<key> 를 쓸 수 있습니다. 웹 에셋, HEAD /, GET /api/version 은 열려 있습니다. loopback 이 아닌 주소에 키 없이 띄우면 시작 시 경고를 한 번 남기고 Ollama 호환을 위해 그대로 서비스합니다.
Models
모델
| IdId | Weights가중치 | Context컨텍스트 | Tools도구 |
|---|---|---|---|
qwen3 (default)qwen3 (기본) | Qwen/Qwen3-0.6B | 40 960 | yes예 |
GET /api/models lists them. Each model file in api/src/main/models/ sets its own system prompt and sampling defaults.
GET /api/models 가 목록을 돌려줍니다. api/src/main/models/ 의 모델 파일마다 시스템 프롬프트와 샘플링 기본값을 정합니다.
Engine
엔진
One engine, api/src/main/engine.py, serves every model. It is built on transformers and runs on whatever import torch resolves to: upstream PyTorch, or torchnative, which replaces import torch. Choose one when you install: uv sync --extra torch or uv sync --extra torchnative (not both), because torchnative replaces import torch. The engine has no GGUF, BIN or GPTQ backend; they were removed in #84.
엔진 하나, api/src/main/engine.py 가 모든 모델을 서빙합니다. transformers 기반이며 import torch 가 가리키는 것 위에서 돕니다. upstream PyTorch 이거나, import torch 를 대체하는 torchnative 입니다. 설치할 때 하나를 고르세요: uv sync --extra torch 또는 uv sync --extra torchnative (둘 다는 안 됩니다). torchnative 가 import torch 를 대체하기 때문입니다. 엔진에는 GGUF, BIN, GPTQ 백엔드가 없습니다. #84 에서 제거했습니다.
Generation streams. Concurrent requests to a model are batched (continuous batching with a paged KV cache); a request the batch cannot serve runs alone, and a request that waits longer than GEMSTONE_QUEUE_TIMEOUT (300 s by default) gets HTTP 503 or WebSocket close code 1013. A WebSocket client that disconnects stops its generation. The paged cache uses plain torch operations; a faster paged-attention kernel is planned (#74).
생성은 스트리밍됩니다. 한 모델에 동시에 들어온 요청은 배치로 묶입니다(페이지드 KV 캐시를 쓰는 연속 배칭). 배치가 처리할 수 없는 요청은 혼자 실행되고, GEMSTONE_QUEUE_TIMEOUT(기본 300초)보다 오래 기다린 요청은 HTTP 503 또는 WebSocket 종료 코드 1013 을 받습니다. WebSocket 클라이언트가 연결을 끊으면 그 생성이 멈춥니다. 페이지드 캐시는 일반 torch 연산을 씁니다. 더 빠른 paged-attention 커널은 계획 단계입니다(#74).
The engine runs on the CPU. CUDA is planned as a cuda extra (#164). 8-bit (q8_0) weights through torchnative are implemented in Gemstone but do not work on the current torchnative release: on 0.1.0b6 generation fails, because its torch._C shim lacks triu_, nansum and Generator.get_state, and importing it re-enables the GIL on 3.15t (#177). 4-bit weights and GGUF are planned (#67); they depend on torchnative.
엔진은 CPU 에서 돕니다. CUDA 는 cuda extra 로 계획되어 있습니다(#164). torchnative 를 통한 8비트(q8_0) 가중치는 Gemstone 에 구현되어 있지만 현재 torchnative 릴리스에서는 동작하지 않습니다. 0.1.0b6 에서는 생성이 실패하는데, 그 torch._C shim 에 triu_, nansum, Generator.get_state 가 없고 import 하면 3.15t 에서 GIL 이 다시 켜지기 때문입니다(#177). 4비트 가중치와 GGUF 는 계획 단계이며(#67) torchnative 에 달려 있습니다.
Several models at once
여러 모델 동시 사용
Several models can be loaded at the same time, and the app, the OpenAI API and the Ollama API share them. When a new model does not fit, the least recently used model that is not generating is unloaded; a model that is answering is never unloaded. If every loaded model is busy, the request waits and fails with HTTP 503 after the timeout. Set these before starting the server:
여러 모델을 동시에 올려 둘 수 있고, 앱·OpenAI API·Ollama API 가 이를 공유합니다. 새 모델이 들어갈 자리가 없으면 생성 중이 아닌 모델 중 가장 오래 쓰지 않은 것을 내립니다. 답하는 중인 모델은 내리지 않습니다. 올라가 있는 모델이 모두 사용 중이면 요청이 기다리다가 제한 시간이 지나면 HTTP 503 으로 실패합니다. 서버를 시작하기 전에 설정하세요.
| Variable변수 | Default기본값 | Meaning뜻 |
|---|---|---|
GEMSTONE_MAX_LOADED_MODELS | 3 | Most models loaded at once동시에 올려 둘 수 있는 최대 모델 수 |
GEMSTONE_MAX_MODEL_MEMORY | no limit제한 없음 | Memory budget for loaded models, e.g. 8GiB (an estimate: weights plus KV cache)올려 둔 모델의 메모리 한도, 예: 8GiB (가중치와 KV 캐시로 계산한 추정치) |
GEMSTONE_LOAD_TIMEOUT | 5m | How long a load waits for a busy model to finish사용 중인 모델이 끝나기를 기다리는 최대 시간 |
GEMSTONE_ALIASES | $HF_HOME/gemstone/aliases.json | Where models made with /api/copy and /api/create are stored/api/copy, /api/create 로 만든 모델을 저장하는 파일 |
The Ollama API also offers /api/copy, /api/create (a new name for a local model with its own system prompt and parameters; no Modelfile or template), /api/embed and /api/embeddings. /api/push answers 501: models come from the Hugging Face Hub.
Ollama API 는 /api/copy, /api/create(로컬 모델에 자신의 시스템 프롬프트와 파라미터를 붙인 새 이름, Modelfile 과 template 은 없음), /api/embed, /api/embeddings 도 제공합니다. /api/push 는 501 을 돌려줍니다. 모델은 Hugging Face Hub 에서 받습니다.
OpenAI-compatible API
OpenAI 호환 API
Any OpenAI client can use the server: point its base URL at http://<host>:23100/v1 and use a model id from GET /v1/models (qwen3). POST /v1/chat/completions supports streaming, tools, temperature, top_p, max_tokens, seed and stop. The key is checked only when GEMSTONE_API_KEY is set. The same seed gives the same tokens whether the request is batched or runs alone (changed in 1.1.0, not yet released; see the changelog).
어떤 OpenAI 클라이언트든 서버를 쓸 수 있습니다: base URL 을 http://<host>:23100/v1 로 두고 GET /v1/models 의 모델 id (qwen3) 를 쓰세요. POST /v1/chat/completions 는 스트리밍, tools, temperature, top_p, max_tokens, seed, stop 을 지원합니다. API 키는 GEMSTONE_API_KEY 를 설정했을 때만 검사합니다. 같은 seed 는 요청이 배치로 묶이든 혼자 실행되든 같은 토큰을 냅니다(1.1.0 에서 바뀐 동작이며, 1.1.0 은 아직 출시 전입니다. 변경 기록을 보세요).
curl http://localhost:23100/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "qwen3", "messages": [{"role": "user", "content": "Hi"}]}'
Tool calls are returned, not run: when the model calls a tool, the reply carries tool_calls and finish_reason: "tool_calls". Your client runs the tool and sends the result back as a tool message. The model's reasoning (<think>) comes back separately as reasoning_content, not in content. The chat app's WebSocket is unchanged and still runs Gemstone's built-in tools on the server.
도구 호출은 실행되지 않고 반환됩니다: 모델이 도구를 부르면 응답에 tool_calls 와 finish_reason: "tool_calls" 가 담깁니다. 클라이언트가 도구를 실행하고 그 결과를 tool 메시지로 다시 보냅니다. 모델의 추론(<think>)은 content 가 아니라 reasoning_content 로 따로 옵니다. 채팅 앱의 WebSocket 은 그대로이며, 여전히 Gemstone 내장 도구를 서버에서 실행합니다.
Pointing clients at Gemstone
클라이언트를 Gemstone 에 연결하기
Gemstone listens on port 23100, not Ollama's 11434. Set the address the client reads:
Gemstone 은 Ollama 의 11434 가 아니라 23100 포트에서 듣습니다. 클라이언트가 읽는 주소를 설정하세요.
OLLAMA_HOST=http://127.0.0.1:23100 ollama run qwen3 # the ollama CLI, Ollama clients
OPENAI_BASE_URL=http://127.0.0.1:23100/v1 OPENAI_API_KEY=x python app.py # OpenAI SDKs
With GEMSTONE_API_KEY set on the server, give OpenAI SDKs that value as OPENAI_API_KEY, and other clients as an Authorization: Bearer header; an Ollama client that cannot send that header should be used against a loopback server without a key. HEAD / and GET /api/version work without a key, for health checks.
서버에 GEMSTONE_API_KEY 를 설정했다면 OpenAI SDK 에는 그 값을 OPENAI_API_KEY 로, 다른 클라이언트에는 Authorization: Bearer 헤더로 주세요. 그 헤더를 보낼 수 없는 Ollama 클라이언트는 키 없는 loopback 서버에서 쓰세요. 상태 확인용 HEAD / 와 GET /api/version 은 키 없이 동작합니다.
Model names: qwen3, qwen3:latest, qwen3:0.6b and qwen3:0.6b-fp16 are the built-in model and are downloaded on first use, by the app, the OpenAI API and the Ollama API alike. smollm2:135m must be pulled first. Any Hugging Face model is pulled by its id (Org/Model); other Ollama library names such as llama3.2 answer 404 with this list. GET /api/version returns Gemstone's own version (1.0.0), a plain MAJOR.MINOR.PATCH that Ollama clients compare as semver.
모델 이름: qwen3, qwen3:latest, qwen3:0.6b, qwen3:0.6b-fp16 는 기본 제공 모델이며 앱, OpenAI API, Ollama API 모두 처음 쓸 때 내려받습니다. smollm2:135m 은 먼저 pull 해야 합니다. Hugging Face 모델은 id(Org/Model)로 pull 합니다. llama3.2 같은 다른 Ollama 라이브러리 이름은 이 목록과 함께 404 를 돌려줍니다. GET /api/version 은 Gemstone 자신의 버전(1.0.0)을 돌려주며, Ollama 클라이언트가 semver 로 비교하는 MAJOR.MINOR.PATCH 형식입니다.
Thinking: Qwen3 reasons by default. Ollama think: false and OpenAI reasoning_effort: "none" (or "minimal") pass enable_thinking=False to the chat template, so the model skips the reasoning; vLLM's chat_template_kwargs is passed through. With none of these set the template's default applies and the <think> block stays in the Ollama content as written (OpenAI returns it as reasoning_content).
추론: Qwen3 는 기본적으로 추론합니다. Ollama 의 think: false 와 OpenAI 의 reasoning_effort: "none"(또는 "minimal")은 채팅 템플릿에 enable_thinking=False 를 넘겨 모델이 추론을 건너뜁니다. vLLM 의 chat_template_kwargs 도 그대로 전달됩니다. 아무것도 설정하지 않으면 템플릿 기본값이 적용되고, Ollama 의 content 에는 <think> 블록이 그대로 남습니다(OpenAI 는 reasoning_content 로 돌려줍니다).
Keys
키
Web search uses SerpApi when a key is present and falls back to scraping Bing otherwise. Put the key in a .env file at the repository root (never commit it):
웹 검색은 키가 있으면 SerpApi 를, 없으면 Bing 스크래핑을 씁니다. 키는 저장소 루트의 .env 파일에 둡니다 (절대 커밋하지 마세요):
cp .env.example .env
# .env
SERPAPI_KEY=<your key>
Weather, holidays and exchange rates use free public APIs that need no key. They still send your query over the internet.
날씨, 공휴일, 환율은 키가 필요 없는 무료 공개 API 를 씁니다. 그래도 질의는 인터넷으로 나갑니다.