从WebView到AI产品:前端转AI开发,我踩过的坑比写过的代码多

写这篇文章的契机

上周帮一个前端朋友排查问题,他问我:“AI项目难不难?”我还没开口,他先补了一句:“我看你做了个读论文的AI工具,感觉挺复杂的”。

复杂?说实话,比我写WebView兼容代码简单多了——但那种“简单”,是另一种维度的复杂。

做了16年移动端WebView开发,去年开始独立开发AI产品(TLDR Scholar)。这一路踩的坑,比我之前10年踩的加起来都多。今天不聊产品,聊聊一个前端老兵转型AI开发时,那些让我怀疑人生的认知冲突和实操踩坑。


一、前端思维 vs AI思维:我以为我很懂,直到AI教我做人

1.1 确定性的执念,被概率论一拳打懵

写前端久了,脑子里根植了一个信念:代码是确定性的

  • 点击按钮 → 触发事件 → 调用函数 → 返回结果
  • 参数一致 → 输出必然一致
  • BUG可复现 → 必然能找到根因

这套逻辑在AI面前完全失效。

我第一次被AI教做人,是在调试Prompt时:

用户输入:一篇关于Transformer的论文
期望输出:简洁的摘要

我写了个Prompt,反复测试,发现AI偶尔会把“摘要”写成“读后感”。我开始怀疑人生:代码明明一样,为什么输出不一样?

后来才明白:AI的输出是概率分布,不是确定性函数。同样的Prompt,温度参数不同、模型版本不同、甚至对话上下文不同,都会导致输出差异。这不是BUG,这是AI的本质。

踩坑总结:前端转AI开发,第一课就是放下确定性执念。你需要学会用概率思维看待AI输出,建立容错机制,而不是追求100%复现。

1.2 UI驱动 vs 数据驱动:两种世界观的碰撞

前端开发的核心是渲染——把数据变成用户看到的界面。React/Vue的设计哲学都是“数据驱动视图”。

但AI产品不一样,核心是理解与生成——把用户的意图转化为可执行的任务,再把结果呈现给用户。

举个例子,在TLDR Scholar里,前端只需要渲染论文分析结果,但背后要做的是:

  1. 解析用户上传的PDF
  2. 提取关键段落
  3. 组装Prompt让AI理解论文结构
  4. 流式输出摘要、关键发现、方法论
  5. 处理超时、截断、格式异常

前端思维:我关心的是第4步的UI怎么渲染好看。
AI思维:我更关心第1、2、3步的数据处理是否准确,因为AI的输入决定输出质量。

这不是说前端不重要,而是优先级重新排序了。在AI产品里,数据处理和Prompt设计的回报率,往往比优化UI高得多。


二、技术栈迁移:从Vue到Next.js,我以为只是换个框架

2.1 为什么是Next.js,而不是继续Vue

TLDR Scholar最开始是用Vue 3写的,驾轻就熟。但当我需要集成AI能力时,问题来了:

  • SEO需求:用户通过搜索找论文解读,需要SSR
  • API路由:需要后端接口处理OpenAI调用
  • 流式响应:需要Server-Sent Events或WebSocket

Vue 3 + Vite + 独立后端服务当然能实现,但维护两套代码仓库、跨域、认证、部署…这些琐事会消耗大量精力。

Next.js的App Router让我一个前端能快速搞定全栈:页面、服务端逻辑、API路由、数据库ORM,全部在一个仓库里。

// 典型的Next.js API路由,处理论文摘要请求
import { NextRequest } from 'next/server';
import { streamText } from 'ai';

export const runtime = 'edge';

export async function POST(req: NextRequest) {
  const { paperContent } = await req.json();
  
  const result = await streamText({
    model: openai('gpt-4o-mini'),
    system: '你是一个学术论文助手,擅长提取论文核心内容...',
    prompt: paperContent,
  });
  
  return result.toDataStreamResponse();
}

踩坑总结:技术栈选择要考虑“团队能力边界”。我是前端,选Next.js是因为它让我用最小的认知切换做全栈。如果你是纯前端且不需要SSR,Next.js可能过度设计。

2.2 从“只管build”到“全链路思考”

前端开发时,我的工作流是:

写代码 → npm run build → 打包部署到CDN → 完成

AI产品上线后,我的工作流变成了:

用户上传PDF → 服务端解析 → 调用AI API → 流式返回 → 前端渲染

每个环节都可能出问题:

  • PDF太大,解析超时
  • AI API响应慢,超时断开
  • 网络不稳定,输出被截断
  • API费用超预期
  • 并发用户多了,API限流

