AI 产品分层怎么分才不打架:前端、BFF、工作流、模型各自该负责什么
AI 产品做到一定阶段,团队里最容易出现的争论往往不是“模型还够不够强”,而是“这件事到底该放哪一层”。前端觉得后端不该管这么多,工作流觉得前端偷偷做了编排,模型层又被塞进越来越多业务判断。分层一旦乱,后面几乎每个需求都会打架。
我后来发现,光列四层职责其实还不够让人真正有感觉。更有帮助的方式,是拿一条真实请求走一遍。
就拿一个很普通的“内容改写”场景来说:用户在前端粘一段原文,点一下“优化”,页面开始流式出结果。如果只看界面,这像是一个按钮加一个流式输出区域;如果往后拆,你会发现这条链路其实很容易在四层之间打架。
先从前端开始:它应该负责体验,不该偷偷做编排
前端当然要管会话体验、流式渲染、交互状态和错误提示。但我越来越不希望它承担这些决定:
- 最终模型输入怎么拼
- 该走哪个供应商
- 哪些字段需要脱敏
- 这条长流程现在推进到第几步
前端最容易犯的错,就是为了图快,把“这次先这样拼一下”留在界面层。刚开始没事,一旦功能变多,这些小修小补就会慢慢变成谁都不敢动的隐蔽编排。
所以我更愿意让前端只提交一个相对干净的请求,比如:
type RewriteRequest = {
sessionId: string;
sourceText: string;
scene: 'rewrite';
templateId?: string;
};
它负责把用户动作表达清楚,但不负责把整条业务真相都拼完。
BFF 这一层,最适合做“收口”
BFF 在我这里最像一个收口层。它应该把前端那份还比较轻的请求,整理成后面系统能稳定消费的输入:
- 身份和租户信息补齐
- 会话上下文聚合
- 权限和脱敏前置处理
- 模型路由需要的基础参数整理
如果这层缺位,前端、工作流和模型层迟早都会开始各自补洞。最后系统当然还能跑,只是每层都带着一点别人应该做的事情,谁也说不清最终输入到底是在哪儿变形的。
工作流层,不是可有可无的中间人
一条 AI 功能只要超过一步,工作流层就几乎不可避免。因为这时候系统已经不只是“发请求拿答案”,而是开始涉及:
- 当前在哪个步骤
- 工具调用失败以后怎么办
- 哪些结果需要转人工
- 哪些副作用必须按顺序发生
这层不一定非得是一个很重的编排引擎,但它至少得承认:长链路状态不能靠前端和模型层之间的默契维持。
模型层最好只负责它最擅长的那一小段
我现在越来越坚持一点:模型层应该专注在推理、生成和工具选择,不应该承接业务真相。
一旦你把这些判断也放进模型层:
- 哪些字段一定要落库
- 哪些状态算审核通过
- 哪些动作必须幂等
系统很快就会变得很难验证。因为这些规则本来就应该是确定性的,不该藏进概率性组件里。
真正健康的链路,走起来大概是什么样
如果顺着刚才那条“内容改写”请求往下走,一条相对健康的链路大概应该是这样的:
- 前端采集用户输入,负责交互反馈和流式展示。
- BFF 补齐身份、上下文和基础路由信息。
- 工作流决定这次要不要走规则预判、要不要转人工、结果怎么落状态。
- 模型层只负责生成或推理。
这样一来,改动一旦发生,大家至少知道自己该去哪一层下手,而不是每次都从头吵一遍“这到底算前端问题还是后端问题”。
那些最常见的越界,其实都很好认
我见得最多的几类越界就是:
- 前端偷偷拼最终 Prompt
- BFF 里塞了一整套长流程业务逻辑
- 工作流层开始定义业务最终真相
- 模型层承担了本该确定执行的规则判断
这些越界在早期都可能“先跑起来”,甚至还会显得效率很高。可一到多人协作和长期维护阶段,代价会越来越明显。
所以我现在对分层这件事的判断也比以前简单了:分层的目标不是画图漂亮,而是让改动发生时,每一层都有清楚边界。AI 产品尤其如此,因为它本来就比传统系统多了一层概率性组件。边界不清,问题会被放大;边界清楚,很多复杂度反而能被拆开处理。
真正好的分层,不是让每层都显得重要,而是让每层都只承担自己最该承担的那部分责任。
