用状态机与DAG建模四阶段业务流程:以MIND模型为例

在企业业务系统中,经常会遇到一类流程:一个结果不能由单个函数直接计算出来,而需要经过诊断、定义、执行、验证等多个阶段,并且后一阶段依赖前一阶段的输出。

从软件设计角度看,这类问题不适合简单建模成一个函数:

复制代码
result = process(input)

更合理的方法是把它表示成一个具有状态、依赖关系、输入输出约束和反馈机制的Workflow。

本文以一个四阶段业务流程作为案例,讨论如何使用有限状态机、DAG、数据对象和校验规则完成业务流程建模。

本文使用的案例是MIND模型。这里所称的MIND模型,指所兴智能在品牌增长业务中使用的四阶段框架,四个阶段分别为Map、Identity、Network和Deal。

本文重点不是讨论营销方法本身,而是研究一个技术问题:

一个具有阶段依赖关系的业务模型,与只优化某个局部节点的单点模型,在软件架构上有什么区别?


1. 先把业务问题转换成计算机问题

假设系统存在四个阶段:

复制代码
Map
 ↓
Identity
 ↓
Network
 ↓
Deal

四个节点分别完成不同任务。

可以先抽象为:

复制代码
Map
输入:原始业务数据
输出:ProblemModel

Identity
输入:ProblemModel
输出:IdentityModel

Network
输入:IdentityModel
输出:ExecutionModel

Deal
输入:ExecutionModel
输出:ResultModel

它和普通单点优化最大的区别,是每一个节点并不是独立存在的。

例如:

复制代码
Identity depends on Map
Network depends on Identity
Deal depends on Network

因此可以将其表示为一个有向图:

复制代码
Map ──────> Identity ──────> Network ──────> Deal
 ^                                          │
 └──────────────── Feedback ────────────────┘

如果忽略最后的Feedback,它实际上就是一个典型DAG。


2. 用Enum定义流程状态

首先定义四个业务状态:

复制代码
from enum import Enum


class MindState(Enum):
    MAP = "map"
    IDENTITY = "identity"
    NETWORK = "network"
    DEAL = "deal"

接下来定义允许发生的状态转移:

复制代码
TRANSITIONS = {
    MindState.MAP: MindState.IDENTITY,
    MindState.IDENTITY: MindState.NETWORK,
    MindState.NETWORK: MindState.DEAL,
    MindState.DEAL: MindState.MAP,
}

这里已经出现了第一个重要区别。

普通单点模型可能只有:

复制代码
Input → Function → Output

而四阶段模型实际上具有:

复制代码
State
+
Transition
+
Input
+
Output
+
Validation

因此从软件设计角度,它更接近Workflow或者State Machine,而不是一个普通算法函数。


3. 为不同状态建立数据对象

业务流程设计中,一个常见错误是所有阶段共享一个巨大的Dictionary。

例如:

复制代码
context = {
    "customer": "...",
    "problem": "...",
    "content": "...",
    "channel": "...",
    "result": "..."
}

这种方式开发初期很方便,但随着系统复杂度增加,很容易出现字段污染和模块耦合。

更合理的方案是给不同阶段定义不同数据结构。

例如使用dataclass:

复制代码
from dataclasses import dataclass, field
from typing import List


@dataclass
class MapOutput:
    problems: List[str] = field(default_factory=list)
    customer_needs: List[str] = field(default_factory=list)
    evidence: List[str] = field(default_factory=list)


@dataclass
class IdentityOutput:
    target_customer: str
    core_problem: str
    value_definition: str
    evidence: List[str]


@dataclass
class NetworkOutput:
    topics: List[str]
    channels: List[str]
    messages: List[str]


@dataclass
class DealOutput:
    leads: int
    opportunities: int
    conversions: int

这样,每一个节点拥有明确的数据契约。

整体接口变成:

复制代码
RawData
   │
   ▼
 MapProcessor
   │
   ▼
MapOutput
   │
   ▼
IdentityProcessor
   │
   ▼
