AB
AiBoss站
教程

Gemini

教程

使用 Gemini 构建流式聊天机器人并部署到 Vercel

本文介绍如何构建一个基于 Gemini 的聊天机器人,后端使用 Vercel Serverless Function 调用 Gemini API 并流式返回响应,前端使用 React 组件实时显示文本。涵盖架构、后端实现、接口测试、前端对接和部署步骤。

Gemini 是 Google 推出的多模态大语言模型,通过 API 可以方便地将 AI 能力集成到自己的应用中。本文介绍如何构建一个聊天机器人,后端使用 Vercel Serverless Function 调用 Gemini API,并将响应以文本流的形式逐步返回给浏览器;前端使用 React 组件读取该流并实时更新聊天窗口。这种流式传输方式让用户无需等待完整回复生成,就能看到文字逐字出现,体验更接近现代 AI 聊天界面。

本教程适合有一定 React 和 Node.js 基础、希望将 AI 对话能力集成到 Web 应用中的开发者。你将了解如何设置 Vercel Serverless Function、如何调用 Gemini 的流式生成接口、如何用 React 处理流式响应,以及如何将整个应用部署到 Vercel。文中还会用 curl 测试接口,确保后端正常工作后再编写前端代码。

关于 Gemini 的更多信息,可以参考 Gemini 工具介绍

准备工作

开始之前,请确保具备以下条件:

  • 本地安装 Node.js 18 或更高版本。
  • 从 Google AI Studio 获取 Gemini API 密钥。
  • 拥有 Vercel 账号,并安装 Vercel CLI。
  • 在项目中安装 @google/genai 包:npm install @google/genai

将 API 密钥存储在环境变量 GOOGLE_API_KEY 中。本地开发时,可以在项目根目录的 .env 文件中设置;部署到 Vercel 时,需要在 Vercel 项目控制台的 Settings → Environment Variables 中添加同名变量。

操作步骤

1. 架构概览

整个应用由两部分组成:

  • 前端:React 聊天组件,用户输入消息,AI 回复以流式方式渲染。
  • 后端:Vercel Serverless Function(例如 api/chat),负责验证请求、调用 Gemini、并将输出流式返回。

工作流程:浏览器向 Vercel Function 发送请求 → Function 调用 Gemini API → Gemini 的响应以文本块形式逐步返回给浏览器。

2. 定义 API 契约

前端发送 POST 请求到 /api/chat,请求体为 JSON,包含用户消息和简历数据(本教程的聊天机器人充当简历教练)。后端结合两者生成针对性回复。

POST /api/chat
{
 "message": "How can I improve my resume summary?",
 "resume": {
 "name": "...",
 "experience": [...],
 "skills": [...]
 }
}

3. 实现后端 Serverless Function

在项目根目录创建 api/chat.js(或 api/chat/index.js),代码如下:

const { GoogleGenAI } = require("@google/genai");
const ai = new GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY });

const MAX_TEXT_LENGTH = 2000;
const MAX_ARRAY_LENGTH = 50;

function sanitizeString(input = "") {
 // 实现字符串清洗逻辑,例如去除多余空白、限制长度
 return input.slice(0, MAX_TEXT_LENGTH);
}

function sanitizeObject(obj = {}) {
 // 实现对象清洗逻辑,例如限制数组长度、去除危险字段
 return obj;
}

const allowCors = fn => async (req, res) => {
 res.setHeader('Access-Control-Allow-Origin', '<<你的Web应用URL>>');
 res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
 res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
 if (req.method === 'OPTIONS') {
 return res.status(200).end();
 }
 return await fn(req, res);
};

const handler = async (req, res) => {
 if (req.url === '/api/chat' && req.method === 'POST') {
 const { message, resume } = req.body || {};
 const safeMessage = sanitizeString(message);
 const safeResume = sanitizeObject(resume);
 if (!safeMessage || !safeResume) {
 return res.status(400).json({ error: 'Missing message or resume data' });
 }
 try {
 const stream = await ai.models.generateContentStream({
 model: "<<Gemini模型名称>>",
 contents: `You are a professional Resume Coach AI.
- Always respond clearly, politely, and professionally.
- <<根据需求添加描述性指令>>
- Resume data: ${JSON.stringify(safeResume, null, 2)}
User question: ${safeMessage}`,
 });
 res.setHeader("Content-Type", "text/plain; charset=utf-8");
 res.setHeader("Cache-Control", "no-cache");
 for await (const chunk of stream) {
 const text = chunk.text;
 if (text) {
 res.write(text);
 }
 }
 res.end();
 } catch (error) {
 console.error('Gemini Error:', error);
 res.status(500).json({ error: 'AI request failed' });
 }
 }
 // 健康检查端点
 if (req.url === '/api/chat?type=healthcheck' && req.method === 'GET') {
 res.status(200).json({ message: 'Hello from the chat endpoint!' });
 }
};

module.exports = allowCors(handler);

