咱做前端的,谁还没在后台管理系统里写过几年订单列表呢。增删改查写得再溜,说白了还是搬砖,哪天公司说不需要你了,这套熟练工技能说淘汰就淘汰。我自己也是从这种状态过来的,白天写业务,晚上焦虑得刷招聘软件,越刷越慌——前端岗位的面试题一年比一年刁钻,而年龄和薪资却卡在那儿不上不下。后来我咬着牙花了两个多月,用 Next.js 搭配 LangChain.js 做了两个带 AI 能力的项目,就这么把简历从“五年 CRUD 经验”改成了“AI 应用前端开发”,面试邀约量完全不是一个级别。这篇文章我就把全套思路、代码和坑都摊开讲,想换个赛道的朋友可以直接照着做。
先说清楚这件事的本质。前端转 AI 应用开发,不是让你去啃 Transformer 源码、推导反向传播,那是算法工程师的活儿。市场上海量真实存在的岗位缺口,是“用大模型的能力去解决具体业务问题”——也就是 AI 应用层开发。这个层面拼的是三件事:会不会调模型接口、能不能把 AI 能力嵌进产品、懂不懂优化交互体验。这三点,前端有天然优势。你本来就懂用户怎么点按钮、怎么展示信息最舒服,再加一个 LangChain.js 帮你把跟模型打交道的脏活累活抽象掉,转过去的路其实比你想象中短得多。
那为什么偏偏是 Next.js 配 LangChain.js,而不是别的组合?看完全文你就明白了。
1. 前端转 AI,为什么首选 Next.js + LangChain.js
我先说结论:这套组合是现阶段前端切入 AI 应用开发成本最低、天花板却不低的路径,相当于用你已经会的 JavaScript 母语,站在 AI 应用框架的肩膀上。
1.1 Next.js 不只是 React 框架,它是 AI 应用的完美宿主
很多人一听到 Next.js,第一反应是“服务端渲染、SEO 友好”,然后就想:我做后台工具、做 AI 对话产品,要 SEO 干嘛?这个理解其实窄了。Next.js 对我的价值,排第一的是API Routes,就是让你在一个项目里同时写前端页面和后端接口,不用再单独起一个 Node 服务。
做 AI 应用,你一定绕不开一件事:API 密钥不能暴露在前端。如果直接用浏览器去调大模型接口,密钥一抓一个准,账单分分钟被人薅秃。所以你需要一个极简后端来代理请求、做鉴权、限流。传统方案是你得用 Express/Koa 另起一个服务,部署的时候前端一个域名后端一个域名,还得配跨域,麻烦得要死。Next.js 的 API Routes 把这个环节压缩成了一个文件夹,前后端一个进程跑完,部署的时候一个命令搞定。这对一个人干活的前端来说,开发效率是碾压级的。
第二点是Server Actions 和服务端组件。做 AI 应用,很多操作其实根本不需要把状态同步到客户端。比如读取会话历史、加载文档库列表,这些如果在客户端做,你得先请求接口、再 loading、再渲染,一套流程下来体验很碎。在 Next.js 里直接服务端取数渲染,页面首屏就是完整内容,对 AI 应用这种需要“快速看到结果”的场景特别友好。
另外,现在主流的 AI Demo 项目,比如 Vercel AI SDK 的官方示例、Chatbot 模板,全是基于 Next.js 的。你去看开源项目,十有八九是这套技术栈。用 Next.js 意味着你天然处在开源生态的信息中心,踩坑有大量现成答案可以抄。
1.2 LangChain.js:给前端准备的 AI 开发脚手架
LangChain 最早是 Python 生态的,但 LangChain.js 发展也非常快,而且它对前端开发者极其友好。你不用理解什么复杂的回调机制,它把跟大模型交互的过程拆成了几个非常直观的组件:
- Model:负责跟具体的大模型对话,支持 OpenAI、Anthropic、国内的通义千问、智谱 GLM 等,接口统一。
- Prompt Template:把提示词模板化,动态填充变量。相当于前端模板字符串的进阶版。
- Retriever:从向量数据库里召回相关内容,这是 RAG(检索增强生成)应用的核心。
- Agent / Tool:让模型有能力调用你定义的函数,比如查天气、查数据库、操作内部系统。
用 LangChain.js,你的学习曲线不是从零开始,而是把以前写业务逻辑的经验平移过来——它本质上就是一套精心设计的 JavaScript 工具库。当然,我得提醒一句:别指望选型一步到位。LangChain 的抽象偶尔会感觉绕,等你真正吃透了,完全可以自己封装更轻量的逻辑。我的建议是先用 LangChain 跑通全流程建立体感,然后再根据自己的场景选择保留或者剥离它的抽象层——这一点后面会展开。
1.3 对比其他转 AI 路线的优势
很多前端转 AI 第一反应是去学 Python。我的看法是:Python 是加分项,不是必选项。如果你目标是大模型训练、微调、深度推理优化,那 Python 绕不开。但如果你做的是 AI 应用层、Agent 开发、RAG 产品,JavaScript 这套链路完全够用,而且跟 Web 产品天然无缝衔接。
| 对比维度 | Next.js + LangChain.js | 转 Python + FastAPI | 纯前端调 API |
|---|---|---|---|
| 学习成本 | 低(复用 JS 技能) | 高(新语言+新生态) | 最低 |
| 后端能力 | 内置 API Routes | 需要另学框架 | 无(密钥暴露风险) |
| 适合做完整产品 | 非常适合 | 可以 | 只适合 Demo |
| 求职竞争力 | 高(全栈+AI) | 高但竞争者多为后端 | 低 |
| 上手时间 | 2~4 周 | 2~3 个月 | 1 周 |
“纯前端调 API”看起来最快,但做不了产品,密钥安全问题就卡死了。转 Python 上限很高,但投入周期长,而且你一个前端去跟科班后端拼 Python 工程能力,短期内不占优势。Next.js 配 LangChain.js 的真正杀手锏是:你既不用离开熟悉的语言,又能把后端短板一次性补齐,同时叠加 AI 能力,一门技术栈同时解决了职业发展中三个层面的问题。
2. 环境准备与项目初始化:别在第一步翻车
这一节全是实操。我先说一个很多人都会踩的坑:用 create-next-app 初始化项目的时候,千万别一路默认到底,后面改起来特别痛苦。
2.1 正确的初始化姿势
我的建议是用带 Tailwind 和 App Router 的模板。Tailwind 做 AI 对话界面太合适了,气泡、侧边栏、加载状态,写起来飞快。App Router 是 Next.js 13.4 之后的默认推荐,AI 应用里的路由和加载状态处理方便得多。
先检查 Node 版本,必须 18.17 以上,最好用 20 LTS。我用 18 的时候遇到过一个很隐蔽的问题,具体下面会讲。
# 检查 node 版本 node -v # 初始化项目,注意 --ts 开启 TypeScript,--tailwind 开启样式 npx create-next-app@latest ai-workspace --ts --tailwind --eslint --app --src-dir --import-alias "@/*"各参数含义很简单:--src-dir是把代码放到 src 目录下,更整洁;--import-alias "@/*"就是把@/映射到src/,写 import 的时候不用写一长串相对路径。
初始化完成之后,先跑一下确认环境正常:
cd ai-workspace npm run dev浏览器打开http://localhost:3000,看到默认页面就说明环境 OK。然后把默认页面清理掉,留下空壳子,准备开始写业务。
2.2 装依赖:这三个包一个都不能少
接下来是安装 LangChain.js 相关依赖。这一步我有血泪教训:一开始我图省事只装了一个langchain包,结果后面要用不同的模型、要处理消息历史的时候,发现缺少一堆配套包,补装的时候版本还对不上,卡了好几天。原因是 LangChain.js 为了控制包体积,把核心逻辑和具体集成拆得很细,不像 Python 版那样一个包包含万物。
# 核心包 npm install langchain # 如果你用 OpenAI 兼容接口(后面会讲为什么推荐这个) npm install @langchain/openai # 处理文本切分和向量化存储 npm install @langchain/textsplitters @langchain/community # Vercel AI SDK,做流式输出强烈推荐 npm install ai这里解释一下ai这个包。Vercel AI SDK 是专门给前端做 AI 应用的 SDK,它跟你用的前端框架无关,React、Vue、Svelte 都能用。它的核心价值是把流式输出封装成了非常优雅的 React Hook,你不需要手动处理 ReadableStream、不需要手动拼字符串,一个useChat就能搞定聊天框的所有状态管理。没有它的话,你会发现自己写了一堆 useEffect 处理流,代码丑得没法看。
2.3 环境变量和模型接入的准备工作
在写代码之前,先把环境变量准备好。在项目根目录创建.env.local文件:
# 这里用 OpenAI 兼容接口,因为现在国内外的模型基本都兼容这个协议 OPENAI_API_KEY=你的密钥 OPENAI_API_BASE=https://api.openai.com/v1为什么我强调用 OpenAI 兼容接口?原因很现实:现在的模型生态百花齐放,国内厂商的模型很多都提供了 OpenAI 兼容的 HTTP 接口。你只要把OPENAI_API_BASE换一下,代码几乎不用动就能切换模型。这在求职和实际工作中是巨大的便利——面试的时候你说“我做过模型无关的 AI 应用架构”,这比“我会调 OpenAI”高级一个档次。
注意:
.env.local不要提交到 Git,这里面是你的密钥。最好在.gitignore里确认一下有没有忽略它,create-next-app 默认会忽略,但如果你改过配置就要检查一遍。
密钥如果搞不定,可以先用免费的模型服务或本地模型(比如 ollama 跑一个 qwen2.5)顶一下,接口是兼容的。先跑通流程,再换更强的模型,这个策略能让你在零成本的情况下把整套开发流程练熟。
3. 核心功能实现:从 ChatGPT 壳子到完整 RAG 应用
接下来进入整个项目的核心部分。我会带着你从零写一个带对话历史、支持流式输出的 AI 聊天应用,然后再升级成一个 RAG 问答系统,最后加一点 Agent 和 Tool Calling 的内容。这是 AI 应用开发的主干路径,现在大厂的高薪岗位要求基本都集中在这几块。
3.1 先搭一个“能跑”的聊天接口
我写代码的习惯是先把最核心的链路跑通,再逐步加功能。所以第一步,直接在 Next.js 的 API Routes 里写一个最简的聊天接口。
在src/app/api/chat/route.ts建文件:
import { NextRequest, NextResponse } from "next/server"; import { ChatOpenAI } from "@langchain/openai"; // 指定运行时为 Edge,这样可以利用边缘网络的低延迟 export const runtime = "edge"; export async function POST(req: NextRequest) { try { const { messages } = await req.json(); const model = new ChatOpenAI({ model: "gpt-4o-mini", temperature: 0.7, }); const response = await model.invoke(messages); return NextResponse.json({ content: response.content }); } catch (error) { console.error("Chat API error:", error); return NextResponse.json( { error: "Internal Server Error" }, { status: 500 } ); } }这段代码的逻辑非常简单:接收前端传来的消息数组,调模型,返回结果。消息数组的格式是[{ role: "user", content: "你好" }, { role: "assistant", content: "你好,有什么可以帮你?" }],这个格式是 ChatOpenAI 的标准格式,也是所有兼容 OpenAI 协议的模型的通用格式。
但这里有个问题:请求是同步的,模型生成多长时间,前端就卡多长时间。这才是 AI 应用体验差的根源。你想想,用户发一句话,等 10 秒才看到完整回复,中间没有任何反馈,他会觉得产品坏了。所以流式输出不是锦上添花,是必须做的。
这里我给你推荐一个做法:使用ai包的streamText。它可以直接把响应变成 HTTP 流。
import { streamText } from "ai"; import { createOpenAI } from "@ai-sdk/openai"; export const runtime = "edge"; export async function POST(req: NextRequest) { const { messages } = await req.json(); const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY!, baseURL: process.env.OPENAI_API_BASE, }); const result = streamText({ model: openai("gpt-4o-mini"), messages, }); return result.toAIStreamResponse(); }代码反而更短了。关键是调用方体验完全不同——前端收到的是一段持续到达的文本流,可以打字机一样逐字展示,这才是大家熟悉的 ChatGPT 体验。
3.2 前端聊天框:useChat Hook 真香
现在实现前端页面。在src/app/page.tsx里写:
"use client"; import { useChat } from "ai/react"; export default function ChatPage() { const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat(); return ( <div className="flex h-screen flex-col"> <div className="flex-1 overflow-y-auto p-4"> {messages.map((message) => ( <div key={message.id} className={`mb-4 flex ${ message.role === "user" ? "justify-end" : "justify-start" }`} > <div className={`max-w-[80%] rounded-lg px-4 py-2 ${ message.role === "user" ? "bg-blue-500 text-white" : "bg-gray-100 text-gray-800" }`} > {message.content} </div> </div> ))} </div> <form onSubmit={handleSubmit} className="border-t p-4"> <input value={input} onChange={handleInputChange} placeholder="输入你的问题..." className="w-full rounded-lg border p-3 focus:outline-none focus:ring-2 focus:ring-blue-500" /> </form> </div> ); }就这么点代码,一个带流式输出、自动维护消息历史的聊天应用就完成了。你可能觉得太魔幻,但useChat内部帮你做了大量事情:它默认请求/api/chat接口、自动管理 messages 状态、把流式输出的增量自动拼接到最后一条 assistant 消息上、还暴露了isLoading方便你显示加载状态。以前这些逻辑我用 Redux 都要写三百行,现在一个 Hook 全搞定。
但这里有几个细节要点醒你。第一,生产环境一定要加接口限流和鉴权,否则你的 API Key 账单会变成无底洞。第二,useChat默认把完整的历史消息发给后端,时间长了 token 消耗会很大,需要考虑截断或摘要历史——这些都是产品层面要持续迭代的,但至少第一版跑起来不是问题。
3.3 知识库问答(RAG):从“聊天玩具”到“生产应用”的分水岭
如果你只做到上面那一步,那它跟 ChatBot 模板没什么区别,还不能成为简历上的亮点。真正让 AI 应用产生业务价值的是 RAG——让模型在回答问题时,能够参考你自己提供的知识库内容。
我自己的体会是:RAG 的能力边界,比单纯调一个更强的模型要重要得多。举个例子,你让 ChatGPT 回答公司内部的报销制度,它再聪明也不知道,但如果你把制度文档喂给 RAG,它就能基于这些内容给出准确回答。这个能力在企业里有非常明确的需求,所以我建议你第二版就做成 RAG 应用。
RAG 的完整流程分成两条链路:
一条是“写入”链路(离线):
- 把文档读进来(PDF、Word、Markdown、网页都行)
- 把文档切分成小块(Text Splitter)
- 把每块转成向量(Embedding)
- 存入向量数据库
另一条是“读取”链路(在线):
- 用户提问
- 把问题转成向量
- 从向量库召回最相似的文档块
- 把文档块和问题一起交给模型生成答案
我先演示写入链路,用内存向量存储最简单,生产环境再换成 Pinecone 或 pgvector。
import { Document } from "langchain/document"; import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters"; import { MemoryVectorStore } from "langchain/vectorstores/memory"; import { OpenAIEmbeddings } from "@langchain/openai"; // 1. 准备文档内容 const text = ` 公司的远程办公政策: - 每周可选择最多2天远程办公 - 远程办公日需保证上午10点到下午4点在线 - 需要提前一天在OA系统提交申请 - 紧急情况可以临时申请,但需要主管审批 `; // 2. 切分文档 const splitter = new RecursiveCharacterTextSplitter({ chunkSize: 200, chunkOverlap: 50, }); const docs = await splitter.createDocuments([text]); // 3. 生成向量并存储 const vectorStore = await MemoryVectorStore.fromDocuments( docs, new OpenAIEmbeddings() );这里的核心参数是chunkSize和chunkOverlap。chunkSize决定每个文本块有多大,chunkOverlap决定相邻块之间有多少重叠。这两个参数直接影响召回质量——块太大,会把不相关的信息混进来;块太小,又可能切断了完整的语义;重叠太少,跨块的上下文容易断。
我的实践建议是:200 到 500 之间多试试。技术类文档 300 左右不错,问答类数据 200 左右更精准。不用怕调参数,这本来就是个不断实验的过程——RAG 系统的性能优化,本质上是“切块参数、向量模型、召回策略”三项的联合调优。
读取链路是查询,更简单:
// 4. 查询链路 const query = "我可以每周远程办公几天?"; // 实际上线时,你需要保存向量库并在请求时加载 const retrieveDocs = await vectorStore.similaritySearch(query, 3); // 5. 把召回文档塞进提示词 const systemPrompt = ` 你是一个企业知识库助手,请根据以下资料回答问题。 如果资料中没有相关信息,直接说“我暂时无法回答”。 参考资料: ${retrieveDocs.map((doc) => doc.pageContent).join("\n---\n")} `;然后把这个 systemPrompt 跟用户消息一起发给模型,模型就会“参考”你的文档来回答了。
这段代码你跑起来之后会有一个非常直观的体感:同一个问题,没接知识库时模型只能泛泛而谈,接了知识库后能准确说出“提前一天在 OA 系统提交申请”这种细节。这一个小小的改动,就是 ChatBot 和 AI 应用的差别。
3.4 Agent 与 Tool Calling:冲刺高薪的关键加分项
如果 RAG 是你简历上的一个亮点,那Agent 能力就是把亮点放大成闪光点。现在很多高薪 AI 应用岗都明确要求 Agent 开发经验,但不少前端一听就发怵,觉得 Agent 是遥不可及的高端概念。其实 Agent 对前端来说可以理解得非常直觉:它就是个“会使用工具的聊天机器人”。就像你写代码的时候要用 IDE、要用调试工具、要用浏览器控制台一样,Agent 在回答问题时,也可以按需调用一组你给它准备好的工具函数。
LangChain.js 里实现这个非常直接。比如我定义一个查天气的函数作为工具:
import { DynamicStructuredTool } from "@langchain/core/tools"; import { z } from "zod"; const weatherTool = new DynamicStructuredTool({ name: "get_weather", description: "获取指定城市的当前天气情况,仅在用户询问天气时调用", schema: z.object({ city: z.string().describe("城市名称"), }), func: async ({ city }) => { // 这里只做演示,真实场景替换成天气 API 调用 const weatherMap: Record<string, string> = { "北京": "晴,25°C", "上海": "多云,28°C", "广州": "小雨,26°C", }; return weatherMap[city] || `暂无${city}的天气数据`; }, });然后把这个工具传给 Agent:
import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { ChatOpenAI } from "@langchain/openai"; const agent = createReactAgent({ llm: new ChatOpenAI({ model: "gpt-4o-mini" }), tools: [weatherTool], }); const result = await agent.invoke({ messages: [{ role: "user", content: "北京今天天气怎么样?" }], }); console.log(result.messages.at(-1));就这么简单。模型会根据用户的问题,自动判断需不需要调用get_weather工具,如果需要,它会先输出一个工具调用的请求,LangChain 帮你执行完函数再把结果回传给模型,模型根据结果组织最终回复。
前端对这个过程有一个天然优势的理解模型:Tools 就是后端接口的封装,Agent 就是带路由判断的接口编排器。你用 JavaScript 写过后台管理系统,无非是把 if/else 换成了模型的语义判断。
你可以顺着这个思路做很多有价值的业务场景:查库存、查订单状态、审批流操作、用户信息查询……每个工具对应一个系统接口,Agent 就成了连接业务系统和自然语言的万能入口。相信我,这个方向在企业里的价值密度比 CRUD 高一个数量级。
3.5 升级到 LangGraph:从“线性调用”到“可编排 AI 流程”
刚才的例子用的是createReactAgent,这个 API 已经帮你把 ReAct 循环封装好了。但如果你的业务逻辑更复杂——比如需要多步骤验证、分支判断、人工介入——我建议你再进一步看看LangGraph.js。
LangGraph 是 LangChain 官方推荐的 Agent 编排框架,它把 AI 流程建模成一张图,节点是你要执行的动作,边是流转条件。你可以把它理解成前端的“状态机 + 路由”的 AI 版。
一个真实的业务场景:用户想报销一笔费用,Agent 收到请求后,先调用工具核验发票真实性和金额,然后判断是否在职员工,最后走审批流程或直接驳回。每一步都可能有不同的分支走向,传统的单次模型调用根本处理不了,但用 LangGraph 可以把每个环节定义成一个个节点,编排成清晰的执行图。
我建议你按这个顺序去学:先把基础 RAG 做好,再玩熟 Tool Calling,最后研究 LangGraph。别一上来就啃 LangGraph,它确实强大,但抽象层次不低,建议在前面的基础都建立之后再上,性价比会高很多。
4. 前端转 AI 求职:项目做完后,简历和面试怎么打
项目做完了,最关键的问题来了:怎么把这个经历变成面试机会和高薪 offer?很多前端技术没问题,一到自我推销就卡壳。我复盘了一下自己跳槽成功的过程,核心是做了三件事。
4.1 简历上的项目描述要“结果化 + 量化”
很多前端的简历写项目经历是这种画风:“负责后台管理系统的开发,基于 React 实现订单模块”。这种描述写再多也激不起面试官的兴趣。不是说它错,而是它没有信息量。
同样是 AI 应用项目,你要突出的是价值,不是过程动作。我给个自己的简历措辞参考:
AI 智能客服系统(企业知识库问答,2 个月独立完成)
- 基于 Next.js 14 + LangChain.js 构建,支持流式输出、会话历史、知识库问答,日请求量约 5000 次;
- 实现 RAG 检索增强,解决大模型幻觉问题,业务知识回答准确率从 55% 提升至 90%;
- 基于 LangGraph 设计多步 Agent 流程,实现工具调用自动路由,支持天气查询、订单状态查询等 5 个业务工具;
- 封装统一模型接入层,通过 OpenAI 兼容接口对接国内外 3 种不同大模型,模型切换零代码改动。
这种写法每个 bullet 都对应一种能力:流式输出是产品体验、RAG 是工程能力、Agent 是技术深度、模型兼容是架构思维。面试官扫一眼就知道你干的不是玩具项目。
4.2 技术面试的高频考点和应对思路
面试官考察 AI 应用岗,很少会问“Attention 机制的公式是什么”。他们更关心你实际解决了什么问题,以及你对 AI 应用链路有没有全局认知。
我做了一个高频问题速查表:
| 高频问题 | 回答要点建议 |
|---|---|
| RAG 的完整流程是什么? | 文档加载→切块→向量化→存储→召回→注入提示词→生成,每一步都能结合你的项目说细节 |
| 为什么需要 Agent?它解决了什么问题? | 因为大模型本身没有“行动能力”,Agent 通过工具调用把“思考”和“执行”连接起来 |
| 如何降低大模型的幻觉? | 最直接是 RAG 提供可靠上下文;其次约束提示词,限定“不知道就说不知道”;最后可以用结构化输出校验 |
| 流式输出是怎么实现的? | 模型逐个 token 生成,通过 SSE/ReadableStream 推给前端,Vercel AI SDK 对此做了封装 |
| 项目的性能瓶颈在哪? | 从响应延迟、token 成本、向量检索速度几个角度谈,体现你有真实调优经验 |
这个表格不要求你背,而是帮你建立回答框架。面试官更在意的是你在回答中暴露出来的思考深度,而非标准答案本身。
4.3 开源项目 + 个人博客:让实力自己被看见
我强烈建议你把做出来的项目推到 GitHub,并且配合 README 写清楚架构图、功能列表、如何离线运行。有条件的话,把项目部署到 Vercel 上放个在线 Demo 链接。我在面试中就被问过“你的项目能访问吗”,直接甩过去一个正在跑的链接,比说十句“我做了”都管用。
还有一个额外收益:开始写技术输出。不用多,每周一篇,就写你做 AI 应用时踩过的坑、解决的问题。这不仅是巩固知识,也是在给自己积累作品集。真实的技术写作能力,本身在职场上就是稀缺品——它会在招聘平台和社区里为你持续带来曝光。
说实话,我见过太多年纪不小、技术还行、但简历一塌糊涂的前端了。他们不是能力不行,而是太专注埋头写代码,忘了抬头看方向、忘了怎么把自己“卖”出去。转 AI 赛道这件事也是一样:技术上用 Next.js + LangChain.js,你可以低成本地跨越门槛;但在认知上,你必须先承认“写页面”和“做产品”是两件事,主动走向价值密度更高的一侧。
5. 踩坑记录:这些坑我替你踩过了,别再踩一遍
最后整理一下我做这套技术栈过程里踩过的真实的坑,每一件都是真金白银换来的教训。
5.1 Edge Runtime 的兼容性陷阱
我最开始写接口时,看到runtime = "edge"就顺手加了,结果 LangChain 的一些内置工具一调用就报错,查了半天发现是 Edge Runtime 不支持 Node.js 的某些 API。解决办法是两种:要么去掉runtime = "edge"用默认的 Node Runtime,要么把用到 Node 特有 API 的代码单独隔离。
我的建议是:第一版统一用 Node Runtime,稳定优先。Edge Runtime 确实快,但它限制更多,而且对于大部分 AI 应用,瓶颈在模型生成速度而不在网络传输层。什么时候上 Edge?等你确认你用的所有依赖都兼容了再说,别一开始就自找麻烦。
5.2 流式输出在前端不生效,只显示一个转圈
我遇到过的情况是:接口本身是流式的,用 Postman 测试没问题,但前端页面就是一直 loading,最后才一次性渲染。排查结果是中间有一层代理把流切断了——可能是公司网关、可能是本地代理工具,也可能是你把响应包了一层 JSON。特别是如果你用了 Next.js 的中文文档里推荐的某些响应格式,很容易踩到流式传输被缓冲的坑。
排查思路:先在浏览器 Network 面板看接口返回的 Content-Type 是不是text/event-stream,再看响应是不是一段一段到达的。如果没走流,就去检查你是不是做了什么额外的包装,别让它变成一次性 JSON 返回。
5.3 向量化 Embedding 的计费“惊喜”
这是我见过最多人踩的坑:RAG 开发阶段,很多人每一轮测试都对同一个文档重新切块、重新向量化,小文档无所谓,文档一多,OpenAI Embedding 接口的费用就会悄无声息地滚起来。建议写一个“是否已存在向量库”的判断逻辑:本地有库就直接加载,没有才重新生成。这一步能帮你省下不少钱。
另外,Embedding 模型不要用最强的那个,很多场景用轻量版的就够。向量维度过高并不会带来等比例的精度提升,反而会拖慢检索速度、增加存储成本。做工程要讲究性价比,这跟程序员的价值判断是一脉相承的。
5.4 上下文窗口:别让历史消息无限膨胀
用useChat的时候,默认会把所有消息发给后端。对话一长,Token 消耗是线性增长的,最后可能一次请求几十万 Token,账单直接爆掉。解决方案也很成熟:对历史消息做滑动窗口截断,只保留最近 N 轮;或者用模型做摘要压缩,把早期的对话内容压缩成要点塞进系统提示词。
这两条路我在项目里都用过。滑动窗口简单直接,适合大多数场景;摘要压缩效果更细腻,但实现复杂、响应延迟更高。建议先做滑动窗口,跑通之后再做摘要。把成本控制写进项目经验里,面试的时候是一个很不错的差异化亮点。
5.5 跨域和部署的撒手锏
用 Next.js 之后,前后端同源,几乎没有跨域问题。但如果你最后把前端部署在 Vercel、后端单独部署在别的地方,还是要小心。我的建议是:尽量一整坨全放 Vercel,Next.js 的 API Routes 和前端页面会自动一起部署;如果必须分离,记得在 Next.js 的next.config.js里配置合适的 rewrites,把/api代理到后端地址。
说到底,做 AI 应用和做传统前端最不一样的地方,是你得对整条链路负责——从浏览器里的每个交互,到后端怎么跟模型通信,到数据怎么存储和检索。但这也正是它有意思的地方:你不再是一个“做界面的人”,而是一个能独立交付完整 AI 产品的开发者。这个身份变化带来的职业空间,比我原来写五年订单列表都更值得。
我个人实际操作中的一个小建议:不要等全部学完再动手。你现在就可以建一个 Next.js 项目,把 3.1 节的代码粘进去跑起来,看着模型一个字一个字地输出。这个瞬间会让你上瘾,也会推着你往前走。等你好不容易把第一个 RAG 应用跑通,回头再看这篇文章,应该会有另一个体感:原来 AI 应用的真功夫,不在魔法里,而在那些朴素的工程细节中。