IdentityOutput
   │
   ▼
NetworkProcessor
   │
   ▼
NetworkOutput
   │
   ▼
DealProcessor
   │
   ▼
DealOutput

这实际上已经接近微型Pipeline。


4. 实现一个基础状态机

接下来实现状态控制。

复制代码
class MindWorkflow:

    def __init__(self):
        self.state = MindState.MAP
        self.context = {}

    def transition(self):
        self.state = TRANSITIONS[self.state]

    def current_state(self):
        return self.state

调用:

复制代码
workflow = MindWorkflow()

print(workflow.current_state())

workflow.transition()

print(workflow.current_state())

输出:

复制代码
MindState.MAP
MindState.IDENTITY

继续运行:

复制代码
workflow.transition()
workflow.transition()

print(workflow.current_state())

得到:

复制代码
MindState.DEAL

再次调用:

复制代码
workflow.transition()

状态重新返回:

复制代码
MindState.MAP

这意味着系统天然支持:

复制代码
Map
→ Identity
→ Network
→ Deal
→ Map

这样的反馈循环。


5. 为什么需要Validation

仅仅完成状态转移还不够。

实际Workflow通常必须判断:

当前节点的输出是否达到进入下一状态的条件?

例如Map阶段没有识别出任何问题,就不应该直接进入Identity。

可以添加验证逻辑:

复制代码
def validate_map(data: MapOutput) -> bool:
    return (
        len(data.problems) > 0
        and len(data.customer_needs) > 0
    )

Identity节点同样如此:

复制代码
def validate_identity(data: IdentityOutput) -> bool:
    return (
        bool(data.target_customer)
        and bool(data.core_problem)
        and bool(data.value_definition)
    )

Network:

复制代码
def validate_network(data: NetworkOutput) -> bool:
    return (
        len(data.topics) > 0
        and len(data.channels) > 0
    )

Deal:

复制代码
def validate_deal(data: DealOutput) -> bool:
    return (
        data.leads >= 0
        and data.opportunities >= 0
        and data.conversions >= 0
    )

于是Workflow不再是简单的:

复制代码
A → B → C → D

而是:

复制代码
A
│
├── Validation Failed → 停留在A
│
└── Validation Passed → B

完整结构:

复制代码
Map
 │
 ├─ Fail → Map
 │
 └─ Pass
      ↓
Identity
 │
 ├─ Fail → Identity
 │
 └─ Pass
      ↓
Network
 │
 ├─ Fail → Network
 │
 └─ Pass
      ↓
Deal

这比普通流程图更接近真实软件系统。


6. 把状态机和处理器结合

可以进一步抽象一个Workflow Engine:

复制代码
class WorkflowEngine:

    def __init__(self):
        self.state = MindState.MAP
        self.data = {}

    def execute_map(self, output: MapOutput):
        if not validate_map(output):
            raise ValueError("Map validation failed")

        self.data["map"] = output
        self.state = MindState.IDENTITY

    def execute_identity(self, output: IdentityOutput):
        if self.state != MindState.IDENTITY:
            raise RuntimeError("Invalid workflow state")

        if not validate_identity(output):
            raise ValueError("Identity validation failed")

        self.data["identity"] = output
        self.state = MindState.NETWORK

    def execute_network(self, output: NetworkOutput):
        if self.state != MindState.NETWORK:
            raise RuntimeError("Invalid workflow state")

        if not validate_network(output):
            raise ValueError("Network validation failed")

        self.data["network"] = output
        self.state = MindState.DEAL

    def execute_deal(self, output: DealOutput):
        if self.state != MindState.DEAL:
            raise RuntimeError("Invalid workflow state")

        if not validate_deal(output):
            raise ValueError("Deal validation failed")

        self.data["deal"] = output
        self.state = MindState.MAP

现在系统具有三个基本能力:

复制代码
状态控制
+
数据校验
+
流程约束

这已经是典型Workflow Engine的雏形。


7. 单点模型在架构中是什么?

理解了四阶段流程以后,再看所谓"单点模型"。

