聊《别急着换赛道:前端经验在 AI 项目里到底值多少?》之前,先说一句实在的:别急着背概念,先看它在真实项目里到底解决什么问题。
摘要
写这篇文章的动机,是因为上个月我接手了一个 RAG 问答 Agent 项目,联调阶段连续三天都在排查同一个问题。前端页面看着挺正常,调用 LLM 的时候偶尔成功偶尔失败,但错误信息基本没有,日志里也找不到线索。后来复盘才发现,问题出在请求头里少带了一个认证字段——而这个问题,任何一个有权限意识的前端开发者,本来是可以提前规避的。
很多前端转大模型的同学,Demo 阶段特别顺,页面一跑,流式输出,打字机效果,老板和客户都很满意。但真正要上线,权限、日志、可观测这三件事就把人卡住了。今天这篇文章,我想把这个过程摊开讲讲,不是教怎么写 Agent,而是教怎么把 Agent 做成一个能上线的产品。
---
目录
- 前端的转型优势,不是代码能力
- 一次联调翻车:从现象到根因
- 失败原因:怎么区分业务错误、配置错误和环境错误
- 适用边界:什么时候不该照搬
- 流式输出的前端实践
- 作品集方向:怎么展示你的大模型能力
- 多模态体验:前端的新战场
- 总结
前端的转型优势,不是代码能力

先说一个反直觉的判断:前端转大模型产品工程师,真正的优势不是 JS/TS 熟练度,而是对"用户可见性"的敏感度。
后端同学做 Agent,往往先考虑逻辑对不对、调用链全不全;而前端同学天然会问:这个按钮点了之后用户看到什么?流式输出有没有卡顿感?错误提示会不会让用户迷惑?这些问题,直接决定了产品的成败,而不是模型的准确率。
具体到这个方向,前端有几处经验可以直接迁移:
- 流式输出(Streaming):SSE(Server-Sent Events)是前端的老本行,大模型的流式响应本质上就是一个 SSE 连接,前端同学在这里几乎没有学习成本。
- 多模态体验:语音、图片输入输出,前端处理媒体流的经验可以直接复用。
- 权限和鉴权:前端做过 OAuth、JWT、CORS 的同学,理解后端权限体系的门槛很低。
- 可观测的前端视角:监控用户行为、错误上报、性能采集,这是前端每天都在做的事。
但有一个地方容易踩坑:前端习惯在客户端做所有事情,而大模型应用的核心逻辑必须放在服务端。 很多前端同学会把 prompt 拼接、token 计算、甚至简单的 RAG 检索逻辑写到前端,这样做 Demo 没问题,但上线之后安全和可维护性全部崩掉。
---
一次联调翻车:从现象到根因