踩坑总结:前端转AI开发,要从“点”思维切换到“链路”思维。你不再只是实现功能,而是要保证整个链路的稳定性、可靠性和成本可控。


三、AI接口集成:我以为调API很简单,结果被教做人

3.1 流式输出处理:从“等待结果”到“实时消费”

前端调后端API习惯了“请求-响应”模式:

const response = await fetch('/api/analyze', {
  method: 'POST',
  body: JSON.stringify({ paperId: '123' })
});
const result = await response.json();
// 显示结果

AI生成内容可能很长(几千字),用户等待几十秒体验很差。业界标准做法是流式输出(Streaming),让AI一个字一个字地吐出来。

// 前端消费流式响应
const response = await fetch('/api/analyze', {
  method: 'POST',
  body: JSON.stringify({ paperContent }),
  headers: { 'Content-Type': 'text/event-stream' }
});

// 读取流式数据
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);
  // chunk可能是: "这", "篇", "论", "文", "讲", "述", ...
  // 需要增量更新UI
  setContent(prev => prev + chunk);
}

踩坑教训:流式输出看着简单,实际坑很多:

  • 不同AI服务商的响应格式不同(OpenAI用SSE,Claude用chunked)
  • 前端需要处理断点续传重连机制
  • 流式UI状态管理复杂(加载中、错误、完成)

3.2 错误重试:AI API不是99.99%可用

前端调自己的后端服务,可用性可以自己保证。但AI API是第三方服务,会出现:

  • 接口限流(429错误)
  • 服务端临时不可用(503错误)
  • 请求超时
  • 内容安全过滤触发

我第一次遇到限流时,TLDR Scholar直接报错,用户体验极差。

async function callAIWithRetry(
  fn: () => Promise<string>, 
  maxRetries = 3
): Promise<string> {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.status === 429) {
        // 限流,等待一段时间后重试
        const waitTime = Math.pow(2, i) * 1000; // 指数退避
        await sleep(waitTime);
        continue;
      }
      throw error; // 其他错误直接抛出
    }
  }
  throw new Error('AI调用失败,已达最大重试次数');
}

踩坑教训

  1. 一定要实现重试机制,但要用指数退避,别猛冲
  2. 对用户要展示友好的加载状态,别让用户以为卡死了
  3. 设置合理的超时时间,别让请求挂死

3.3 多模型切换:不要把鸡蛋放在一个篮子里

OpenAI虽强,但不是万能的。不同场景需要不同模型:

  • 论文摘要:GPT-4o-mini(性价比高)
  • 代码解释:Claude 3.5 Sonnet(编程能力强)
  • 长文本分析:Claude 200K上下文版本

多模型切换带来新的复杂度:

// 抽象AI调用层
class AIService {
  async analyze(paper: Paper, scenario: 'summary' | 'code' | 'deep') {
    const config = this.getModelConfig(scenario);
    
    try {
      return await this.callModel(config);
    } catch (error) {
      // 如果首选模型失败,尝试备用模型
      if (config.fallback) {
        return await this.callModel(config.fallback);
      }
      throw error;
    }
  }
  
  private getModelConfig(scenario: string) {
    // 根据场景返回不同配置
    return { ... }; 
  }
}

踩坑教训

  • 抽象出统一的AI调用层,方便切换模型
  • 每个模型有不同的价格、速率限制、输出格式,要分别处理
  • 考虑成本优化,不是所有场景都需要最强模型

四、Prompt工程:从前端写逻辑,到AI开发写指令

4.1 前端的“函数思维” vs AI的“指令思维”

前端写代码是定义函数

function getUserInfo(userId: string): User {
  return database.findUser(userId);
}

给AI写Prompt是下达指令

你是一个专业的学术论文助手。你的职责是:
1. 提取论文的核心论点(1-2句话)
2. 列出3个关键发现
3. 说明论文的创新点和局限性

注意:
- 使用简洁、专业的语言
- 避免主观评价
- 如果论文某些信息缺失,明确说明

核心区别

  • 函数是精确的,有明确的输入输出
  • Prompt是模糊的,需要通过“约束”和“示例”来引导输出

4.2 我的Prompt迭代心路

早期写Prompt,我倾向于写得非常详细,试图覆盖所有场景:

你是一个学术论文助手。你需要分析论文的标题、摘要、正文、方法论、实验结果、结论等部分。
对于每个部分,你需要提取关键信息,生成简洁的摘要。
如果论文是机器学习方向的,你需要额外关注模型架构、训练数据、评估指标。
如果论文是系统方向的,你需要额外关注系统设计、性能指标、可扩展性。
...

