Skip to content
阅读进度0%
Agent待复核

什么是 BFF?从前后端解耦到微服务与 Agent 架构中的实践

CSDN 原文全文镜像:BFF 并不是什么复杂的新技术。前端需要的数据,与后端提供的业务能力之间存在天然差异。Frontend↓BackendFrontend↓十几个 Microservices服务发现接口聚合数据转换异常处理权限拼装业务编排系统边界会越来越混……

CSDN 原文镜像

本文为作者 CSDN 博客的全文镜像,原文发布于 2026-08-26。为适配本站结构,仅补充了站内元数据与来源说明,正文主体保持原文内容。

在这里插入图片描述

在很多项目刚开始时,系统架构往往非常简单:

text
Frontend
|
v
Backend
|
v
Database

前端调用后端提供的几个接口,后端查询数据库并返回数据。

这种架构没有什么问题。

但随着业务越来越复杂,后端开始拆成:

text
用户服务
订单服务
文件服务
权限服务
搜索服务
Agent 服务
RAG 服务
模型服务
观测服务
……

前端也从一个简单页面逐渐发展成 Web、App、小程序甚至多个管理后台。

这时候,经常会出现一个问题:

前端为了展示一个页面,需要调用五六个甚至十几个后端服务。

例如一个 Agent 详情页可能需要:

text
Agent 基本信息
模型配置
知识库
Tools
最近运行记录
Token 消耗
用户权限

前端开始不得不理解整个后端微服务体系。

这时候,BFF 就开始变得非常有价值。

BFF,全称:

Backend for Frontend

直译就是:

为前端服务的后端。

它不是一个新的编程框架,也不是某个具体产品,而是一种架构模式

它真正想解决的问题是:

前端真正需要的数据模型,与后端按照业务领域设计的数据模型,往往不是一回事。


一、为什么会出现 BFF?

假设我们有一个 Agent 平台。

后端已经拆成多个服务:

text
User Service
Agent Service
RAG Service
Knowledge Service
File Service
Metrics Service
Permission Service

现在前端打开 Agent 详情页面。

需要请求:

http
GET /agents/123

GET /agents/123/model

GET /agents/123/knowledge-bases

GET /agents/123/tools

GET /agents/123/runs

GET /agents/123/metrics

GET /agents/123/permissions

为了展示一个页面,浏览器发送了七个请求。

这还只是最简单的情况。

前端接下来还需要:

text
判断接口有没有失败

处理超时

处理鉴权

合并返回结果

转换字段

转换状态

处理部分服务不可用

决定页面显示什么

慢慢地,我们会发现:

前端承担的已经不只是 UI 展示逻辑,而是在做后端服务编排。

更麻烦的是,前端开始知道:

text
Agent Service 是什么

RAG Service 是什么

Metrics Service 是什么

Knowledge Service 在哪里

哪个接口先调用

哪个接口失败可以忽略

哪个接口失败整个页面不能显示

这意味着:

后端微服务架构已经泄漏到了前端。

于是可以增加一层:

text
                Web
|
v
BFF
|
+---------+---------+
|         |         |
v         v         v
Agent      RAG       User
Service   Service   Service
|                   |
v                   v
Metrics             Permission

前端只调用:

http
GET /bff/agents/123/detail

BFF 内部完成:

text
查询 Agent
+
查询知识库
+
查询 Tools
+
查询运行记录
+
查询 Metrics
+
查询权限

并发调用

数据聚合

字段转换

返回页面需要的数据

最终前端拿到:

