ReMe/docs/zh/proactive.md
imrewce 354837f9af
feat(proactive): separate proactive refresh from auto dream (#488)
* refractor(proactive): upgrade proactive feature with disentangled job and steps

* refactor(proactive): apply audit fixes

- rename read-side job 'proactive' -> 'proactive_read' (less confusing vs the refresh pipeline)
- drop dedicated agent_wrapper.proactive; extraction reuses the default wrapper
- simplify schema: remove unused ProactiveExtractOutput/TopicUpdate, drop resource_paths
- extract no longer scans resource/ directly (daily notes already carry resource content)
- update tests and docs accordingly

* feat(proactive): strict extract-output gate and prompt total budget

- parse_extract_reply now requires a contract section (follow_ups/extends/updates
  as a list); non-empty replies with misspelled section names trigger the
  existing one-shot retry instead of silently checkpointing changed files
- pack_paths gains max_total_chars; extract packs newest daily material first,
  keeps the first file on overflow, and records omitted files in a trailer
  (default budget 300000 chars, configurable via max_total_chars)
- tests: schema gate unit, schema-error retry e2e, budget unit + e2e

* feat(proactive): add scenario-card plan step and generative agenda step

* feat(proactive): digest-personal profile personalization and leaner LLM contract

- extract/plan/agenda now draw a user profile block from <digest_dir>/personal/*.md
  (frontmatter description + body excerpt, per-file budget, profile.md fallback)
- all daily access honours the configured daily_dir (prompt paths parameterized,
  config-driven fallbacks) so workspaces using e.g. memory/ work unchanged
- schema trim: drop dead fields errors/material_paths, carry_forward_all -> count
- shrink LLM output contract: new topics emit title/reason/confidence/paths only;
  keywords removed end-to-end, evidence derived from paths[0] (updates keep it)

* fix(proactive): skip checkpoint when extract reply stays unusable after retry

Two consecutive unparseable replies now short-circuit the round without
checkpointing, so the same material is retried next round instead of being
silently consumed (closes the residual audit #1 gap: the structural gate
detected schema-wrong output but a double failure still checkpointed).

* fix(proactive): replace running bool with reference-counted job activity tracker for the idle gate

* refactor(proactive): remove job activity tracking and idle gate, restore job tree to upstream

* fix(proactive): address second audit round (readonly reader, mtime checkpoint, wider fallbacks, profile containment, horizon content, expiry boundary)

* refactor(dream): strip interests.yaml ownership from dream, proactive is now the sole writer

* refactor(dream): separate proactive topic generation

* ci: update renamed auto dream smoke test

* fix(proactive): complete refresh migration and docs

---------

Co-authored-by: jinli.yl <jinli.yl@alibaba-inc.com>
2026-09-07 17:23:37 +08:00

9.5 KiB
Raw Blame History

Proactive

proactive_read 是 ReMe 的主动记忆读取接口。它不重新分析 daily也不调用 LLM只读取独立 proactive refresh 流程写出的兴趣主题:

daily/<date>/interests.yaml

上层 Agent 可以用它获取“今天值得主动关注什么”,再决定是否提醒、追问、推荐下一步或生成主动洞察。

interests.yaml 由 proactive refresh writer 链路生成,默认通过 proactive_refresh_cron 定时执行; proactive_read 只负责读取和暴露结果。Auto Dream 是独立的 daily-to-digest 流程,不读取或写入 proactive 状态。

配置入口

默认配置在 reme/config/default.yaml。同一组 refresh steps 有两个入口:用于维护和调试的本地 one-shot job 以及按应用时区每天 18:00 执行的定时任务:

proactive_refresh:
  backend: base
  enable_serve: false
  steps: &proactive_refresh_steps
    - backend: proactive_extract_step
      file_catalog: proactive
      scan_days: 2
      carry_forward_days: 14
      max_carry_forward_topics: 20
      llm_timeout_seconds: 300
      max_chars_per_file: 60000
      max_total_chars: 300000
    - backend: proactive_topics_step
      known_threshold: 0.85
      known_threshold_calibrated_for: text-embedding-v4@1024
      min_push_confidence: 0.5
      max_topics: 10
    - backend: proactive_plan_step
    - backend: proactive_agenda_step
    - backend: proactive_finish_step
      file_catalog: proactive

proactive_refresh_cron:
  backend: cron
  cron: "0 18 * * *"
  steps: *proactive_refresh_steps

上面的 anchor 只是为了紧凑展示;default.yaml 中显式写出了两组 steps。读取 job 为:

proactive_read:
  backend: base
  description: "Proactive: read daily/<date>/interests.yaml and expose the latest user-interest topics."
  parameters:
    type: object
    properties:
      date:
        type: string
        default: ""
      include_content:
        type: boolean
        default: true
      horizon_days:
        type: integer
        default: 1
      min_confidence:
        type: number
        default: 0.4
  steps:
    - backend: proactive_step
      min_confidence: 0.4

参数含义:

参数 作用
date 要读取的日期,格式为 YYYY-MM-DD。为空时使用应用时区中的今天。
include_content 是否在 answer 和 metadata 中返回 YAML 原文,默认 true
horizon_days 读取单日曝光文件,或在更宽时间窗下读取 truth source默认 1
min_confidence 返回 topic 的最低置信度,默认 0.4;旧版 topic 使用 0.5

Refresh 成本、文件与关闭方式

没有 daily Markdown 发生变化时refresh 会在调用 LLM 前结束也不会生成新的曝光文件。有变化素材时extract 通常调用一次 LLM回复不可用时最多重试一次。存在 push candidates 时plan 会再调用一次;候选数大于一个时, agenda 会再调用一次。因此默认链路单轮最多调用四次 LLM。

Refresh 会维护可重建的 truth source daily/_proactive.yaml,写入 daily/<date>/interests.yaml,并推进独立的 proactive file catalog。Auto Dream 不读取或写入这些 proactive 产物。

如需关闭自动 refresh请使用不包含 proactive_refresh_cron job 的显式应用配置。若仍需按需维护,可保留 本地 one-shot 的 proactive_refresh;它设置了 enable_serve: false,不会暴露到 HTTP 或 MCP。

输入契约

当前 proactive refresh 生成的文件如下:

version: 2
date: 2026-06-20
generated_at: 2026-06-20T18:00:00+08:00
push: true
topics:
  - id: b2120f3573cb
    title: 记忆检索链路的质量回归
    reason: 用户近期持续修改 search、node_search 和 dream 集成链路。
    kind: follow_up
    confidence: 0.86
    first_seen: 2026-06-20
    last_evidence_at: 2026-06-20
    evidence: daily/2026-06-20/session.md
    paths:
      - daily/2026-06-20/session.md
agenda:
  - topic_id: b2120f3573cb
    title: 记忆检索链路的质量回归
    scenario_type: resume_task
    opener: 下次发布前先回顾最近的检索回归。
    next_action: 对比失败查询与上一个索引快照。
    preconditions: []
    delivery: in_conversation
    linked_memory: []
    order_reason: 证据较新且下一步明确。
suppressed: []

当前 v2 topic 包含稳定 ID、类型、置信度、证据日期和来源路径。读取器仍兼容包含 titlereasonevidencekeywordspaths 的 v1 文件;缺少 v2 置信度时按 0.5 处理。

返回结果

成功读取时,proactive_step 会在主要 answer 中返回 summarytopics;当 include_content=true 时还会返回 content。相同的结果字段也会保留在标准 response metadata 中:

字段 说明
date 实际读取的日期。
path daily/<date>/interests.yaml
topics 解析后的 topic 列表。
content YAML 原文;仅在 include_content=true 时返回。
skipped 文件不存在时为 true
error 读取或解析异常。
summary 简短摘要。
agenda 当日主动议程(可选,仅 v2 文件携带时返回)。

当当天的 interests.yaml 由 proactive refresh 链路生成并携带议程时answer 会附带 agenda 字段:按顺序排列的当日议程条目,每条包含 topic_idtitlescenario_typeopener(自然口吻的开场白)、next_action(最小可执行动作)、preconditionsdeliverylinked_memoryorder_reason。读侧会过滤已解决或低于 min_confidence 的主题对应的议程条目;文件不含议程时该字段不出现。

文件存在且解析成功时answer 是结构化数据,例如:

{
  "summary": "Read 1 proactive topic(s) from daily/2026-06-20/interests.yaml",
  "topics": [
    {
      "id": "b2120f3573cb",
      "title": "记忆检索链路的质量回归",
      "reason": "用户最近反复修改了 search、node_search 和 dream integration。",
      "kind": "follow_up",
      "confidence": 0.86,
      "first_seen": "2026-06-20",
      "last_evidence_at": "2026-06-20",
      "evidence": "daily/2026-06-20/session.md",
      "paths": ["daily/2026-06-20/session.md"]
    }
  ],
  "agenda": [
    {
      "topic_id": "b2120f3573cb",
      "title": "记忆检索链路的质量回归",
      "scenario_type": "resume_task",
      "opener": "下次发布前先回顾最近的检索回归。",
      "next_action": "对比失败查询与上一个索引快照。",
      "preconditions": [],
      "delivery": "in_conversation",
      "linked_memory": [],
      "order_reason": "证据较新且下一步明确。"
    }
  ],
  "content": "date: 2026-06-20\n..."
}

include_content=falseanswer 不包含 content 字段。文件缺失和读取失败仍分别返回明确的 Skipped: ...Error: ... 消息。

文件不存在时不会报错,而是成功返回 skipped

Skipped: interests file not found at daily/2026-06-20/interests.yaml

这让上层 Agent 可以把“今天还没有 proactive refresh 结果”当作正常空状态处理。

运行方式

通过正常应用生命周期立即执行一次 refresh

reme start job=proactive_refresh date=2026-06-20

该命令可能调用配置的 LLM并更新 _proactive.yamlinterests.yaml 与 proactive catalog它不会运行 Auto Dream。

读取生成的 topics

reme proactive_read date=2026-06-20

不返回 YAML 原文:

reme proactive_read date=2026-06-20 include_content=false

与 auto_dream 的关系

Proactive refresh 和 Auto Dream 各自独立消费 daily notes

daily notes -> auto_dream -> digest
daily notes -> proactive_refresh_cron -> daily/<date>/interests.yaml -> proactive_read -> upper-level agent

Proactive 职责边界如下:

模块 职责
proactive_refresh 从本地 CLI 单次运行 refresh writer 链路。
proactive_refresh_cron 每天 18:00 运行同一套 writer 链路。
proactive_step 读取 interests.yaml,暴露给上层 Agent。

proactive_read 不修改任何文件,不更新 catalog也不负责判断是否应该主动打扰用户。它只提供当天主题材料是否推送、何时推送、用什么语气推送应由调用方根据产品策略决定。

失败模式

场景 行为
interests.yaml 不存在 success=trueskipped=truetopics=[]
YAML 无法读取或解析异常 success=falseanswer 返回错误摘要。
YAML 存在但没有合法 topics success=truetopics=[]

因此推荐调用方先检查 success,再检查 skipped,最后检查 topics 是否为空。