执行层设计
Action Layer 是六层架构中统一约束"系统真正做了什么"的执行层。 它不决定该不该行动(那是 Cognitive Core 的事),只负责执行动作、记录结果、防骚扰约束和失败处理。 如本文与《产品与架构设计》冲突,以后者为准。 最后更新:2026-03-18
一、架构定位
在统一认知架构的六层体系中,Action Layer 的位置如下:
text
Cognitive Core 统一裁决
↓
Action Layer ── 执行动作、记录结果
↓
动作结果回写 Fact Layer一句话定义:
Action Layer 负责统一约束所有对外行为的执行规范、结果记录和防骚扰策略。
职责
- 执行认知中枢或 Concern 引擎发出的动作指令
- 记录每个动作的执行结果
- 将动作结果回写 Fact Layer(
action_result类 Fact) - 统一实施防骚扰约束
不职责
- 不决定该不该行动(认知中枢负责)
- 不保存系统状态(Agenda / Concern 负责)
- 不解释事实(Perception 负责)
- 不维护人物真源(Person Layer 负责)
二、动作类型分类
系统中的所有对外行为收敛为 6 类:
| action_type | 定义 | 典型场景 |
|---|---|---|
send_message | 向某人发送消息(期望回复) | Concern 联系张三、追问进度 |
notify | 单向通知(不等待回复) | 任务逾期提醒、审批催办、晨报推送 |
escalate | 升级给更高层决策者 | 风险标记 block/escalate → 老板审批 |
backflow | 结果回流给发起人 | Concern resolve 后通知老板 |
query | 查询外部系统获取信息 | 查飞书任务状态、查考勤、查多维表格 |
internal_update | 更新系统内部状态 | 写 Person.work_state、写 Memory |
分类边界
send_message与notify的区别:前者关联 Concern 的waiting_reply状态,后者不等待回复escalate是特殊的notify:目标固定为更高层决策者,且会阻塞原始回复链路query的结果可能触发后续 Signal,但 query 本身只是信息获取internal_update不涉及外部渠道,但仍需写 Fact 记录
三、Action 数据模型
每个 Action 执行后,应可追溯到:谁决定的、对谁做的、做了什么、结果如何。
python
Action(
action_id: str, # 格式 act_{YYYYMMDD}_{seq:03d}
action_type: str, # 6 种之一
decision_ref: str, # 关联的 decision_id 或 concern_id
target_person_id: str, # 动作目标人(可为空,如 query 类)
channel: str, # 执行渠道: feishu / telegram / internal
content_preview: str, # 动作内容摘要(≤200 字)
result: str, # success / failed / blocked / pending
result_detail: dict, # 渠道返回的详情(msg_id、error_code 等)
timestamp: str, # 执行时间(ISO 8601)
)字段说明
| 字段 | 必填 | 说明 |
|---|---|---|
action_id | 是 | 全局唯一标识 |
action_type | 是 | 6 种动作类型之一 |
decision_ref | 是 | 触发此动作的决策依据,如 dec_001(Agenda decision)或 con_001(Concern) |
target_person_id | 否 | 动作目标人(query、internal_update 类可为空) |
channel | 是 | 执行渠道标识 |
content_preview | 是 | 人类可读的动作摘要 |
result | 是 | 执行结果状态 |
result_detail | 否 | 渠道返回的详细信息 |
timestamp | 是 | 执行完成时间 |
result 状态说明
| result | 含义 |
|---|---|
success | 动作执行成功,渠道确认送达 |
failed | 动作执行失败(渠道不可达、目标人找不到等) |
blocked | 被防骚扰层拦截,未实际执行 |
pending | 异步执行中,等待确认(如审批流程) |
四、Fact 回写规则
硬规则:每个 Action 执行完成后,必须写一条 action_result 类 Fact。
这是 Action Layer 与 Fact Layer 的核心联结点。没有 Fact 回写,系统就无法追溯"到底做了什么"。
Fact 内容格式
json
{
"fact_id": "fact_20260318_042",
"fact_type": "action_result",
"source": "action_layer",
"person_refs": ["p_zhangsan"],
"content": {
"action_id": "act_20260318_007",
"action_type": "send_message",
"decision_ref": "con_20260318_001",
"channel": "feishu",
"content_preview": "老板想了解提测什么时候能给?",
"result": "success",
"result_detail": {"msg_id": "om_xxx"}
},
"timestamp": "2026-03-18T10:35:00+08:00"
}各模块的改造方向
| 模块 | 当前回写情况 | 改造方向 |
|---|---|---|
| concern/engine.py 发送消息 | timeline + conversation_log | 额外写一条 action_result Fact |
| concern/engine.py 回流 | timeline | 额外写一条 action_result Fact |
| notification.py 通知 | 无任何记录 | 写一条 action_result Fact |
| awareness/engine.py 通知 | decision_log | decision_log 记录同步写 Fact |
| avatar_core.py 风险路由 | trace | trace 不替代 Fact,需额外写 |
不需要写 Fact 的情况
internal_update类动作中,如果目标已有对应真源更新(如Person.work_state已写入),不需要额外写action_resultFactquery类动作如果仅用于当前回复上下文、不影响系统运行态,可以不写 Fact
五、防骚扰分层规范
系统有四层防骚扰机制,执行顺序从上到下,任一层拒绝则不执行动作。
text
Layer 1: Person.interaction_policy(最高优先级)
├─ allow_proactive_ping(是否允许主动联系)
├─ max_proactive_contacts_per_day(每日主动联系上限)
├─ preferred_channel(偏好渠道)
└─ 特定时段限制
↓ 通过后
Layer 2: Concern 业务约束
├─ 全局活跃 concern ≤ 30
├─ 单人活跃 concern ≤ 5
└─ 追问间隔策略(按 priority 递增)
↓ 通过后
Layer 3: Channel 接触限制
└─ 同一 concern 对同一人 24h 内 ≤ 2 次
↓ 通过后
Layer 4: Notification 冷却
└─ 同类型通知的冷却间隔(task_overdue: 4h 等)各层约束的适用范围
| 约束层 | 适用的 action_type | 不适用 |
|---|---|---|
| Layer 1 interaction_policy | send_message, notify, escalate, backflow | query, internal_update |
| Layer 2 Concern 业务约束 | send_message(Concern 关联) | 非 Concern 类动作 |
| Layer 3 Channel 接触限制 | send_message(Concern 关联) | 非 Concern 类动作 |
| Layer 4 Notification 冷却 | notify | send_message, escalate, backflow |
Concern 追问与 Notification 冷却的关系
这两套约束作用于不同 action_type,不冲突:
- Concern 追问间隔约束
send_message类动作(关联 Concern) - Notification 冷却约束
notify类动作(不关联 Concern) - 同一人同时受两套约束时,分别计算,互不覆盖
六、渠道选择规则
执行 send_message / notify / escalate / backflow 时,渠道选择遵循以下优先级:
| 优先级 | 渠道来源 | 说明 |
|---|---|---|
| 1 | Person.interaction_policy.preferred_channel | 人物偏好渠道 |
| 2 | Concern 发起渠道 | 从哪个渠道发起的 Concern,优先用该渠道 |
| 3 | 人物已绑定的可达渠道 | 从 channel_bindings 中选择可达的 |
渠道降级
如果首选渠道不可达(发送失败),降级到下一个可用渠道。所有绑定渠道都失败时,标记 result: "failed"。
七、失败处理规则
| 失败类型 | 处理方式 | 是否写 Fact |
|---|---|---|
| 渠道不可达(网络错误) | 标记 result: "failed",不自动重试 | 是 |
| 目标人找不到 | 标记 result: "failed",escalate 给发起人 | 是 |
| 被防骚扰层拦截 | 标记 result: "blocked",含拦截原因 | 是 |
| 渠道返回发送失败 | 尝试降级渠道,仍失败则标记 failed | 是 |
| query 超时 | 返回空结果,不写 Fact | 否 |
不做的事
- 不做自动重试队列(当前规模不需要)
- 不做异步发送队列(同步发送已够用)
- 不做消息确认机制(信赖渠道层返回值)
八、与其他层的关系
text
Action Layer
├─← Cognitive Core(发出 direct_action / escalate 指令)
├─← Concern Engine(发出 send_message / backflow 指令)
├─← ConcernScheduler(触发 Concern 到期动作)
├─→ Fact Layer(动作结果写入 action_result Fact)
└─→ 外部渠道(Telegram / 飞书 / 内部系统)各层与 Action 的交互
| 层 | 读 Action | 写 Action | 说明 |
|---|---|---|---|
| Cognitive Core | 否 | 发出指令 | 裁决后调用 Action 执行 |
| Concern Engine | 否 | 发出指令 | raise_concern / resolve_concern 中执行发送和回流 |
| Fact Layer | 否 | 接收结果 | Action 结果回写为 action_result Fact |
| Person Layer | 否 | 否 | Action 不直接修改人物真源 |
| Perception | 是 | 否 | 可读取 action_result Fact 理解系统动作 |
九、当前实现映射
| 概念层职责 | 当前实现 | 收口方向 |
|---|---|---|
| send_message 执行 | concern/channel.py send_message() | 保留,补 Fact 回写 |
| notify 执行 | notification.py notify_*() | 保留,补 Fact 回写 |
| escalate 执行 | avatar_core.py 风险路由 | 保留,补 Fact 回写 |
| backflow 执行 | concern/engine.py resolve_concern() | 保留,补 Fact 回写 |
| query 执行 | direct/tools/ 各工具 | 保留,query 类按需回写 |
| 防骚扰 Layer 1 | Person.interaction_policy | 保留 |
| 防骚扰 Layer 2 | concern/engine.py 活跃数检查 | 保留 |
| 防骚扰 Layer 3 | concern/channel.py _check_contact_limit() | 保留 |
| 防骚扰 Layer 4 | notification.py _check_cooldown() | 保留 |
当前阶段不新建统一 ActionExecutor 模块,只约束现有模块的行为边界。后续认知中枢完全收口后,可考虑统一执行入口。
十、当前原则
- 每个动作必须挂靠决策 — action 的
decision_ref必须指向某个 Agenda decision 或 Concern - 动作结果必须回写 Fact — 保证系统的每个外部行为可追溯
- 防骚扰四层叠加 — 从 Person policy 到 Notification 冷却,任一层拒绝则不执行
- 渠道选择尊重偏好 — 优先 Person 偏好渠道,不可达时降级
- 失败不自动重试 — 标记失败写 Fact,由认知中枢或 Concern 决定后续
- Action 不拥有状态 — 它只是执行层,不保存系统运行态
Action Layer 的职责可以概括成一句话:
让系统的每一个行动都可追溯、受约束、有结果记录。