본문으로 건너뛰기

타입이 지정된 사전 구성 옵션

재사용하려는 chat()(또는 generateImage(), generateSpeech(), …) 구성이 있을 수 있습니다. 여러 라우트에서 사용하거나, 서버 함수와 호출자 사이에 전달하거나, 명확성을 위해 핸들러에서 분리할 수 있습니다. 이 가이드를 마치면 어댑터의 모델, 모달리티, 프로바이더 옵션을 추론하고 타입 안전성을 잃지 않은 채 어느 호출 위치에나 펼칠 수 있는 하나의 타입 지정 옵션 객체를 갖게 됩니다.

패턴

@tanstack/ai의 모든 활동에는 활동 자체와 정확히 같은 옵션 객체를 받아 변경 없이 반환하는 대응 createXxxOptions 헬퍼가 제공됩니다. 런타임에는 항등 함수입니다. 핵심은 타입 추론입니다. 반환된 객체가 어댑터의 전체 타입을 가지므로 활동에 펼쳐 넣을 때 TypeScript가 modelOptions, 콘텐츠 모달리티, outputSchema를 선택한 어댑터에 맞게 계속 좁힙니다.

import { chat, createChatOptions } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'

const chatOptions = createChatOptions({
adapter: openaiText('gpt-5.5'),
// modelOptions, systemPrompts, tools — all type-checked against the
// adapter+model pair above. Sampling params (temperature, top_p,
// max_output_tokens, …) live inside modelOptions, under each provider's
// native key.
modelOptions: {
temperature: 0.3,
reasoning: { effort: 'medium' },
},
})

// Later, anywhere in your codebase:
const stream = chat({ ...chatOptions, messages: [{ role: 'user', content: 'Hello' }] })

헬퍼가 없다면 모든 호출 위치에 구성을 인라인으로 작성하거나 어댑터/모델 제네릭을 직접 해석해 전체 채팅 옵션 타입을 수기로 작성해야 하지만, createChatOptions가 이를 대신합니다.

사용 시점

  • 여러 라우트에서 구성 공유 — 한 번 정의하고 각 핸들러에 펼칩니다.
  • 레이어를 통해 옵션 전달(서버 함수, 래퍼, 테스트 픽스처) — 어댑터의 모델별 타입을 지우지 않습니다.
  • 타입을 유지한 채 런타임 값에 따라 분기 — 하나의 chat({...}) 호출에 조건문을 엮는 대신 서로 다른 옵션 객체를 만들고 그중 하나를 선택합니다.
  • 도구, 시스템 프롬프트, 미들웨어를 대상 어댑터와 함께 배치합니다.

한 곳에서 활동을 한 번만 호출한다면 이 헬퍼가 필요하지 않습니다. 옵션을 인라인으로 작성합니다.

사용 가능한 헬퍼

각 헬퍼는 대응하는 활동을 그대로 반영합니다. 옵션과 반환 타입이 같습니다.

HelperActivity어댑터
createChatOptionschat()텍스트 어댑터 (예: openaiText, anthropicText)
createSummarizeOptionssummarize()요약 어댑터 (예: openaiSummarize)
createImageOptionsgenerateImage()이미지 어댑터 (예: openaiImage, falImage)
createAudioOptionsgenerateAudio()오디오 어댑터 (예: falAudio, geminiAudio)
createVideoOptionsgenerateVideo() / getVideoJobStatus()비디오 어댑터 (예: falVideo, openaiVideo)
createSpeechOptionsgenerateSpeech()음성 어댑터 (예: openaiSpeech, elevenlabsSpeech)
createTranscriptionOptionsgenerateTranscription()전사 어댑터 (예: openaiTranscription, falTranscription)

모든 헬퍼는 @tanstack/ai에서 내보냅니다.

예시: 라우트 간 채팅 구성 공유

여러 라우트가 동일한 프로바이더 옵션과 도구 집합으로 같은 모델을 호출한다고 가정합니다. 구성을 한 번 분리합니다.

