高级与实验功能
本页介绍不放入配置向导的扩展能力。它们需要手动修改 backend/.env,并通过 CLI、主 API 或外部调度器显式调用。修改环境变量后需要重启后端。
| 功能 | 状态 | 默认行为 | 入口 |
|---|---|---|---|
| 聊天记录分析 | 高级离线功能 | 不运行 | xuwen analyze 或 /analysis/* |
| 历史图片导入 | 高级离线功能 | 只导入文本占位符 | xuwen import-images |
| 主动消息 | 独立实验功能 | 关闭,不分析、不主动推送 | xuwen analyze-proactive、/v1/companion/proactive/* |
这些功能可能处理比普通单轮聊天更大范围的私人数据。使用前请阅读 负责任使用与数据隐私,并确认你有权处理聊天双方的记录和图片。
聊天记录分析
聊天记录分析会重新读取保留逐条时间戳的原始 JSON/JSONL,而不是从 LanceDB 反推。它可以生成:
- 关系事件时间线和关系阶段;
- 目标角色的普通性格报告;
- 目标角色的作息、饮食、活动和忙闲规律;
- 默认关闭的实验性人格与关系假设。
配置模型
块级模型负责从聊天块提取结构化候选,最终模型负责跨块归并。以下字段全部留空时复用主聊天模型:
ANALYSIS_API_URL=
ANALYSIS_API_KEY=
ANALYSIS_MODEL=
ANALYSIS_FINAL_API_URL=
ANALYSIS_FINAL_API_KEY=
ANALYSIS_FINAL_MODEL=完整的 token、并发和超时设置见后端环境变量:关系分析。
使用 CLI
在 backend/ 目录运行:
# 生成时间线和性格报告;多个文件必须属于同一个目标角色
uv run xuwen analyze chat.json --language zh-CN
uv run xuwen analyze source-a.json source-b.jsonl --language zh-CN
# 只生成其中一类结果
uv run xuwen analyze chat.json --timeline-only --language zh-CN
uv run xuwen analyze chat.json --personality-only --language zh-CN
# 单独或组合运行指定关系分析;可重复传入 --target
uv run xuwen analyze chat.json --target timeline --target personality --language zh-CN
uv run xuwen analyze chat.json --target life --language zh-CN
uv run xuwen analyze chat.json --target experimental --language zh-CN
# 只分析指定月份以后;默认复用已成功的块缓存
uv run xuwen analyze chat.json --since 2025-01 --language zh-CN
# 不调用模型,仅检查确定性分块
uv run xuwen analyze chat.json --list-blocks --language zh-CN
uv run xuwen analyze chat.json --inspect-block BLOCK_ID --language zh-CNCLI 可通过 --language en|zh-CN 指定输出,无参数时读取 XUWEN_LANGUAGE,默认英文。生成分析缓存只复用相同输出语言,旧无语言标记缓存会重算;原文证据保留。
默认输出到 ANALYSIS_DATA_DIR,通常为 backend/.data/analysis/。主要产物包括:
| 文件 | 作用 |
|---|---|
timeline.json / timeline.md | 结构化和可读时间线 |
personality_report.json / personality_report.md | 普通性格报告 |
personality_prompt_context.md | 可选注入主聊天模型的去证据摘要 |
life_profile.json / life_context.md | 目标角色的生活规律 |
manifest.json | 本次输入、缓存和跳过块统计 |
failures/*.json | 被模型拒绝或连续返回坏 JSON 的块及调试信息 |
分析支持增量续跑。模型拒绝或连续返回无效 JSON 的单个块会记录到 failures/ 并跳过, 不会调用最终大模型处理该块,也不会让其它成功块失效。
使用主 API
运行完整后端后可使用:
| 方法与路径 | 作用 |
|---|---|
POST /analysis/start | 启动分析任务 |
GET /analysis/{task_id} | 查询状态 |
GET /analysis/{task_id}/stream | 订阅 SSE 进度 |
POST /analysis/{task_id}/cancel | 取消任务 |
GET /analysis/timeline | 读取时间线结果 |
GET /analysis/personality | 读取普通性格报告 |
GET /analysis/experimental | 读取已启用的实验结果 |
HTTP 可通过 Accept-Language: en 或 zh-CN 选择分析生成语言。
任务 API 的 files 只接受 CONFIG_UI_UPLOADS_DIR 内的文件。分析其它路径时使用 CLI。请求体和响应格式见 后端 API:关系分析接口。
是否用于聊天和生活时间线
生成报告不等于自动使用报告。下面的开关默认关闭:
# 把普通人格摘要提供给主聊天模型
ANALYSIS_PERSONALITY_PROMPT_ENABLED=false
# 把目标角色生活规律提供给生活时间线模型
ANALYSIS_LIFE_CONTEXT_ENABLED=false
# 生成实验性分析;第二项控制是否提供给主聊天模型
ANALYSIS_EXPERIMENTAL_ENABLED=false
ANALYSIS_EXPERIMENTAL_PROMPT_ENABLED=false历史分析只能提供候选倾向,不能证明对方此刻正在做什么,也不能证明人格、动机或健康状况。 当前对话、当天时间线和检索到的真人原文具有更高优先级。
数据范围
分析可能把所选文件中的全部清洗后聊天块发送给 Analysis API。ANALYSIS_* 留空时,数据会发送给 主聊天模型的服务商。需要完全离线时,应把块级和最终模型都指向本地 OpenAI 兼容服务。
历史图片导入
普通文本导入只保留 [图片] 等占位符和可解析的图片引用。历史图片导入是单独的离线步骤: 它读取导出目录中的原图,调用视觉模型生成短摘要,再把摘要写入 history_images 向量表。
准备导出目录
保留聊天文件和对应资源目录,例如:
export-dir/
chat.json
resources/
images/
image-a.jpg实际目录名可以不同,导入器会递归查找 JSON/JSONL 和图片文件,并根据导出记录里的图片引用匹配原图。
配置并导入
历史图片导入必须配置独立 VLM。即使主聊天模型支持视觉,也不能省略 VISION_API_*:
VISION_ENABLED=true
VISION_API_URL=https://example.invalid/v1
VISION_API_KEY=replace-with-your-key
VISION_MODEL=vision-model-name然后在 backend/ 目录运行:
# 建议先完成同一份记录的文本导入
uv run xuwen import chat.json --language zh-CN
# 再导入导出包中的历史图片
uv run xuwen import-images export-dir --language zh-CN
# 自动识别失败时可明确指定导入 plugin
uv run xuwen import-images export-dir --plugin afterglow_v1 --language zh-CN导入器会:
- 解析聊天文件中的图片引用及前后文;
- 按 SHA-256 去重并把原图保存到
IMAGE_DATA_DIR; - 每个唯一图片只生成一次视觉摘要;
- 将摘要、消息时间、发送者和上下文写入
history_images; - 自动尝试为达到阈值的向量表建立索引。
重复执行同一目录会复用已有图片摘要和索引记录。可以运行 uv run xuwen stats --language zh-CN 查看 history_images 数量。
限制与隐私
- 只有对应 ingestion plugin 能提取图片引用时才会导入;纯
[图片]占位符无法定位原图。 - 当前不会下载聊天记录中的远程 CDN URL,也不会导入 data URL;带有效期的远程链接应先由导出工具落盘。
- 超过
VISION_MAX_IMAGE_BYTES、找不到原文件或视觉描述失败的图片会跳过。 - 原图会保存在本机,但图片内容会发送给你配置的 VLM。云端服务的留存和训练政策由服务商决定。
- 聊天时通常只检索并发送图片的文字摘要,不会重复把全部历史原图交给主模型。
更多格式细节见导入聊天记录:历史图片。
主动消息(独立实验,默认关闭)
维护者说明:我认为当前的主动消息体验并不好。这个功能很依赖数量足够、时间连续、包含大量自然开场的高质量聊天记录,而我没有这样的数据来充分验证和调优。现有实现是一次尽力而为的实验,不应被理解为成熟能力,也不建议一般用户启用。
主动消息与普通历史导入、上面的聊天记录分析是三条独立路径:
| 路径 | 是否自动运行 | 作用 |
|---|---|---|
xuwen import | 仅在用户执行导入时运行 | 建立向量索引,并保留一个兼容用的轻量主动画像;不调用主动倾向 AI,也不代表数据适合主动发送 |
xuwen analyze | 仅在用户执行关系分析时运行 | 生成时间线、人格和 Life 等报告;不会生成或更新主动倾向报告 |
xuwen analyze-proactive | 必须由用户单独执行 | 生成完整主动倾向报告,并按配置决定是否调用 AI 做开聊原因归因 |
不要因为完成了普通导入或关系分析就开启主动消息。建议依次完成“单独分析、质量检查、人工决定启用”三个步骤。
单独运行主动倾向分析
在 backend/ 目录运行:
# 单文件或同一目标角色的多个文件
uv run xuwen analyze-proactive chat.json --language zh-CN
uv run xuwen analyze-proactive source-a.json source-b.jsonl --language zh-CN
# 可选:只分析指定月份以后;默认复用相同开场的已有 AI 归因
uv run xuwen analyze-proactive chat.json --since 2025-01 --language zh-CN
uv run xuwen analyze-proactive chat.json --no-resume --language zh-CN该命令独立生成 ANALYSIS_DATA_DIR/proactive_analysis.json,内容包括双方开聊记录、对方主动频率、沉默间隔、小时/星期/月度分布,以及可选的 AI 开聊原因归因。它不会生成时间线、人格或 Life 报告。
是否调用 AI 由下面的独立开关控制:
# true:用分析最终模型补充开聊原因和时间原因;false:只做本地确定性统计
ANALYSIS_PROACTIVE_ENABLED=trueAI 归因只在用户执行 xuwen analyze-proactive 时触发。普通 xuwen import、xuwen analyze、后端启动和主动消息轮询都不会触发这项离线归因。模型给出的原因带有不确定性,不是当事人的真实因果陈述。
先检查数据质量
分析完成后运行只读检查:
uv run python scripts/check_proactive_quality.pyscripts/analyze_persona.py 和 scripts/check_proactive_quality.py 是独立辅助脚本,目前没有 --language 参数,部分控制台提示仍为中文。不要给它们追加该参数;需要选择语言的导入或分析任务请使用主 CLI 的 --language zh-CN / --language en。
检查脚本不调用 AI、不修改报告,也不会自动打开主动消息。它会根据有效长间隔样本、占位符比例、可形成具体话题的样本比例、other 分类比例和 AI 归因覆盖率,输出:
ready:数据通过当前规则检查,仍需用户自行决定是否启用;limited:可以观察倾向,但不建议自动发送;not_ready:不建议启用。
检查结论只是保守提示,不是质量保证。即使显示 ready,也应先用手动接口查看实际输出,不要直接接入真实联系人或无人值守的外部 Bot。
主动消息会从已入库的历史窗口学习目标角色主动开聊的大致时段、沉默间隔、上一轮上下文和开场类型, 再结合当前 Life 状态、每日上限和安静时段决定是否适合主动发起。
该功能仍是实验状态,默认关闭。主动开场质量、话题选择和防打扰策略尚不稳定,不建议直接接入生产产品。
主动生成、话题钩子、重写与固定兜底始终使用后端 XUWEN_LANGUAGE,不由页面语言或请求头改变;已有原始素材不翻译。
它不会自动做什么
Afterglow 后端不会自行建立跨设备定时器,也不会直接向网页、QQ、微信或其它 IM 推送消息。 外部前端、bot 或调度器必须:
- 调用轮询或决策接口;
- 遵守接口返回的下一次检查时间;
- 在
should_send=true或state="sent"时负责实际投递; - 使用稳定的
conversation_id,需要区分调用方时同时传caller_id。
报告存在与缺失时的行为
运行时按以下顺序选择调度画像:
- 独立分析产生且包含有效样本的
proactive_analysis.json; - 普通导入产生的兼容轻量画像
.data/persona/proactive_profile.json; - 从已入库的
dialogue_windows临时重建; - 无可用数据时使用保守空画像。
这种回退用于兼容旧数据,不表示未运行独立分析时也适合启用主动消息。如果你希望依据完整报告运行,应先确认 profile 接口返回 profile_source="analysis"。
启用门控
最小配置:
PROACTIVE_ENABLED=true
PROACTIVE_SCORE_THRESHOLD=0.55
PROACTIVE_CHECK_INTERVAL_SECONDS=900
PROACTIVE_MIN_IDLE_MINUTES=180
PROACTIVE_MAX_PER_DAY=1
PROACTIVE_QUIET_HOURS=00:00-08:30
PROACTIVE_SKIP_WHEN_LIFE_BUSY=true只有用户明确设置 PROACTIVE_ENABLED=true 后运行时门控才会生效。完整字段见后端环境变量:主动聊天。
接口选择
| 方法与路径 | 适用场景 |
|---|---|
POST /v1/companion/proactive | 立即生成一次主动开场;绕过学习门控,只适合手动调试 |
POST /v1/companion/proactive/decide | 立即计算是否适合发送;不维护待发送候选 |
POST /v1/companion/proactive/poll | 推荐的实验入口;维护候选并返回 next_poll_at_ms |
GET /v1/companion/proactive/profile | 查看学习画像和最近审计记录 |
GET /analysis/proactive | 只读查看独立生成的主动倾向报告 |
轮询请求示例:
{
"conversation_id": "conversation-placeholder",
"caller_id": "client-placeholder",
"reason": "learned_rhythm",
"auto_send": true
}首次调用通常返回 state="scheduled" 和 next_poll_at_ms。外部调度器应等到该时间后再请求。 到点且通过门控时,auto_send=true 会让响应进入 sent 或 silenced,生成内容位于 proactive.message。
用户通过 Afterglow 的 /v1/chat/completions 或 /v1/responses 发送新消息时,后端会记录活动并取消 尚未发送的候选。如果外部系统绕过这些聊天入口,调用方需要自行维护用户活动时间,并在轮询时传入 last_user_message_at_ms。
防打扰边界
- 保持每日上限和安静时段,不要为了提高触发率直接关闭所有门控。
PROACTIVE_SKIP_WHEN_LIFE_BUSY=true时,Life 状态为忙碌、睡眠或离开会阻止主动发起。- 系统没有可靠的在线、已读或正在看手机等 presence 信号,不应把生成内容当作这些状态的证明。
- 最近决策可从 profile 接口查看,完整审计写入
.data/persona/proactive_audit.jsonl。 - 主动生成仍可能输出不合适或重复的话题,实际投递方应保留最终的关闭开关和人工可控边界。
完整请求与响应结构见后端 API:主动消息。