如何在 Expo 移动应用中用 AI SDK 搭建第一个流式聊天 Agent

发布时间:2026/9/13 16:35:25
如何在 Expo 移动应用中用 AI SDK 搭建第一个流式聊天 Agent 如何在 Expo 移动应用中用 AI SDK 搭建第一个流式聊天 Agent【免费下载链接】aiThe AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents项目地址: https://gitcode.com/GitHub_Trending/ai/ai本任务是在 Expo 移动应用中用 AI SDK 搭建一个带流式聊天界面的简单 Agent后端 API Route 调用streamText生成响应前端useChathook 实时接收 token 并以流式方式渲染。前提是本地已安装 Node.js 22 和 pnpm并已申请一个 Vercel AI Gateway API key教程主路径用它一个 key 访问不同厂商的模型。完成后的结果是在手机或浏览器中打开应用输入消息后聊天界面实时显示模型回复。前置条件本地开发机Node.js 22、pnpm。一个 Vercel AI Gateway API key用于以应用身份调用 Gateway 中的模型。Expo 52 或更高版本。后续用expo/fetch替代原生fetch来启用聊天响应的流式传输该能力要求 Expo 52。可选阅读如果对流式传输HTTP Streaming或 Prompt 工程还不熟悉可以先到 Streaming 基础 补课不影响按本文执行。创建 Expo 应用并安装依赖在本地任意目录执行命令会新建名为my-ai-app的目录并初始化一个基础的 Expo 应用pnpm create expo-applatest my-ai-app cd my-ai-app然后安装 AI SDK 相关依赖aiAI SDK 核心包Vercel AI Gateway provider 已内置其中、ai-sdk/reactReact hooks、zod用于后续定义 tool 输入 schema 的校验库pnpm add ai ai-sdk/react zod如果你不用 pnpm文档同时给出 npmnpm install ai ai-sdk/react zod、yarnyarn add ai ai-sdk/react zod、bunbun add ai ai-sdk/react zod三种等价写法选一种即可。配置 AI Gateway API key在项目根目录新建.env.local文件touch .env.local编辑.env.local把xxxxxxxxx替换为你的真实 AI Gateway API keyAI_GATEWAY_API_KEYxxxxxxxxxAI SDK 的 Vercel AI Gateway Provider 默认读取AI_GATEWAY_API_KEY环境变量所以只需要配置这个变量名不需要在代码里显式传 key。创建流式聊天 API Route新建app/api/chatapi.tsExpo 的 Route Handler 约定对外暴露POST /api/chat完整代码如下。这里使用 Gateway 方式不需要 provider importimport { streamText, UIMessage, convertToModelMessages, createUIMessageStreamResponse, toUIMessageStream, } from ai; export async function POST(req: Request) { const { messages }: { messages: UIMessage[] } await req.json(); const result streamText({ model: anthropic/claude-sonnet-4.5, messages: await convertToModelMessages(messages), }); return createUIMessageStreamResponse({ stream: toUIMessageStream({ stream: result.stream }), headers: { Content-Type: application/octet-stream, Content-Encoding: none, }, }); }代码中各部分的作用异步POSThandler 从请求体取出messages即用户与聊天机器人之间的对话历史为下一次生成提供上下文。调用ai包导出的streamText配置对象包含model模型标识和经convertToModelMessages转换后的messages。streamText返回StreamTextResult把它的stream传给toUIMessageStream再用createUIMessageStreamResponse包装为流式响应返回给客户端。如何选择 model 写法Gateway 是默认的 global provider因此model可以直接写成模型名字符串如上面的anthropic/claude-sonnet-4.5可以换成 Gateway 中任意的文本模型。等价地也可以显式引用 gateway// 方式 1从 ai 包导入默认已包含 import { gateway } from ai; model: gateway(anthropic/claude-sonnet-4.5); // 方式 2安装并导入 ai-sdk/gateway 包 import { gateway } from ai-sdk/gateway; model: gateway(anthropic/claude-sonnet-4.5);可选分支如果想绕过 Gateway 直接对接某个模型厂商安装对应 provider 包并创建实例即可例如直接对接 OpenAIpnpm add ai-sdk/openaiimport { openai } from ai-sdk/openai; model: openai(gpt-5.1);也可以修改全局 global provider让所有字符串形式的 model 引用都走你指定的 provider细节见 AI SDK Core 文档 中的 provider management 章节。编写聊天界面更新根页面app/(tabs)/index.tsx。核心是ai-sdk/react的useChathook它通过DefaultChatTransport连接到你刚建的/api/chat路由import { generateAPIUrl } from /utils; import { useChat } from ai-sdk/react; import { DefaultChatTransport } from ai; import { fetch as expoFetch } from expo/fetch; import { useState } from react; import { View, TextInput, ScrollView, Text, SafeAreaView } from react-native; export default function App() { const [input, setInput] useState(); const { messages, error, sendMessage } useChat({ transport: new DefaultChatTransport({ fetch: expoFetch as unknown as typeof globalThis.fetch, api: generateAPIUrl(/api/chat), }), onError: error console.error(error, ERROR), }); if (error) return Text{error.message}/Text; return ( SafeAreaView style{{ height: 100% }} View style{{ height: 95%, display: flex, flexDirection: column, paddingHorizontal: 8, }} ScrollView style{{ flex: 1 }} {messages.map(m ( View key{m.id} style{{ marginVertical: 8 }} View Text style{{ fontWeight: 700 }}{m.role}/Text {m.parts.map((part, i) { switch (part.type) { case text: return Text key{${m.id}-${i}}{part.text}/Text; } })} /View /View ))} /ScrollView View style{{ marginTop: 8 }} TextInput style{{ backgroundColor: white, padding: 8 }} placeholderSay something... value{input} onChange{e setInput(e.nativeEvent.text)} onSubmitEditing{e { e.preventDefault(); sendMessage({ text: input }); setInput(); }} autoFocus{true} / /View /View /SafeAreaView ); }useChat提供的关键状态messages是当前聊天消息数组每项有id、role、partssendMessage把消息发送到聊天 API。模型输出通过消息的parts数组访问这是一个有序数组按模型生成顺序保留每个输出片段纯文本、reasoning token 等因此 UI 只需遍历parts就能按序渲染。页面里用expo/fetch而不是原生fetch是为了在 Expo 环境中启用响应流式传输这也是要求 Expo 52 的原因。创建 API URL 生成器因为移动端用的是expo/fetch而非 node 的fetch需要按客户端环境web 或 mobile生成正确的 base URL。在项目根目录新建utils.tsimport Constants from expo-constants; export const generateAPIUrl (relativePath: string) { const origin Constants.experienceUrl.replace(exp://, http://); const path relativePath.startsWith(/) ? relativePath : /${relativePath}; if (process.env.NODE_ENV development) { return origin.concat(path); } if (!process.env.EXPO_PUBLIC_API_BASE_URL) { throw new Error( EXPO_PUBLIC_API_BASE_URL environment variable is not defined, ); } return process.env.EXPO_PUBLIC_API_BASE_URL.concat(path); };该函数在开发环境用 Expo 开发服务器地址拼接路径生产环境则要求设置EXPO_PUBLIC_API_BASE_URL环境变量指向你的 API 服务器 base URL否则运行时会抛错。本地跑通即可部署到生产环境前必须先配置这个变量。运行并验证启动应用pnpm expo在浏览器打开http://localhost:8081。验证成功的标志页面出现输入框在其中输入一条消息并提交后AI 回复以流式方式实时显示在界面上。这就是整个链路useChat→POST /api/chat→streamText→toUIMessageStream工作的证据。如果移动端遇到Property structuredClone doesnt exist报错AI SDK 内部使用的部分函数在 Expo 运行时中可能不可用需要加 polyfillpnpm add ungap/structured-clone stardazed/streams-text-encoding在项目根目录新建polyfills.jsimport { Platform } from react-native; import structuredClone from ungap/structured-clone; if (Platform.OS ! web) { const setupPolyfills async () { const { polyfillGlobal } await import(react-native/Libraries/Utilities/PolyfillFunctions); const { TextEncoderStream, TextDecoderStream } await import(stardazed/streams-text-encoding); if (!(structuredClone in global)) { polyfillGlobal(structuredClone, () structuredClone); } polyfillGlobal(TextEncoderStream, () TextEncoderStream); polyfillGlobal(TextDecoderStream, () TextDecoderStream); }; setupPolyfills(); } export {};然后在根_layout.tsx中引入它import /polyfills;可选扩展让 Agent 调用工具到这里基础流式聊天 Agent 已经完成。如果要让 Agent 执行模型自身做不了的动作如查天气可以在同一个 API Route 上追加 tool。以天气工具为例更新app/api/chatapi.tsexecute里返回随机温度只是模拟实际可以请求真实天气 APIimport { streamText, UIMessage, convertToModelMessages, tool, createUIMessageStreamResponse, toUIMessageStream, } from ai; import { z } from zod; export async function POST(req: Request) { const { messages }: { messages: UIMessage[] } await req.json(); const result streamText({ model: anthropic/claude-sonnet-4.5, messages: await convertToModelMessages(messages), tools: { weather: tool({ description: Get the weather in a location (fahrenheit), inputSchema: z.object({ location: z.string().describe(The location to get the weather for), }), execute: async ({ location }) { const temperature Math.round(Math.random() * (90 - 32) 32); return { location, temperature, }; }, }), }, }); return createUIMessageStreamResponse({ stream: toUIMessageStream({ stream: result.stream }), headers: { Content-Type: application/octet-stream, Content-Encoding: none, }, }); }tool 的三个组成部分description帮助模型判断何时调用inputSchema用 Zod 声明入参此处要求location字符串模型会从对话上下文中提取提取不到会向用户追问execute是运行在服务器端的异步函数。模型判断需要该工具时会生成 tool callexecute自动执行工具结果以tool消息加入messages。在 UI 侧message.parts中会出现类型为tool-weather的 parttool part 命名固定为tool-{toolName}即定义工具时用的 key在switch (part.type)中加一个分支即可展示case tool-weather: return ( Text key{${m.id}-${i}} {JSON.stringify(part, null, 2)} /Text );此时问 Whats the weather in New York?你会看到界面上是空的文本回复——因为模型只生成了 tool call 而没有生成文本。要模型拿到工具结果后继续作答需要用stopWhen开启多步工具调用默认值是isStepCount(1)即生成完第一步拿到工具结果就停。改为import { isStepCount } from ai; // 在 streamText 配置中 stopWhen: isStepCount(5),允许单次生成最多 5 个 step模型会把工具结果回传给自己继续生成直到满足停止条件。改完 API Route 或 UI 后可能需要重启开发服务器让变更生效。限制与边界本教程要求 Expo 52expo/fetch流式能力开发机要求 Node.js 22。主路径使用 Vercel AI Gateway provider 作为默认 global provider换厂商时要么安装对应 provider 包显式实例化要么改全局 provider 配置。生产环境必须设置EXPO_PUBLIC_API_BASE_URL否则utils.ts会抛错。移动端缺少structuredClone等全局函数时按上文加 polyfill仅非 web 平台生效Platform.OS ! web分支内。本文代码中的execute返回随机温度、以及anthropic/claude-sonnet-4.5模型名均为文档示例值可按需替换为真实数据源或其他 Gateway 文本模型替换方式以 streamText 与 tools 文档Tools and Tool Calling为准。【免费下载链接】aiThe AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents项目地址: https://gitcode.com/GitHub_Trending/ai/ai创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考