← 返回文章列表

从踩坑到定理(三):架构决策轴——为什么状态会散落、失败靠运气、验收翻车?

从踩坑到定理:Dify 应用工程的通用理论 · 3/7

📖 摘要:架构决策没有唯一解,但有一条经过验证的优选路径:状态最小化 → 失败外置 → 测试分层。三条定理顺序依赖,分别回答状态怎么管、失败怎么办、怎么证明它可靠,并落地为可直接使用的评审清单。

📌 本文要解决的核心痛点

  • 工单应用状态散落各处,多轮对话后错乱?
  • 失败路径靠运气,线上偶发崩溃?
  • 验收时「看起来能跑」,上线就翻车?
  • 本文用三条设计法则(状态最小化、失败外置、测试分层)回答:状态怎么管、失败怎么办、怎么证明它可靠。

前两个维度都是「约束」:平台约束违反必错,LLM 行为违反必不稳定。架构决策轴是自由度——平台不规定你怎么做,模型也不限制你怎么做。状态存哪、失败怎么处理、验证怎么分层,都是我们的选择。

自由度的坏消息是:没有唯一正确答案,方案好坏全看设计功力。好消息是:自由度的空间里藏着可复用的设计法则——不是「必须这样」,是「这样经过验证更优」。

场景

做一个企业级工单流转应用:用户提交工单 → 状态机流转(待处理/处理中/已完成)→ 过程中可能失败(外部系统不可用、模型超时)→ 多轮对话收集信息。

如果设计时每个决策都「临时想」,会出现什么?状态散落在各处(有的在会话变量、有的在临时拼的参数里)、失败路径靠运气(没想过外部系统挂了会怎样)、验证靠手工点几遍「看起来能跑」。

我们第一版就长这样。直到验收阶段被一连串问题打回:状态不一致、失败后重试把数据搞脏、验证漏掉的边界在线上炸了。这版经验直接逼出了这一篇的三条定理。

结论

架构决策没有唯一解,但有一条经过验证的优选路径:状态最小化 → 失败外置 → 测试分层。

三条定理,一条比一条靠后——只有前一条做对了,后一条才有意义。

定理 3:状态最小化——无状态优先,状态必须显式化。

定理 4:失败外置——失败路径是设计出来的,不是运行时发现的。

定理 5:测试分层——节点级形状断言 + 链路级端到端,两种失效模式要两种验证手段。

推导链:三条定理怎么推出来的

定理 3 的推导。 LLM 应用里「状态」是最危险的东西:它不可复现(模型输出是采样)、它容易污染(跨轮次上下文传染)、它难以排查(看不到中间值)。所以状态越少越好,且每一份状态必须显式化——放在看得见、查得到的地方(会话变量、外部存储),而不是散落在节点参数或隐式上下文里。

显式化的标准动作是:需要跨运行保存的状态,放显式存储(如 Dify 的会话变量、外部 KV 容器),而不是依赖「这次运行刚好还留着」。状态最小化不是「不用状态」,是「每一份状态都有名字、有出处、有生命周期」。

定理 4 的推导。 LLM 应用的外部依赖多(模型 API、知识库、外部系统),任何一步都可能失败。失败不是异常,是默认情形。如果不设计失败路径,失败时应用会怎样?报错、卡死、返回垃圾数据——都是运行时才发现。失败外置的意思是:在设计期就把「失败时走哪条路」定好——重试、降级、兜底、明确报错,每条失败路径都是设计出来的,不是撞出来的。

定理 5 的推导。 这来自一个被反复验证的事实:节点是局部的、链路是全局的。LLM 节点的非确定性是局部的(这个节点输出可能漂移),链路的可靠性是全局的(数据流跨多个节点,某处断裂全链失败)。两种失效模式需要两种验证手段:节点级验证用形状断言(输入输出是否符合契约),链路级验证用端到端用例(真实业务路径是否通)。只用一种验证,必然漏掉另一种失效模式。

正例实证:工单流转应用的完整正确设计

按三条定理重做后的工单应用,验收一次通过:

graph TD S["待处理"] -->|"提交资料"| P["处理中"] P -->|"资料不全"| S P -->|"完成处理"| D["已完成"] P -->|"外部系统失败"| F["降级路径:缓存兜底 + 明确提示"] F --> P

反例实证:第一版怎么翻的车

第一版的三宗罪,正好是三条定理的反例:

反例 1(状态最小化):状态散落。

现象:工单状态同时存在会话变量、拼接参数、临时字段里,互相不同步,多轮对话后状态错乱。

根因:没做状态设计——「用的时候随手放一个地方」。

修复:状态收敛到唯一显式存储,其余全部删掉。删完状态相关 bug 归零。

反例 2(失败外置):失败路径靠运气。

现象:外部系统测试时正常,上线后偶发不可用,应用直接报错卡死,用户看到一屏英文错误。

根因:设计时没想过「外部系统会挂」——失败路径是空的。

修复:补全降级/重试/兜底路径。之后外部系统故障时,应用行为是「设计好的行为」,不是「崩溃」。

反例 3(测试分层):验证漏边界。

现象:验收时手工点了几遍主路径「看起来能跑」,上线的第一周,链路边界场景(半路失败、极端输入)连续出问题。

根因:只做了链路级「能不能跑」,没做节点级断言,也没按路径枚举用例。

修复:补节点级形状断言 + 路径枚举用例。之后边界场景由用例覆盖,不再是线上「惊喜」。

扩展:三条定理怎么落地成评审清单

理论要可操作,就得能变成评审时的检查项。我们实际用的评审清单,就是三条定理的直接展开:

定理 3(状态最小化)检查项:

定理 4(失败外置)检查项:

定理 5(测试分层)检查项:

清单化的价值在于:评审不再靠「感觉对不对」,而是逐项过检查点。我们实测过,带清单评审比不带清单,漏检率显著下降——因为人的记忆会漏,清单不会。

实践动作

边界与版本

版本无关:三条定理是 LLM 应用的普遍设计法则,与平台无关。Dify 只是实现它们的载体之一。

边界说明:定理 4 的验证覆盖了模型超时、外部 API 不可用、LLM 输出不合法三类失败;其他失败类型(如平台自身故障、数据源损坏)按同样方法设计,但具体路径未全部实测。

收尾

三条定理合起来回答了架构决策轴的核心问题:状态怎么管、失败怎么办、怎么证明它可靠。 它们之间是顺序依赖——状态最小化让失败路径简单(状态少,失败面小),失败外置让链路可控(每条路都有设计),测试分层让这一切可证明(两层验证全覆盖)。

下一篇进入第四个维度——数据/记忆。这是四个维度里坑源最密集的一个:RAG 的检索质量、知识新鲜度、query 归一化,每一个都是「看起来简单,做起来全是坑」。

下一篇:从踩坑到定理(四):数据/记忆轴——为什么页面能搜到、工作流里却召回失败?

💬 讨论区:你的应用里状态散落过吗?失败路径是设计出来的还是线上撞出来的?验收时有没有「看起来能跑、交付就翻车」?评论区聊聊你的架构决策故事。

本文基于真实项目交付经验撰写(Dify 1.16.x 环境、69 个实验与验收记录)。文中数据均来自我们自己的实测记录,理论部分以「已验证 / 推断待验证」标注边界。

联系我

15088711270

手机端点击号码可直接拨打 · 桌面端可复制

微信二维码

扫码加微信 · 备注「门户」更快通过