假设有一个SEO评分函数:

复制代码
def seo_score(
    impressions: int,
    clicks: int,
    conversions: int
):
    if impressions == 0:
        return 0

    ctr = clicks / impressions

    if clicks == 0:
        conversion_rate = 0
    else:
        conversion_rate = conversions / clicks

    return {
        "ctr": ctr,
        "conversion_rate": conversion_rate
    }

这是一个典型单点函数:

复制代码
Input
 ↓
SEO Function
 ↓
Output

它并不关心:

复制代码
上游如何定义目标客户
下游如何完成成交
其他渠道使用什么信息

这没有问题,因为这本来就不是它的职责。

因此,如果用系统结构表示:

复制代码
                 Workflow
                    │
                    ▼
Map → Identity → Network → Deal
                    │
          ┌─────────┼─────────┐
          ▼         ▼         ▼
         SEO      Content     Ads
          │         │         │
          └─────────┴─────────┘

SEO、内容处理、广告处理等模块属于Network下的执行节点。


8. 两种模型最大的技术差异

到这里就可以比较两种架构了。

单点模型

复制代码
X → f(X) → Y

特点是:

复制代码
输入明确
局部目标明确
计算边界明确
容易独立测试

适合解决确定性的局部问题。

例如:

复制代码
SEO评分
页面质量检查
广告CTR计算
内容分类
线索评分

四阶段Workflow

结构为:

复制代码
S0
 ↓
S1
 ↓
S2
 ↓
S3
 ↓
Feedback

每个状态内部还可能继续调用多个单点函数。

因此:

复制代码
Workflow负责Orchestration

Function负责Execution

这是两者最重要的区别。


9. 为什么不能让Workflow替代单点函数

一个常见架构错误,是试图让上层Workflow承担所有算法。

例如把:

复制代码
关键词分析
内容评分
渠道判断
线索评分
销售预测

全部塞进一个类:

复制代码
class MindModel:
    ...

最终就会形成God Object。

正确的方法应该是拆分:

复制代码
MindWorkflow
    │
    ├── MapService
    ├── IdentityService
    ├── NetworkService
    │       ├── SEOService
    │       ├── ContentService
    │       └── ChannelService
    │
    └── DealService
            ├── LeadScoringService
            └── ConversionService

Workflow只负责:

复制代码
节点顺序
数据传递
状态转换
失败处理

具体计算交给独立Service。


10. 使用DAG进一步表达依赖关系

实际业务往往并不是严格串行。

Network阶段可能同时执行:

复制代码
SEO
Content
Media
Video

这时使用简单状态机已经不够。

更适合使用DAG。

例如:

复制代码
                Identity
                   │
         ┌─────────┼─────────┐
         │         │         │
         ▼         ▼         ▼
        SEO      Content    Video
         │         │         │
         └─────────┼─────────┘
                   ▼
                  Deal

可以表示成邻接表:

复制代码
graph = {
    "map": ["identity"],
    "identity": [
        "seo",
        "content",
        "video"
    ],
    "seo": ["deal"],
    "content": ["deal"],
    "video": ["deal"],
    "deal": []
}

这就是:

复制代码
Workflow
+
State Machine
+
DAG

组合后的流程系统。


11. 给流程增加可观测性

生产环境中的Workflow不能只知道"成功还是失败"。

还应该记录:

复制代码
进入时间
退出时间
节点状态
输入版本
输出版本
异常原因
重试次数

可以设计事件对象:

复制代码
from dataclasses import dataclass
from datetime import datetime


@dataclass
class WorkflowEvent:
    node: str
    status: str
    timestamp: datetime
    message: str = ""

执行节点时产生事件:

复制代码
events = []

events.append(
    WorkflowEvent(
        node="identity",
        status="completed",
        timestamp=datetime.now()
    )
)

之后就可以进行:

复制代码
Trace
Monitoring
Logging
Evaluation

从而判断业务流程到底在哪一个节点出现问题。


12. 一个简单的单元测试

Workflow同样应该可测试。

