Gemcook Tech Blog
🤖

TanStack AI × Claude Codeでチャットアプリを作成してみた

に公開

みなさん、AIを活用したチャットアプリケーションを開発したことはありますか?
最近ではVercel AI SDKなどを利用して開発する方も多いかと思いますが、TanStackチームが提供するTanStack AIを使うと、型安全かつフレームワーク非依存なAIチャットアプリケーションを簡単に構築することができます。

さらに、今回はAnthropicが提供するClaude Codeを活用し、AIにコードの生成・修正を任せながら開発を進めました。
本記事では、TanStack AIとClaude Codeを組み合わせてチャットアプリを作成した手順やポイントについて紹介します。

TanStack AIとは

TanStack AIは、TanStack QueryやTanStack Routerなどを開発しているTanStackチームが提供する、AIアプリケーション構築のためのSDKです。

https://tanstack.com/ai/latest/docs

主な特徴について以下にまとめます。

特徴 説明
型安全性 TypeScript + Zodによる型推論をサポート
フレームワーク非依存 React、SolidJS、バニラJSなどで利用可能
プロバイダー非依存 OpenAI、Anthropic、Geminiなど複数のLLMプロバイダーに対応
ストリーミング対応 SSE(Server-Sent Events)やHTTPストリームによるリアルタイムレスポンス
Isomorphic Tools toolDefinition()で一度定義し、.server().client()で実装可能
Approval Flow ツール実行の承認フローを組み込み可能

TanStack AIのエコシステムは主に以下のパッケージで構成されています。

パッケージ 役割
@tanstack/ai コアライブラリ(chat関数、toolDefinitionなど)
@tanstack/ai-react React向けフック(useChatなど)
@tanstack/ai-anthropic Anthropicアダプター

使用技術

今回作成したチャットアプリで使用した技術スタックは以下の通りです。

