做AI全栈开发这大半年,我最大的感受是:这个领域最大的门槛不是“AI”这两个字,而是“全栈”二字背后多出来的那条不确定性链路。你写传统全栈项目时,接口返回什么字段、用户输入什么格式,基本都是确定的;到了AI应用里,模型输出是不可控的,上下文是会爆的,token成本是会吓你一跳的。从最早用AI写点小脚本,到最近把一个AI写作助手完整跑通上线,中间踩过的坑、绕过的弯,我觉得值得好好记录下来。
这篇文章围绕的是一个真实的AI应用开发项目,核心就是讲清楚AI全栈开发的完整链路:从vibe coding那种“写完就扔”的状态,转到harness加sdd这种工程化开发范式,再到模型接入、Agent编排、后端服务、前端流式、部署监控这几个关键环节的实操细节。适合正在做AI应用开发、AI编程、AI Agent相关项目的朋友,尤其是已经有传统全栈基础、准备往AI全栈方向转型的人。你不需要懂太深的模型原理,但看完之后,应该能少走不少弯路。
1. 从“vibe coding”到工程化:AI全栈开发到底在做什么
1.1 一句话拆解AI全栈开发
AI全栈开发,不是“全干工程师”的简单套娃。传统全栈是前端、后端、数据库、部署这四件套,你做的是把确定的需求翻译成确定的代码。AI全栈在这条链路上,硬生生多出了三个绕不开的新角色:模型层、上下文层、Agent编排层。模型层解决“用哪个模型、怎么接入、怎么控成本”;上下文层解决“模型记不记得住你们刚才聊了什么、怎么在有限的上下文窗口里塞下最关键的信息”;Agent编排层解决“怎么让模型不只回答,还能调用工具、做决策、完成多步骤任务”。
如果你觉得抽象,我用一个生活类比来帮你理解。传统全栈开发像开一家餐厅,你负责定菜单、管后厨、跑堂、收银,所有流程都在你掌控范围内。AI全栈开发呢,等于你把一个特能干但偶尔会自由发挥的机器人大厨请进了后厨。你不光要管餐厅运营,还得研究这个机器人大厨怎么理解菜单、怎么应对客人临时改需求、怎么在客流高峰时不崩盘、怎么确保他炒的每道菜都符合食品安全标准。你的核心工作变成了三件事:给机器人大厨设定规则、设计兜底方案、持续监控他的出品质量。这就是为什么AI全栈开发比传统全栈难,因为你要在不确定性的基础上,构建确定性。
1.2 为什么传统全栈经验在AI时代容易吃瘪
作为从传统全栈转过来的人,我最直观的感受是:以前写代码,核心工作是“把逻辑翻译成机器行为”;现在写AI应用,核心工作变成了“设计约束与兜底”。你不再完全掌控输出,模型的回答可能这次靠谱下次就跑偏,你写的每一行代码都在跟概率打交道。
这就得说说vibe coding这个热门话题了。这个词指什么?就是顺着感觉让AI写代码,用自然语言描述需求,然后看着AI咔咔生成一大片代码,运行一下好像能跑,就完事了。这个模式在写小脚本、做原型验证时非常爽,效率极高。但项目稍微复杂一点,问题就来了:AI生成的代码模块之间相互打架、上下文对不上、你改一个变量名可能引发连锁崩坏、报错信息极其抽象。我见过不少人拿着vibe coding的成果去演示,结果现场翻车。
所以近半年来圈子里开始流行一个词叫harness x sdd。按我自己的理解和实践经验,harness指的是工程约束套件,sdd是spec-driven development,规格驱动开发。说白了,就是从“让AI自由发挥”变成“先定规格,再让AI在轨道上跑”。vibe coding负责灵感和草稿,harness和sdd负责质量和稳定。新入坑的朋友我建议从一开始就把这个观念立住:AI是来当队友的,不是来当替身的,你要用工程化手段约束它、指引它、校验它,而不是放任它。
2. 技术栈选型:AI全栈应用的七个关键层
2.1 模型接入层:别自己卷模型,先学会用对API
很多人一提到AI全栈开发,第一反应是“我要训练一个自己的模型”。说实话,99%的业务场景用不到这一步。你真正需要想清楚的,是怎么用好现成的模型API。
模型选型这件事,核心维度是任务类型和成本。通用对话、创意写作、复杂推理,选能力最强的旗舰模型;结构化抽取、分类、标题生成、摘要这类任务,选一个小而快的模型就够,成本能差出10倍甚至更多。我自己的经验是建立一个“任务到模型”的映射表,比如:
| 任务类型 | 推荐模型档位 | 参考场景 |
|---|---|---|
| 复杂推理/长文写作 | 旗舰级大模型 | 合同分析、长篇文章、多步骤Agent |
| 日常对话/通用问答 | 中端模型 | 聊天机器人、客服问答、内容生成 |
| 结构化抽取/分类 | 轻量级模型 | 信息提取、意图识别、打标、格式化输出 |
| 实时低延迟场景 | 轻快模型 | 流式补全、实时助手、边打字边出结果 |
选好模型之后,接入才是重头戏。目前OpenAI兼容协议基本成了行业事实标准,大部分模型服务商都支持这个协议,这意味着你写一套客户端代码,换个base_url和API key就能切换不同供应商。但我更推荐你在客户端和模型之间加一层模型网关,我自己的选型是LiteLLM Proxy,它能做统一接入、多模型路由、限流、计费归集、故障切换。
我举一个很实际的场景:你的应用同时接了三家模型服务,如果直接写在业务代码里,每次切换模型都要改代码、发版本。有了LiteLLM Proxy之后,只需要改一个配置文件。比如这样:
model_list: - model_name: chat-main litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: chat-fast litellm_params: model: anthropic/claude-sonnet-4 api_key: os.environ/ANTHROPIC_API_KEY - model_name: chat-cheap litellm_params: model: deepseek/deepseek-chat api_key: os.environ/DEEPSEEK_API_KEY业务代码里只需要请求一个统一的/chat/completions接口,真正用哪个模型由网关决定。这样你就能做模型灰度、成本控制、故障自动切换,不用动一行业务代码。
2.2 Agent编排层:从单次调用到自主任务
模型接入解决的是“一次调用”,Agent编排解决的是“一个任务”。两者的区别在于,Agent具备循环能力:模型先生成一个计划,调用工具,观察工具返回结果,再决定下一步做什么,直到任务完成。
我先把AI Agent的核心运转方式拆解一下,大家记住一个公式:Agent等于模型加工具再加循环。这里最关键的技术是function calling,中文叫工具调用或函数调用。具体说,就是你告诉模型有哪些工具可用,模型在回答时不是直接输出文字,而是输出一段结构化的工具调用请求,你拿到这个请求去执行真实操作,再把操作结果喂回给模型。
举个实际例子,我做一个写作助手时,给Agent配置了一个联网搜索工具和一个文档查询工具。当用户问“帮我写一篇关于最近AI编程工具的评测文章”时,模型会先调用搜索工具去查最新资料,拿到搜索结果后,再结合写作指令生成文章。整个过程用户看到的是“搜索中,拿到5条结果,开始写作”,感觉很智能,背后其实就是一次工具调用的循环。
关于编排框架的选型,我做了一个对比,大家在选型时可以直接参考:
| 框架 | 适合场景 | 特点 | 上手成本 |
|---|---|---|---|
| LangGraph | 复杂多Agent、状态机、人类介入 | 图结构编排,控制力最强 | 较高 |
| Semantic Kernel | 企业级应用、C#/Python体系 | 微软生态,插件模型清晰 | 中等 |
| Spring AI | Java技术栈团队 | 与Spring Boot无缝集成 | 中等 |
| 自研编排 | 简单场景、固定流程 | 代码可控,依赖少 | 低 |
这里我有句掏心窝的话:不要一上来就上Agent框架。我见过太多项目,明明一个简单的“输入—处理—输出”流程就够,非要上Agent框架,结果多出几十个概念、一堆抽象层,出了问题排查起来欲哭无泪。判断标准很简单:你的任务是不是需要多步决策、是不是需要动态选择工具?如果需要,上框架;如果只是固定流程,直接写代码调模型就完了。工具是为你服务的,不是你去伺候工具的。
2.3 应用服务层与数据层:和普通后端到底差在哪
很多人以为AI应用的后端跟普通后端差不多,无非加个模型API调用。真做起来你会发现,差异不是一点半点。
数据层首先就不一样。传统后端存的是用户、订单、库存、文章,都是结构化数据;AI应用还得额外面对三类数据:对话历史、向量嵌入、上下文状态。对话历史你总得存吧,用户聊到一半刷新了页面,再打开总不能让AI失忆。向量嵌入是用来做语义检索的,你不能全文匹配用户问题,得把文本转成向量再做相似度搜索,这就是RAG方案的基础。上下文状态是Agent运行时的中间数据,任务执行到哪一步了、哪些工具已经调过了,这些如果不记录,Agent跑着跑着就迷路了。
我的技术选型比较务实:PostgreSQL加pgvector扩展,一张表存业务数据,一张表存向量数据,一个数据库搞定,省去维护ES和专用向量库的运维成本。
流式输出是另一个重大差异。传统后端接口返回一个完整JSON就算完,AI应用不行,用户等不了五六秒出全文,他要求看到文字一个一个蹦出来。这意味着后端接口要从普通JSON响应改成SSE流式响应,也就是Server-Sent Events。这里有个FastAPI的实现示例:
from fastapi import FastAPI from fastapi.responses import StreamingResponse import asyncio, json app = FastAPI() async def generate_chat_stream(messages): # 这里是调用模型API的流式接口,逐chunk产出文本 async for chunk in model_client.stream_chat(messages): if chunk: yield f"data: {json.dumps({'delta': chunk}, ensure_ascii=False)}\n\n" yield "data: [DONE]\n\n" @app.post("/api/chat") async def chat(request: dict): messages = request["messages"] return StreamingResponse( generate_chat_stream(messages), media_type="text/event-stream", headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"} )注意X-Accel-Buffering: no这个响应头,你要是用了Nginx做反向代理,不关掉缓冲,流式数据会被Nginx攒在一起,前端就看不到打字机效果了。这个坑我踩过,后面在第三章还会详细讲。
3. 实操:从零搭建一个AI写作助手全栈应用
3.1 项目脚手架与目录结构设计
理论讲多了容易飘,直接上实操。我最近做的这个AI写作助手,功能不算复杂:用户输入一个主题,Agent自动搜索资料、列大纲、生成文章,支持流式输出,可以设置文章风格和字数。整个项目我用到的技术栈是:前端Next.js加React,后端FastAPI,数据库PostgreSQL加pgvector,模型网关LiteLLM Proxy,用Docker Compose做本地部署。
项目的目录结构是踩过几次坑之后慢慢调整出来的,我觉得蛮有参考价值,直接放出来:
ai-writing-assistant/ ├── frontend/ # Next.js 前端 │ ├── app/ │ │ ├── page.tsx # 主页面 │ │ └── api/ # Next.js API route(如果有需要) │ ├── components/ # 前端组件 │ └── lib/ # 前端工具函数 ├── backend/ # FastAPI 后端 │ ├── app/ │ │ ├── main.py # 应用入口 │ │ ├── routers/ # 路由层 │ │ ├── services/ # 业务逻辑层 │ │ ├── agents/ # Agent 编排逻辑 │ │ ├── prompts/ # 提示词模板 │ │ └── models/ # 数据模型 │ ├── tests/ # 后端测试 │ └── requirements.txt ├── litellm/ # LiteLLM Proxy 配置 │ └── config.yaml ├── docker-compose.yml └── .env.example这个结构最大的好处是把Agent逻辑跟业务逻辑分开,提示词单独建目录管理。千万别把提示词散落在各个代码文件里,等你想统一调优的时候会疯掉。提示词改起来比代码改起来更频繁,它值得拥有独立版本管理的待遇。
3.2 后端Agent服务实现细节
先看核心的Agent服务。我设计的流程是“搜索加写作”两步式:第一步根据用户主题生成搜索关键词并调用搜索工具,第二步把搜索结果整理成参考资料,结合用户的风格要求生成文章。用一个状态机来管理这两个步骤,比让模型自由发挥要稳定得多。
这个流程里的提示词工程很关键。很多人写提示词就是一句话“你是一个写作助手”,这远远不够。我的做法是把系统提示词拆成几个模块:角色定义、任务约束、输出格式、禁忌事项。拿我这个项目的系统提示词举例:
你是资深内容创作助手。你的任务是基于真实参考资料,撰写结构清晰、观点鲜明的文章。 任务约束: 1. 必须基于提供的搜索结果写作,不得随意编造事实和数据。 2. 若搜索结果为0条,明确告知用户并建议更换主题。 3. 遵循用户指定的风格:正式、轻松、或者深度分析。 4. 输出结构:吸引人的标题、引言、2-3个主体小节、结论。 输出格式: 使用Markdown格式输出,二级标题使用##,正文使用段落,重要结论可以加粗。 禁忌事项: 1. 不要输出"作为AI模型"之类的免责声明。 2. 不要重复搜索结果中的同一信息点。 3. 不要生成空洞的套话和正确的废话。这些约束不是拍脑袋写的,每一条都对应着我之前踩过的坑。比如写“必须基于搜索结果写作”,是因为我遇到过模型在没有资料的情况下编造论文引用,非常尴尬。提示词就是你和模型之间的“劳动合同”,写得越具体,模型越不像在糊弄你。
上下文管理是Agent服务里最容易出问题的地方。我的做法是维护一个结构化的消息列表,系统提示词放最前,用户原始请求放后面,搜索结果作为上下文插入中间,并限制整体token数量。当对话轮次多了,先丢弃最早的非关键消息,再做一次摘要压缩。简单说就是:留最新的细节,老的对话总结成一段话。
3.3 前端与交互层的流式体验
后端实现了SSE流式,前端得有配套处理,不然照样卡住。我用React加fetch原生处理,没有引额外的SDK,因为这个场景用原生的足够了。核心代码是这样的:
const response = await fetch("/api/chat", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ messages: conversation }), }); if (!response.ok || !response.body) { setError("服务暂时不可用,请稍后重试"); return; } const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ""; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); // SSE 数据以 \n\n 分隔,按行解析处理 const lines = buffer.split("\n\n"); buffer = lines.pop() ?? ""; for (const line of lines) { const trimmed = line.trim(); if (!trimmed.startsWith("data:")) continue; const payload = trimmed.slice(5).trim(); if (payload === "[DONE]") continue; try { const json = JSON.parse(payload); setOutput((prev) => prev + json.delta); } catch { // 解析失败就跳过,保证流式体验不中断 } } }这段代码里有三个细节要留意。
第一,decoder.decode必须传{ stream: true },不然中文会乱码,因为流式传输时一个中文字符可能被切成两半,这个参数就是告诉解码器“后面还有数据,先别急着下结论”。第二,SSE协议用换行符分隔消息,但网络传输可能把一个消息切开,所以要用buffer缓冲。第三,JSON解析要包try-catch,因为网络分包可能导致一次只收到半个JSON,这种情况直接跳过等下一个chunk就行。
交互层除了流式效果,还有个大家容易忽略的点:中断请求。用户看到AI开始胡说八道,会本能地想点“停止生成”。实现方式很简单,用AbortController,点击停止时调用controller.abort()。前端这一下体验提升极大,千万别省。
3.4 部署上线与模型网关配置
部署这块,我的方案是Docker Compose一键编排。总共四个服务:前端容器、后端容器、PostgreSQL容器、LiteLLM容器。Nginx直接在宿主机或者前端容器里做反向代理。
Docker Compose的配置大致长这样:
version: "3.8" services: litellm: image: ghcr.io/berriai/litellm:main-latest command: ["--config", "/app/config.yaml", "--port", "4000"] ports: - "4000:4000" env_file: - .env volumes: - ./litellm/config.yaml:/app/config.yaml backend: build: ./backend environment: - DATABASE_URL=postgresql://postgres:postgres@postgres:5432/aiwriter - LITELLM_URL=http://litellm:4000 depends_on: - litellm - postgres postgres: image: pgvector/pgvector:pg16 environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: aiwriter volumes: - pgdata:/var/lib/postgresql/data frontend: build: ./frontend ports: - "3000:3000" environment: - BACKEND_URL=http://backend:8000 volumes: pgdata:部署前有一个检查清单,我建议你直接截图保存:第一,环境变量不要写死在代码里,全部走环境变量注入,.env文件加入.gitignore;第二,LiteLLM的密钥从环境变量读取,配置文件里不允许出现明文key;第三,Nginx配置里针对/api/chat这个路径要关闭缓冲,否则流式输出失效;第四,PostgreSQL数据要挂载持久化卷,不然容器一重启数据全没了。
我上线那一天,以上四个坑挨个踩了一遍,尤其是Nginx缓冲那个问题,排查了将近两个小时,前端一直看到文字卡顿,后来发现是Nginx默认把SSE响应缓冲了一大块才吐给前端。这个问题网上讨论很多,但遇到时还是会愣一下,大家引以为戒。
4. 常见问题与排查技巧实录
4.1 模型输出不稳定、格式解析失败怎么办
AI应用开发里,最让人头秃的问题就是模型输出不稳定。明明同样的输入,这次返回合法JSON,下次就在JSON后面多了一段解释文字,直接把解析器干崩。
处理这个问题,我的方案是三层递进的。
第一层,从源头降低概率。能用JSON Mode就用JSON Mode,能用Function Calling就用Function Calling。这两者在协议层面就要求模型输出结构化数据,比你在提示词里写“请以JSON格式返回”要可靠得多。Function Calling尤其好用,你把输出格式定义成一个函数参数结构,模型会严格按照这个schema来输出。
第二层,写一个健壮的解析函数,不能指望一次成功。我的做法是设计一条“解析、校验、修复、重试”四步流水线:先用JSON解析,失败了尝试掐头去尾找JSON片段,再不行用正则提取关键字段,最后还不行就把错误信息回传给模型让它自己修复。
第三层,就是兜底策略。修复不了就返回一个默认值或者友好错误,绝不能让用户看到一堆堆栈信息。这里我想特别强调:AI应用的容错设计跟传统软件不在一个量级,你要抱着“它一定会出错”的心态去写代码,你的稳定兜底就是你比其他竞品用户体验好的地方。
4.2 上下文爆掉与token成本失控
上下文窗口是AI应用开发里最贵的奢侈品。模型一次能处理的token数量是有限的,你塞进去的内容越多,成本越高,响应还越慢。很多新手的第一个线上事故,就是用户多聊了几轮之后,应用开始疯狂报错或者账单突然飙升。
先讲上下文管理。我的实践是给对话设置一个动态窗口:保留系统提示词、保留最近三轮对话完整内容、把更早的对话实时压缩成摘要放在中间。这样既保留了上下文连贯性,又控制住了token数量。
再讲成本控制。分享一个我自己的估算方法:先统计平均每轮对话的输入token数和输出token数,乘以模型单价,再乘以预估的日活用户量和人均对话轮数,就能算出一天的模型成本。算完之后你会发现,一个看起来人畜无害的AI写作助手,重度用户一天就能烧掉几块钱。所以成本控制必须从架构层面做,而不是事后看账单。
具体的省钱手段有几个:第一,简单任务用小模型,复杂任务才用大模型;第二,做缓存,完全相同或高度相似的问题直接命中缓存,不再调模型;第三,对单用户单IP做限流,防止有人刷接口把你刷破产;第四,流式输出时设置合理的max_tokens上限,防止模型在某些场景下无限输出。
4.3 并发、超时与流式断连
模型API的延迟,说句不好听的,比你自己数据库查询慢两个数量级。一个完整生成可能耗时10秒到30秒,这期间任何网络波动都可能断连。所以AI应用的后端,要专门设计超时和重试策略。
超时方面,我给不同环节设置了不同阈值:连接超时5秒,读取超时60秒,整体请求上限120秒。重试采用指数退避策略,第一次等1秒,第二次等2秒,第三次等4秒,最多重试3次,超过就返回错误。注意,不是所有错误都适合重试,比如鉴权错误重试100次大概率还是失败,只会浪费时间和钱。只有网络超时、5xx这类临时错误值得重试。
流式断连这块,很多人容易忽略客户端断开的场景。用户看了一半觉得不满意,直接关了页面,此时后端如果还在傻乎乎地调模型API,不仅浪费钱,还会占用连接。正确做法是在SSE流式响应里监听客户端断开事件:
from fastapi import Request from sse_starlette.sse import EventSourceResponse async def generate(request: Request): async def event_generator(): try: async for chunk in model_client.stream_chat(messages): if await request.is_disconnected(): break # 客户端断开,立即终止生成 yield {"event": "message", "data": chunk} finally: await model_client.close() return EventSourceResponse(event_generator())这段代码的关键在request.is_disconnected(),它在每次chunk产出前检查客户端是否还在,一旦断开马上终止循环。配合finally块清理客户端连接,保证资源不泄漏。
4.4 安全合规与数据隐私底线
说点严肃的。做AI应用,技术可以激进,但安全合规这关必须稳。我自己在这块有非常明确的底线,也建议所有做AI全栈的人把这条刻在脑子里。
第一,用户数据不能未经处理就直接喂给外部模型API。尤其是姓名、电话、身份证号、住址这类个人敏感信息,一定要做脱敏处理。我的做法是在后端加一道检测拦截,用正则加模型双重判断识别敏感信息,命中后要么打码再传给模型,要么直接拒绝处理。
第二,生成内容要过一遍内容安全检查。模型不是每次都知道分寸的,应用层必须加一道过滤机制,对违规内容做拦截。这不是为了别的,是为了产品和用户的长期安全。
第三,日志里绝对不能出现明文API key、用户完整对话、个人敏感信息。我见过有人调试时把整个请求体打进日志,连Authorization请求头都打出来了,这是重大事故。
第四,关于版权和数据的合法使用,一定不要碰来路不明的数据,不要做侵权生成,不要拿用户数据去做未经授权的训练。市面上确实有一些打着“无限制”“不用登录”旗号的AI应用,技术上一时跑得欢,但法律风险、商业风险、道德风险全都悬在头上,做不长久。正规团队不应该做,更不应该学。
5. 把AI全栈做成“最佳实践”的几个心法
5.1 测试策略:AI应用到底怎么测
传统软件的测试方法是断言函数输出,AI应用不行,因为模型输出本身带有随机性,你没法写一个“assert输出等于XXX”。但这不意味着AI应用不用测试,反而更需要测试,只是测试策略要变化。
我的做法是分三层测试。第一层是纯逻辑单元测试,工具函数、上下文裁剪、token估算、解析器这些纯代码逻辑,全部用传统方式测。第二层是集成测试,mock掉模型API的返回,验证整个流程能不能跑通。第三层是模型质量评估,这是AI应用最特别的地方:准备一个评估集,里面是50到100条典型的用户输入和期望的输出标准,每次改完提示词或切换模型,跑一遍评估集,人工打标打分,对比前后差异。
这个评估集价值非常大。我之前有一次优化提示词,主观感觉效果变好了,结果跑完评估集发现特定场景下的输出反而变差了,还好有评估集兜底,不然上线就是事故。建立评估集需要投入时间,但它是把AI应用从“玄学”变成“工程”的关键一步。
5.2 可观测性与持续迭代
AI应用上线只是开始,持续迭代才是常态。迭代的前提是你能看见线上发生了什么。所以可观测性是AI全栈的刚需,不是可选项。
我在每个请求里都带一个request_id,日志里记录这些字段:请求内容摘要、用了哪个模型、输入token数、输出token数、总延迟、成本估算、是否命中缓存、用户有没有点击停止、AI输出的长度、人工评分(如果有)。这些数据收集起来之后,你可以做很多事:找出最烧钱的用户、定位延迟最高的模型、发现某类问题经常触发重试、评估提示词修改前后的效果差异。
工具方面,技术圈现在有一些专门做LLM可观测性的开源工具,比如Langfuse、LangSmith这类,能直接追踪提示词版本、token消耗、Agent每一步的调用链。如果公司有监控平台,把这些数据接进去也行。就算没有平台,自己写个定时任务把日志聚合成报表,也比啥都不看强。
5.3 先定义体验再写代码:AI产品经理思维
最后聊聊一个很多技术人容易忽略的点。AI技术给你的应用加了不少“看起来很酷”的能力,但很多AI应用最终失败,不是技术不行,而是产品体验定义不清。用户打开你的AI应用,不知道该拿它干什么,或者第一次用就觉得没什么用,之后再也不来。
我的建议是,动手写代码之前,先写清楚用户故事和成功标准。比如我做的写作助手,用户故事是这样的:一个自媒体创作者想写一篇关于AI编程工具的文章,他输入主题和风格,5秒内能看到文章框架,1分钟内能看到完整文章,不满意可以重新生成或者微调局部。成功标准是:第一篇文章的可用率达到70%,用户不用大改就能发布;生成速度不能超过60秒;单篇成本控制在2毛钱以内。
这些标准写清楚之后,技术方案完全围绕它们来设计:为了5秒出框架,我做两段式生成,先输出大纲,再逐段补充;为了1分钟出全文,我选了流式输出;为了单篇成本控制,我做了模型分级和缓存。你看,体验定义清楚之后,技术决策会变得非常顺畅,不会纠结。
我的另一个经验是“最小可用但完整”原则。哪怕你的AI应用只有一个功能,也要把流式、错误处理、重试、空状态、加载状态全部做全。宁可功能少,体验不能糙。一个会让用户卡住、转圈、报错却不知道发生了什么的功能,比不做还伤产品。
我个人的体会是,AI全栈开发真正的分水岭不在技术栈本身,而在于你怎么驾驭不确定性。vibe coding写个原型爽是真的爽,但产品真正跑在线上,靠的是约束、测试、监控这套又老又土的工程方法,AI领域至今没有绕开它的捷径。如果你正准备入局,我的建议是别贪多,挑一个小而真实的场景,把模型接入、Agent编排、后端服务、前端流式、部署监控这条路完整走一遍,哪怕功能再简单,这趟全流程下来收获会比背十个框架都有用。
最后再分享一个小技巧:把你自己在开发过程中犯过的提示词错误、输出解析问题、成本超支案例,整理成一份团队内部的checklist。每次新功能上线前对着checklist过一遍,你会发现AI应用的稳定性肉眼可见地提升。这些踩坑记录才是你真正的方法论,比任何框架和工具都值钱。