OpenAI 호환 어댑터
많은 프로바이더가 OpenAI Chat Completions API(/chat/completions)를 제공합니다. DeepSeek, Moonshot/Kimi, Together, Fireworks, Cerebras, Alibaba Qwen, Perplexity, NVIDIA NIM, 그리고 LM Studio, Ollama, vLLM 같은 로컬 서버가 이에 해당합니다. 프로바이더마다 전용 패키지를 사용하는 대신 TanStack AI는 하나의 범용 어댑터를 제공합니다. 호환되는 baseURL을 지정하고 모델을 전달하면, 우선 지원 어댑터와 동일한 타입 안전 chat() 환경을 사용할 수 있습니다.
프로바이더가 OpenAI Chat Completions 와이어 형식을 사용하지만 자체 @tanstack/ai-* 패키지가 없을 때 사용합니다. 전용 어댑터(OpenAI, Grok, Groq, OpenRouter)가 있다면 해당 어댑터를 우선 사용합니다. 전용 어댑터에는 모델별로 엄선된 메타데이터가 포함됩니다. Vercel AI Gateway의 경우 @tanstack/ai-vercel-gateway를 설치하고 vercelGatewayText를 사용합니다. Vercel AI Gateway를 참조합니다. Lovable AI Gateway의 경우 @tanstack/ai-lovable을 설치하고 lovableText를 사용합니다(이미지, 비디오, 임베딩, 음성 팩토리도 제공됩니다). Lovable AI Gateway를 참조합니다.
Perplexity Sonar 채팅은 이 어댑터를 계속 사용합니다. @tanstack/ai-perplexity는 Search/grounding 전용이며 openaiCompatible을 chat()에서 대체하지 않습니다. 선택 사항으로, 해당 패키지의 defaultHeaders: getPerplexityIntegrationHeaders()를 전달하면 Perplexity의 X-Pplx-Integration 출처 표시 헤더를 보낼 수 있습니다.
설치
어댑터는 @tanstack/ai-openai의 /compatible 서브패스에 포함되어 있으므로 추가 설치가 필요하지 않습니다.
npm install @tanstack/ai-openai
기본 사용법
openaiCompatible({ baseURL, apiKey, models })로 프로바이더를 한 번 구성한 다음 호출마다 모델을 선택합니다. 반환되는 모델 이름은 선언한 모델들의 타입 안전 유니온입니다.
import { chat } from "@tanstack/ai";
import { openaiCompatible } from "@tanstack/ai-openai/compatible";
const deepseek = openaiCompatible({
name: "deepseek", // optional label shown in devtools/errors (default: "openai-compatible")
baseURL: "https://api.deepseek.com/v1",
apiKey: process.env.DEEPSEEK_API_KEY!,
models: ["deepseek-chat", "deepseek-reasoner"],
});
const stream = chat({
adapter: deepseek("deepseek-chat"),
messages: [{ role: "user", content: "Hello!" }],
});
deepseek("deepseek-reasoner")는 유효하지만 deepseek("gpt-4o")는 타입 오류입니다. 선언한 모델만 허용됩니다.
일회성 사용
단일 모델을 사용할 때는 프로바이더 팩토리를 생략하고 openaiCompatibleText로 어댑터를 인라인으로 구성합니다.
import { chat } from "@tanstack/ai";
import { openaiCompatibleText } from "@tanstack/ai-openai/compatible";
const stream = chat({
adapter: openaiCompatibleText("deepseek-chat", {
baseURL: "https://api.deepseek.com/v1",
apiKey: process.env.DEEPSEEK_API_KEY!,
}),
messages: [{ role: "user", content: "Hello!" }],
});
모델 선언
models 배열은 다음 두 형식을 허용하며 함께 사용할 수 있습니다.
- 단순 문자열 — 낙관적인 기본값을 적용합니다.
text+image입력과streaming,function_calling,structured_outputs를 지원합니다. 일반적인 채팅 모델에 적합합니다. createModel(name, capabilities)정의 — 모델별 기능을 정확하게 선언하여 타입이 실제 동작과 일치하게 합니다(예: 이미지 입력이 없는 추론 모델).
import { openaiCompatible } from "@tanstack/ai-openai/compatible";
import { createModel } from "@tanstack/ai";
const provider = openaiCompatible({
baseURL: "https://api.deepseek.com/v1",
apiKey: process.env.DEEPSEEK_API_KEY!,
models: [
"deepseek-chat", // string → optimistic defaults
createModel("deepseek-reasoner", {
input: ["text"], // text only
features: ["reasoning", "structured_outputs"],
}),
],
});
기능은 타입 수준에서 적용됩니다. 프로바이더가 런타임에 기능을 거부하는 경우(예: 도구를 지원하지 않는 모델에서 도구 사용), 해당 모델을
createModel로 선언하고 지원하지 않는 기능을 생략하면 타입이 해당 호출을 방지합니다.
구성
openaiCompatible은 모든 OpenAI SDK ClientOptions 필드 중 apiKey/baseURL을 제외한 필드를 허용합니다(두 필드는 필수이며 최상위로 승격됩니다). 추가 인증 또는 라우팅 매개변수가 필요한 프로바이더에는 defaultHeaders와 defaultQuery가 가장 유용합니다.
import { openaiCompatible } from "@tanstack/ai-openai/compatible";
const provider = openaiCompatible({
baseURL: "https://api.example.com/v1",
apiKey: process.env.EXAMPLE_API_KEY!,
models: ["some-model"],
defaultHeaders: { "X-Custom-Header": "value" },
defaultQuery: { "api-version": "2026-01-01" },
});
Chat Completions와 Responses 비교
기본적으로 어댑터는 호환 프로바이더 대부분이 구현하는 Chat Completions API(/chat/completions)를 대상으로 합니다. OpenAI의 Responses API도 구현하는 드문 프로바이더(예: Azure OpenAI)의 경우 api: "responses"를 지정해 사용합니다.
import { openaiCompatible } from "@tanstack/ai-openai/compatible";
const provider = openaiCompatible({
baseURL: "https://my-resource.openai.azure.com/openai/v1",
apiKey: process.env.AZURE_OPENAI_API_KEY!,
models: ["gpt-4o"],
api: "responses", // default is "chat-completions"
});
추론: 추론 델타는 사고 콘텐츠로 스트리밍됩니다. 2025년 7월 이전 OpenAI 사양으로 고정된 엔드포인트는 여전히 레거시 이벤트 이름 response.reasoning.delta를 내보낼 수 있습니다(response.reasoning_text.delta를 사용하도록 사양에서 제거됨). 어댑터는 두 이름을 모두 인식하고 동일하게 매핑합니다.
지원되는 프로바이더
OpenAI Chat Completions API를 구현하는 모든 프로바이더가 작동합니다. 일반적인 프로바이더는 다음과 같지만, 시간이 지나면서 변경되므로 각 프로바이더의 최신 문서에서 baseURL과 모델 ID를 확인해야 합니다. 프로바이더 자체 환경 변수로 API 키를 설정하고 apiKey로 전달합니다.
| 프로바이더 | baseURL | 예시 모델 |
|---|---|---|
| DeepSeek | https://api.deepseek.com/v1 | deepseek-chat, deepseek-reasoner |
| Moonshot / Kimi | https://api.moonshot.ai/v1 | kimi-k2-0711-preview |
| Alibaba Qwen (DashScope, intl) | https://dashscope-intl.aliyuncs.com/compatible-mode/v1 | qwen-max, qwen-plus |
| Alibaba Qwen (DashScope, China) | https://dashscope.aliyuncs.com/compatible-mode/v1 | qwen-max |
| Together AI | https://api.together.xyz/v1 | meta-llama/Llama-3.3-70B-Instruct-Turbo |
| Fireworks AI | https://api.fireworks.ai/inference/v1 | accounts/fireworks/models/llama-v3p3-70b-instruct |
| Cerebras | https://api.cerebras.ai/v1 | llama-3.3-70b |
| DeepInfra | https://api.deepinfra.com/v1/openai | meta-llama/Llama-3.3-70B-Instruct |
| Perplexity | https://api.perplexity.ai | sonar, sonar-pro |
| Requesty | https://router.requesty.ai/v1 | openai/gpt-4o-mini |
| Mistral | https://api.mistral.ai/v1 | mistral-large-latest |
| Nebius | https://api.studio.nebius.ai/v1 | meta-llama/Llama-3.3-70B-Instruct |
| Z.AI (GLM) | https://api.z.ai/api/paas/v4 | glm-4.6 |
| Baseten | https://inference.baseten.co/v1 | 모델 의존적 |
| Hugging Face (router) | https://router.huggingface.co/v1 | meta-llama/Llama-3.3-70B-Instruct |
| NVIDIA NIM | https://integrate.api.nvidia.com/v1 | meta/llama-3.3-70b-instruct |
로컬 및 자체 호스팅 서버
어댑터가 모든 로컬 OpenAI 호환 서버를 가리키도록 설정합니다. API 키는 일반적으로 플레이스홀더입니다.
import { openaiCompatible } from "@tanstack/ai-openai/compatible";
// LM Studio
const lmstudio = openaiCompatible({
name: "lmstudio",
baseURL: "http://localhost:1234/v1",
apiKey: "lm-studio",
models: ["local-model"],
});
// vLLM
const vllm = openaiCompatible({
name: "vllm",
baseURL: "http://localhost:8000/v1",
apiKey: "not-needed",
models: ["meta-llama/Llama-3.3-70B-Instruct"],
});
// Ollama's OpenAI-compatible endpoint
const ollama = openaiCompatible({
name: "ollama",
baseURL: "http://localhost:11434/v1",
apiKey: "ollama",
models: ["llama3.3"],
});
Ollama에는 네이티브 API를 이해하는 전용 어댑터
@tanstack/ai-ollama도 있습니다. Ollama의 OpenAI 호환 인터페이스를 특별히 사용하려는 경우에만openaiCompatible을 사용합니다.
LiteLLM 프록시
LiteLLM은 100개가 넘는 프로바이더(OpenAI, Anthropic, Google, Azure, AWS Bedrock, Mistral, Groq 등) 앞에서 단일 OpenAI Chat Completions 엔드포인트를 제공하는 자체 호스팅 게이트웨이입니다. 프록시는 OpenAI 와이어 형식을 사용하므로 전용 패키지가 필요하지 않습니다. openaiCompatible이 프록시의 baseURL(기본값 http://localhost:4000/v1)을 가리키도록 설정하고 LiteLLM의 provider/model 이름으로 프로바이더에 라우팅합니다.
import { openaiCompatible } from "@tanstack/ai-openai/compatible";
const litellm = openaiCompatible({
name: "litellm",
baseURL: "http://localhost:4000/v1", // your LiteLLM proxy
apiKey: process.env.LITELLM_API_KEY!, // a virtual key issued by the proxy
models: [
"anthropic/claude-sonnet-5",
"openai/gpt-5.5",
"gemini/gemini-3.5-flash",
],
});
litellm("anthropic/claude-sonnet-5")는 Anthropic 경로를 선택하고, litellm("openai/gpt-5.5")는 OpenAI를 선택합니다. 모두 하나의 프록시를 통해 수행됩니다. 프록시에 구성한 모델 경로만 선언합니다. 모델별 기능을 정확하게 지정하려면(예: 이미지 입력이 없는 추론 경로) 모델 선언에 설명된 것처럼 createModel을 사용합니다.
프록시는 각 업스트림 프로바이더의 실제 자격 증명을 보관합니다. 여기의
apiKey는 업스트림 프로바이더의 키가 아니라 프록시 자체의 가상/마스터 키입니다.
Azure OpenAI
Azure는 리소스 범위 URL과 별도의 API 버전을 사용합니다. 버전에는 defaultQuery를, api-key 헤더에는 defaultHeaders를 사용하여 /openai/v1 엔드포인트를 사용합니다.
import { openaiCompatible } from "@tanstack/ai-openai/compatible";
const azure = openaiCompatible({
name: "azure",
baseURL: "https://YOUR_RESOURCE.openai.azure.com/openai/v1",
apiKey: process.env.AZURE_OPENAI_API_KEY!, // also sent as Bearer; Azure accepts the api-key header below
models: ["gpt-4o"], // your Azure deployment name
defaultQuery: { "api-version": "2026-01-01-preview" },
defaultHeaders: { "api-key": process.env.AZURE_OPENAI_API_KEY! },
});
Azure의 API 인터페이스는 OpenAI와 독립적으로 발전하므로 Azure 문서에서 현재
api-version과 엔드포인트 형식을 확인합니다.
예시: 도구 사용
함수 호출을 지원하는 모델에서는 다른 어댑터와 동일하게 도구가 작동합니다.
import { chat, toolDefinition } from "@tanstack/ai";
import { openaiCompatible } from "@tanstack/ai-openai/compatible";
import { z } from "zod";
const getWeatherDef = toolDefinition({
name: "get_weather",
description: "Get the current weather",
inputSchema: z.object({ location: z.string() }),
});
const getWeather = getWeatherDef.server(async ({ location }) => {
return { temperature: 72, conditions: "sunny" };
});
const deepseek = openaiCompatible({
baseURL: "https://api.deepseek.com/v1",
apiKey: process.env.DEEPSEEK_API_KEY!,
models: ["deepseek-chat"],
});
const stream = chat({
adapter: deepseek("deepseek-chat"),
messages: [{ role: "user", content: "What's the weather in Tokyo?" }],
tools: [getWeather],
});
다음 단계
- OpenAI 어댑터 - 우선 지원되는 OpenAI 어댑터
- OpenRouter 어댑터 - 하나의 게이트웨이를 통해 300개가 넘는 모델에 액세스
- 도구 가이드 - 도구 알아보기
- 어댑터 확장 - 모든 어댑터에 사용자 지정 모델 추가