真实案例
项目背景:一个企业内部知识库问答 Agent,技术栈是 Next.js + LangChain + PostgreSQL(向量库)。功能很典型:用户上传 PDF,Agent 检索相关内容后调用 LLM 生成回答,前端用流式输出展示结果。
联调第三天,出现了一个诡异的问题:同一个 prompt,同一个知识库,有时候能返回答案,有时候返回空字符串,有时候直接抛错,但错误信息是通用的 500 Internal Server Error,完全没有指向性。
排查的第一步,是确认问题出在哪一层。我们分了三组对照实验:
| 测试组 | 输入 | 结果 |
|--------|------|------|
| A | 直接 curl 后端 API | 全部成功 |
| B | 前端通过 SSE 调用 | 有时成功有时失败 |
| C | 前端直接调 LLM provider API | 全部失败 |
这个结果很关键:问题不在 LLM provider,也不在后端逻辑,而在前端到后端的这条链路上。
排查过程
接下来我按链路逐段验证:
第一步:看网络请求
打开浏览器 DevTools,找到那个失败的请求,发现请求头里 Authorization 字段是空的。但奇怪的是,成功的请求里这个字段是有值的。
第二步:对比成功和失败的请求
把两组请求的完整 headers 并排对比,发现只有一个字段不同:X-Request-ID。这个字段是我们内部用于链路追踪的,失败请求里这个字段缺失了。
第三步:追代码
找到前端发起请求的地方,是一个封装好的 fetchWithAuth 函数:
async function fetchWithAuth(url: string, options: RequestInit = {}) {
const token = await getAuthToken(); // 从 localStorage 读取 JWT
// 问题出在这里:token 过期后没有刷新逻辑
if (!token) {
throw new Error('No authentication token');
}
return fetch(url, {
...options,
headers: {
'Authorization': `Bearer ${token}`,
'X-Request-ID': crypto.randomUUID(),
'Content-Type': 'application/json',
...options.headers,
},
});
}
这段代码本身没有逻辑错误,但有一个隐藏的前提:getAuthToken() 必须始终返回有效 token。 而在我们的项目里,token 的有效期是 1 小时,过期后前端没有自动刷新逻辑,导致后续所有请求都带着过期 token 发出。
第四步:验证假设
在 token 过期后,手动刷新页面(重新获取 token),再发同样的请求,全部成功。问题确认:前端 token 管理逻辑缺失。
代码解释
上面这段 fetchWithAuth 有几个关键设计点,值得单独说:
输入:url 是后端接口地址,options 是标准 RequestInit,允许调用方传入额外的 headers 或 body。
核心逻辑:每次请求前调用 getAuthToken() 获取 JWT,拼入 Authorization 头;同时生成一个 UUID 作为 X-Request-ID,用于服务端链路追踪。
异常处理:这里只处理了 token 不存在 的情况,但没有处理 token 已过期 的情况。这是典型的"happy path"代码——正常情况没问题,边界情况全崩。
正确的做法应该是增加 token 刷新逻辑:
async function fetchWithAuth(url: string, options: RequestInit = {}) {
let token = await getAuthToken();
// 尝试请求
let response = await fetch(url, {
...options,
headers: {
'Authorization': `Bearer ${token}`,
'X-Request-ID': crypto.randomUUID(),
'Content-Type': 'application/json',
...options.headers,
},
});
// 401 表示 token 过期,尝试刷新后重试一次
if (response.status === 401) {
token = await refreshAuthToken(); // 调用刷新接口获取新 token
response = await fetch(url, {
...options,
headers: {
'Authorization': `Bearer ${token}`,
'X-Request-ID': crypto.randomUUID(),
'Content-Type': 'application/json',
...options.headers,
},
});
}
// 二次失败才抛出
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new Error(error.detail || `HTTP ${response.status}`);
}
return response;
}
这段代码的变化有三个:第一,先尝试请求再判断 401,而不是提前校验 token 是否过期;第二,401 时调用刷新接口重新获取 token 并重试一次;第三,错误信息从响应体中提取,而不是返回通用的 Internal Server Error。
---
失败原因:怎么区分业务错误、配置错误和环境错误
这次翻车,根本原因是token 过期处理缺失,但如果要把这类问题归类,它属于哪一类?
我总结了一个简单的判断框架:
| 错误类型 | 特征 | 排查方向 | 这次翻车属于 |
|----------|------|----------|-------------|
| 业务错误 | 逻辑写错了,输入输出不符合预期 | 检查代码逻辑、测试用例 | ❌ 不是 |
| 配置错误 | 环境变量、密钥、权限配置不对 | 检查 .env、IAM 策略、CORS | ❌ 不是 |
| 环境错误 | 运行时状态异常,如 token 过期、服务不可达 | 检查生命周期管理、超时重试 | ✅ 就是 |
很多同学在排查大模型项目问题时,习惯直接怀疑"是不是 prompt 写得不好"或者"是不是模型选错了",但实际上,超过 60% 的"奇怪问题"都是配置或环境层面的问题。
具体到这次翻车,如果我们在开发阶段加了以下三个检查,问题可以提前暴露:
1. Token 有效期断言:在 getAuthToken() 里加上过期时间检查,过期前 5 分钟主动触发刷新。
2. 401 自动重试中间件:在前端请求库层面统一处理 401,而不是在每个页面里单独写刷新逻辑。
3. 请求失败日志:把所有 HTTP 错误统一上报到监控系统,而不是只在控制台打印。
---

