mirror of
https://github.com/agentscope-ai/ReMe.git
synced 2026-09-14 23:21:04 +00:00
* 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>
250 lines
9.5 KiB
Markdown
250 lines
9.5 KiB
Markdown
# Proactive
|
||
|
||
`proactive_read` 是 ReMe 的主动记忆读取接口。它不重新分析 daily,也不调用 LLM,只读取独立 proactive refresh
|
||
流程写出的兴趣主题:
|
||
|
||
```text
|
||
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 执行的定时任务:
|
||
|
||
```yaml
|
||
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 为:
|
||
|
||
```yaml
|
||
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 生成的文件如下:
|
||
|
||
```yaml
|
||
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、类型、置信度、证据日期和来源路径。读取器仍兼容包含 `title`、`reason`、`evidence`、
|
||
`keywords`、`paths` 的 v1 文件;缺少 v2 置信度时按 `0.5` 处理。
|
||
|
||
## 返回结果
|
||
|
||
成功读取时,`proactive_step` 会在主要 answer 中返回 `summary` 和 `topics`;当 `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_id`、`title`、`scenario_type`、
|
||
`opener`(自然口吻的开场白)、`next_action`(最小可执行动作)、`preconditions`、
|
||
`delivery`、`linked_memory` 与 `order_reason`。读侧会过滤已解决或低于 `min_confidence`
|
||
的主题对应的议程条目;文件不含议程时该字段不出现。
|
||
|
||
文件存在且解析成功时,answer 是结构化数据,例如:
|
||
|
||
```json
|
||
{
|
||
"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=false` 时,answer 不包含 `content` 字段。文件缺失和读取失败仍分别返回明确的
|
||
`Skipped: ...` 和 `Error: ...` 消息。
|
||
|
||
文件不存在时不会报错,而是成功返回 skipped:
|
||
|
||
```text
|
||
Skipped: interests file not found at daily/2026-06-20/interests.yaml
|
||
```
|
||
|
||
这让上层 Agent 可以把“今天还没有 proactive refresh 结果”当作正常空状态处理。
|
||
|
||
## 运行方式
|
||
|
||
通过正常应用生命周期立即执行一次 refresh:
|
||
|
||
```bash
|
||
reme start job=proactive_refresh date=2026-06-20
|
||
```
|
||
|
||
该命令可能调用配置的 LLM,并更新 `_proactive.yaml`、`interests.yaml` 与 proactive catalog;它不会运行 Auto
|
||
Dream。
|
||
|
||
读取生成的 topics:
|
||
|
||
```bash
|
||
reme proactive_read date=2026-06-20
|
||
```
|
||
|
||
不返回 YAML 原文:
|
||
|
||
```bash
|
||
reme proactive_read date=2026-06-20 include_content=false
|
||
```
|
||
|
||
## 与 auto_dream 的关系
|
||
|
||
Proactive refresh 和 Auto Dream 各自独立消费 daily notes:
|
||
|
||
```text
|
||
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=true`,`skipped=true`,`topics=[]`。 |
|
||
| YAML 无法读取或解析异常 | `success=false`,answer 返回错误摘要。 |
|
||
| YAML 存在但没有合法 topics | `success=true`,`topics=[]`。 |
|
||
|
||
因此推荐调用方先检查 `success`,再检查 `skipped`,最后检查 `topics` 是否为空。
|