背景
数字人(automation app)目前有两个互相隔离的执行面:
- 定时任务
executeRun(src/main/apps/runtime/execute.ts):headless、无状态、用完即焚的独立 SDK session,report_to_user 为完成契约。
- 聊天会话
sendAppChatMessage(src/main/apps/runtime/app-chat.ts):长期存活,按 app-chat:{appId}:{channel}:{chatType}:{chatId} 绑定到具体联系人,回复经 onReply → pushToChat 发出。
当数字人要主动触达主人时,只能走 notify_bot / im-auto-sync —— 本质是一次性 pushToChat(notify-tool.ts:286、im-auto-sync.ts:117),不进会话、不触发人格。
问题
主动推送是"盲发",导致体验上"不像一个真正的人":
- 会话面 ≠ 执行上下文:通知落进主人那条聊天线时,主人前面还有别的对话上下文,容易误以为这条通知跟前文有关,实际它是另一个隔离上下文单独发出来的。
- 通知是"朝着"会话线喊,不是"在"会话线里说:推送前没有加载这条线最近聊了啥,无法"读空气",措辞不带上下文感知。
- 没有可见的话题分股:新通知直接糊进旧上下文,无法标明"这是独立一股新事"。
- 由此还带来确认闭环的断裂:
notify_bot 发完这轮任务即结束,没有等待环节;主人的回复落到另一个上下文,拿不到原任务现场(目前只能靠 memory 做胶水两段式,脆弱、啰嗦)。
根因:"无状态任务 × 单一身份出口",缺的是"连续上下文 × 会话面感知"。后台任务能直接捅穿到人,是结构性错误。
方向:所有对人的输出收敛到"人格前台"
后台照旧干活(headless),但凡要触达主人的,一律走主人那条聊天会话,由人格在上下文里替它转达:
- 后台干活无感
- 有事要报 → 唤醒"主人 ↔ 数字人"那条聊天会话 → 人格结合"刚跟主人聊过啥"组一句话发出,并标明"这是后台独立一股,与刚才话题无关"
- 主人在同一条会话里回复 → 因为是同一条会话,天然对上号(无需 correlation id),人格直接用自带工具执行或回触发工人
关键发现:wakeTarget 已经实现了这套能力(团队场景)
src/main/apps/runtime/team/orchestration.ts:194 的 wakeTarget 干的正是:后台事件 → 唤醒一个会话走一轮 → 回复自动路由回 IM 联系人,并已处理"对方 mid-turn 时先进 mailbox 缓冲、说完再消化"(team/message-bus.ts:298/548)。
单人 IM 会话现在没接这根管子,但接法就是照抄它。
相关的其它现成件:
injectMessage(src/main/services/agent/inject-message.ts:30):mid-turn 注入,但仅 IPC 可达、仅活跃 session。
nudgeLead(orchestration.ts:337):系统合成 [System] 消息触发一轮的先例。
- 忙/闲缓冲:
activeSessions.has() + supplement buffer(dispatch-inbound.ts:276/404/735)。
- 分层 memory:
memory.md → memory/ → runs/*.jsonl 已存在,可做"交接件摘要 + 按需下钻"。
硬性前提(代码已验证):pushToChat 依赖缓存的 context_token,主人没先私信过就推不出去(weixin-ilink.provider.ts:191-198 直接 return false)。需在产品上体现为「等待主人首次对话激活」状态。
建议方案
要新建的核心能力(一件事)
把 wakeTarget 泛化到单人 IM 会话:让跑完的定时任务能"往绑定主人的那条会话里投一个内部交接 turn"。复用 sendAppChatMessage(conversationId=IM会话key, message=内部交接, onReply→pushToChat) + 现成忙闲缓冲。
护栏
- 工人投进去的输入对主人不可见,只有人格组出来的那句才发出去(两条通道分开)。
- 人话只由人格组(单一写入者 = 连贯性的结构保证)。
- 内部 turn 标成系统事件,不伪装成主人说的话(仿
nudgeLead)。
- 交接件只递摘要 + 指针,细节留在分层 memory,人格追问时再 page-in。
产品配置
- 数字人「转达方式」设置:
直接推送(现状) / 经前台人格转达(新增,推荐)。
- 可见状态:「等待主人首次对话激活」。
待定
- 主人批准后由人格自己用工具执行(倾向,少一跳、上下文全),还是回触发工人?
- "经前台转达"设为绑定主人数字人的默认,还是先做可选开关灰度?
- 沉淀为通用能力「数字人前台代言」供所有数字人使用(倾向),运营只是第一个用例。
背景
数字人(automation app)目前有两个互相隔离的执行面:
executeRun(src/main/apps/runtime/execute.ts):headless、无状态、用完即焚的独立 SDK session,report_to_user为完成契约。sendAppChatMessage(src/main/apps/runtime/app-chat.ts):长期存活,按app-chat:{appId}:{channel}:{chatType}:{chatId}绑定到具体联系人,回复经onReply → pushToChat发出。当数字人要主动触达主人时,只能走
notify_bot/im-auto-sync—— 本质是一次性pushToChat(notify-tool.ts:286、im-auto-sync.ts:117),不进会话、不触发人格。问题
主动推送是"盲发",导致体验上"不像一个真正的人":
notify_bot发完这轮任务即结束,没有等待环节;主人的回复落到另一个上下文,拿不到原任务现场(目前只能靠 memory 做胶水两段式,脆弱、啰嗦)。根因:"无状态任务 × 单一身份出口",缺的是"连续上下文 × 会话面感知"。后台任务能直接捅穿到人,是结构性错误。
方向:所有对人的输出收敛到"人格前台"
后台照旧干活(headless),但凡要触达主人的,一律走主人那条聊天会话,由人格在上下文里替它转达:
关键发现:
wakeTarget已经实现了这套能力(团队场景)src/main/apps/runtime/team/orchestration.ts:194的wakeTarget干的正是:后台事件 → 唤醒一个会话走一轮 → 回复自动路由回 IM 联系人,并已处理"对方 mid-turn 时先进 mailbox 缓冲、说完再消化"(team/message-bus.ts:298/548)。单人 IM 会话现在没接这根管子,但接法就是照抄它。
相关的其它现成件:
injectMessage(src/main/services/agent/inject-message.ts:30):mid-turn 注入,但仅 IPC 可达、仅活跃 session。nudgeLead(orchestration.ts:337):系统合成[System]消息触发一轮的先例。activeSessions.has()+ supplement buffer(dispatch-inbound.ts:276/404/735)。memory.md → memory/ → runs/*.jsonl已存在,可做"交接件摘要 + 按需下钻"。硬性前提(代码已验证):
pushToChat依赖缓存的context_token,主人没先私信过就推不出去(weixin-ilink.provider.ts:191-198直接 return false)。需在产品上体现为「等待主人首次对话激活」状态。建议方案
要新建的核心能力(一件事)
把
wakeTarget泛化到单人 IM 会话:让跑完的定时任务能"往绑定主人的那条会话里投一个内部交接 turn"。复用sendAppChatMessage(conversationId=IM会话key, message=内部交接, onReply→pushToChat)+ 现成忙闲缓冲。护栏
nudgeLead)。产品配置
直接推送(现状) /经前台人格转达(新增,推荐)。待定