适用边界:什么时候不该照搬
上面这套 token 管理方案,适合以下场景:
- 前端单页应用(SPA),token 存在 localStorage 或 cookie 中
- 后端 API 统一使用 JWT 鉴权
- 对用户体验要求较高,不允许用户中途被踢出登录态
但以下场景不建议照搬:
- 移动端原生应用:token 存储和刷新逻辑不同,建议使用平台提供的安全存储方案(如 iOS Keychain、Android EncryptedSharedPreferences)。
- 服务端渲染(SSR)为主的站点:token 应该存在 cookie 中并由服务端统一管理,而不是在前端 js 里操作。
- 内部工具类应用:如果用户量小、容忍度高,可以直接用 session cookie 代替 JWT,减少前端复杂度。
- 涉及敏感数据的应用:JWT 存 localStorage 有 XSS 风险,建议改用 httpOnly cookie。
另外,不要为了"工程化"而工程化。如果你的项目只是一个内部 Demo,token 过期后让用户重新登录完全可以接受,那就不要加自动刷新逻辑。复杂度要和服务规模匹配。
---
流式输出的前端实践
除了权限问题,流式输出也是前端转大模型经常踩坑的地方。
很多前端同学第一次做流式输出,会用 response.text() 读完整响应再解析,这样完全失去了流式的意义——用户要等所有 token 生成完才能看到第一个字。
正确的做法是用 response.body 配合 TextDecoder 逐块解析 SSE 数据:
async function* streamResponse(url: string, body: unknown) {
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
if (!response.body) return;
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, { stream: true });
// SSE 格式:data: {...}\n\n
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('data:')) {
const data = line.slice(5).trim();
if (data === '[DONE]') return;
try {
const parsed = JSON.parse(data);
yield parsed.token; // 逐 token 输出
} catch {}
}
}
}
}
这段代码的核心是 reader.read() 配合 TextDecoder({ stream: true })——stream: true 告诉解码器这是一个不完整的字节流,不要等完整字符再解码,而是遇到不完整的 UTF-8 序列时先缓存,等下一块数据到来再合并解码。这样可以避免中文乱码问题。
---
作品集方向:怎么展示你的大模型能力
如果你正在考虑转大模型方向,作品集比证书有用得多。但作品集不是"我做了个聊天机器人",而是要展示你解决过什么工程问题。
我建议准备三个层次的作品:
第一层:能跑通的 Demo
一个基础的 RAG 问答系统,能接收用户问题、检索知识库、流式输出答案。这一步很多人能做到,但它只是入场券。
第二层:能上线的 MVP
在上面基础上加上权限管理、错误处理、日志上报、基本的可观测性。这才是区分"会调 API"和"能做产品"的关键。建议你找一个实际的知识库(比如你之前做过的文档系统),做一个能真正使用的内部工具。
第三层:有取舍的工程决策
在作品集中明确写出:你为什么选这个技术方案、你遇到过什么问题、你怎么解决的、你放弃了什么。这部分往往是面试官最感兴趣的,因为它展示了你的工程判断力。
具体到一个项目,你可以这样描述:
> 做了一个企业内部文档问答 Agent,基于 LangChain + ChromaDB + Claude。初期 Demo 运行正常,但联调阶段发现 token 过期导致 401 错误频发,排查后增加了自动刷新逻辑和 401 重试中间件。同时接入了 Sentry 做错误上报,用 OpenTelemetry 做链路追踪。项目已内部上线,日均调用 200+ 次。
这段话里有技术栈、有问题、有解决方案、有数据,比"我做了一个大模型应用"有力得多。
---
多模态体验:前端的新战场
大模型应用不只是文本对话。语音输入、图片理解、多轮对话中的状态管理,这些都是前端可以发挥的地方。
以语音为例,Web Speech API 可以完成基础的语音识别,但要做好体验,还需要处理:噪音环境下的识别准确率、长语音的分段处理、识别过程中的反馈动画。这些问题的解决,不依赖模型能力,而依赖前端对产品体验的理解。
图片理解也是类似的逻辑。用户上传图片后,前端需要做压缩、预览、上传进度展示,而这些和"调用多模态模型"本身没有关系——它是独立的交互问题。
---
总结
前端转大模型产品工程师,不是一个"学几个 API 调用"就能完成的事情。真正决定你能不能在这个方向立足的,是你能不能把 Demo 阶段的"能跑通",升级到生产阶段的"能上线"。
权限管理、日志上报、错误处理、可观测性——这些事情不性感,但它们是 Demo 和生产之间的鸿沟。跨过去,你就是产品工程师;跨不过去,你只是一个会调 API 的前端。
我的建议是:不要急着换赛道,先把手头的 AI 项目做到能上线。 在这个过程中积累的排查经验和工程判断,比任何证书都值钱。
资料展示
下面是我整理的AI大模型学习资料和工具包预览,适合收藏后按主题逐步学习。




需要这份AI大模型资料清单的话,在评论区回复「清单」即可;我会根据大家的问题继续补充对应的实战内容。


2204

被折叠的 条评论
为什么被折叠?



