본문으로 건너뛰기

빠른 시작: React

몇 분 만에 TanStack AI를 시작할 수 있습니다. 이 가이드에서는 React 통합과 OpenAI 어댑터를 사용하여 간단한 채팅 애플리케이션을 만드는 방법을 안내합니다.

다른 프레임워크를 사용하시나요? Vue, Svelte, Octane 또는 서버 전용 Node.js의 빠른 시작을 참조하세요.

React Native 또는 Expo 앱인가요? 절대 서버 URL과 모바일 호환 transport를 사용하는 헤드리스 React 훅을 사용하세요. 빠른 시작: React Native를 참조하세요.

팁: 개별 AI 제공업체에 가입하고 싶지 않다면 OpenRouter를 사용하세요. 단일 API 키로 300개 이상의 모델에 액세스할 수 있어 가장 쉽게 시작할 수 있습니다.

설치

npm install @tanstack/ai @tanstack/ai-react @tanstack/ai-openai
# or
pnpm add @tanstack/ai @tanstack/ai-react @tanstack/ai-openai
#or
yarn add @tanstack/ai @tanstack/ai-react @tanstack/ai-openai

서버 설정

먼저 채팅 요청을 처리하는 API route를 만드세요. 다음은 간소화된 예시입니다.

TanStack Start

import { chat, toServerSentEventsResponse } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";
import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/api/chat")({
server: {
handlers: {
POST: async ({ request }) => {
// Check for API key
if (!process.env.OPENAI_API_KEY) {
return new Response(
JSON.stringify({
error: "OPENAI_API_KEY not configured",
}),
{
status: 500,
headers: { "Content-Type": "application/json" },
},
);
}

const body = await request.json();

try {
// Create a streaming chat response. `chat()` reads the AG-UI
// `threadId` for devtools correlation when available.
const stream = chat({
adapter: openaiText("gpt-5.5"),
messages: body.messages,
});

// Convert stream to HTTP response
return toServerSentEventsResponse(stream);
} catch (error) {
return new Response(
JSON.stringify({
error:
error instanceof Error ? error.message : "An error occurred",
}),
{
status: 500,
headers: { "Content-Type": "application/json" },
},
);
}
},
},
},
});

Next.js

import { chat, toServerSentEventsResponse } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";

export async function POST(request: Request) {
// Check for API key
if (!process.env.OPENAI_API_KEY) {
return new Response(
JSON.stringify({
error: "OPENAI_API_KEY not configured",
}),
{
status: 500,
headers: { "Content-Type": "application/json" },
}
);
}

const body = await request.json();

try {
// Create a streaming chat response. `chat()` reads the AG-UI
// `threadId` for devtools correlation when available.
const stream = chat({
adapter: openaiText("gpt-5.5"),
messages: body.messages,
});

// Convert stream to HTTP response
return toServerSentEventsResponse(stream);
} catch (error) {
return new Response(
JSON.stringify({
error: error instanceof Error ? error.message : "An error occurred",
}),
{
status: 500,
headers: { "Content-Type": "application/json" },
}
);
}
}

클라이언트 설정

React 프론트엔드에서 채팅 API를 사용하려면 Chat 컴포넌트를 만드세요.

// components/Chat.tsx
import { useState } from "react";
import { useChat, fetchServerSentEvents } from "@tanstack/ai-react";

export function Chat() {
const [input, setInput] = useState("");

const { messages, sendMessage, isLoading, error } = useChat({
connection: fetchServerSentEvents("/api/chat"),
});

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (input.trim() && !isLoading) {
sendMessage(input);
setInput("");
}
};

return (
<div className="flex flex-col h-screen">
{/* Messages */}
<div className="flex-1 overflow-y-auto p-4">
{messages.map((message) => (
<div
key={message.id}
className={`mb-4 ${
message.role === "assistant" ? "text-blue-600" : "text-gray-800"
}`}
>
<div className="font-semibold mb-1">
{message.role === "assistant" ? "Assistant" : "You"}
</div>
<div>
{message.parts.map((part, idx) => {
if (part.type === "thinking") {
return (
<div
key={idx}
className="text-sm text-gray-500 italic mb-2"
>
💭 Thinking: {part.content}
</div>
);
}
if (part.type === "text") {
return <div key={idx}>{part.content}</div>;
}
return null;
})}
</div>
</div>
))}
</div>

{/* Error */}
{error && (
<p role="alert" className="px-4 text-red-600">
{error.message}
</p>
)}

{/* Input */}
<form onSubmit={handleSubmit} className="p-4 border-t">
<div className="flex gap-2">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Type a message..."
className="flex-1 px-4 py-2 border rounded-lg"
disabled={isLoading}
/>
<button
type="submit"
disabled={!input.trim() || isLoading}
className="px-6 py-2 bg-blue-600 text-white rounded-lg disabled:opacity-50"
>
Send
</button>
</div>
</form>
</div>
);
}

환경 변수

AI 제공업체에 연결하려면 환경 변수에 API 키를 설정하세요. .env.local 파일을 만드세요(설정에 따라 .env 파일을 사용할 수도 있습니다).

# OpenRouter (recommended — access 300+ models with one key)
OPENROUTER_API_KEY=sk-or-...

# OpenAI
OPENAI_API_KEY=your-openai-api-key

# Anthropic
ANTHROPIC_API_KEY=your-anthropic-api-key

# Google Gemini
GEMINI_API_KEY=your-gemini-api-key

서버 키를 사용하지 않으려면 브라우저에서 사용자가 직접 키를 붙여 넣도록 할 수 있습니다. Bring Your Own Key를 참조하세요.

이것으로 끝입니다!

이제 작동하는 채팅 애플리케이션이 완성되었습니다. useChat 훅은 다음을 처리합니다.

  • 메시지 상태 관리
  • 스트리밍 응답
  • 로딩 상태
  • 오류 처리

도구 사용

TanStack AI는 프레임워크에 종속되지 않으므로 어떤 환경에서든 도구를 정의하고 사용할 수 있습니다. 다음은 도구를 정의하고 채팅에서 사용하는 간단한 예시입니다.

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

const getProductsDef = toolDefinition({
name: 'getProducts',
description: 'Search the product catalog',
inputSchema: z.object({ query: z.string() }),
outputSchema: z.array(z.object({ id: z.string(), name: z.string() })),
})

const getProducts = getProductsDef.server(async ({ query }) => {
return await db.products.search(query)
})

const stream = chat({
adapter: openaiText('gpt-5.5'),
messages: [{ role: 'user', content: 'Find products' }],
tools: [getProducts],
})

다음 단계