在传统软件开发中,Actor模型常被视为一种解决并发问题的技术方案。但当我们步入AI时代,这种认知需要被彻底刷新。Actor不再只是线程或进程的替代品,而应成为领域驱动设计(DDD)中的基本构建块。
我最近在构建一个智能客服系统时深刻体会到:当系统需要处理大量非结构化AI输入时,传统的服务调用方式会立即面临崩溃。某个客户可能说"我想退上周买的那个蓝色毛衣",而另一个客户则说"退货:订单号20231125-456"。面对这种语义相同但表达迥异的情况,常规的API接口根本无法稳定工作。
即便采用消息队列等"消息驱动"架构,大多数系统仍然存在硬性耦合。消息结构需要预先定义,接收方必须准确知道每个字段的含义和位置。这导致:
我在电商系统中就遇到过这种情况:当我们需要在退货流程中新增一个"退货原因分类"字段时,不得不协调五个不同团队同步修改代码。
现代AI系统产生的输入具有三个典型特征:
例如用户可能说:"我上周买的手机有问题,充电很慢",其中包含时间、商品类型、问题描述等多个信息点,但没有任何固定结构可言。
经过多次迭代,我总结出AI Actor的稳定结构应由三个部分组成:
code复制+---------------------+
| Agent | 🡅 语义边界
+----------+----------+
| Mailbox | 🡅 任务队列
+----------+----------+
| 领域服务程序 | 🡅 执行引擎
+---------------------+
在物流系统中,我实现了这样一个Agent:
python复制class LogisticsAgent:
def process_input(self, raw_msg):
# 使用LLM解析意图
intent = llm.detect_intent(raw_msg)
# 验证语义完整性
if not self._validate_intent(intent):
return self._build_error_response()
# 转换为结构化任务
task = {
'type': intent['type'],
'params': self._extract_params(intent),
'context': self._load_related_data(intent)
}
return task
这个Agent能够处理从"我的包裹去哪了"到"改送到朝阳门地铁站"等各种自然语言表达。
Mailbox的设计要点:
使用Redis实现的Mailbox示例:
bash复制# 任务入队
RPUSH actor:tasks '{"type":"address_change", "order":"12345", "new_addr":"..."}'
# 任务出队
BLPOP actor:tasks 30
领域服务程序的关键特征:
一个订单处理的状态机片段:
javascript复制class OrderService {
async execute(task) {
switch(task.type) {
case 'RETURN':
return this.handleReturn(task);
case 'ADDRESS_CHANGE':
return this.changeAddress(task);
//...
}
}
}
以客户修改收货地址为例:
json复制{
"type": "address_update",
"orderId": "12345",
"newAddress": "科技园A座3层"
}
语义理解与业务逻辑严格分离
错误消息要足够友好:
❌ "Invalid address format"
✅ "您提供的地址缺少楼层信息,请补充如'科技园A座3层'这样的完整地址"
维护明确的意图清单:
yaml复制supported_intents:
- order_query
- address_change
- return_request
#...
在电商系统中,我采用事件溯源模式:
code复制order_12345_events:
- {type: "created", ...}
- {type: "paid", ...}
- {type: "address_changed", ...}
这样当需要重新处理任务时,可以完全重建状态。
基本单元 聚合根 AI Actor
通信方式 方法调用 语义消息
接口契约 严格DTO 意图协议
错误处理 类型校验 语义验证
状态管理 当前快照 事件流
扩展方式 版本化接口 新意图注册
当两个相似意图可能引起混淆时:
python复制def resolve_intent(text):
candidates = llm.detect_possible_intents(text)
if len(candidates) > 1:
return ask_for_clarification(candidates)
#...
对于退货等复杂流程,将其拆分为多个原子意图:
每个步骤都是独立的Actor交互。
建立专门的监控Actor,收集:
使用Prometheus实现的监控示例:
go复制func recordIntentMetrics(intent string) {
metrics.WithLabelValues(intent).Inc()
}
DAD架构特别适合:
而对于简单的CRUD应用,传统DDD可能更合适。
在实施过程中,我建议从核心业务流开始试点。比如在电商系统中,先改造客户服务模块,再逐步扩展到订单、物流等环节。每个AI Actor应该保持足够小,专注于单一职责,这样既能获得架构优势,又不至于增加过多复杂度。