Use Cases (更新: 2026/6/2)

用 Claude Code 开发聊天机器人的实战指南

用 Claude Code 高效开发 AI 聊天机器人,涵盖会话历史管理、流式响应、RAG 构成,配合可运行代码讲解。

用 Claude Code 开发聊天机器人的实战指南

用 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 个技巧

总结

借助 Claude Code,你可以高效地开发出涵盖聊天 UI、流式 API、会话管理乃至 RAG 结构的完整聊天机器人。采用循序渐进、逐步添加功能的做法会更有效果。

更多细节请参阅 Claude Code 官方文档Anthropic API 参考

2026 生产化升级

聊天机器人不是一个漂亮的输入框,而是一个能接收用户问题、保留必要上下文、再给出下一步回复的小型应用。用更简单的话说,它是网站里的对话入口,可以承担客服、售前咨询、内部知识库检索、课程推荐或故障信息收集。真正决定效果的不是模型有多强,而是你有没有定义清楚它能回答什么、不能回答什么、什么时候要转给人工。

用 Claude Code 开发时,第一版应该尽量小。只回答十个高频问题,比做一个什么都想回答的助手更容易验证。范围越窄,测试越明确,成本越可控,也越容易把对话导向购买、咨询或培训。

架构表

层级作用生产环境注意点
React UI输入、历史记录、加载状态和重试状态管理可先参考 React useState 文档
API 路由在服务端保护 API key,并校验请求增加长度限制、认证和超时
Streaming边生成边返回,减少等待感Web Streams 的基础见 MDN Streams API
会话存储支持继续对话、审计和改进只保存必要内容,并设计删除流程
RAG从产品文档、政策或知识库中检索依据没有可靠资料时不要编造答案
Webhook把事件发送到 CRM、工单或 Slack可继续阅读 Claude Code Webhook Implementation
Analytics统计解决率、转人工率和 CTA 点击可结合 Claude Code Analytics Implementation

API 请求结构建议保持简单,参考 Claude Code API Development:前端只发送 role 和 content,系统提示词放在服务端,响应使用 stream 返回。这样以后要换 UI、增加移动端或调整模型,都不需要重写整套流程。

可直接运行的 streaming demo

把下面代码保存为 chatbot-stream-demo.mjs,执行 node chatbot-stream-demo.mjs。它不调用外部 API,只用于确认流式输出和会话历史的基本逻辑。

const encoder = new TextEncoder();
const decoder = new TextDecoder();

const faq = new Map([
  ["password", "Open the account page, choose Reset password, and follow the email link."],
  ["pricing", "The pricing page explains plans. For a custom quote, collect team size and required features."],
  ["refund", "Refund requests should be routed to support with the order id and purchase email."],
]);

const history = [];

function chooseAnswer(question) {
  const normalized = question.toLowerCase();
  for (const [keyword, answer] of faq) {
    if (normalized.includes(keyword)) return answer;
  }
  return "I could not find a safe answer in the FAQ. I will hand this to a human operator.";
}

async function* streamText(text) {
  for (const token of text.split(/(\s+)/)) {
    await new Promise((resolve) => setTimeout(resolve, 15));
    yield encoder.encode(token);
  }
}

async function ask(question) {
  history.push({ role: "user", content: question });
  const answer = chooseAnswer(question);
  process.stdout.write(`\nUser: ${question}\nAssistant: `);

  let fullAnswer = "";
  for await (const chunk of streamText(answer)) {
    const token = decoder.decode(chunk);
    fullAnswer += token;
    process.stdout.write(token);
  }

  history.push({ role: "assistant", content: fullAnswer });
}

await ask("How do I reset my password?");
await ask("Can I see pricing before talking to sales?");

console.log(`\n\nSaved ${history.length} messages.`);

上线时,把 chooseAnswer 换成 Claude API 调用即可。顺序不要变:先保存用户问题,再流式显示回答,最后保存完整回答。这样可以避免一个常见 failure mode:前端看起来已经输出了内容,但数据库里保存的是空回复。

真实 use case

第一个场景是 SaaS 售前咨询。机器人回答价格、安全、权限、集成方式等问题,当用户表现出明确购买意图时,再引导到咨询表单。这样销售团队不用反复回答基础问题,可以集中处理更有价值的线索。

第二个场景是公司内部 help desk。报销、请假、VPN、设备申请、入职流程都适合做成知识库问答。RAG 可以返回对应政策页面,必要时再通过 webhook 创建工单。

第三个场景是内容或课程网站。读者不知道下一步该学 API、Webhook 还是 Analytics 时,机器人可以推荐相关文章,并在需要实操帮助时引导到 training。这种 workflow 比直接弹广告自然,也更容易产生转化。

第四个场景是故障信息收集。机器人先问错误信息、时间、浏览器、账号和复现步骤,再把完整信息交给支持团队。这里的成功不是马上解决问题,而是减少来回追问。

具体坑点和风险

不要把无限长的聊天记录都发给模型。历史越长,成本越高,速度越慢,旧指令还可能干扰当前问题。更稳妥的做法是总结旧对话,只保留当前任务需要的事实。

不要让 RAG 在没有证据时强行回答。如果搜索结果很弱,机器人应该说明没有找到可靠资料,并提供人工咨询或工单入口。这个规则能减少很多错误承诺。

不要把 streaming 当成装饰。网络中断、重复点击、空消息气泡、加载状态不结束,都会让用户失去信任。第一版就要实现禁用按钮、取消请求、超时和重试提示。

不要没有数据就谈优化。至少要记录未解决问题、转人工、CTA 点击、以及哪些对话带来了购买或咨询。消息数量多不等于体验好,也不等于能赚钱。

变现 CTA

如果这个聊天机器人服务于商业网站,最后的行动要非常明确:预约咨询、实现审查、购买模板或参加培训。ClaudeCodeLab 推荐把高意向用户引导到 training,因为它能把阅读兴趣转成具体实施。

推荐阅读路径是:先在本文理解整体设计,再看 Claude Code API Development 搭建 API,用 webhooks 连接外部系统,最后用 analytics 评估转化效果。

#Claude Code #chatbot #AI #streaming #RAG
免费

免费 PDF: Claude Code 速查表

输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。

我们会妥善保护你的信息,不发送垃圾邮件。

把 Claude Code 变成真正能带来结果的工作流

先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。

Masa

关于作者

Masa

专注 Claude Code 实务流程、团队导入和内容转化的工程师。