How to Develop a Chatbot with Claude Code
Learn how to develop a chatbot using Claude Code. Includes practical code examples and step-by-step guidance.
Claude Codeでチャットボットを開発する
AIチャットボットの開発には、UI実装、API連携、会話管理、ストリーミング処理など多くの要素があります。Claude Codeなら、これらを統合したチャットボットを短時間で構築できます。
基本的なチャットUIの実装
> Reactでチャットボットのコンポーネントを作って。
> ストリーミング応答対応、会話履歴表示、入力フォーム付きで。
import { useState, useRef, useEffect } from "react";
interface Message {
id: string;
role: "user" | "assistant";
content: string;
}
export function ChatBot() {
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState("");
const [isLoading, setIsLoading] = useState(false);
const messagesEndRef = useRef<HTMLDivElement>(null);
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages]);
const sendMessage = async () => {
if (!input.trim() || isLoading) return;
const userMessage: Message = {
id: crypto.randomUUID(),
role: "user",
content: input,
};
setMessages((prev) => [...prev, userMessage]);
setInput("");
setIsLoading(true);
const assistantId = crypto.randomUUID();
setMessages((prev) => [
...prev,
{ id: assistantId, role: "assistant", content: "" },
]);
try {
const response = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
messages: [...messages, userMessage].map(({ role, content }) => ({
role,
content,
})),
}),
});
const reader = response.body!.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
setMessages((prev) =>
prev.map((m) =>
m.id === assistantId
? { ...m, content: m.content + chunk }
: m
)
);
}
} catch (error) {
setMessages((prev) =>
prev.map((m) =>
m.id === assistantId
? { ...m, content: "An error occurred. Please try again." }
: m
)
);
}
setIsLoading(false);
};
return (
<div className="flex flex-col h-[600px] border rounded-lg">
<div className="flex-1 overflow-y-auto p-4 space-y-4">
{messages.map((msg) => (
<div
key={msg.id}
className={`flex ${msg.role === "user" ? "justify-end" : "justify-start"}`}
>
<div
className={`max-w-[70%] p-3 rounded-lg ${
msg.role === "user"
? "bg-blue-600 text-white"
: "bg-gray-100 text-gray-900"
}`}
>
{msg.content}
</div>
</div>
))}
<div ref={messagesEndRef} />
</div>
<div className="border-t p-4 flex gap-2">
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === "Enter" && !e.shiftKey && sendMessage()}
placeholder="Type a message..."
className="flex-1 p-2 border rounded-lg"
disabled={isLoading}
/>
<button
onClick={sendMessage}
disabled={isLoading}
className="px-4 py-2 bg-blue-600 text-white rounded-lg disabled:opacity-50"
>
送信
</button>
</div>
</div>
);
}
ストリーミング対応のAPIルート
バックエンドでAnthropicのAPIを呼び出し、ストリーミングで返すAPIルートです。
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
export async function POST(request: Request) {
const { messages } = await request.json();
const stream = await client.messages.stream({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
system: "あなたは親切で丁寧なアシスタントです。日本語で回答してください。",
messages,
});
const encoder = new TextEncoder();
const readable = new ReadableStream({
async start(controller) {
for await (const event of stream) {
if (
event.type === "content_block_delta" &&
event.delta.type === "text_delta"
) {
controller.enqueue(encoder.encode(event.delta.text));
}
}
controller.close();
},
});
return new Response(readable, {
headers: { "Content-Type": "text/plain; charset=utf-8" },
});
}
会話履歴の永続化
会話をデータベースに保存して、後から続きを再開できるようにします。
import { db } from "@/lib/database";
export async function saveConversation(
userId: string,
messages: Message[]
) {
return db.conversation.upsert({
where: { id: `${userId}-current` },
update: {
messages: JSON.stringify(messages),
updatedAt: new Date(),
},
create: {
id: `${userId}-current`,
userId,
messages: JSON.stringify(messages),
},
});
}
export async function loadConversation(userId: string): Promise<Message[]> {
const conv = await db.conversation.findUnique({
where: { id: `${userId}-current` },
});
return conv ? JSON.parse(conv.messages as string) : [];
}
RAG(検索拡張生成)の組み込み
社内ドキュメントをもとに回答するチャットボットを作る場合、RAG構成が有効です。
import { searchDocuments } from "@/lib/vector-search";
async function generateRAGResponse(query: string, conversationHistory: Message[]) {
// Search related documents
const relevantDocs = await searchDocuments(query, { limit: 5 });
const context = relevantDocs
.map((doc) => `---\n${doc.title}\n${doc.content}\n---`)
.join("\n");
const systemPrompt = `以下のドキュメントを参考に質問に回答してください。
ドキュメントに情報がない場合は「その情報は見つかりませんでした」と答えてください。
${context}`;
return client.messages.stream({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
system: systemPrompt,
messages: conversationHistory,
});
}
MCPサーバーとの連携で機能を拡張する方法はMCPサーバーガイドを、効果的なプロンプト設計はプロンプトを改善する5つのTipsをご覧ください。
Summary
Claude Codeを使えば、チャットUI、ストリーミングAPI、会話管理、RAG構成まで含めたチャットボットを効率的に開発できます。段階的に機能を追加していくアプローチが効果的です。
詳しくはClaude Code公式ドキュメントとAnthropic API リファレンスを参照してください。
Related Posts
How to Supercharge Your Side Projects with Claude Code [With Examples]
How to Supercharge Your Side Projects with Claude Code [With Examples]. A practical guide with code examples.
How to Automate Refactoring with Claude Code
Learn how to automate refactoring using Claude Code. Includes practical code examples and step-by-step guidance.
Complete CORS Configuration Guide with Claude Code
Learn about complete cors configuration guide using Claude Code. Practical tips and code examples included.