结果:AI懵了,输出变得冗长且不可控

后来学会做减法:

角色:学术论文助手
任务:生成论文摘要(200字以内)
约束:
- 3句话概括核心内容
- 包含研究问题和主要结论
- 禁止主观评价

踩坑教训

  1. 约束比描述更重要——告诉AI“不要做什么”往往比告诉它“做什么”更有效
  2. 示例比描述更精准——给2-3个输入输出示例,AI能更好地理解你的意图
  3. 保持Prompt简洁——Prompt太长会增加推理成本和不确定性

4.3 Few-shot Prompting:让AI照着例子学

当纯指令不够用时,示例是最有力的武器:

任务:为学术论文生成关键发现列表

示例1:
论文:关于Transformer在NLP任务中的应用研究
关键发现:
- Self-Attention机制能有效捕获长距离依赖
- Position Encoding对模型性能有显著影响
- 在翻译任务上比RNN快3倍

示例2:
论文:...(另一个示例)

现在分析以下论文:
论文:[用户输入的论文]
关键发现:
-

踩坑教训

  • 示例要涵盖不同类型,覆盖边界情况
  • 示例的格式要和你期望的输出格式一致
  • 示例数量不是越多越好,3-5个高质量示例往往比20个普通示例有效

五、部署运维:前端只管build,AI产品要管的可多了

5.1 API成本:每个Token都是钱

前端项目部署到CDN,流量费用相对固定。但AI产品的成本是按量计费

  • OpenAI GPT-4o:$2.5/1M输入tokens,$10/1M输出tokens
  • Claude 3.5 Sonnet:$3/1M输入tokens,$15/1M输出tokens

如果你不做控制,用户一篇论文可能吃掉你几美元的API费用。

我的成本控制方案

  1. 设置单次请求的Token上限(截断超长输出)
  2. 使用缓存避免重复调用(相同的论文不要重复分析)
  3. 根据内容复杂度智能选择模型(简单摘要用小模型)
  4. 实施用量监控和告警
// Token截断示例
function truncateText(text: string, maxTokens: number): string {
  // 简单估算:中文约2个字符=1个token
  const maxChars = maxTokens * 2;
  if (text.length <= maxChars) return text;
  return text.slice(0, maxChars) + '...(已截断)';
}

5.2 并发处理:别让AI API成为瓶颈

用户多了,AI API的限流会让你怀疑人生:

  • OpenAI默认限流:每分钟3-60个请求(取决于账户等级)
  • Claude限流:每分钟50-100个请求

解决方案:

  1. 请求队列:超过限流就排队,不要直接拒绝用户
  2. 优雅降级:高峰期返回“服务器繁忙,请稍后再试”
  3. 分布式部署:多个地区的服务器分担请求

5.3 监控与告警:没有监控的AI产品是裸奔

前端项目上线,刷新页面能正常访问就算OK。AI产品需要监控:

  • API调用成功率
  • 平均响应时间
  • 错误类型分布
  • Token消耗趋势
  • 用户使用模式

踩坑教训:不要等到用户投诉才发现问题。接入监控工具,设置合理的告警阈值,让问题在影响用户之前被发现。


六、最大的收获和反思

6.1 放下“全栈焦虑”,专注核心价值

转型过程中,我一度焦虑于“不会Java、不懂微服务、运维菜如狗”。后来想通了:我的核心价值是前端能力和产品思维,而不是成为全栈工程师。

AI开发的关键链路(Prompt设计、用户体验、数据处理)是前端出身的优势领域。至于后端、数据库、DevOps,可以慢慢学,也可以用托管服务。

6.2 AI是工具,不是银弹

AI能做的事很多,但不代表AI适合所有场景。在TLDR Scholar里,AI负责“理解论文内容”,但“解析PDF格式”、“提取参考文献”、“生成目录结构”这些确定性任务,还是传统代码更靠谱。

找到AI和传统代码的边界,比单纯追新更有价值。

6.3 产品思维 > 技术栈

写了16年代码,最大的收获是:技术是为产品服务的

TLDR Scholar的核心不是用了什么AI模型、搭了什么架构,而是帮用户省了多少时间、解决了什么问题

从“写代码”到“做产品”,这是我转型最大的思维转变。


写在最后

前端转AI开发,坑很多,但值得。

如果你也在考虑转型,或者正在经历类似的困惑,欢迎在评论区交流。

最后,附上TLDR Scholar的链接:https://www.tldrscholar.cn

如果你经常读论文,不妨试试。产品只是载体,重要的是在开发过程中,我重新找到了写代码的热情。


如果有问题或建议,欢迎交流!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