[PRD] arise 主动性与真人感(Proactivity & Liveliness)—— Phase 4 落地 #33
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
背景
Phase 3(能力与多模态)五片(#20-#24)+ 缺口补齐(#28)已通过 PR #29/#30/#31 全部合并进
main,docs/design.md"上线路线"第三阶段完成。当前状态:src/下 23 个模块覆盖了反应式核(会话/去抖/已发日志/安全基线)、工具与记忆(画像/Delta/embedding/knowledge/工具港)、能力与多模态(能力声明/
标签/多模态路由/已读延迟窗/三因子召回),但
Config里没有任何一个字段涉及情感态、门控阈值、沉默预算、关系轴——CONTEXT.md"主动性与真人感"整节、以及"记忆与画像"节里依赖情感态的部分,目前是零代码。
这不是遗漏,是顺序使然:这些机制此前经历了持续到 2026-07-11 的多轮独立 grill(ADR-0029
统一触发路径、ADR-0005 情感态选型、ADR-0006
能动性反坍缩护栏、ADR-0007 冷启动、ADR-0008
关系多轴、ADR-0014 环境感知、ADR-0018
时间感、ADR-0021 人设漂移守护、ADR-0025
即刻追问、ADR-0026 实时状态感知),每条决策都已拍板、
互相打过架、排查过数值重叠,但从未被收进一个 PRD 落地。本阶段把这十条 ADR 一次性收口——它们互为
前提(两级门控要读情感态才能算阈值基值;反思闭环写 profile/skill 要靠漂移守护才敢自动落库;渐进
解锁是笼罩其余全部机制的安全阀),拆开发反而会让实现期反复回填基础设施。
范围裁剪(已与项目负责人确认):
docs/design.md的"上线路线"把"真人感"(第4阶段)与"能动性"(第5阶段,含深挖任务委托)列为两个先后阶段——但该路线图写于 ADR-0029(reactive 与主动开口合一)
之前,其"主动开口三件套"与 drive-tick 分属两阶段的划分已被 ADR-0029 推翻(两者现共用同一套两级门控
判定代码,不再是能割裂开的两套机制)。本 PRD 因此把两阶段的核心决策链合并为一个 Phase 4,但不
把"深挖任务委托"(ADR-0020)一并收进来——它是用户请求触发(非主动性决策)、完成投递刻意"无门控直接
送回"(不过两级门控)、用主力模型(非反思用的 auxiliary 模型)、独立成本池,架构上与本 PRD 的决策
引擎正交,塞进来只会稀释本已很大的范围。详见 Out of Scope 与 Further Notes。
Problem Statement
从终端用户角度:现在的 arise 是一个纯反应式机器人——被 @ 才说话,说完就完,没有心情、不会主动
找你聊天、不会区分老朋友和陌生人、对同一句话在任何时候的反应都一样、被无视了也不会调整下次的分寸感,
也感知不到群里其它插件/命令产生的动静(有人查了成绩它毫无所感)。这跟 CONTEXT.md 开篇定义的
"拟人聊天陪伴型智能体内核"存在明显落差——目前只有"聊天",没有"陪伴"。
从 host 部署者角度:没有任何机制约束"机器人会不会刷屏""新部署第一天会不会对着陌生群乱开口""自我
学习的反思闭环会不会把机器人调教偏离人设而没人发现"。这些不是锦上添花的功能,是能不能把这个插件
放心装进一个真实、会持续运行数月的群聊/好友列表的前提。
从维护者角度:情感态、门控、关系轴这些"拟人参数"如果不从一开始就设计成可注入时钟/无 IO 的纯函数,
后续任何调参都只能靠人工观感判断,重蹈 CONTEXT.md 反复提及的"旧实现不可测"覆辙。
Solution
实现
docs/design.md上线路线第 4/5 阶段的合并版——十条 ADR 收口为一套互相咬合的决策引擎:interaction 命中本人/
EnvironmentSignaltier-2 显著信号/drive-tick 周期评估)走同一套两级门控 +沉默预算决策链,取代 Phase 3 里"被找到必然处理"的隐式假设。
双时间尺度(快/慢)机械模型,作为全部拟人参数的唯一中央调节器。
主动重连 + 自发目标 + 离线反思闭环(hit-rate 目标 + 反坍缩护栏)。
tension 四轴,客观派生优先。
EnvironmentSignal分层消费(tier-1 氛围传染 + tier-2 显著反应)。
否决闸,是反思闭环敢自动落库的前提。
(ADR-0026):复用 Recall/drive-tick 既有出口的两个
轻量触发点,不新增出口。
User Stories
私聊用户视角:主动关心与情绪连贯
而不是永远等我先开口。
我一旦真的回复了,它才会把"已经找过我"这件事完全放下;我只是没回,它下次找我的间隔应该只是
部分缓解,不是当作"已经联系上了"。
一样追问一句"在吗",但这个追问不该发生在它随口一说、不期待回应的场合。
我们聊得开心,它会更有活力——而不是每次交互都是同一种语气模板。
新的刺激时,这种情绪会自然回摆。
对我一直阴阳怪气。
它会因为"我上线了"这件事而更倾向找我说句话,而不是完全无感知我的在线状态。
插话。
而不是每次开场白都一样;但如果我们其实没多久前才聊过,我不希望它说出"距上次交互 4 分钟"这种
尴尬的精确数字。
群聊用户视角:主动开口的分寸感
(除非频率确实太高被限流),不会出现"叫了没人应"的情况。
也不回应太多次——但我理解极端刷屏场景下机器人确实可能暂时不接话,这是被明确接受的行为。
而不是对同群其它插件的产出完全无感。
值得一提的事偶尔搭话,大部分时候安静地"感受气氛"就够了。
对周围的气氛完全免疫。
它会知趣地把这次主动开口撤销,而不是抢在真人前面抢话。
概率随口接一句,就像一个人刚被人搭话后会更愿意继续参与讨论。
一下,但这个行为在群里应该复用它已有的"要不要主动开口"判断,不是另开一套独立通道。
新用户/陌生群视角:冷启动
一上来就跟熟人一样到处主动搭话,让人觉得唐突。
过渡地直接聊起来。
的主动性会自然、渐进地放开,而不是某个时间点突然"性情大变"。
——冷启动的保守只体现在"主动"上,不该体现成"叫不应"。
老朋友/熟人视角:关系网
——更愿意主动找我、语气更放松。
而不是对谁都一个尺度。
熟悉度的增长应该更看重"我们经常聊"而不是"我们这次聊了很久"。
即使这不是它直接问出来的。
Host 部署者/运维者视角:安全与可控
分寸感参数,且这些调整是有界的、会随时间衰减回基线,不会无限跑偏。
审核,偏离了就直接不落库,而不是等我事后发现机器人性格跑偏了才能补救。
问题"和"刷屏惹人烦"之间选一个更小的风险,我希望系统默认偏向前者。
这句话说出来"的执念场景。
这些状态本身仍然是有界、可解释的数值,而不是我完全看不懂的黑箱。
@event_postprocessor环境信号推送时,机器人的环境感知能力整体优雅静默降级,不影响其它已有功能正常运行。
只保留最基础的反应式 + Recall,用于我还不确定要不要开放更多主动性的过渡期。
维护者/贡献者视角:可测性
"衰减最终收敛""数值不会越过上下界""重复同类刺激会被打折",不需要真实等待时间流逝或接入真实
LLM 才能验证。
判断→落库或丢弃"整条链路,不需要真实网络请求,且能覆盖"判断调用失败时候选被丢弃"这条 fail-closed
路径。
状态,不需要真的跑几天数据。
与当时一致,用于后续调参时防回归。
命名,不会因为都叫"recall"而在代码评审/搜索时被搞混。
机器人行为验收视角
完整记入决策快照,供后续排查"为什么没回那条"使用。
都经过同一道漂移守护判断,不存在某条写入路径绕过了这道闸。
任何个人的 per-user 慢情感态。
让路,不与真人抢时间线,而是顺延到下一次评估。
Implementation Decisions
范围边界(先说清楚"不做什么"):本阶段不实现深挖任务委托(ADR-0020)、习得贴纸(ADR-0024)、
跨平台资料拉取(ADR-0027)、记忆深度搜索(ADR-0031)、mood_congruence 接入三因子召回(ADR-0009 更新)、
环境遥测 Ambient Telemetry(ADR-0014 2026-07-11 更新)、以及 ADR-0010 完整运营面(
/cost//why//why_query//diagnose、六池成本治理、系统自检信号层)——只交付决策快照的写入这一个最小必要切片,供本阶段自身测试与未来
/why消费,不交付任何聊天管理命令。详见 Out of Scope。统一触发路径与两级门控(ADR-0029)
EnvironmentSignaltier-2 显著信号/drive-tick 周期评估)统一走同一套两级门控判定代码;注入策略按触发源分流,决策逻辑不分流——事件触发注入全量
对话上下文,周期触发注入 isolated/light context(persona+情感态+未决意图+近期摘要+距上次交互+
时段字段)。
预算耗尽时可能被压下,这是明确接受的行为。
floor=1的适用范围从"选择性回应"扩为"共享预算本身"——事件触发的评估预算下限强制 ≥1,周期触发不设下限。
addressed_message_ids/skipped_message_ids字段保留,产出方改为统一级二判定。即撤销这次主动开口(补位而非抢话)。
高 energy 窗口的自然结果,不是独立判定分支。
addressed/skipped_message_ids、注入的记忆条目、情感态三轴、沉默预算余量、命中意图),供 Testing Decisions 的录制回放使用。
情感态(ADR-0005)
(valence, energy, dominance),双时间尺度:快情感态(per-chat,分钟级)+ 慢情感态(per-user + per-group 对称三轴,天级,连续衰减、无硬重置边界)。
valence:互动极性驱动,负性偏差——为负时向慢层回摆比为正时更慢。energy:互动极性 + 资源态推送 + 群氛围传染 EMA(仅速率无内容,来自EnvironmentSignaltier-1)dominance:共享结局分类器(landed/fell-flat/annoyed)驱动,专管房间级进取性/主动开口门槛基值,不介入自我披露。
输入表;群聊场景下快情感态只读 per-group 慢情感态,从不读取任何个人的 per-user 慢情感态。
慢情感态自身衰减向中性零点。
负向冲击、低位区间抑制正向冲击(非对称锁定区)。
——不新增 persona port 数值配置面。
情绪抖动项,不重建整个打字节奏机制)、linger 概率、门控阈值基值、自我披露倾向(
valence倾向 +trust封顶,dominance明确不参与)、兴趣门阈值。能动性:Drive Tick + Recall + 自发目标 + 反思闭环(ADR-0006)
开工先读状态防重复关心;不与真人抢 lane(busy 时 defer 到下一 tick)。群事件驱动 / 私聊冷场定时;
事件触发复用同一入口但改用全量上下文(见"统一触发路径")。
("确实努力了"),只有对方真实回复才触发全量重置("连接达成"),复用既有 Sent Log + 回复归属检测
判定"是否已被回复"。命名提醒:不与既有『三因子召回』模块混淆,须使用独立的模块/标识符命名
(如"主动重连"而非任何形式的裸 "recall")。
决定是否成 context 模式 pending intent,走既有
inject_intents+ Recall 单一出口消费,不新起循环、不新增独立出口;默认低优先 + 强衰减 + 可被真人抢占 + fail-closed + 灰度可一键关。
话题延续/energy 升;负:被无视/被"别烦"/冷场/被追问)产自然语言教训(带证据指针);目标 = 主动
尝试逐次得体率(hit-rate),明确不是"最小化负反馈"(沉默坍缩退化解)也不是"最大化净参与"(噪声
坍缩退化解);自主写三处——门控阈值 offset(对称有界
[floor, ceiling],步长不对称:抬静默阈值快于降,无信号衰减朝安静,offset 本身锚回基值)、per-chat 画像、技能——全部 fail-closed + 可回溯
可撤销 + 灰度;profile/skill/Knowledge 写入路径全部先过人设漂移守护否决闸才落库;在线反思绝
不做。
landed/fell-flat/annoyed)为同一份分类逻辑,三路消费:dominance 快路(同轮)、反思 hit-rate 慢路(沉淀 offset)、per-user 慢情感态.dominance(更慢路),不重复写分类代码。
精炼现有条目,不命中才新建)。
冷启动与渐进解锁(ADR-0007,被 ADR-0029 更新为单轴)
(统一门控,沉默预算/兴趣门连续收紧) → 三因子召回(Phase 2 已交付)→ 关系网注入 → 自发目标;不存在"反应式已解锁但主动开口未解锁"的中间态。read_delayscope_ceiling 冷启动收紧共用同一条轴线。关系网与关系多轴(ADR-0008)
CTE ≤2 或
lookup_relation按需)、知情-gate(敏感数据私聊例外 ⇔ current 是某知情者的私聊)。familiarity(互动次数/时长客观派生,零 LLM)、
trust(复用 Delta 压缩管线已有的sensitive打标作为"自我展露深度"代理信号,命中sensitive 的内容对 trust 正向贡献权重更高,不新增专门的 LLM 分类调用)、
affinity(≈旧warmth,注入排序键)、
tension(近期冲突,自然衰减防记仇)。4 轴各自独立封顶。familiarity客观派生增量按自然日分桶——同一天内互动的边际贡献递减,不同天始终满额计;零 LLM、零新状态字段(用现有互动时间戳分桶计算)。
环境感知(ADR-0014)
EnvironmentSignal:前处理 port 与ConversationInput并列的独立类型{plugin, action, outcome?, subject_id?, actor_id?, chat_id, time};源 = host@event_postprocessor实时 push(真
group_id+ 真user_id);subject_id可空(无主体事件如文件上传/群公告则空);actor_id可空,专用于第三方 poke/reaction 场景记录发起方。有界传染封顶,冷启动仍受 ADR-0007 高阈值压制。
→ 主动开口),不新开输出出口;级一本地启发式(零 LLM)筛候选,级二主模型决定反应/沉默。
真反应,反应本身走正常对话记忆路径(send + 他人回复自然沉淀)。
时间感(ADR-0018)
启发式已经在追踪的数据源,只加一层文本暴露;低于阈值不注入。reactive 与 Drive Tick 两条路径都持有。
可锚定"现在几点";reactive 路径不重复注入(模型已能从消息自带时间戳读出)。
平行但不冲突的墙钟接入点。
人设漂移守护(ADR-0021)
紧跟一次独立(不承接产出候选那条推理链的新鲜调用)LLM-as-judge 判断——喂 persona port 完整
结构化人设(
persona/backstory/speech_patterns/sample_dialogue)+ 候选内容,做二元判断"是否与人设基线冲突" + 简短理由。
可重新尝试产出(非永久拉黑对应教训)。
不能被被监督对象动手脚。
ADR-0006 自己已有的反坍缩护栏)。
即刻追问(ADR-0025)
send_message新增可选参数expects_reply: bool——模型显式声明这条消息是否在等待回应,不用文本启发式(问号结尾等)推断。
两级门控 → 主动开口决策链。
覆盖)。
实时状态感知(ADR-0026,私聊专属)
同一接入点),不设熟悉度硬门槛。
发送时机,不接入已读延迟窗(避免神经质地对每次"对方开始打字"都跑一遍门控)。
read_online_status、read_typing_status独立开位,某平台缺哪项即整字段在对应机制里缺席,优雅降级。
Testing Decisions
真的发出了消息,而不是内部某个中间变量的取值。
计时器、渐进解锁阈值曲线、
familiarity自然日分桶——全部设计为无 IO 纯函数(时钟/随机可注入),比照既有
recall.py::recency_decay()、read_delay.py的f(energy)风格独立单测,不需要接入RuntimeLoop或真实 LLM。(不越过 clamp 上下界,非对称锁定区在边界附近生效)的性质测试,而非仅断言几个具体数值。
ScriptedLLMClient跑一遍,断言决策快照(级一/级二裁决、
addressed/skipped_message_ids)与预期一致;后续调参时同一批固定输入重放,防回归。
RuntimeLoop保持为 Phase 1-3 沿用至今的唯一集成级测试入口——本阶段只是新增一个 Drive Tick 触发入口(与既有的消息触发入口共享同一套门控代码),继续用
tests/runtime_loop_helpers.py::make_loop()+ScriptedLLMClient(tests/fake_llm.py)+FakeClock/FakeEgress(tests/fake_egress.py)驱动,不引入新的集成测试框架。delta.py(DeltaCompressor)的离线任务测试形状——注入
FakeClock+ 两个独立的ScriptedLLMClient脚本(一个产出反思候选、一个扮演漂移守护判断)+ 假存储,覆盖"候选通过→落库""候选被否决→丢弃""判断调用失败→fail-closed 丢弃"
三条路径。
ScriptedLLMClient驱动,测试中不发起真实网络请求。self_recall/三因子召回等 Phase 1-3 既有行为在两级门控接入后不能变化(比如三因子召回本身的评分公式本阶段不改动)——沿用既有测试文件,只在集成点补充断言"门控裁决为'回应'之后,
下游行为与 Phase 3 一致"。
Out of Scope
决策)、完成投递刻意不过两级门控、用主力模型、独立成本池——架构上与本阶段的决策引擎正交,留待
单独一个 phase。
与主动性/情感态无耦合。
任务委托(ADR-0020),需等其先落地;且涉及 per-user 显式同意流程,属独立隐私议题。
主动调用检索,不依赖情感态/门控。
需要本阶段交付的情感态数值作为输入源,但把它接进
recall.py评分公式属于对 Phase 2 已交付模块的增量修改,留给下一个触碰记忆管线的 phase 处理——本阶段只保证情感态数值本身可被外部读取。
尚未设计的 LLM/VLM 预筛选基础设施,
EnvironmentSignaltier-1/tier-2 本身不受影响。/cost//why//why_query//diagnose等聊天管理命令、六池成本治理(分池预算 + 熔断)、系统自检信号层、Prompt Cache 命中率遥测、"忘记我"命令——均为运营/可观测性
打磨,非本阶段决策引擎的阻塞项;本阶段只交付决策快照的写入这一个最小必要切片。
Further Notes
docs/design.md"上线路线"需要一次刷新:其第 4/5 阶段("真人感"/"能动性")的划分早于ADR-0029 的 reactive/主动开口合一决策,"主动开口三件套"与 drive-tick 分属两阶段的表述已经过时;
该文档把深挖任务委托也归进第 5 阶段"能动性",但如上所述其触发/投递语义与本阶段的决策引擎正交。
建议本阶段落地后顺手把路线图这两节合并改写,避免继续误导后来者。
recall.py目前是"三因子记忆召回"(ADR-0009),本阶段新增的"私聊主动重连"机制(CONTEXT.md 里同样叫"Recall",源自 ADR-0006)是完全不同的概念,只是英文都习惯叫 recall——
实现期务必用不同的模块/类型名区分(比如"主动重连"/"reconnect"一类,避免与既有召回模块混淆),
这条在 Implementation Decisions 里也提了一遍,这里再强调一次因为踩坑代价(一次不小心的 grep 改错
模块)比较高。
规划(对应 Phase 1-3 "PRD issue → 拆 slice issue"的既有模式)会被拆成 6-8 个 slice issue,这不
属于本 PRD 阶段的工作。
familiarity 分桶阈值、渐进解锁各档具体门槛、距上次交互的"低阈"数字、时段划分粒度等)均按
ADR-0011 阈值三层分类推迟到真实 QQ 场景数据标定,保守
默认起步,Testing Decisions 里的"录制回放"机制正是为这条标定路径准备的。