Backend For Frontend

BFF 是为前端提供专用 API 层的架构模式。在 AI Agent 应用中,Go 后端作为 BFF 层,负责会话管理、上下文组装、协议转换、权限控制和 SSE 网关。

#type / concept #status / evergreen #tech / backend #tech / architecture

[!info] related notes

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()
    }
}

常见坑

  1. BFF 变成纯转发层: 不做上下文组装、不做权限控制,只是透传
  2. BFF 做太多事: 把 Agent 推理逻辑也放在 Go 里
  3. 不做错误处理: AI Service 返回错误时 BFF 没有处理
  4. 不做超时控制: AI Service 长时间无响应导致 BFF 挂起
  5. 不做审计: 无法追踪谁在什么时候调用了什么

参考资料

创建于 2026/6/30 更新于 2026/7/15