カテゴリ 技術
フレームワーク React
言語 TypeScript
ビルドツール Vite
AIライブラリ TanStack AI(@tanstack/ai@tanstack/ai-react@tanstack/ai-anthropic
スタイリング TailwindCSS
AIコーディング Claude Code

手順1: 事前準備

Claude APIキーの発行

今回はAnthropicのClaude APIを利用するため、事前にAPIキーの発行が必要です。
以下のサイトにアクセスし、アカウント作成・APIキーの発行を行ってください。

https://platform.claude.com/

APIキーの発行手順は以下の通りです。

  1. 上記URLにアクセスし、Anthropicアカウントでログイン(アカウントがない場合は新規作成)
  2. ダッシュボードの「API Keys」セクションに移動
  3. 「Create Key」をクリックしてAPIキーを生成
  4. 生成されたAPIキーをコピーして安全な場所に保管

手順2: プロジェクトのセットアップ

Vite + Reactでプロジェクトを作成する

まず、Viteを利用してReact + TypeScriptのプロジェクトを作成します。

npm create vite@latest tanstack-chat-app -- --template react-ts
cd tanstack-chat-app
npm install

TanStack AIのパッケージをインストールする

TanStack AIの必要なパッケージをインストールします。
今回はAnthropicのClaude APIを利用するため、@tanstack/ai-anthropicもインストールします。

npm install @tanstack/ai @tanstack/ai-react @tanstack/ai-anthropic

環境変数の設定

プロジェクトのルートに.envファイルを作成し、手順1で発行したAPIキーを設定します。

ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxxxxxxx

プロジェクトの構成は以下のようになります。

tanstack-chat-app/
├── public/
├── src/
│   ├── components/       # UIコンポーネント
│   ├── App.tsx           # メインアプリケーション
│   ├── main.tsx          # エントリーポイント
│   └── index.css         # グローバルスタイル
├── .env                  # 環境変数(APIキー)
├── index.html
├── package.json
├── tsconfig.json
├── vite.config.ts
└── postcss.config.js

手順3: Claude Codeでの開発フローについて

Claude Codeを利用した開発の流れ

Claude Codeを利用した開発では、以下のような流れで進めました。

1. やりたいことを自然言語で伝える

ターミナル上でClaude Codeを起動し、やりたいことを伝えます。

claude

> TanStack AIの@tanstack/ai-reactのuseChatフックを使って、チャットUIコンポーネントを作成してください。
> メッセージの送信、ストリーミングレスポンスの表示、ローディング状態の管理を含めてください。

2. 生成されたコードの確認と修正を繰り返す

Claude Codeが生成したコードを確認し、必要に応じて追加の指示を行います。

> チャットのメッセージ表示部分にスクロールの自動追従を追加してください。
> また、送信ボタンはローディング中に無効化してください。

3. エラーが出たらClaude Codeにデバッグを依頼する

エラーが発生した際もClaude Codeに解決を依頼することで、スムーズに開発を進めることができます。

> TypeScriptのエラーが出ています。useChatの型定義を確認して修正してください。

Claude Codeで開発する際のポイント

Claude Codeを効率的に使うためのポイントをいくつか紹介します。

  • 具体的に指示を出す: 「チャットアプリを作って」ではなく、使用するライブラリやフック名、UIの詳細を具体的に伝えると良い結果が得られます。
  • 段階的に開発を進める: 一度に全ての機能を依頼するのではなく、UIの構築 → API連携 → スタイリングのように段階的に進めると精度が高くなります。
  • CLAUDE.mdを活用する: プロジェクトのルートにCLAUDE.mdファイルを配置しておくと、Claude Codeがプロジェクトのコンテキストを理解した上でコードを生成してくれます。

手順4: チャットUIの実装

サーバーサイド: チャットAPIの作成

今回はVite + Reactの構成のため、バックエンド側は別途Express等のサーバーを立てるか、あるいはAPIルートを用意する形になります。
TanStack AIのchat関数とtoServerSentEventsResponseを利用して、ストリーミングレスポンスを返すAPIを作成します。

import { chat, toServerSentEventsResponse } from "@tanstack/ai";
import { anthropicText } from "@tanstack/ai-anthropic";

export async function POST(request: Request) {
  const { messages } = await request.json();

  const stream = chat({
    adapter: anthropicText("claude-sonnet-4-20250514"),
    messages,
  });

  return toServerSentEventsResponse(stream);
}

chat関数に渡す主なオプションは以下の通りです。

オプション 説明
adapter LLMプロバイダーのアダプター(anthropicTextなど)
messages チャットのメッセージ履歴
tools AIが利用可能なツールの定義
systemPrompts システムプロンプト
conversationId 会話の識別子

クライアントサイド: useChatフックの利用

TanStack AIの@tanstack/ai-reactパッケージが提供するuseChatフックを使うことで、チャットのステート管理やストリーミング処理を簡潔に実装することができます。

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

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

  const { messages, sendMessage, isLoading } = 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">
      {/* メッセージ表示エリア */}
      <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" ? "AI" : "あなた"}
            </div>
            {message.parts.map((part, idx) => {
              if (part.type === "text") {
                return <span key={idx}>{part.content}</span>;
              }
              return null;
            })}
          </div>
        ))}
      </div>

      {/* 入力フォーム */}
      <form onSubmit={handleSubmit} className="p-4 border-t">
        <div className="flex gap-2">
          <input
            value={input}
            onChange={(e) => setInput(e.target.value)}
            placeholder="メッセージを入力..."
            disabled={isLoading}
            className="flex-1 border rounded-lg px-4 py-2"
          />
          <button
            type="submit"
            disabled={isLoading}
            className="bg-blue-500 text-white px-6 py-2 rounded-lg disabled:opacity-50"
          >
            送信
          </button>
        </div>
      </form>
    </div>
  );
}

useChatフックが返す主な値は以下の通りです。

