Language 中文 English
当 AI 开始写代码,前后端分离还该是默认选项吗?
News 2026-07-27 · About 34 min read

当 AI 开始写代码,前后端分离还该是默认选项吗?

过去十年,"前后端分离"几乎是 Web 应用默认的、无需辩论的架构起点。前端一个仓库、后端一个仓库,中间用一份 REST / OpenAPI 契约连接——这套组合拳成了无数团队的肌肉记忆。可当 Vibe Coding(AI 全流程辅助生成代码)真正进入日常,我们得把这套肌肉记忆拿出来重新审视:在 AI 充当"主程"把应用从零生成出来的场景下,默认分离还是最优解吗?

导语

过去十年,"前后端分离"几乎是 Web 应用默认的、无需辩论的架构起点。前端一个仓库、后端一个仓库,中间用一份 REST / OpenAPI 契约连接——这套组合拳成了无数团队的肌肉记忆。可当 Vibe Coding(AI 全流程辅助生成代码)真正进入日常,我们得把这套肌肉记忆拿出来重新审视:在 AI 充当"主程"把应用从零生成出来的场景下,默认分离还是最优解吗?

本文的结论很明确:未必。至少在"后台应用 / 内部系统 / 标准 CRUD"这一大类场景里,Vibe Coding 时代更稳的第一性原理,是"默认单语言 + 服务端驱动 UI"。

一、AI Agent 全流程生成,面临三条核心约束

当我们让一个 AI Agent 从零到一地把一个后台应用"生成"出来并直接跑通,它本质上在和一个残酷的物理现实搏斗:它不能同时"看见"整个世界。任何生成式 Agent 的产出质量,都受制于三条约束。

约束一:上下文窗口与 Token 成本。 Agent 每次能装进上下文窗口的文件有限,而每多引入一种语言、一套构建链,就多占掉一块本可用于"业务理解"的上下文预算。语言越少、文件越少,Agent 越能把注意力集中在真正重要的业务逻辑上。

约束二:接缝(Seam)数量。 每多一个进程边界、一份契约边界,就多一份"双份真相"——前端一份类型、后端一份契约,二者天然容易漂移;同时多一类集成出错点,需要 Agent 额外推理"两边怎么对上"。接缝越多,Agent 越容易在"对齐"上翻车。

约束三:脚手架确定性。 目录布局、命名约定越是可预测,Agent "一次生成即跑通"的概率越高。反之,结构越发散,Agent 越容易在"文件该放哪、叫什么名"上出错,把力气耗在拼装上而不是逻辑上。

这三条约束可以凝结成一个朴素公式——它不是严谨定理,却是一个可操作的判断标尺:

Agent 产出质量 ≈ 1 /(语言数 × 接缝数 × 结构不确定性)

分母越小,质量越高。它告诉我们一个简单事实:凡是能在三个分母上"做减法"的架构,都会让 AI 生成更稳、更省、更不容易翻车。

二、前后端分离,恰好在三个分母上同时放大

现在把上面的公式套到"前后端分离"上,结论可能让人不舒服:经典分离形态(以 Laravel API + Vue 为例)几乎在每一个分母上都做了加法。

语言数 ×2。 后端 PHP(或其它服务端语言),前端 TypeScript。两套语法、两套标准库心智、两类报错语义,Agent 要在两种"世界观"之间来回切换,上下文预算被直接劈成两半。

接缝数铺开。 路由在两边各一套、CORS 配置、鉴权流的 token 传递、序列化 / 反序列化、前端状态管理……每一个都是独立的出错点。Agent 最容易栽倒的地方,往往不是业务逻辑本身,而是"接口联调"和"前后端类型不一致"——这恰恰是分离架构最密集的接缝区。

结构不确定性偏高。 前端有构建链(Vite / Webpack)、有自己的目录约定(components / views / store),后端又有自己的约定。两份脚手架各自演进,"一次生成即合规"的概率被稀释。

这就是为什么在 Vibe Coding 实测里,Agent 的错误高度集中在"契约对不齐、类型漂了、CORS 拦了"这类接缝问题上,而非业务算法本身。分离的代价,被 AI 生成放大了——你为"组织解耦"买的单,在"AI 代写"的语境下变得格外贵。

对比一下两段典型代码。分离形态下,后端要先定义一个契约、前端再写一遍配合的类型:

// 后端:Laravel API Controller(分离形态)
Route::get('/api/posts', [PostController::class, 'index']);
// 前端:Vue 组件 + axios + 手写 TypeScript 类型
const res = await axios.get<Post[]>('/api/posts');

而在服务端驱动形态下,这一段"契约 + 类型"整体消失,只剩一份声明。这正是下一篇要展开的主线。

三、全栈集成,三个分母同时收敛

反过来看"全栈集成"路线——单语言代码库 + 服务端驱动 UI(如 Livewire、Inertia、HTMX、Reflex 等),它恰好在公式的三个分母上同步做减法。

语言数收敛为 1。 以 Laravel + Livewire / Volt 为例,页面交互用 PHP 组件表达,没有独立的前端构建链,Agent 只写 PHP 一种语言。

接缝数量收敛。 路由、数据、渲染都在单一进程内,没有 CORS、没有额外的序列化契约、没有前端状态机与后端响应之间的"对齐"问题。Agent 要推理的边界大幅减少。

