AI 集成

2026年9月6日

Vercel AI SDK 把模型调用、流式输出、前端 hook 收成一套。Next 的 Route Handler 很适合当聊天后端。


安装

按你用的模型装对应包。DeepSeek 便宜,适合练手;换成 OpenAI 只改 provider。

pnpm add ai @ai-sdk/deepseek @ai-sdk/react
# 或
pnpm add ai @ai-sdk/openai @ai-sdk/react
bash

到模型控制台生成 API Key,放进环境变量,例如 DEEPSEEK_API_KEY,不要写进仓库。


流式接口

app/api/chat/route.ts

import { NextRequest } from "next/server";
import { convertToModelMessages, streamText } from "ai";
import { createDeepSeek } from "@ai-sdk/deepseek";

const deepseek = createDeepSeek({
  apiKey: process.env.DEEPSEEK_API_KEY,
});

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

  const result = streamText({
    model: deepseek("deepseek-chat"),
    messages: convertToModelMessages(messages),
    system: "你是一名靠谱的工程师,回答简洁、可执行。",
  });

  return result.toUIMessageStreamResponse();
}
ts

useChat 默认 POST 到 /api/chat,body 里带 messages。SDK 的消息结构和模型 API 不完全一样,所以要 convertToModelMessages


前端 useChat

"use client";

import { useChat } from "@ai-sdk/react";
import { useState } from "react";

export default function ChatPage() {
  const [input, setInput] = useState("");
  const { messages, sendMessage } = useChat();

  return (
    <div>
      <ul>
        {messages.map((m) => (
          <li key={m.id}>
            <b>{m.role}</b>
            {m.parts.map((part, i) =>
              part.type === "text" ? <p key={i}>{part.text}</p> : null
            )}
          </li>
        ))}
      </ul>
      <form
        onSubmit={(e) => {
          e.preventDefault();
          if (!input.trim()) return;
          sendMessage({ text: input });
          setInput("");
        }}
      >
        <textarea
          value={input}
          onChange={(e) => setInput(e.target.value)}
        />
        <button type="submit">发送</button>
      </form>
    </div>
  );
}
tsx

一条消息大致是:idroleuser / assistant)、parts 数组。文本在 type === "text" 的 part 里。流式过程中 assistant 的文本会一点点变长,直接按 messages 渲染即可。

回车发送、Shift+Enter 换行,在 onKeyDown 里判断即可。长对话记得把滚动容器钉在底部。


注意

  • Key 只放服务端,Route Handler 里读 process.env
  • 生产要做鉴权、限流,否则接口会被刷
  • 换模型:换 provider 包和 model(...) 那一行,前端 hook 不用动

下一篇是 Next 16 的 Proxy(以前叫 Middleware)。


参考文档