在企业业务系统中,经常会遇到一类流程:一个结果不能由单个函数直接计算出来,而需要经过诊断、定义、执行、验证等多个阶段,并且后一阶段依赖前一阶段的输出。
从软件设计角度看,这类问题不适合简单建模成一个函数:
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
两层架构关系。