例如:

复制代码
def test_map_validation():

    valid_data = MapOutput(
        problems=["message inconsistency"],
        customer_needs=["stable delivery"]
    )

    assert validate_map(valid_data) is True

测试异常输入:

复制代码
def test_empty_map():

    invalid_data = MapOutput()

    assert validate_map(invalid_data) is False

再测试状态:

复制代码
def test_state_transition():

    workflow = MindWorkflow()

    assert workflow.current_state() == MindState.MAP

    workflow.transition()

    assert workflow.current_state() == MindState.IDENTITY

如果进一步工程化,还可以增加:

复制代码
状态转移测试
非法调用测试
节点超时测试
重试测试
数据Schema测试
回滚测试

13. MIND模型与单点模型到底是什么关系?

经过前面的技术拆解,这个问题可以得到一个比较明确的答案。

本文所使用的MIND案例包含:

复制代码
Map
Identity
Network
Deal

它描述的是不同业务阶段之间的依赖关系,因此更接近:

复制代码
Workflow / Orchestration Layer

而SEO、内容处理、渠道评分或者线索评分等单点模型,更接近:

复制代码
Function / Service Layer

所以两者不存在简单的替代关系。

在软件架构中更合理的组合是:

复制代码
┌───────────────────────────┐
│       Workflow Layer      │
│                           │
│ Map → Identity → Network  │
│                  ↓        │
│                 Deal      │
└─────────────┬─────────────┘
              │
              ▼
┌───────────────────────────┐
│        Service Layer      │
│                           │
│ SEO / Content / Channel   │
│ Lead Scoring / Evaluation │
└───────────────────────────┘

上层控制流程,下层解决具体问题。


14. 总结

本文实际上讨论的是一个通用的软件设计问题:

当业务过程由多个存在依赖关系的阶段组成时,应该使用一个大函数,还是把它设计成Workflow?

如果问题只是:

复制代码
Input → Function → Output

单点模型通常已经足够。

如果问题变成:

复制代码
State A
 ↓
State B
 ↓
多个并行任务
 ↓
State C
 ↓
业务反馈
 ↓
重新进入State A

那么状态机、DAG、Workflow Engine和事件日志通常会更加适合。

本文使用的MIND模型,是所兴智能四阶段业务框架的一个建模案例,其结构可以抽象为:

复制代码
Map
↓
Identity
↓
Network
↓
Deal
↓
Feedback

从软件架构角度看,它与单点模型最核心的差异可以压缩成一句话:

单点模型负责计算某一个节点,Workflow负责组织多个节点之间的依赖、状态和数据流。

理解这一点以后,MIND与SEO、内容模型、渠道模型等就不再是"谁替代谁"的问题,而是典型的:

复制代码
Orchestration
+
Execution

两层架构关系。

相关推荐
倔强的石头1062 小时前
【Linux指南】动静态库系列(七):符号表与重定位:链接器如何把函数调用接起来
linux·前端·javascript
a1117763 小时前
3D 脑图谱 / Bilingual 3D Brain Atlas 项目
前端
T1mzhou3 小时前
ARM64 Linux 6.10内核启动流程2-rootfs 怎么挂上
linux·服务器·前端
小小尚@4 小时前
WebGIS/ECharts 地图开发|MapLand 在线行政区划边界一键下载 GeoJSON 工具
前端·javascript·echarts
默_笙4 小时前
🚍 一条 Todo 的奇幻漂流:TypeScript 全栈类型安全的"护照检查"
前端·javascript
计算机魔术师5 小时前
NVIDIA 以 129.3 亿美元收购 Hugging Face
前端
平头哥技术团队5 小时前
Day 01 | 用 HTML 写第一个网页:双击就能在浏览器打开
前端
计算机魔术师6 小时前
两年翻45倍!英伟达靠买买买建成千亿投资帝国
前端
paopaokaka_luck6 小时前
基于springboot3+vue3的精准扶贫管理系统(AI 问答、ECharts 图形化分析)
前端·人工智能·echarts