// lib/ai/chat-options.ts
import { createChatOptions, toolDefinition } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
import { z } from 'zod'
import { db } from './db'

const lookupOrderDef = toolDefinition({
name: 'lookupOrder',
description: 'Look up a customer order by ID',
inputSchema: z.object({ orderId: z.string() }),
})

const lookupOrder = lookupOrderDef.server(async ({ orderId }) => {
return db.orders.findUnique({ where: { id: orderId } })
})

export const supportChatOptions = createChatOptions({
adapter: openaiText('gpt-5.5'),
systemPrompts: ['You are a customer-support assistant for Acme Corp.'],
tools: [lookupOrder],
modelOptions: {
reasoning: { effort: 'medium' },
},
})
// routes/api/support/chat.ts
import { chat, toServerSentEventsResponse } from '@tanstack/ai'
import { supportChatOptions } from '@/lib/ai/chat-options'

export async function POST(request: Request) {
const { messages } = await request.json()
const stream = chat({ ...supportChatOptions, messages })
return toServerSentEventsResponse(stream)
}
// routes/api/support/draft-reply.ts — same adapter+tools, different schema
import { chat } from '@tanstack/ai'
import { supportChatOptions } from '@/lib/ai/chat-options'
import { z } from 'zod'

export async function POST(request: Request) {
const { ticket } = await request.json()
const draft = await chat({
...supportChatOptions,
messages: [{ role: 'user', content: `Draft a reply to: ${ticket}` }],
outputSchema: z.object({ subject: z.string(), body: z.string() }),
stream: false,
})
return Response.json(draft)
}

두 라우트는 어댑터, 시스템 프롬프트, 도구, 추론 설정을 공유하고 각각 필요한 항목을 추가합니다. 호출 위치에서 필드를 재정의하거나 생략할 수 있으며 오른쪽에 펼친 값이 우선합니다.

예시: 타입이 지정된 사전 구성 이미지 생성

import { createImageOptions, generateImage } from '@tanstack/ai'
import { openaiImage } from '@tanstack/ai-openai'

const heroImageOptions = createImageOptions({
adapter: openaiImage('gpt-image-2'),
prompt: 'A glass sphere refracting a sunset over a calm sea',
size: '1536x1024',
numberOfImages: 1,
})

const result = await generateImage(heroImageOptions)

동일한 패턴이 createVideoOptions, createSpeechOptions, createTranscriptionOptions, createAudioOptions, createSummarizeOptions에도 적용됩니다. 어댑터가 타입 지정 옵션 객체에 캡처되고 이후의 모든 호출이 해당 어댑터에 맞게 좁혀집니다.

헬퍼가 하지 않는 일

  • 런타임 동작 없음. createChatOptions(opts)opts입니다. 검증, 동결, 복제 또는 메모이제이션을 수행하지 않습니다. 생성 후 반환된 객체를 변경하면 다음 호출에서 변경 사항이 적용됩니다. 관례상 결과를 불변으로 취급합니다.
  • 부분 타입 지정 없음. 헬퍼는 펼쳐 넣을 전체 옵션 형태를 요구합니다. 옵션을 점진적으로 구성해야 한다면 중간 상태를 직접 타입 지정하고(전체 채팅 옵션 형태의 Partial<>) 형태가 완성되는 경계에서만 헬퍼를 호출합니다.
  • 요청 실행 없음. 헬퍼는 모델을 호출하지 않습니다. 활동 함수(chat, generateImage, …)만 요청을 수행합니다.
  • 모델별 타입 안전성 — 어댑터 + 모델 쌍이 modelOptions 추론을 어떻게 수행하는지.
  • 트리 셰이킹 — 각 어댑터가 별도로 내보내지는 이유, 그리고 타입 옵션 패턴이 번들을 작게 유지하는 방법.
  • 어댑터 확장 — 어댑터에 커스텀 모델을 추가하면서 동일한 타입 옵션 에르고노믹스를 잃지 않을 때.