json
<span class="token punctuation">{<!-- --></span>
<span class="token string-property property">"agent"</span><span class="token operator">:</span> <span class="token punctuation">{<!-- --></span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string-property property">"model"</span><span class="token operator">:</span> <span class="token punctuation">{<!-- --></span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string-property property">"knowledgeBases"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string-property property">"tools"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string-property property">"recentRuns"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string-property property">"metrics"</span><span class="token operator">:</span> <span class="token punctuation">{<!-- --></span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string-property property">"permissions"</span><span class="token operator">:</span> <span class="token punctuation">{<!-- --></span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>

然后直接渲染页面。

这就是 BFF 最核心的价值。


二、为什么叫 Backend for Frontend

BFF 这个名字真正重要的不是 Backend。

而是:

for Frontend

传统后端 API 通常站在业务领域的角度设计。

例如用户服务:

text
User

订单服务:

text
Order

Agent 服务:

text
Agent
AgentVersion
Run

知识库服务:

text
KnowledgeBase
Document
Chunk

所以接口可能是:

http
GET /users/{id}

GET /orders/{id}

GET /agents/{id}

GET /runs/{id}

GET /knowledge-bases/{id}

这些 API 在回答:

我的业务能力是什么?

而 BFF 站在前端页面的角度思考。

比如:

text
首页
Agent 详情页
Agent 编辑页
Run 详情页
Dashboard

所以它可能提供:

http
GET /bff/home

GET /bff/agents/{id}/detail

GET /bff/agents/{id}/editor

GET /bff/runs/{id}/detail

GET /bff/dashboard

注意:

text
Dashboard

本身甚至不是一个真正的业务领域。

后端数据库里通常也不会存在:

text
dashboard_table

Dashboard 只是把:

text
Agent 数据
+
用户数据
+
运行数据
+
Token 数据
+
费用数据

组合成一个前端视图。

这正是 BFF 最擅长处理的问题。


三、BFF 本质上是在做一次“模型转换”

前后端之间存在一个非常重要的问题:

text
Backend Domain Model

Frontend View Model

例如后端可能围绕这些对象设计:

text
User
Agent
AgentVersion
KnowledgeBase
Document
Run
RunStep
Metric
Tool

但前端真正关心的对象可能是:

text
AgentListItem

AgentDetailPage

RunDetailPage

DashboardCard

ChatMessage

后端设计关注的是:

业务领域如何建模。

前端设计关注的是:

页面怎样展示。

因此 BFF 可以理解成:

text
Domain Model

BFF

View Model

它在两个世界之间建立了一层转换。


四、BFF 最核心的四种职责

一个比较健康的 BFF,通常主要负责四件事情。

1. Aggregation:接口聚合

例如:

text
Frontend
|
v
BFF
|
+------> Agent Service
|
+------> User Service
|
+------> Knowledge Service
|
+------> Metrics Service

然后 BFF 将结果聚合后一次返回。

而且这些服务通常可以并发请求:

text
Agent ──────────┐
Knowledge ──────┤
Metrics ────────┼──→ Merge → Response
Runs ───────────┘

而不是串行:

text
Agent

Knowledge

Metrics

Runs

这既降低了前端复杂度,也可能减少页面整体加载时间。


五、Transformation:数据转换

后端 API 往往更接近数据库和领域模型。

例如:

json
<span class="token punctuation">{<!-- --></span>
<span class="token string-property property">"id"</span><span class="token operator">:</span> <span class="token number">123</span><span class="token punctuation">,</span>
<span class="token string-property property">"status"</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
<span class="token string-property property">"owner_id"</span><span class="token operator">:</span> <span class="token number">98</span><span class="token punctuation">,</span>
<span class="token string-property property">"created_at"</span><span class="token operator">:</span> <span class="token string">"2026-08-26T10:00:00Z"</span>
<span class="token punctuation">}</span>

但前端真正希望得到的可能是:

json
<span class="token punctuation">{<!-- --></span>
<span class="token string-property property">"id"</span><span class="token operator">:</span> <span class="token string">"123"</span><span class="token punctuation">,</span>
<span class="token string-property property">"status"</span><span class="token operator">:</span> <span class="token punctuation">{<!-- --></span>
<span class="token string-property property">"code"</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
<span class="token string-property property">"label"</span><span class="token operator">:</span> <span class="token string">"运行中"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string-property property">"owner"</span><span class="token operator">:</span> <span class="token punctuation">{<!-- --></span>
<span class="token string-property property">"id"</span><span class="token operator">:</span> <span class="token number">98</span><span class="token punctuation">,</span>
<span class="token string-property property">"name"</span><span class="token operator">:</span> <span class="token string">"张三"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string-property property">"createdAt"</span><span class="token operator">:</span> <span class="token string">"2026-08-26 18:00"</span>
<span class="token punctuation">}</span>

这里涉及:

text
字段重命名
状态转换
时间转换
对象拼装
字段裁剪
数据补充

这些逻辑如果大量散落在 React/Vue Component 里面,前端代码会越来越难维护。

BFF 可以统一完成这层转换。


六、Orchestration:服务编排

BFF 不一定只是简单地:

text
请求 A
请求 B
Merge

有时候一个前端操作可能需要:

text
先查询用户权限

查询 Agent

获取 AgentVersion

根据 Version 查询 Tools

根据 KnowledgeBase 查询知识库

拼装编辑页面

甚至:

text
A 成功以后调用 B

B 失败以后降级到 C

这属于轻量级的:

Orchestration

也就是服务编排。

不过这里要特别注意一个边界:

BFF 可以编排业务能力,但不应该成为业务能力本身。

这个问题后面还会重点讨论。


七、Frontend-specific Logic:前端特有逻辑

还有一些逻辑天然属于某个客户端。

例如:

text
Web Dashboard 展示哪些字段

App 首页返回多少条数据

小程序是否需要分享信息

Web 是否需要 SEO Metadata

App 是否需要 Deep Link

这些内容没有必要进入核心领域服务。

非常适合放到对应 BFF。

于是可以出现:

text
                 Backend Services

+----------+----------+
|          |          |
Web BFF     App BFF    Mini BFF
↑          ↑          ↑
Web        App       小程序

这其实也是 BFF 模式最初的思想之一:

不同前端,可以拥有自己的 Backend for Frontend。


八、BFF 和 API Gateway 到底有什么区别?

这是讨论 BFF 时最容易混淆的问题。

很多人会问:

“我已经有 API Gateway 了,为什么还需要 BFF?”

因为它们解决的问题完全不同。

典型架构:

text
Client
|
v
API Gateway
|
v
BFF
|
+-------- User Service
|
+-------- Agent Service
|
+-------- RAG Service
|
+-------- File Service

API Gateway 更多负责:

text
统一入口
路由
认证
限流
WAF
负载均衡
IP 黑白名单
TLS
流量治理

而 BFF 负责:

text
数据聚合
接口编排
DTO 转换
前端 ViewModel
客户端特有逻辑

可以用一句话区分:

Gateway 管“流量怎样进入系统”,BFF 管“前端需要什么数据”。

例如:

text
用户请求有没有 Token?

更偏 Gateway。

text
这个 Agent 详情页应该返回哪些信息?

更偏 BFF。

当然现实系统的边界并不会永远这么绝对,但从职责设计上应该尽量保持这个方向。


九、BFF 和 Controller 不是一回事

另外一个容易混淆的概念是 Controller。

例如一个典型 Java 服务:

text
Controller

Service

Repository

Database

这里 Controller 只是:

单个服务内部的接口入口层。

而 BFF 是:

text
             BFF
|
+-------+-------+
|       |       |
v       v       v
User    Agent    RAG
Service  Service  Service

它通常运行在多个 Backend Service 上层。

所以:

text
Controller ≠ BFF

但是:

BFF 自己当然也可以有 Controller。

例如:

text
AgentBffController

AgentDetailFacade

+-------+--------+--------+
|       |        |        |
Agent  User     RAG     Metrics
API    API      API       API

十、BFF 和 GraphQL 是什么关系?

GraphQL 也经常和 BFF 一起出现。

但二者同样不是一回事。

GraphQL 是:

API Query Language / Runtime

而 BFF 是:

Architecture Pattern

因此完全可以:

text
Frontend
|
v
GraphQL BFF
|
+------ User Service
+------ Agent Service
+------ RAG Service

前端请求:

graphql
query {
agent(id: "123") {
name
model {
name
}
knowledgeBases {
name
}
runs {
status
}
}
}

GraphQL BFF 再负责从后端多个服务获取这些数据。

所以:

GraphQL 可以是实现 BFF 的一种技术方案,但 GraphQL 本身不是 BFF。


十一、Next.js 为什么天然适合承担 BFF?

现在很多 React 项目使用 Next.js。

这时:

text
Route Handler
Server Action
Server Component

本身就天然拥有服务器运行环境。

于是架构可以变成:

text
Browser
|
v
Next.js
|
+------ Java Backend
|
+------ Python Agent Service
|
+------ RAG Service

此时 Next.js Server Layer 就可以承担一部分 BFF 职责。

例如:

text
Cookie / Session 读取
接口聚合
Token 转换
服务端鉴权
DTO 转换
内部服务地址隐藏
SSE 转发
错误转换

浏览器完全不需要知道:

text
agent-service.internal:8000

rag-service.internal:8111

java-api.internal:8080

浏览器只访问:

text
/api/*

这是现代 Web 项目中非常常见的一种 BFF 实现方式。


十二、BFF 在 Agent 系统里尤其有价值

随着 Agent 系统逐渐复杂,BFF 的价值会更加明显。

例如:

text
                     Web
|
v
Agent BFF
|
+-----------+-----------+
|           |           |
v           v           v
Agent       Conversation   File
Runtime        Service     Service
|
+-----+-----+
|           |
v           v
RAG        Tools

用户发送:

http
POST /api/chat

BFF 内部可能执行:

text
获取当前 User

验证 Agent 权限

查询 Conversation

处理附件

创建 Agent Run

连接 Agent Runtime

代理 SSE Stream

转换事件

返回浏览器

这里有一个特别典型的 Agent 场景:

SSE Event Adapter

Agent Runtime 内部可能产生:

text
run.created

model.started

model.delta

retrieval.started

retrieval.completed

tool.started

tool.completed

subagent.started

subagent.completed

run.completed

但是前端不一定想理解整个 Agent Runtime 协议。

前端真正关心的可能只是:

text
text_delta

thinking

tool_call

status

done

于是:

text
Agent Runtime Events

BFF

Frontend Event Model

这样即使以后底层 Agent Runtime 改了:

text
LangGraph
→ 自研 Runtime

只要 BFF 对外协议不变,前端就不需要全部重写。

这其实也是 BFF 很重要的一层价值:

隔离前端与内部实现细节。


十三、BFF 最大的坑:慢慢变成“第二个业务后端”

BFF 很方便。

也正因为方便,非常容易失控。

最开始:

text
BFF 调用订单服务

后来:

text
顺手判断一下订单状态。

再后来:

text
顺手判断退款条件。

然后:

text
顺手算一下退款金额。

最后甚至:

text
BFF 直接操作数据库。

慢慢变成:

text
               BFF
|
大量业务规则
|
+-------+-------+
|               |
DB            Backend

这时 BFF 实际已经变成:

第二个业务后端。

这是非常危险的架构演化。


十四、BFF 到底应该放什么,不应该放什么?

我比较推荐用下面这个公式理解:

text
BFF
=
Aggregation
+
Transformation
+
Orchestration
+
Frontend-specific Logic

而不是:

text
BFF
=
Domain Business Logic

适合放 BFF

例如:

text
多个 API 聚合

并发请求多个服务

DTO 转换

ViewModel 拼装

Cookie → Token 转换

SSE 代理

Agent Event 转换

页面级数据裁剪

客户端特有字段

轻量接口降级

不应该放 BFF

例如:

text
退款业务规则

订单金额计算

库存扣减规则

权限核心模型

RAG 检索算法

Agent Runtime 状态机

招投标业务规则

财务规则

一个很好判断的方法是:

如果明天没有这个 Web 页面,这段逻辑还应该存在吗?

如果答案是:

应该存在。

那它很可能属于:

text
Domain Service

而不是 BFF。


十五、BFF 什么时候值得引入?

不是所有系统都需要 BFF。

如果你的架构只有:

text
一个 Web
+
一个 Backend

而且:

text
接口简单
页面不复杂
前端请求数量不多

那么:

text
Frontend → Backend

完全够用。

没必要为了:

“架构看起来高级”

再增加一个 BFF。

因为每增加一个服务,就意味着增加:

text
部署
日志
监控
Trace
超时
重试
容灾
开发成本
维护成本

BFF 真正适合下面这些场景。


场景一:前端开始调用很多微服务

例如:

text
一个页面调用 5~10 个服务。

这是非常典型的信号。


场景二:前端大量写数据拼装代码

如果 React/Vue 项目里面开始大量出现:

text
Promise.all

map

filter

merge

normalize

transform

permissionCheck

而且这些逻辑并不是 UI 本身,而是在适配后端数据。

就值得考虑 BFF。


场景三:有多个客户端

例如:

text
Web
App
小程序
后台管理端

而不同客户端的数据需求差异明显。

这正是 BFF 最经典的应用场景。


场景四:微服务内部结构不希望暴露给前端

前端已经开始知道:

text
User Service
Agent Service
File Service
RAG Service
Metrics Service

甚至保存多个:

text
BASE_URL

通常意味着服务边界已经泄漏到客户端。


场景五:Agent / AI 应用

尤其是:

text
Agent Runtime
RAG
File
Conversation
User
Permission
Observability

多个系统共同组成一个 AI 产品时。

BFF 非常适合作为前端与 AI Backend 之间的适配层。


十六、一个比较完整的企业架构

最终系统可能演进成:

text
                      Client Layer

Web          App        Mini Program
|            |              |
v            v              v
Web BFF      App BFF        Mini BFF
\            |             /
\           |            /
+----------+-----------+
|
API Gateway
|
+-------------+-------------+
|             |             |
v             v             v
User          Agent          File
Service       Service        Service
|
+-------+-------+
|               |
v               v
RAG            Model
Service         Service

现实系统也非常常见:

text
Client

Gateway

BFF

Microservices

究竟 Gateway 在 BFF 前还是后,取决于:

text
网络拓扑
部署方式
Ingress
安全边界
服务治理方案

并没有唯一答案。


十七、理解 BFF 最简单的比喻:餐厅服务员

可以把整个系统想象成一家餐厅。

前端:

顾客。

不同微服务:

text
主食档口
饮料档口
甜品档口
凉菜档口

如果没有 BFF:

text
顾客

跑去主食档点菜

跑去饮料档点饮料

跑去甜品档点甜点

自己拿回来拼成一顿饭

这就类似:

text
Frontend
|
+------ User Service
+------ Agent Service
+------ RAG Service
+------ File Service

有 BFF 后:

text
顾客

服务员

各个厨房档口

服务员负责:

text
理解这一桌要什么

分别找对应档口下单

协调多个请求

把东西整理好

一次性交给顾客

这个“服务员”就是:

BFF。

但这里还有一个非常重要的边界:

服务员不会自己去厨房炒菜。

这句话几乎可以帮助我们判断绝大多数 BFF 架构问题。

BFF 可以:

text
叫菜
协调
组合
整理
交付

但是业务服务才真正负责:

text
做菜。

十八、从 BFF 背后真正应该理解的架构思想

BFF 本身并不是最重要的。

更重要的是它体现出的一个架构原则:

不同系统应该面向自己的消费者设计边界。

业务后端面向的是:

text
业务能力

所以围绕:

text
用户
订单
支付
Agent
知识库

设计。

而 BFF 面向的是:

text
前端体验

所以围绕:

text
首页
详情页
工作台
会话页
Dashboard

设计。

这两个视角本来就不应该被强行统一。

因此:

text
Backend Domain Model

和:

text
Frontend View Model

之间拥有一个清晰的适配层,往往反而能让整个系统的边界更加稳定。


结语

BFF 并不是什么复杂的新技术。

它真正解决的是一个随着系统规模扩大几乎必然出现的问题:

前端需要的数据,与后端提供的业务能力之间存在天然差异。

当一个系统从:

text
Frontend

Backend

逐渐演变成:

text
Frontend

十几个 Microservices

如果仍然让浏览器直接理解所有后端服务,前端最终就会逐渐承担:

text
服务发现
接口聚合
数据转换
异常处理
权限拼装
业务编排

系统边界会越来越混乱。

BFF 的意义,就是重新把这层复杂度收回来:

text
Frontend

BFF

Backend Services

所以理解 BFF,可以记住两句话:

Gateway 解决“请求怎么进系统”,BFF 解决“前端需要什么”。

以及:

BFF 可以负责点菜、协调和拼盘,但不要让它自己下厨房炒菜。

对于现代微服务,以及越来越复杂的 Agent / RAG / AI 应用,这种架构思想会越来越有价值。

基于 VitePress 构建