代码要点:

  • 初始化客户端:使用 GoogleGenAI 和 API 密钥创建客户端。
  • 输入清洗:对 messageresume 进行清洗,避免将不可信的用户输入直接传给 AI。
  • CORS 处理allowCors 包装函数设置跨域头,并处理浏览器预检请求(OPTIONS)。
  • 请求验证:若消息或简历数据缺失,返回 400 错误,避免无效调用。
  • 流式调用:使用 generateContentStream 获取异步迭代器,用 for await...of 循环读取每个文本块,并通过 res.write(text) 立即发送给浏览器。
  • 错误处理与健康检查:捕获异常并返回 500;提供 GET 健康检查端点便于测试。

4. 测试接口

在编写前端之前,先用 curl 验证流式响应是否正常:

curl -N -X POST "http://localhost:3000/api/chat" \
 -H "Content-Type: application/json" \
 -d '{"message":"Give me 3 resume summary tips","resume":{"name":"Test"}}'

-N 参数禁用 curl 的输出缓冲,你会看到文本在终端中逐步出现,这证明流式传输已生效。

5. 实现前端 React 组件

前端核心是 sendMessage 函数,它负责发送用户输入并读取流式响应。组件外壳如下:

function ChatWidget({ resume }) {
 const [messages, setMessages] = useState([]);
 const [input, setInput] = useState("");
 const [loading, setLoading] = useState(false);
 const [error, setError] = useState(null);

 async function sendMessage() {
 // 实现见下文
 }

 return (
 <div className="chat-widget">
 {/* 消息列表、输入框和发送按钮 */}
 </div>
 );
}

sendMessage 的完整实现:

async function sendMessage() {
 const messageText = input.trim();
 if (!messageText || loading) return;

 const userMessage = { role: "user", text: messageText };
 setMessages((prev) => [...prev, userMessage]);
 setInput("");
 setLoading(true);
 setError(null);

 try {
 const res = await fetch("<<你的Vercel函数URL>>/api/chat", {
 method: "POST",
 headers: { "Content-Type": "application/json" },
 body: JSON.stringify({ message: messageText, resume })
 });

 if (!res.ok) {
 throw new Error(`Failed to get response: ${res.status}`);
 }

 const reader = res.body.getReader();
 const decoder = new TextDecoder();
 let fullText = "";

 // 添加一个空的助手消息,用于逐步填充
 setMessages((prev) => [...prev, { role: "assistant", text: "" }]);

 while (true) {
 const { value, done } = await reader.read();
 if (done) break;
 const chunk = decoder.decode(value);
 fullText += chunk;
 // 更新最后一条助手消息的文本
 setMessages((prev) => {
 const newMessages = [...prev];
 newMessages[newMessages.length - 1] = { role: "assistant", text: fullText };
 return newMessages;
 });
 }
 } catch (err) {
 setError(err.message);
 } finally {
 setLoading(false);
 }
}

该函数将用户消息添加到列表,清空输入框,然后发送 POST 请求。通过 res.body.getReader() 读取响应流,每次读取到新文本块时更新最后一条助手消息,实现实时显示。

6. 部署到 Vercel

在项目根目录运行 vercel 命令,按照提示登录并部署。确保在 Vercel 项目设置中添加 GOOGLE_API_KEY 环境变量。部署后,将前端中的 <<你的Vercel函数URL>> 替换为实际部署的 URL。

一个完整示例

假设我们要构建一个简历教练聊天机器人,完整流程如下:

  1. 创建项目目录并初始化 Node.js:npm init -y
  2. 安装依赖:npm install @google/genaivercel(全局或本地)。
  3. 创建 api/chat.js,写入上述后端代码,将模型名称替换为可用的 Gemini 模型(如 gemini-2.0-flash),并将 CORS 中的 <<你的Web应用URL>> 替换为你的前端域名(本地开发可用 http://localhost:3000)。
  4. .env 文件中设置 GOOGLE_API_KEY=你的密钥
  5. 本地启动 Vercel 开发服务器:vercel dev
  6. 用 curl 测试接口,确认流式响应正常。
  7. 创建 React 应用(例如使用 Vite 或 Next.js),实现 ChatWidget 组件,并将 fetch 的 URL 指向本地或部署后的函数地址。
  8. 部署:运行 vercel --prod,并在 Vercel 控制台设置环境变量。

注意事项

  • API 密钥安全:切勿将密钥硬编码在前端代码中,务必通过环境变量管理。
  • 输入清洗:示例中的 sanitizeStringsanitizeObject 需要根据实际需求实现,防止提示注入或超长输入。
  • CORS 配置:如果聊天组件嵌入在不同域名,必须正确设置 Access-Control-Allow-Origin,否则浏览器会拦截请求。
  • 模型选择:代码中的 <<Gemini模型名称>> 需要替换为当前可用的模型 ID,不同模型可能有不同的速率限制和计费标准,请参考 Gemini 官方文档。
  • 配额与计费:Gemini API 有调用配额和费用,具体限制以 Google AI Studio 或官方文档为准。
  • 错误处理:前端应处理网络错误、HTTP 错误状态,并给用户适当反馈。
  • 流式传输的浏览器兼容性fetch 的流式读取需要现代浏览器支持,旧浏览器可能无法正常工作。