Backend For Frontend
BFF 是为前端提供专用 API 层的架构模式。在 AI Agent 应用中,Go 后端作为 BFF 层,负责会话管理、上下文组装、协议转换、权限控制和 SSE 网关。
#type / concept
#status / evergreen
#tech / backend
#tech / architecture
[!info] related notes
- 所属 MOC: AI Agent Application MOC
- 相关: API Gateway, SSE Gateway
- 架构: Agentic Application Stack
Backend For Frontend
一句话定义
BFF (Backend For Frontend) 是为前端提供专用 API 层的架构模式。在 AI Agent 应用中,Go 后端作为 BFF 层,不直接做 Agent 推理,而是负责会话管理、上下文组装、协议转换、权限控制和 SSE 网关。
它解决什么问题
如果前端直接调用 Python AI Service:
- 缺少统一的鉴权和权限控制
- AI Service 需要直接查业务数据库(职责混乱)
- 前端需要了解 AI Service 的内部协议
- 无法统一做审计日志和限流
如果让 AI Service 做所有事:
- AI Service 变成”万能服务”,职责不清
- 业务逻辑和 AI 逻辑耦合
- 难以独立扩缩容
BFF 层让每一层做自己擅长的事。
核心原理
BFF 的职责
Go BFF 层负责: Go BFF 层不负责:
├─ 用户鉴权 (Auth) ├─ Agent 推理
├─ 会话管理 (Session) ├─ LLM 调用
├─ 消息持久化 (Message) ├─ 工具执行
├─ 上下文组装 (Context Builder) ├─ RAG 检索
├─ 协议转换 (HTTP ↔ gRPC/SSE) └─ 向量搜索
├─ SSE 网关 (流式事件转发)
├─ 权限控制 (RBAC)
├─ 审计日志 (Audit Log)
├─ 限流 (Rate Limiting)
└─ 请求编排 (多服务协调)
请求流
React 前端
│ HTTP POST /api/chat
▼
Go BFF 层
├─ Auth: 验证 JWT Token
├─ Rate Limit: 检查限流
├─ Session: 获取/创建会话
├─ Context Builder: 组装上下文
├─ 持久化: 保存用户消息
│
├─ 调用 Python AI Service ──────────┐
│ ▼
│ Python AI Service
│ (Agent 推理 + 工具执行)
│ │
├─ SSE 网关: 转发事件 ◄──────────────┘
├─ 持久化: 保存 AI 回复
├─ 审计: 记录调用日志
│
▼
React 前端 (SSE 流式接收)
典型工程实现
Go BFF 代码结构
apps/api/
├── main.go
├── handler/
│ ├── chat.go # /api/chat 路由
│ ├── session.go # /api/sessions 路由
│ └── health.go # /health 路由
├── middleware/
│ ├── auth.go # JWT 鉴权中间件
│ ├── ratelimit.go # 限流中间件
│ └── audit.go # 审计日志中间件
├── service/
│ ├── chat_service.go # 聊天业务逻辑
│ └── session_service.go
├── ai_context/
│ ├── builder.go # Context Builder
│ ├── message_filter.go
│ └── token_budget.go
├── proxy/
│ └── sse_proxy.go # SSE 网关
└── repository/
├── session_repo.go
└── message_repo.go
Chat Handler 示例
func (h *ChatHandler) HandleChat(w http.ResponseWriter, r *http.Request) {
// 1. 鉴权
user, err := h.authMiddleware.GetUser(r)
if err != nil {
http.Error(w, "Unauthorized", 401)
return
}
// 2. 限流
if !h.rateLimiter.Allow(user.ID) {
http.Error(w, "Too Many Requests", 429)
return
}
// 3. 解析请求
var req ChatRequest
json.NewDecoder(r.Body).Decode(&req)
// 4. 获取/创建会话
session, _ := h.sessionService.GetOrCreate(r.Context(), user.ID, req.SessionID)
// 5. 保存用户消息
h.messageService.SaveUserMessage(r.Context(), session.ID, req.Message)
// 6. 组装上下文
contextBundle, _ := h.contextBuilder.Build(r.Context(), session.ID, req.Message)
// 7. 调用 AI Service (SSE)
aiStream, _ := h.aiService.Chat(r.Context(), contextBundle)
// 8. SSE 网关: 转发事件
w.Header().Set("Content-Type", "text/event-stream")
for event := range aiStream {
// 持久化 assistant 消息
if event.Type == "text_delta" {
h.messageService.AppendAssistantMessage(session.ID, event.Data)
}
// 审计
h.auditLog.Record(event)
// 转发
fmt.Fprintf(w, "event: %s\ndata: %s\n\n", event.Type, event.JSON())
w.(http.Flusher).Flush()
}
}
常见坑
- BFF 变成纯转发层: 不做上下文组装、不做权限控制,只是透传
- BFF 做太多事: 把 Agent 推理逻辑也放在 Go 里
- 不做错误处理: AI Service 返回错误时 BFF 没有处理
- 不做超时控制: AI Service 长时间无响应导致 BFF 挂起
- 不做审计: 无法追踪谁在什么时候调用了什么