プロパティ 説明
messages チャットのメッセージ一覧(UIMessage[]
sendMessage メッセージを送信する関数
isLoading レスポンス待ちかどうかのフラグ
error エラー情報
stop ストリーミングを停止する関数
clear メッセージをクリアする関数

メッセージの表示について

TanStack AIのメッセージはpartsという配列で構造化されています。
partsにはtext(テキスト)、thinking(思考過程)、tool-call(ツール呼び出し)などの種類があり、それぞれに応じた表示を行うことができます。

{message.parts.map((part, idx) => {
  if (part.type === "thinking") {
    return (
      <div key={idx} className="text-sm text-gray-500 italic">
        💭 {part.content}
      </div>
    );
  }
  if (part.type === "text") {
    return <span key={idx}>{part.content}</span>;
  }
  if (part.type === "tool-call") {
    return (
      <div key={idx} className="bg-gray-100 p-2 rounded">
        🔧 ツール呼び出し: {part.name}
      </div>
    );
  }
  return null;
})}

手順5: ストリーミングの設定

TanStack AIでは、SSE(Server-Sent Events)を使ったストリーミングが標準でサポートされています。
fetchServerSentEventsを利用することで、サーバーからのストリーミングレスポンスをリアルタイムで受け取り、メッセージの表示に反映させることができます。

const { messages, sendMessage, isLoading } = useChat({
  connection: fetchServerSentEvents("/api/chat"),
  onChunk: (chunk) => {
    // チャンクごとの処理(デバッグなど)
    console.log("Received chunk:", chunk);
  },
  onFinish: (message) => {
    // ストリーミング完了時の処理
    console.log("Stream finished:", message);
  },
});

ストリーミングのイベントタイプは以下のような種類があります。

イベントタイプ 説明
TEXT_MESSAGE_START テキストメッセージの開始
TEXT_MESSAGE_CONTENT テキストコンテンツのストリーミング
TEXT_MESSAGE_END テキストメッセージの終了
TOOL_CALL_START ツール呼び出しの開始
TOOL_CALL_ARGS ツール呼び出しの引数
TOOL_CALL_END ツール呼び出しの終了
RUN_FINISHED 実行完了
RUN_ERROR エラー発生

TanStack AIを使ってみた感想

useChatフックの使いやすさ

useChatフックがメッセージのステート管理、ストリーミング処理、ローディング状態の管理をすべて行ってくれるため、チャットUIの実装が非常にシンプルになりました。
Vercel AI SDKのuseChatと使用感が近いため、移行もしやすいと感じました。

プロバイダーの切り替えが容易

アダプターを変更するだけでLLMプロバイダーを切り替えることができるため、AnthropicからOpenAIやGeminiへの変更がとても簡単です。
アプリケーションのロジックを書き直す必要がないのは大きなメリットだと感じました。

型安全性

TypeScript + Zodによる型推論がしっかりしているため、ツール定義やメッセージの型が自動的に推論されます。
開発中に型エラーで問題に気付くことができるのは安心感があります。

まとめ

TanStack AIは、型安全でプロバイダー非依存なAIアプリケーション開発を可能にする新しいSDKです。
useChatフックを利用することで、ストリーミング対応のチャットUIを少ないコードで実装することができました。

また、Claude Codeを組み合わせることで開発のスピードが大幅に向上し、TanStack AIの新しいAPIにもスムーズにキャッチアップすることができました。

まだalpha版ではありますが、TanStackエコシステムとの統合やIsomorphic Toolsなどの独自機能は非常に魅力的です。
今後のアップデートに期待しつつ、ぜひ皆さんもTanStack AI × Claude Codeでの開発を試してみてはいかがでしょうか。

さらに詳しく知りたい方は以下のリソースを参照してみてください。

https://tanstack.com/ai/latest/docs

https://github.com/TanStack/ai

最後まで読んでいただきありがとうございました!

Gemcook Tech Blog
Gemcook Tech Blog

Discussion