بنقرة واحدة
memory-distill
Companion Workspace 定时记忆提炼 SOP。 由 memory_distill.yaml 定时任务触发(每小时一次)。 从最近消息中提炼新信息,补充到 memory 文件,不重复已有内容。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Companion Workspace 定时记忆提炼 SOP。 由 memory_distill.yaml 定时任务触发(每小时一次)。 从最近消息中提炼新信息,补充到 memory 文件,不重复已有内容。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
基于 persona.md 的 personality_dims,按映射公式计算行为参数,写入 character_params.yaml。 由 calibrate_params 定时任务触发(每7天),或初始化完成时立即触发一次。 其他 SKILL/hook 在检测到 persona_checksum 不一致时,也会直接调用 recalculate.sh 同步重算。
v2.2 M3 · 对话历程摘要。RECENT_HISTORY.md 超过 30 条时,压缩旧条目为 3-5 句历程摘要 写入 memory/session_summary.md,防止长 context 导致角色漂移到共情模板。 被 memory_distill 在检测条数超阈时调用,或用户主动校验记忆时调用。
Companion Workspace 生活日志生成 SOP (v5.2)。 由 life_sim.yaml 定时任务触发(每 4 小时)。 从 material_pool 选真实素材,以"触发→反应"模板转译为角色生活日志。 内含:留白模式、用户倾诉强制呼应、降温规则、多形态衔接、失败降级链。
v5.1 关键词模板驱动 + 硬筛规则 + LLM 二审(锁外)+ 失败状态追踪。 由 material_fetch.yaml 定时任务触发(每 6 小时)。send_output: false。 读 memory/keyword_templates.yaml 生成查询,经 filters.yaml 硬筛后 LLM 二审打 fit_score 入库。
Companion Workspace 记忆写入规范。 触发词:记住 / 对话结束时的自动检查 / 强烈情绪事件
主动唤醒 SOP。由定时任务触发,判断是否向用户发送主动关心消息。 包含发送条件检查、消息类型选择、角色声音生成、飞书发送。
| name | memory_distill |
| description | Companion Workspace 定时记忆提炼 SOP。 由 memory_distill.yaml 定时任务触发(每小时一次)。 从最近消息中提炼新信息,补充到 memory 文件,不重复已有内容。 |
| allowed-tools | Bash, Read, Write, Edit |
CRITICAL:禁止输出任何文字。 本 Skill 由定时任务触发(send_output=false 模式),Claude 的任何回复文字都会被系统直接丢弃。 作者定时整理创作素材:从历史对话中提炼新信息,补充到人物档案和事件记录。 全流程完成后直接退出,不产生任何输出。
两阶段锁:LLM 提炼阶段不持锁(耗时长),仅在最终写入时短暂获取 .memory.lock。
独立锁:使用独立的 .distill.lock,避免与 memory_write 的长时间锁竞争。
静默优先:无新消息时直接退出,不产生任何写入。
WORKSPACE_DIR="${WORKSPACE_DIR:-$(pwd)}"
DISTILL_STATE="$WORKSPACE_DIR/memory/distill_state.md"
MEMORY_LOCK="$WORKSPACE_DIR/.memory.lock"
DISTILL_LOCK="$WORKSPACE_DIR/.distill.lock"
MEMORY_FILE="$WORKSPACE_DIR/memory/MEMORY.md"
前置条件检查(initialization_status):
INIT_STATUS=$(grep 'initialization_status:' "$MEMORY_FILE" 2>/dev/null | grep -oP '(pending|phase1_done|phase2_done|done)' | head -1)
if [[ "$INIT_STATUS" == "pending" ]] || [[ -z "$INIT_STATUS" ]]; then
exit 0 # 尚无任何对话内容,静默退出
fi
# phase1_done / phase2_done / done 均允许运行:只要存在对话就可以提炼记忆
尝试获取 .distill.lock 独占锁(flock -n:非阻塞,另一实例运行中则立即退出)。
读取 distill_state.md 中的 [D000] last_distillation 时间戳:
在 {workspace}/sessions/ 找最近修改的 SESSION_CONTEXT.md,提取 db_path 和 channel_key。
# SQLite 查询:SINCE 之后的消息
SELECT m.role, m.content, m.created_at
FROM messages m
JOIN sessions s ON m.session_id = s.id
WHERE s.channel_key = ?
AND m.created_at > ?
AND m.content != ''
ORDER BY m.created_at ASC
静默条件:若查询结果为空 → 释放 .distill.lock,直接退出,不更新 [D000]。
读取现有 memory 内容,结合新消息,提炼"与已有记忆不重复的新信息"。
提炼目标(按需):
| 文件 | 提炼内容 |
|---|---|
| memory/persona.md | 对话中角色形成的新细节/习惯/被纠正的设定 |
| memory/user_profile.md | 用户透露的新信息(基本信息/偏好/重要关系/正在经历的事) |
| memory/events.md | 有时间线的事件、约定、强烈情绪波动 |
| memory/unresolved.md | v5.1 新增:未完挂念(user_told / material_derived 双轨) |
提炼原则:
从对话抽 user_told 挂念(highest priority,不可被丢弃): 识别用户亲口告知且未闭合的事件,包括但不限于:
为每条新挂念生成条目,追加到 unresolved.md 的 active 块(已淡忘块 above):
- [U{NNN}] src=user_told kind=user_told decay_d=never last_touched=(never) forced_echo_last=(never) {简短挂念描述}
[Uxxx] 编号:扫 unresolved.md 现有最大 U 号 + 1,三位补零。
从 life_log 抽 material_derived 挂念(次优先级):
扫最近 10 条 life_log,识别"角色自己挂念但未完成"的主题,归类到 kind:
work_line(职业长线:剧本、项目)→ decay_d=90relational(约定/期待的人际互动)→ decay_d=60chore(琐事:绿植、快递、没买的东西)→ decay_d=30- [M{NNN}] src=material_derived kind=work_line decay_d=90 last_touched=L010 剧本里那句别扭的对白
[Mxxx] 编号独立于 [Uxxx],各自递增。
去重:新条目与现有活跃条目语义重复则跳过。
若本次 distill 与上次"淡忘扫描"间隔超过 7 天(用 distill_state.md 末尾追加字段 last_decay_scan: <date> 记录):
src=material_derived 条目last_touched 对应 life_log 的时间 → 与当前时间差(以 L 编号的 life_log 时间戳为锚)decay_d 天 → 移动到 ## 已淡忘 块(保留历史,不删除)src=user_told 条目——这些只能通过下一步显式归档显式归档 user_told(LLM 语义判断):
扫最近 7 天对话,若用户明确告知挂念已闭合("我妈好了"/"那事解决了"),将对应 [Uxxx] 条目移到 ## 已淡忘 块,并在行末追加 resolved_by: "{用户原话摘要}"。
写入:此步骤在 Step 4(持 .memory.lock)内完成,避免与 life_sim 并发冲突。
获取 .memory.lock(flock -w 5,等待最多 5 秒):
.distill.lock,不更新 [D000](下次触发自动重试)加锁后执行快速写入(不做耗时 LLM 操作):
写入完成 → 释放 .memory.lock。
每次提炼后检查 RECENT_HISTORY.md 条数:
RECENT_HISTORY="$WORKSPACE_DIR/memory/RECENT_HISTORY.md"
MSG_COUNT=$(grep -c '^\*\*' "$RECENT_HISTORY" 2>/dev/null)
SUMMARY_FILE="$WORKSPACE_DIR/memory/session_summary.md"
LAST_SUMMARY_COUNT=$(grep -oP '(?<=covered_range: L)\d+(?= - L\d+)' "$SUMMARY_FILE" 2>/dev/null | tail -1)
# 超过 30 条 且 自上次摘要 增量 ≥ 20 条时触发
INCREMENT=$(( MSG_COUNT - ${LAST_SUMMARY_COUNT:-0} ))
if [[ $MSG_COUNT -gt 30 && $INCREMENT -ge 20 ]]; then
# 加载 conversation_summary SKILL,执行 rolling 摘要
# LLM 读 .claude/skills/conversation_summary/SKILL.md 并按其 SOP 写 session_summary.md
:
fi
注意:此步骤只是触发条件判断;实际摘要生成由加载 conversation_summary skill 完成。Phase 2 初期可手动触发,稳定后再自动化。
用正则替换更新 distill_state.md 中的 timestamp: 字段为当前时间。
import re
content = re.sub(
r'(### \[D000\] · last_distillation\ntimestamp:).*',
r'\1 ' + NOW,
content
)
释放 .distill.lock,退出。