结构不确定性收敛。 服务端框架的目录约定是稳定的,Agent 生成的东西"落在哪里"高度可预测,"一次生成即跑通"的概率显著提高。

换句话说,全栈集成不是"技术倒退",而是在 AI 生成语境下,把不确定性系统性地压低。它把 Agent 的注意力从"怎么让两边对齐"释放回"业务到底要怎样"。

架构对比图:前后端分离 vs 后端驱动UI

四、一张对比矩阵,看清差距

为了把"体感"变成"可比较的数字",我们按六个维度对几种形态做了 0–5 分评估(分数越高,越适合 Vibe Coding 生成):单语言友好、上下文 / Token 成本、接缝数量、脚手架确定性、Agent 工具生态、交互能力。

| 形态 | 单语言友好 | 上下文成本 | 接缝数量 | 脚手架确定性 | Agent 工具生态 | 交互能力 | 综合 | | ------------------------- |:-----:|:-----:|:----:|:------:|:----------:|:----:|:-------:| | Laravel + Livewire / Volt | 5 | 5 | 5 | 5 | 5(Boost) | 4 | 5 | | Laravel + Inertia | 4 | 4 | 4 | 5 | 4 | 5 | 4.5 | | Laravel API + Vue(分离) | 2 | 2 | 2 | 2 | 2 | 5 | 2 |

几个看点:

  • 服务端驱动形态在五个分母维度上几乎拉满:单语言友好、上下文成本、接缝、脚手架确定性、Agent 工具生态全在 4–5 分。它们的代价主要在"交互能力"上——纯 Livewire 的极致交互手感略逊于原生 SPA。
  • 分离形态各项仅 2 分,唯一占优的"交互能力"来自前端框架本身的表达力,但这恰恰是需要额外成本维护的部分——等于用最高的维护代价,换一项它本来就该有的能力。
  • Inertia 是折中:交互能力拉满(接近 SPA 体验),代价是单语言友好与接缝略逊于纯 Livewire(仍有一份前端类型与桥接)。它适合"想要 SPA 手感但又不想手写 REST 契约"的场景。

评分是相对判断,不是绝对值;维度权重也因项目而异。但它清晰地指向一个结论:在"适合 AI 生成"这件事上,服务端驱动形态对分离形态是碾压式的。

五、什么时候,分离仍然是正确选择

诚实地说,"不分离"不是银弹。以下三类场景,前后端分离依然值得选:

  1. 超高交互复杂度:实时协作(如多人同编文档)、重客户端状态(如复杂拖拽编排)、离线优先(PWA / 本地优先)、以及明确的多端(Web + 原生 App 共用一套后端)。这些场景的"交互 / 状态"成本,值得为它支付"双语言 + 多接缝"的代价。
  2. 大型组织的前后端团队并行:当两个团队本就独立编制、独立排期,分离带来的"解耦"在组织层面有价值,远比"Agent 省一个上下文"重要。
  3. 已有独立前端中台或设计系统:当公司已有成熟的组件库、设计 token 体系、前端工程基建,强行回归服务端驱动会浪费存量资产。

判断的标准其实是一句话:你的"交互 / 组织复杂度"是否高到值得为它支付"双语言 + 多接缝"的 AI 生成成本。 如果答案是"是",分离该选还选;如果答案是"大多数后台 CRUD 场景",那默认分离就只是一种惯性,而非经过权衡的取舍。

结语:"不分离"在实际里长什么样

那么"不分离"在代码里长什么样?以 Laravel + Filament 为例,你用 PHP 声明一个 Resource 类,Filament 提供固定的渲染基座,后端牢牢拥有路由与数据,没有手写 REST 契约,没有前端类型漂移:

// app/Filament/Resources/PostResource.php
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Forms;

class PostResource extends Resource
{
    protected static ?string $model = Post::class;

    public static function table(Tables\Table $table): Tables\Table
    {
        return $table
            ->columns([
                Tables\Columns\TextColumn::make('title')->searchable(),
                Tables\Columns\TextColumn::make('author.name')->label('作者'),
                Tables\Columns\IconColumn::make('published')->boolean(),
            ])
            ->filters([
                Tables\Filters\SelectFilter::make('author')
                    ->relationship('author', 'name'),
            ])
            ->actions([Tables\Actions\EditAction::make()]);
    }

    public static function form(Forms\Form $form): Forms\Form
    {
        return $form->schema([
            Forms\Components\TextInput::make('title')->required(),
            Forms\Components\RichEditor::make('body'),
        ]);
    }
}

一个约 30–60 行的 PHP 声明类,就描述清楚了一张完整的后台列表页 + 表单页。AI 只需要理解"PHP 声明 + 固定基座"这一个世界——没有第二套语言,没有第二份契约。

金句:在 Vibe Coding 时代,把"默认分离"的肌肉记忆,换成"默认单语言 + 服务端驱动",才是第一性原理。

这也是本系列想贯穿的一个核心判断。下一篇,我们以 Laravel + Filament 为范例,拆解"不分离"为什么对 AI 尤其友好;再下一篇,我们把同样的逻辑搬到 ThinkPHP + Vue,证明这条路线并不绑定某一门语言。