Refine OpenClaw payloads and reorganize docs
This commit is contained in:
+57
-22
@@ -1,20 +1,43 @@
|
||||
# 文档索引
|
||||
# 文档索引
|
||||
|
||||
## 当前目录结构
|
||||
|
||||
- `docs/README.md`
|
||||
- 文档总索引
|
||||
- `docs/current/`
|
||||
- 当前状态、收束入口、阶段导航
|
||||
- `docs/design/`
|
||||
- 当前实现的设计文档
|
||||
- `docs/openclaw/`
|
||||
- OpenClaw 日报聚合与下游对象设计
|
||||
- `docs/notes/`
|
||||
- 较上层的方案笔记与非最终设计
|
||||
- `docs/archive/`
|
||||
- 历史归档,不作为最新事实来源
|
||||
|
||||
## 当前推荐阅读顺序
|
||||
|
||||
1. `context-reset-brief.md`
|
||||
1. `docs/current/context-reset-brief.md`
|
||||
- 当前真实进度与下一步入口
|
||||
2. `summary-mcp-service-design.md`
|
||||
2. `docs/openclaw/openclaw-candidate-input-field-spec.md`
|
||||
- 提供给 OpenClaw 的单篇结构化输入字段说明
|
||||
3. `docs/openclaw/openclaw-delivery-payload-spec.md`
|
||||
- 提供给 OpenClaw 的批量投递 envelope 说明
|
||||
4. `docs/design/summary-mcp-service-design.md`
|
||||
- 当前 MCP 服务的职责、接口和边界
|
||||
3. `filter-rule-engine-design.md`
|
||||
5. `docs/design/filter-rule-engine-design.md`
|
||||
- 过滤层的输入输出、规则结构与当前实现
|
||||
4. `markdown-sink-design.md`
|
||||
6. `docs/design/markdown-sink-design.md`
|
||||
- 第一版 Markdown sink 的输入输出、目录结构与落地方式
|
||||
5. `source-schema-design.md`
|
||||
7. `docs/openclaw/openclaw-daily-digest-refactor.md`
|
||||
- 为什么要从单篇入库改成 OpenClaw 日报聚合链路
|
||||
8. `docs/openclaw/article-candidate-daily-digest-schema.md`
|
||||
- `ArticleCandidateRecord`、`OpenClawCandidateInput` 与 `DailyDigest` 的正式设计
|
||||
9. `docs/design/source-schema-design.md`
|
||||
- `source -> item -> document` 的对象设计
|
||||
6. `reading-pipeline-design-notes.md`
|
||||
10. `docs/notes/reading-pipeline-design-notes.md`
|
||||
- 更上层的阅读流方案与阶段划分
|
||||
7. `summary-loop-explained.md`
|
||||
11. `docs/design/summary-loop-explained.md`
|
||||
- 当前 LLM 摘要校验闭环的解释
|
||||
|
||||
## 当前文档分层
|
||||
@@ -25,39 +48,51 @@
|
||||
- 仓库入口与脚本运行方式
|
||||
- `TODO.md`
|
||||
- 当前优先级、已完成项、下一阶段任务
|
||||
- `docs/context-reset-brief.md`
|
||||
- `docs/current/context-reset-brief.md`
|
||||
- 当前阶段状态的最短摘要
|
||||
- `docs/README.md`
|
||||
- 文档索引与阅读顺序
|
||||
|
||||
### 2. 当前实现设计
|
||||
|
||||
- `docs/summary-mcp-service-design.md`
|
||||
- `docs/design/summary-mcp-service-design.md`
|
||||
- 当前内容提取 MCP 的真实设计
|
||||
- `docs/summary-core-interface-design.md`
|
||||
- `docs/design/summary-core-interface-design.md`
|
||||
- 摘要/提取内核的接口抽象
|
||||
- `docs/source-schema-design.md`
|
||||
- `docs/design/source-schema-design.md`
|
||||
- `source`、`item`、`document` 三层 schema
|
||||
- `docs/summary-loop-explained.md`
|
||||
- `docs/design/summary-loop-explained.md`
|
||||
- 提取 JSON -> LLM 摘要 JSON -> 校验 的闭环说明
|
||||
- `docs/filter-rule-engine-design.md`
|
||||
- `docs/design/filter-rule-engine-design.md`
|
||||
- 第一版规则过滤引擎设计与落地位置
|
||||
- `docs/markdown-sink-design.md`
|
||||
- `docs/design/markdown-sink-design.md`
|
||||
- 第一版 Markdown sink 设计与落地位置
|
||||
|
||||
### 3. 上下游方案设计
|
||||
### 3. OpenClaw 与下游设计
|
||||
|
||||
- `docs/reading-pipeline-design-notes.md`
|
||||
- `docs/openclaw/openclaw-candidate-input-field-spec.md`
|
||||
- 提供给 OpenClaw 的单篇结构化输入字段说明
|
||||
- `docs/openclaw/openclaw-delivery-payload-spec.md`
|
||||
- 提供给 OpenClaw 的批量投递 envelope 说明
|
||||
- `docs/openclaw/openclaw-daily-digest-refactor.md`
|
||||
- 改造为 OpenClaw 日报聚合链路的原因与目标结构
|
||||
- `docs/openclaw/article-candidate-daily-digest-schema.md`
|
||||
- `ArticleCandidateRecord`、`OpenClawCandidateInput` 与 `DailyDigest` 的字段设计与对象关系
|
||||
|
||||
### 4. 方案笔记
|
||||
|
||||
- `docs/notes/reading-pipeline-design-notes.md`
|
||||
- 整体阅读流、规则、sink、push 的方案笔记
|
||||
|
||||
### 4. 历史归档
|
||||
### 5. 历史归档
|
||||
|
||||
- `docs/content-extract-mcp-mvp-archive.md`
|
||||
- `docs/archive/content-extract-mcp-mvp-archive.md`
|
||||
- MVP 阶段归档,部分状态已被后续进展覆盖
|
||||
|
||||
## 当前文档维护原则
|
||||
|
||||
- `context-reset-brief.md` 记录当前最新状态
|
||||
- `docs/current/context-reset-brief.md` 记录当前最新状态
|
||||
- `TODO.md` 记录任务优先级与下一步
|
||||
- `content-extract-mcp-mvp-archive.md` 只当历史快照,不再作为最新事实来源
|
||||
- 新增阶段性进展,优先更新 `README.md`、`TODO.md`、`context-reset-brief.md`
|
||||
- `outputs/README.md` 记录当前输出目录约定
|
||||
- `docs/archive/content-extract-mcp-mvp-archive.md` 只当历史快照,不再作为最新事实来源
|
||||
- 新增阶段性进展,优先更新 `README.md`、`TODO.md`、`docs/current/context-reset-brief.md`
|
||||
@@ -1,4 +1,4 @@
|
||||
# 项目当前状态简报
|
||||
# 项目当前状态简报
|
||||
|
||||
## 当前已完成
|
||||
|
||||
@@ -60,11 +60,11 @@
|
||||
- Markdown sink 脚本:
|
||||
- `scripts/run_markdown_sink.py`
|
||||
- Markdown sink 文档:
|
||||
- `docs/markdown-sink-design.md`
|
||||
- `docs/design/markdown-sink-design.md`
|
||||
- 当前提示词:
|
||||
- `outputs/llm-summary-prompt.txt`
|
||||
- `outputs/prompts/llm-summary-prompt.txt`
|
||||
- 过滤结果样例:
|
||||
- `outputs/filter-decision.json`
|
||||
- `outputs/reference/filter/filter-decision.json`
|
||||
- 文档索引:
|
||||
- `docs/README.md`
|
||||
- 当前 TODO:
|
||||
@@ -99,4 +99,4 @@
|
||||
|
||||
## 一句话结论
|
||||
|
||||
当前 MVP 已完成,FreshRSS 上游、第一版规则过滤层和第一版 Markdown sink 都已接通,下一阶段应转向推送层与更完整的下游集成。
|
||||
当前 MVP 已完成,FreshRSS 上游、第一版规则过滤层和第一版 Markdown sink 都已接通,下一阶段应转向推送层与更完整的下游集成。
|
||||
@@ -1,4 +1,4 @@
|
||||
# 规则过滤引擎设计
|
||||
# 规则过滤引擎设计
|
||||
|
||||
## 1. 目标
|
||||
|
||||
@@ -169,9 +169,9 @@
|
||||
|
||||
```bash
|
||||
python scripts/run_filter_rules.py ^
|
||||
--summary outputs/result.json ^
|
||||
--extracted outputs/read-flow-2026.extracted.json ^
|
||||
--output outputs/filter-decision.json
|
||||
--summary outputs/reference/summary/result.loop.json ^
|
||||
--extracted outputs/reference/extracted/read-flow-2026.extracted.json ^
|
||||
--output outputs/reference/filter/filter-decision.json
|
||||
```
|
||||
|
||||
### 9.2 带上下文的调用
|
||||
@@ -1,4 +1,4 @@
|
||||
# Summary Loop 工作说明
|
||||
# Summary Loop 工作说明
|
||||
|
||||
## 1. 目的
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
这个闭环由三部分组成:
|
||||
|
||||
- 提取结果
|
||||
- 来自 `outputs/*.extracted.json`
|
||||
- 来自 `outputs/reference/extracted/*.json` 或 `outputs/freshrss/extracted/*.json`
|
||||
- 提供标题、链接、正文、质量标记
|
||||
|
||||
- LLM 摘要
|
||||
@@ -53,8 +53,8 @@
|
||||
|
||||
脚本主要使用两个输入文件:
|
||||
|
||||
- 提取结果:`outputs/read-flow-2026.extracted.json`
|
||||
- 摘要 prompt:`outputs/llm-summary-prompt.txt`
|
||||
- 提取结果:`outputs/reference/extracted/read-flow-2026.extracted.json`
|
||||
- 摘要 prompt:`outputs/prompts/llm-summary-prompt.txt`
|
||||
|
||||
提取结果不会整包无差别塞给 LLM,而是先裁剪成更小的摘要输入:
|
||||
|
||||
@@ -187,16 +187,16 @@ validator
|
||||
|
||||
每次执行脚本都会在输出目录下留下调试痕迹:
|
||||
|
||||
- `result.loop.attempt-1.raw.txt`
|
||||
- `outputs/reference/summary/result.loop.attempt-1.raw.txt`
|
||||
- 模型原始输出
|
||||
|
||||
- `result.loop.attempt-1.json`
|
||||
- `outputs/reference/summary/result.loop.attempt-1.json`
|
||||
- 提取出的 JSON 结果
|
||||
|
||||
- `result.loop.attempt-1.validation.json`
|
||||
- `outputs/reference/summary/result.loop.attempt-1.validation.json`
|
||||
- 这一轮的校验报告
|
||||
|
||||
- `result.loop.json`
|
||||
- `outputs/reference/summary/result.loop.json`
|
||||
- 当前最终结果
|
||||
|
||||
这些文件的价值是:
|
||||
@@ -0,0 +1,488 @@
|
||||
# Article Candidate / OpenClaw Input / Daily Digest 设计
|
||||
|
||||
## 1. 文档目的
|
||||
|
||||
本文档正式定义 OpenClaw 日报链路中的三层对象:
|
||||
|
||||
- `ArticleCandidateRecord`
|
||||
- `OpenClawCandidateInput`
|
||||
- `DailyDigest`
|
||||
|
||||
目标不是只定义字段,而是明确每一层对象的职责边界,避免把“内部记录对象”和“发给 OpenClaw 的下游输入对象”混成同一个 payload。
|
||||
|
||||
---
|
||||
|
||||
## 2. 这次为什么要改
|
||||
|
||||
前一版设计里,`article_candidate` 同时承担了三种职责:
|
||||
|
||||
1. 本地审计与追溯
|
||||
2. 规则过滤后的内部候选记录
|
||||
3. 发给 OpenClaw 的下游输入
|
||||
|
||||
这会直接带来三个问题:
|
||||
|
||||
- 字段过重
|
||||
- `article.plain_text` 这类正文内容会显著增加 token 消耗
|
||||
- 字段过细
|
||||
- `filter_decision.matches`、`matched_rules`、`labels` 这类规则证据链更适合本地审计,不适合发给下游聚合器
|
||||
- 字段过耦合
|
||||
- `source_refs` 是本地文件系统路径,对 OpenClaw 没有意义,反而会让上下游绑定内部实现
|
||||
|
||||
批量跑完 `FreshRSS -> extraction -> LLM summary -> filter -> article_candidate` 后,这个问题已经非常清楚:
|
||||
|
||||
- 本地对象需要尽量保留信息,便于追溯误判
|
||||
- OpenClaw 输入需要尽量精简,便于聚合日报和控制 token
|
||||
|
||||
因此,正确改法不是继续给一个 `article_candidate` 做加减法,而是把对象拆层。
|
||||
|
||||
---
|
||||
|
||||
## 3. 设计结论
|
||||
|
||||
建议正式拆成三层:
|
||||
|
||||
### 3.1 `ArticleCandidateRecord`
|
||||
|
||||
定位:
|
||||
|
||||
- 内部候选记录对象
|
||||
- 面向本地留档、审计、调试、复跑
|
||||
|
||||
它回答的问题是:
|
||||
|
||||
- 这条候选内容从哪里来
|
||||
- 提取、摘要、过滤各阶段到底产出了什么
|
||||
- 为什么规则引擎会给出当前决策
|
||||
- 后续如果要重放或排查,该去哪里追溯
|
||||
|
||||
### 3.2 `OpenClawCandidateInput`
|
||||
|
||||
定位:
|
||||
|
||||
- 发给 OpenClaw 的精简输入对象
|
||||
- 面向日报聚合与编排
|
||||
|
||||
它回答的问题是:
|
||||
|
||||
- 这条内容是什么
|
||||
- 为什么值得放进候选池
|
||||
- 应该如何排序和栏目化
|
||||
|
||||
它不负责保存本地调试信息,也不负责承载完整正文。
|
||||
|
||||
### 3.3 `DailyDigest`
|
||||
|
||||
定位:
|
||||
|
||||
- OpenClaw 聚合后的日级主产物
|
||||
- 面向日报汇报、知识沉淀、人工 review
|
||||
|
||||
它回答的问题是:
|
||||
|
||||
- 今天最值得关注的内容是什么
|
||||
- 这些内容能提炼出什么结论
|
||||
- 哪些内容值得进入长期知识库
|
||||
|
||||
---
|
||||
|
||||
## 4. 推荐链路
|
||||
|
||||
推荐把链路明确为:
|
||||
|
||||
`item -> article -> summary -> filter_result -> ArticleCandidateRecord -> OpenClawCandidateInput -> DailyDigest`
|
||||
|
||||
这里有两个关键转换:
|
||||
|
||||
1. `summary + filter_result` 先生成 `ArticleCandidateRecord`
|
||||
- 这是内部标准记录
|
||||
2. `ArticleCandidateRecord` 再投影成 `OpenClawCandidateInput`
|
||||
- 这是跨系统传输对象
|
||||
|
||||
这样做的本质是:
|
||||
|
||||
- 内部对象追求可追溯
|
||||
- 下游对象追求低耦合、低 token、高可消费性
|
||||
|
||||
---
|
||||
|
||||
## 5. `ArticleCandidateRecord` 设计
|
||||
|
||||
### 5.1 角色定义
|
||||
|
||||
`ArticleCandidateRecord` 是当前项目内部的正式候选记录对象。
|
||||
|
||||
它不是:
|
||||
|
||||
- 发给 OpenClaw 的最终 payload
|
||||
- 发给用户的日报消息
|
||||
- 最终知识库对象
|
||||
|
||||
它是下游所有再加工动作之前的“内部事实底稿”。
|
||||
|
||||
### 5.2 设计原则
|
||||
|
||||
- 保留上游对象,便于调试和重放
|
||||
- 保留规则证据链,便于解释误判
|
||||
- 保留本地引用,便于审计
|
||||
- 允许后续重新生成不同版本的下游 payload
|
||||
|
||||
### 5.3 建议字段
|
||||
|
||||
```json
|
||||
{
|
||||
"candidate_id": "cand:sha256:xxx",
|
||||
"item": {"...": "Item"},
|
||||
"article": {"...": "ExtractedArticle"},
|
||||
"summary": {"...": "LlmSummaryResult"},
|
||||
"filter_result": {"...": "FilterDecisionResult"},
|
||||
"digest_section_hint": "insights",
|
||||
"digest_rank": 60,
|
||||
"review_state": "pending",
|
||||
"rendered_markdown": null,
|
||||
"metadata": {
|
||||
"generated_at": "2026-03-25T10:00:00Z",
|
||||
"pipeline_version": "v2",
|
||||
"producer": "summary_mcp",
|
||||
"run_id": "candidate-2026-03-25-001"
|
||||
},
|
||||
"source_refs": {
|
||||
"item_path": "outputs/freshrss/items/batch/item-01.item.json",
|
||||
"extracted_path": "outputs/freshrss/extracted/batch/item-01.extracted.json",
|
||||
"summary_path": "outputs/freshrss/summary/batch/item-01/result.loop.json",
|
||||
"filter_path": "outputs/freshrss/filter/batch/item-01.filter.json"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.4 字段说明
|
||||
|
||||
- `candidate_id`
|
||||
- 候选记录唯一标识
|
||||
- 建议基于 `item_id` 或 `extract_id` 派生
|
||||
|
||||
- `item`
|
||||
- 保留来源、标题、发布时间、作者等上游元数据
|
||||
|
||||
- `article`
|
||||
- 保留正文提取结果与质量标记
|
||||
- 供本地调试与重放使用
|
||||
|
||||
- `summary`
|
||||
- 保留结构化摘要结果
|
||||
- 是后续 OpenClaw 输入映射的主要来源
|
||||
|
||||
- `filter_result`
|
||||
- 保留规则引擎的完整裁决与命中细节
|
||||
- 主要用于解释和排查
|
||||
|
||||
- `digest_section_hint`
|
||||
- 给 OpenClaw 的栏目建议
|
||||
|
||||
- `digest_rank`
|
||||
- 给 OpenClaw 的排序信号
|
||||
|
||||
- `review_state`
|
||||
- 记录人工复核状态
|
||||
|
||||
- `rendered_markdown`
|
||||
- 可选的人类可读卡片
|
||||
- 用于调试或 fallback 展示
|
||||
|
||||
- `metadata`
|
||||
- 记录运行时元信息
|
||||
|
||||
- `source_refs`
|
||||
- 仅用于本地追溯
|
||||
- 不应进入跨系统 payload
|
||||
|
||||
### 5.5 为什么内部对象要保留正文和完整过滤结果
|
||||
|
||||
因为这层对象不是给 OpenClaw 直接消费的,而是给系统内部留档的。
|
||||
|
||||
如果这里过早裁掉字段,会丢失两种关键能力:
|
||||
|
||||
1. 误判排查能力
|
||||
- 例如文章被误判为 `paywall` 时,必须能回看 `article` 与 `filter_result`
|
||||
2. 下游重放能力
|
||||
- 后面如果调整了 OpenClaw payload 或摘要策略,可以从这层重新投影,而不必重新抓取全文
|
||||
|
||||
---
|
||||
|
||||
## 6. `OpenClawCandidateInput` 设计
|
||||
|
||||
### 6.1 角色定义
|
||||
|
||||
`OpenClawCandidateInput` 是当前项目发给 OpenClaw 的正式输入对象。
|
||||
|
||||
它应当是:
|
||||
|
||||
- 扁平化的
|
||||
- 精简的
|
||||
- 稳定的
|
||||
- 不依赖本地文件路径的
|
||||
|
||||
### 6.2 设计原则
|
||||
|
||||
- 不携带正文全文
|
||||
- 不携带规则引擎的完整证据链
|
||||
- 不携带本地 `source_refs`
|
||||
- 只保留 OpenClaw 聚合日报真正需要的字段
|
||||
|
||||
### 6.3 建议字段
|
||||
|
||||
```json
|
||||
{
|
||||
"candidate_id": "cand:sha256:xxx",
|
||||
"title": "套壳中国大模型撑起500亿美元估值?扒一扒 Cursor 的套壳疑云",
|
||||
"url": "http://www.ruanyifeng.com/blog/2026/03/kimi-cursor.html",
|
||||
"published_at": "2026-03-21T10:19:11Z",
|
||||
"author": "阮一峰",
|
||||
"source_name": "阮一峰博客",
|
||||
"summary": "2 到 3 句话摘要",
|
||||
"highlights": ["...", "...", "..."],
|
||||
"keywords": ["Cursor", "Kimi K2.5"],
|
||||
"topics": ["人工智能", "商业伦理"],
|
||||
"category": "观点评论",
|
||||
"worth_keeping": true,
|
||||
"worth_reason": "有持续性的行业洞察价值",
|
||||
"selection_decision": "review",
|
||||
"selection_reason": "worth_keeping=true but no stronger keep rule matched",
|
||||
"digest_section_hint": "insights",
|
||||
"digest_rank": 60
|
||||
}
|
||||
```
|
||||
|
||||
### 6.4 字段说明
|
||||
|
||||
- `candidate_id`
|
||||
- 与内部记录保持同一主键,便于回溯
|
||||
|
||||
- `title` / `url` / `published_at` / `author` / `source_name`
|
||||
- OpenClaw 做日报聚合所需的最小来源信息
|
||||
|
||||
- `summary` / `highlights` / `keywords` / `topics` / `category`
|
||||
- OpenClaw 聚合时真正需要的语义材料
|
||||
|
||||
- `worth_keeping` / `worth_reason`
|
||||
- 摘要层提供的长期价值判断信号
|
||||
|
||||
- `selection_decision` / `selection_reason`
|
||||
- 规则层的压缩结果
|
||||
- 用于告诉 OpenClaw:这条为什么进入候选池,以及应该怎样对待
|
||||
|
||||
- `digest_section_hint` / `digest_rank`
|
||||
- OpenClaw 做栏目化和排序时最直接的信号
|
||||
|
||||
### 6.5 为什么不用正文全文
|
||||
|
||||
因为 OpenClaw 当前承担的是“日报聚合”角色,不是“再次全文阅读器”。
|
||||
|
||||
如果把 `article.plain_text` 一并发给 OpenClaw,会出现三个问题:
|
||||
|
||||
1. token 浪费
|
||||
- 每条都携带全文,批量聚合时成本会迅速膨胀
|
||||
2. 角色混乱
|
||||
- OpenClaw 会被迫重新阅读原文,而不是消费上游已经压缩好的摘要结果
|
||||
3. 输入不稳定
|
||||
- 正文长度差异很大,会让聚合阶段的上下文更难控制
|
||||
|
||||
因此,正文应保留在 `ArticleCandidateRecord`,而不是进入 `OpenClawCandidateInput`。
|
||||
|
||||
### 6.6 为什么过滤结果要压缩
|
||||
|
||||
完整的 `filter_result` 适合本地审计,不适合跨系统传输。
|
||||
|
||||
OpenClaw 通常只需要知道:
|
||||
|
||||
- 这条是 `keep / review / drop` 中的哪一种
|
||||
- 为什么会进入候选池
|
||||
- 优先级大概是多少
|
||||
|
||||
它通常不需要知道:
|
||||
|
||||
- 具体命中了哪几条规则
|
||||
- 每条规则携带了哪些 labels
|
||||
- 完整的 `matches` 证据链
|
||||
|
||||
所以建议把规则层压缩为:
|
||||
|
||||
- `selection_decision`
|
||||
- `selection_reason`
|
||||
- `digest_rank`
|
||||
|
||||
### 6.7 为什么不要 `source_refs`
|
||||
|
||||
因为 `source_refs` 是本地实现细节,不是业务语义。
|
||||
|
||||
把它发给 OpenClaw 的问题有两个:
|
||||
|
||||
1. 没价值
|
||||
- OpenClaw 无法消费本地磁盘路径
|
||||
2. 高耦合
|
||||
- 这会让 OpenClaw 输入隐式依赖当前项目的目录结构与输出命名方式
|
||||
|
||||
因此,`source_refs` 应只保留在 `ArticleCandidateRecord`。
|
||||
|
||||
---
|
||||
|
||||
## 7. 两个对象之间的映射关系
|
||||
|
||||
建议映射规则如下:
|
||||
|
||||
- `OpenClawCandidateInput.candidate_id`
|
||||
- 来自 `ArticleCandidateRecord.candidate_id`
|
||||
- `title` / `url` / `published_at` / `author`
|
||||
- 优先来自 `item`
|
||||
- `source_name`
|
||||
- 优先来自 `item.source_title`,没有时可退化为域名或作者来源
|
||||
- `summary` / `highlights` / `keywords` / `topics` / `category`
|
||||
- 来自 `summary`
|
||||
- `worth_keeping` / `worth_reason`
|
||||
- 来自 `summary.worth_keeping` 与 `summary.reason`
|
||||
- `selection_decision`
|
||||
- 来自 `filter_result.decision`
|
||||
- `selection_reason`
|
||||
- 可取 `filter_result.reasons[0]` 或压缩后的组合说明
|
||||
- `digest_section_hint`
|
||||
- 来自 `ArticleCandidateRecord.digest_section_hint`
|
||||
- `digest_rank`
|
||||
- 来自 `ArticleCandidateRecord.digest_rank`
|
||||
|
||||
简化理解:
|
||||
|
||||
- `ArticleCandidateRecord` 保留证据
|
||||
- `OpenClawCandidateInput` 保留结论
|
||||
|
||||
---
|
||||
|
||||
## 8. `DailyDigest` 设计
|
||||
|
||||
### 8.1 角色定义
|
||||
|
||||
`DailyDigest` 是 OpenClaw 聚合多个 `OpenClawCandidateInput` 后形成的日级主产物。
|
||||
|
||||
它不应该再携带单篇全文,也不应该回退到内部调试结构。
|
||||
|
||||
### 8.2 建议字段
|
||||
|
||||
```json
|
||||
{
|
||||
"digest_id": "digest:2026-03-25",
|
||||
"date": "2026-03-25",
|
||||
"title": "2026-03-25 阅读日报",
|
||||
"summary": "今天的输入主要围绕 AI 工具、工程实践和软件产品策略展开。",
|
||||
"sections": [
|
||||
{
|
||||
"section_id": "insights",
|
||||
"title": "观察与判断",
|
||||
"summary": "今天更值得关注的是 AI 对软件行业护城河和商业包装的影响。",
|
||||
"items": [
|
||||
{
|
||||
"candidate_id": "cand:sha256:xxx",
|
||||
"title": "文章标题",
|
||||
"summary": "单篇摘要压缩版",
|
||||
"why_it_matters": "为什么今天值得被放进这个栏目",
|
||||
"action": "值得继续跟进"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"top_items": ["cand:sha256:xxx"],
|
||||
"key_takeaways": [
|
||||
"摘要层和知识沉淀层应分开。",
|
||||
"规则证据链应保留在本地,而不是直接下发给聚合器。"
|
||||
],
|
||||
"watchlist": [
|
||||
"继续收敛 paywall 误判。"
|
||||
],
|
||||
"candidate_ids": ["cand:sha256:xxx"],
|
||||
"source_refs": [
|
||||
{
|
||||
"candidate_id": "cand:sha256:xxx",
|
||||
"url": "https://example.com/post/1"
|
||||
}
|
||||
],
|
||||
"editor_notes": "今天的输入以观点和周刊类内容为主。",
|
||||
"stats": {
|
||||
"candidate_total": 12,
|
||||
"kept_total": 4,
|
||||
"review_total": 6,
|
||||
"dropped_total": 2
|
||||
},
|
||||
"metadata": {
|
||||
"generated_at": "2026-03-25T21:00:00Z",
|
||||
"producer": "openclaw",
|
||||
"pipeline_version": "v2"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8.3 `sections.items[]` 子结构建议
|
||||
|
||||
```json
|
||||
{
|
||||
"candidate_id": "cand:sha256:xxx",
|
||||
"title": "文章标题",
|
||||
"summary": "单篇摘要压缩版",
|
||||
"why_it_matters": "为什么这条内容今天值得看",
|
||||
"action": "值得试用 / 值得跟进 / 值得收藏 / 待验证"
|
||||
}
|
||||
```
|
||||
|
||||
这里最关键的不是原始摘要复述,而是 `why_it_matters`。
|
||||
|
||||
因为日报的价值不在于再列一遍新闻,而在于表达“今天为什么值得看”。
|
||||
|
||||
---
|
||||
|
||||
## 9. 为什么这样设计更合理
|
||||
|
||||
### 9.1 控制 token 成本
|
||||
|
||||
把正文全文挡在 OpenClaw 之前,能显著降低聚合阶段的 token 开销。
|
||||
|
||||
### 9.2 保持对象职责单一
|
||||
|
||||
- `ArticleCandidateRecord` 负责本地审计
|
||||
- `OpenClawCandidateInput` 负责下游消费
|
||||
- `DailyDigest` 负责日级成品
|
||||
|
||||
每层只做一件事,后续更容易演进。
|
||||
|
||||
### 9.3 降低上下游耦合
|
||||
|
||||
OpenClaw 不需要知道本地 `outputs/` 目录结构,也不应该依赖规则引擎的内部细节。
|
||||
|
||||
### 9.4 保留调试与重放能力
|
||||
|
||||
内部对象依然保留全文、质量标记、完整过滤证据链,因此不会因为“下游精简”而损失工程可维护性。
|
||||
|
||||
### 9.5 为后续人审与知识库沉淀留出口
|
||||
|
||||
当日报和知识库真正接起来时:
|
||||
|
||||
- OpenClaw 基于精简输入做日报聚合
|
||||
- 人工基于日报成品做最终判断
|
||||
- 本地记录对象作为审计底稿长期保留
|
||||
|
||||
这个边界是清晰且可持续的。
|
||||
|
||||
---
|
||||
|
||||
## 10. 当前阶段的实现建议
|
||||
|
||||
建议按这个顺序推进:
|
||||
|
||||
1. 在文档层正式采用这三个对象
|
||||
2. 将当前代码里的 `article_candidate` 重命名或重新定位为 `ArticleCandidateRecord`
|
||||
3. 新增 `OpenClawCandidateInput` 模型
|
||||
4. 增加 `ArticleCandidateRecord -> OpenClawCandidateInput` 的转换逻辑
|
||||
5. 让 OpenClaw 只消费精简输入对象
|
||||
6. 后续再补 `DailyDigest` 的真实生成逻辑
|
||||
|
||||
---
|
||||
|
||||
## 11. 一句话结论
|
||||
|
||||
这次改动的本质,不是“删掉几个字段”,而是把“内部候选记录对象”和“发给 OpenClaw 的精简输入对象”彻底分层;只有这样,当前项目才能同时保留审计能力、控制 token 成本,并稳定服务 OpenClaw 的日报聚合。
|
||||
@@ -0,0 +1,351 @@
|
||||
# OpenClaw Candidate Input 字段说明
|
||||
|
||||
## 1. 文档目的
|
||||
|
||||
本文档定义当前项目输出给 OpenClaw 的结构化输入对象:`OpenClawCandidateInput`。
|
||||
|
||||
这是一份面向 OpenClaw 消费侧的接口说明文档,不要求了解本项目内部的 `item`、`article`、`filter_result` 等实现细节。
|
||||
|
||||
当前定位是:
|
||||
|
||||
- 单篇候选内容的精简输入
|
||||
- 用于 OpenClaw 做日报聚合、排序、栏目分配和后续汇报
|
||||
- 不承载正文全文、不承载本地文件路径、不承载规则引擎完整证据链
|
||||
|
||||
---
|
||||
|
||||
## 2. 设计原则
|
||||
|
||||
这个 payload 的设计遵循以下原则:
|
||||
|
||||
1. 足够轻
|
||||
- 不发送正文全文,避免浪费 token
|
||||
2. 足够稳定
|
||||
- 不暴露本地目录结构和内部中间文件路径
|
||||
3. 足够可消费
|
||||
- 字段扁平化,避免 OpenClaw 反复解析嵌套对象
|
||||
4. 足够有判断信号
|
||||
- 保留摘要、主题、价值判断、筛选结果、排序信号
|
||||
5. 足够可去重
|
||||
- 同时提供原始 `url` 与归一化后的 `canonical_url`
|
||||
|
||||
---
|
||||
|
||||
## 3. 完整 JSON 示例
|
||||
|
||||
```json
|
||||
{
|
||||
"candidate_id": "cand:sha256:4139f277b8cb621b02b3398f8a7bd78e3f9eef7bcd320b70b8590e802540c6ca",
|
||||
"title": "套壳中国大模型撑起500亿美元估值?扒一扒 Cursor 的\"套壳\"疑云",
|
||||
"url": "http://www.ruanyifeng.com/blog/2026/03/kimi-cursor.html?utm_source=rss",
|
||||
"canonical_url": "http://www.ruanyifeng.com/blog/2026/03/kimi-cursor.html",
|
||||
"published_at": "2026-03-21T10:19:11Z",
|
||||
"author": "阮一峰",
|
||||
"source_name": "阮一峰的网络日志",
|
||||
"language": "zh-CN",
|
||||
"summary": "AI编程工具Cursor推出的Composer 2模型被证实套壳中国Kimi K2.5模型,引发侵权争议。Kimi官方确认Cursor通过Fireworks AI获得授权,不存在侵权。作者分析Cursor隐瞒事实是为了支撑其不断膨胀的估值,将其包装成大模型公司。",
|
||||
"highlights": [
|
||||
"Cursor的Composer 2模型被技术手段揭露实际调用的是Kimi K2.5模型。",
|
||||
"Kimi官方确认Cursor通过Fireworks AI获得授权,因此不构成侵权。",
|
||||
"Cursor隐瞒使用Kimi模型,被认为是为了支撑其高达500亿美元的估值。"
|
||||
],
|
||||
"keywords": ["Cursor", "Composer 2", "Kimi K2.5", "Fireworks AI", "AI编程工具"],
|
||||
"topics": ["人工智能", "大模型", "商业伦理"],
|
||||
"category": "观点评论",
|
||||
"worth_keeping": true,
|
||||
"worth_reason": "文章深入剖析了AI行业的热点事件,涉及技术真相、商业动机和行业趋势,具有较高的参考价值。",
|
||||
"selection_decision": "review",
|
||||
"selection_reason": "Worth-keeping signal is positive but no stronger keep rule matched.",
|
||||
"digest_section_hint": "insights",
|
||||
"digest_rank": 60
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 字段总览
|
||||
|
||||
| 字段名 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `candidate_id` | `string` | 是 | 单篇候选内容唯一标识 |
|
||||
| `title` | `string` | 是 | 文章或内容标题 |
|
||||
| `url` | `string` | 是 | 原始链接 |
|
||||
| `canonical_url` | `string \| null` | 否 | 归一化链接,用于更稳定的去重 |
|
||||
| `published_at` | `string \| null` | 否 | 发布时间,ISO 8601 格式 |
|
||||
| `author` | `string \| null` | 否 | 作者名 |
|
||||
| `source_name` | `string \| null` | 否 | 来源名称,例如博客名、站点名、Feed 名 |
|
||||
| `language` | `string \| null` | 否 | 语言标记,例如 `zh-CN`、`en` |
|
||||
| `summary` | `string` | 是 | 2 到 3 句话的精简摘要 |
|
||||
| `highlights` | `string[]` | 是 | 3 到 5 条单句要点 |
|
||||
| `keywords` | `string[]` | 是 | 5 到 8 个关键词 |
|
||||
| `topics` | `string[]` | 是 | 3 到 5 个高层主题标签 |
|
||||
| `category` | `string` | 是 | 内容分类 |
|
||||
| `worth_keeping` | `boolean` | 是 | 摘要层给出的长期保留判断 |
|
||||
| `worth_reason` | `string` | 是 | 对 `worth_keeping` 的解释 |
|
||||
| `selection_decision` | `string` | 是 | 规则层压缩后的筛选决策 |
|
||||
| `selection_reason` | `string \| null` | 否 | 对 `selection_decision` 的简短解释 |
|
||||
| `digest_section_hint` | `string \| null` | 否 | 建议栏目 |
|
||||
| `digest_rank` | `integer` | 是 | 建议排序分值,范围 `0-100` |
|
||||
|
||||
---
|
||||
|
||||
## 5. 字段详细说明
|
||||
|
||||
### 5.1 `candidate_id`
|
||||
|
||||
含义:
|
||||
- 单篇候选内容的稳定唯一标识
|
||||
|
||||
约束:
|
||||
- 同一条上游内容在当前系统中应保持稳定
|
||||
- OpenClaw 可以把它作为去重、回溯、引用的主键
|
||||
|
||||
### 5.2 `title`
|
||||
|
||||
含义:
|
||||
- 候选内容标题
|
||||
|
||||
来源:
|
||||
- 优先来自标准化 `item.title`
|
||||
- 如果上游标题缺失,则退回摘要结果中的 `summary.title`
|
||||
|
||||
### 5.3 `url`
|
||||
|
||||
含义:
|
||||
- 原始内容链接
|
||||
|
||||
用途:
|
||||
- OpenClaw 在日报中回链原文
|
||||
- 后续人工 review 或知识库引用时回溯来源
|
||||
|
||||
### 5.4 `canonical_url`
|
||||
|
||||
含义:
|
||||
- 对原始 `url` 做轻量归一化后的链接
|
||||
|
||||
当前归一化策略:
|
||||
- 去掉 fragment
|
||||
- 去掉常见追踪参数,例如 `utm_*`、`fbclid`、`gclid`、`ref` 等
|
||||
- 保留其他非追踪 query 参数
|
||||
|
||||
用途:
|
||||
- 让 OpenClaw 在去重时更稳定
|
||||
- 避免同一篇文章因为带不同追踪参数被当成两篇
|
||||
|
||||
说明:
|
||||
- `url` 保留原始值,`canonical_url` 提供去重辅助
|
||||
- OpenClaw 建议优先用 `canonical_url` 做去重键,不足时再结合 `candidate_id`
|
||||
|
||||
### 5.5 `published_at`
|
||||
|
||||
含义:
|
||||
- 内容发布时间
|
||||
|
||||
格式:
|
||||
- ISO 8601,例如 `2026-03-21T10:19:11Z`
|
||||
|
||||
### 5.6 `author`
|
||||
|
||||
含义:
|
||||
- 作者名称
|
||||
|
||||
### 5.7 `source_name`
|
||||
|
||||
含义:
|
||||
- 内容来源名称
|
||||
|
||||
常见示例:
|
||||
- `阮一峰的网络日志`
|
||||
- `FreshRSS`
|
||||
- 某个 Feed 标题
|
||||
- 某个站点域名
|
||||
|
||||
### 5.8 `language`
|
||||
|
||||
含义:
|
||||
- 语言标记
|
||||
|
||||
常见示例:
|
||||
- `zh`
|
||||
- `zh-CN`
|
||||
- `en`
|
||||
|
||||
用途:
|
||||
- OpenClaw 后续处理多语言输入时做风格和分类控制
|
||||
- 为知识库入库、多语言日报、翻译或过滤策略留出口
|
||||
|
||||
说明:
|
||||
- 如果当前上游无法可靠识别语言,可以为 `null`
|
||||
|
||||
### 5.9 `summary`
|
||||
|
||||
含义:
|
||||
- 摘要主文本
|
||||
|
||||
约束:
|
||||
- 当前上游约束是 2 到 3 句话
|
||||
- 长度不超过 140 个中文字符
|
||||
|
||||
### 5.10 `highlights`
|
||||
|
||||
含义:
|
||||
- 关键要点列表
|
||||
|
||||
约束:
|
||||
- 3 到 5 条
|
||||
- 每条一条独立信息
|
||||
|
||||
### 5.11 `keywords`
|
||||
|
||||
含义:
|
||||
- 具体实体、工具名、方法名、关键概念
|
||||
|
||||
约束:
|
||||
- 5 到 8 个
|
||||
|
||||
### 5.12 `topics`
|
||||
|
||||
含义:
|
||||
- 高层主题标签
|
||||
|
||||
约束:
|
||||
- 3 到 5 个
|
||||
- 语义层级高于 `keywords`
|
||||
|
||||
### 5.13 `category`
|
||||
|
||||
含义:
|
||||
- 内容分类
|
||||
|
||||
当前允许值:
|
||||
- `资讯`
|
||||
- `方法论`
|
||||
- `工具实践`
|
||||
- `观点评论`
|
||||
|
||||
### 5.14 `worth_keeping`
|
||||
|
||||
含义:
|
||||
- 这条内容是否具有持续保留价值
|
||||
|
||||
说明:
|
||||
- 这是摘要层的价值判断,不是最终入库决定
|
||||
- OpenClaw 可以把它当作优先筛选信号,而不是绝对真值
|
||||
|
||||
### 5.15 `worth_reason`
|
||||
|
||||
含义:
|
||||
- 对 `worth_keeping` 的解释
|
||||
|
||||
### 5.16 `selection_decision`
|
||||
|
||||
含义:
|
||||
- 规则引擎压缩后的筛选决策
|
||||
|
||||
当前允许值:
|
||||
- `keep`
|
||||
- `review`
|
||||
- `drop`
|
||||
|
||||
### 5.17 `selection_reason`
|
||||
|
||||
含义:
|
||||
- 对 `selection_decision` 的简短解释
|
||||
|
||||
说明:
|
||||
- 当前一般取规则引擎 reasons 的第一条压缩说明
|
||||
- 不承诺包含全部规则命中细节
|
||||
|
||||
### 5.18 `digest_section_hint`
|
||||
|
||||
含义:
|
||||
- 建议日报栏目
|
||||
|
||||
当前允许值:
|
||||
- `top_news`
|
||||
- `tools_and_workflows`
|
||||
- `risk_and_security`
|
||||
- `open_source`
|
||||
- `insights`
|
||||
- `deep_dive`
|
||||
- `null`
|
||||
|
||||
### 5.19 `digest_rank`
|
||||
|
||||
含义:
|
||||
- 建议排序分值
|
||||
|
||||
范围:
|
||||
- `0` 到 `100`
|
||||
|
||||
建议解释:
|
||||
- `80-100`:高优先级,建议优先关注
|
||||
- `50-79`:中优先级,建议正常进入候选池
|
||||
- `0-49`:低优先级,建议降权或仅保留参考
|
||||
|
||||
---
|
||||
|
||||
## 6. OpenClaw 消费建议
|
||||
|
||||
推荐 OpenClaw 主要消费这几组信号:
|
||||
|
||||
### 6.1 语义聚合信号
|
||||
|
||||
- `summary`
|
||||
- `highlights`
|
||||
- `keywords`
|
||||
- `topics`
|
||||
- `category`
|
||||
|
||||
### 6.2 选择与排序信号
|
||||
|
||||
- `worth_keeping`
|
||||
- `worth_reason`
|
||||
- `selection_decision`
|
||||
- `selection_reason`
|
||||
- `digest_rank`
|
||||
- `digest_section_hint`
|
||||
|
||||
### 6.3 来源展示信号
|
||||
|
||||
- `title`
|
||||
- `url`
|
||||
- `canonical_url`
|
||||
- `published_at`
|
||||
- `author`
|
||||
- `source_name`
|
||||
- `language`
|
||||
|
||||
---
|
||||
|
||||
## 7. 当前不会提供的字段
|
||||
|
||||
OpenClaw 当前不应期待以下字段:
|
||||
|
||||
- 正文全文,例如 `plain_text`
|
||||
- 本地文件路径,例如 `source_refs`
|
||||
- 完整规则证据链,例如 `filter_result.matches`
|
||||
- 内部中间对象,例如完整的 `item`、`article`、`summary`、`filter_result`
|
||||
- 人工确认状态,例如 `review_status`、`knowledge_decision`
|
||||
|
||||
最后一类字段不会放在这个对象中,原因是:
|
||||
|
||||
- `OpenClawCandidateInput` 表示的是上游候选事实
|
||||
- 人工确认和知识沉淀属于下游流程状态
|
||||
- 两者混在一起会让输入对象逐渐失真、变脏
|
||||
|
||||
---
|
||||
|
||||
## 8. 兼容性约定
|
||||
|
||||
当前版本约定:
|
||||
|
||||
- 这是单篇输入对象,不是批量 envelope
|
||||
- 批量投递由上层 `OpenClawDeliveryPayload` 承载
|
||||
- 本文档只约束 `candidates[]` 中单条对象的字段
|
||||
|
||||
---
|
||||
|
||||
## 9. 一句话结论
|
||||
|
||||
`OpenClawCandidateInput` 是“给 OpenClaw 聚合日报用的单篇精简对象”:它保留来源信息、摘要语义、价值判断、去重辅助和排序信号,但不会携带正文全文、本地路径、规则证据链或人工确认状态。
|
||||
@@ -0,0 +1,222 @@
|
||||
# OpenClaw 日报聚合改造说明
|
||||
|
||||
## 1. 为什么要改
|
||||
|
||||
当前项目已经跑通了:
|
||||
|
||||
`FreshRSS -> item -> extraction -> LLM summary -> validator -> filter -> Markdown sink`
|
||||
|
||||
这条链路证明了上游拉取、结构化提取、摘要校验和规则过滤都是可行的。
|
||||
|
||||
但如果最终目标是:
|
||||
|
||||
- 每日提炼总结进入知识库
|
||||
- OpenClaw 向用户汇报今天的日报
|
||||
|
||||
那么当前“单篇过滤后直接写入本地 Markdown 知识库”的主路径就不够准确了。
|
||||
|
||||
原因有四点:
|
||||
|
||||
1. 单篇文章更像原材料,不是最终成品
|
||||
2. 用户要的是“日报级总结 + 知识沉淀”,不是“每篇都直接入库”
|
||||
3. 参考文章中真正的终态是 `Digest -> Daily Review -> 人工确认 -> Lumina`
|
||||
4. 当前 `article_candidate` 如果同时承担内部记录和下游投递,会导致 payload 过重、token 过高、边界混乱
|
||||
|
||||
所以当前项目要从“单篇直接入库”切换为“单篇候选材料 -> 日报聚合 -> 人工确认 -> 知识沉淀”。
|
||||
|
||||
## 2. 参考文章给出的真实结构
|
||||
|
||||
参考文章里的关键分层是:
|
||||
|
||||
1. `Digest`
|
||||
- 去重、抓正文、质量检查、生成摘要
|
||||
- 产出可判断的候选内容
|
||||
2. `Daily Review`
|
||||
- 从候选内容中做栏目化精选
|
||||
- 产出当天的日报
|
||||
3. `Human in the loop`
|
||||
- 人工判断哪些内容值得长期保留
|
||||
4. `Lumina`
|
||||
- 只承接真正值得长期保留的内容
|
||||
|
||||
这意味着:
|
||||
|
||||
- 日报不是知识库的替代品
|
||||
- 知识库也不应该承接所有单篇文章
|
||||
- 单篇内容更适合作为日报生成前的候选材料
|
||||
|
||||
## 3. 当前设计哪里不够
|
||||
|
||||
当前的不足主要在下游:
|
||||
|
||||
### 3.1 `sink` 语义过重
|
||||
|
||||
现在的 `Markdown sink` 更像“最终入库器”。
|
||||
|
||||
但在新的目标里,它最多只应扮演:
|
||||
|
||||
- debug sink
|
||||
- fallback sink
|
||||
- 审计/归档 sink
|
||||
|
||||
主路径不应再把它视为最终知识库形态。
|
||||
|
||||
### 3.2 缺少“日级对象”
|
||||
|
||||
当前项目有:
|
||||
|
||||
- `item`
|
||||
- `article`
|
||||
- `summary`
|
||||
- `filter_decision`
|
||||
|
||||
但还没有:
|
||||
|
||||
- `ArticleCandidateRecord`
|
||||
- `OpenClawCandidateInput`
|
||||
- `DailyDigest`
|
||||
|
||||
如果没有这三个对象,就无法稳定表达:
|
||||
|
||||
- 单篇内容如何作为内部候选材料存在
|
||||
- 单篇内容如何以低 token 的形式发给 OpenClaw
|
||||
- 一天的内容如何被聚合为一个正式产物
|
||||
|
||||
### 3.3 缺少人工确认层
|
||||
|
||||
规则引擎的 `keep` 只能表示“值得进入下一步”,不能直接等价于“正式入知识库”。
|
||||
|
||||
如果没有人工确认层,系统就会退化成“规则命中即永久沉淀”,这和参考文章强调的 `Human in the loop` 不一致。
|
||||
|
||||
### 3.4 下游输入边界不清楚
|
||||
|
||||
如果把正文全文、完整规则证据链、本地文件路径都发给 OpenClaw,会出现三个直接问题:
|
||||
|
||||
- token 浪费
|
||||
- 对象职责混乱
|
||||
- OpenClaw 输入与本地实现耦合
|
||||
|
||||
所以必须把“内部记录对象”和“下游精简输入对象”分开。
|
||||
|
||||
## 4. 改造后的主路径
|
||||
|
||||
建议主路径调整为:
|
||||
|
||||
`FreshRSS/RSS -> extraction -> LLM summary -> validator -> rule engine -> ArticleCandidateRecord -> OpenClawCandidateInput -> OpenClaw -> DailyDigest -> human review -> knowledge base`
|
||||
|
||||
这里要注意几件事:
|
||||
|
||||
1. 当前项目负责生成高质量候选材料与精简输入
|
||||
2. OpenClaw 负责按天聚合、生成日报、编排后续动作
|
||||
3. 知识库只接收日报和人工确认后的长期内容
|
||||
|
||||
## 5. 新的对象分层
|
||||
|
||||
### 5.1 `ArticleCandidateRecord`
|
||||
|
||||
定位:
|
||||
|
||||
- 单篇内容的内部候选记录
|
||||
- 用于留档、追溯、重放、审计
|
||||
|
||||
最少应包含:
|
||||
|
||||
- `item`
|
||||
- `article`
|
||||
- `summary`
|
||||
- `filter_result`
|
||||
- `metadata`
|
||||
- 可选 `source_refs`
|
||||
- 可选 `rendered_markdown`
|
||||
|
||||
### 5.2 `OpenClawCandidateInput`
|
||||
|
||||
定位:
|
||||
|
||||
- 当前项目发给 OpenClaw 的标准投递对象
|
||||
- 用于日报聚合与排序
|
||||
|
||||
最少应包含:
|
||||
|
||||
- `candidate_id`
|
||||
- `title`
|
||||
- `url`
|
||||
- `published_at`
|
||||
- `author`
|
||||
- `summary`
|
||||
- `highlights`
|
||||
- `topics`
|
||||
- `category`
|
||||
- `worth_keeping`
|
||||
- `selection_decision`
|
||||
- `selection_reason`
|
||||
- `digest_section_hint`
|
||||
- `digest_rank`
|
||||
|
||||
它不应包含:
|
||||
|
||||
- `article.plain_text`
|
||||
- `filter_result.matches`
|
||||
- `source_refs`
|
||||
|
||||
### 5.3 `DailyDigest`
|
||||
|
||||
定位:
|
||||
|
||||
- 一天的主产物
|
||||
- 同时服务于“知识沉淀”和“日报汇报”
|
||||
|
||||
建议至少包含:
|
||||
|
||||
- `date`
|
||||
- `sections`
|
||||
- `top_items`
|
||||
- `key_takeaways`
|
||||
- `watchlist`
|
||||
- `candidate_ids`
|
||||
- `source_refs`
|
||||
- `editor_notes`
|
||||
|
||||
## 6. 为什么这样更合理
|
||||
|
||||
这样改造有几个直接收益:
|
||||
|
||||
1. 知识库不会被大量单篇摘要污染
|
||||
2. OpenClaw 不需要再次消费全文,token 更可控
|
||||
3. OpenClaw 的输入边界更清晰,不依赖本地目录结构和规则证据链
|
||||
4. 当前项目仍然保留完整候选记录,因此误判排查和重放能力不会丢
|
||||
5. 未来扩展周报、专题文章和反馈回流会更自然
|
||||
|
||||
本质上,这是把当前系统从“单篇落库工具”调整为“日报生产链路中的候选记录生产器 + 精简投递器”。
|
||||
|
||||
## 7. 对当前实现的影响
|
||||
|
||||
不需要推翻已有能力,主要是重新定位:
|
||||
|
||||
- `extraction` 保留
|
||||
- `LLM summary validator` 保留
|
||||
- `rule engine` 保留
|
||||
- `FreshRSS integration` 保留
|
||||
- `Markdown sink` 保留,但降级为调试/回退能力
|
||||
|
||||
真正新增的是:
|
||||
|
||||
- `ArticleCandidateRecord` schema
|
||||
- `OpenClawCandidateInput` schema
|
||||
- `ArticleCandidateRecord -> OpenClawCandidateInput` 映射逻辑
|
||||
- `DailyDigest` schema
|
||||
- 人工确认后的状态流转
|
||||
|
||||
## 8. 下一步应该做什么
|
||||
|
||||
建议按这个顺序推进:
|
||||
|
||||
1. 在代码里把当前 `article_candidate` 重新定位为 `ArticleCandidateRecord`
|
||||
2. 新增 `OpenClawCandidateInput` 模型
|
||||
3. 增加精简 payload 的本地输出脚本或转换函数
|
||||
4. 让 OpenClaw 只消费精简输入对象
|
||||
5. 再设计批量聚合和 `DailyDigest` 生成
|
||||
|
||||
## 9. 一句话结论
|
||||
|
||||
如果最终目标是“每天有日报汇报,同时把日级提炼沉淀进知识库”,那么当前项目就不该继续围绕“单篇直接入库”演进,而应拆成“内部候选记录对象 + OpenClaw 精简输入对象 + 日级成品对象”三层结构。
|
||||
@@ -0,0 +1,195 @@
|
||||
# OpenClaw Delivery Payload 字段说明
|
||||
|
||||
## 1. 文档目的
|
||||
|
||||
本文档定义当前项目批量投递给 OpenClaw 的外层 envelope:`OpenClawDeliveryPayload`。
|
||||
|
||||
它不是单篇 candidate 对象,而是承载一批 `OpenClawCandidateInput` 的批次对象。
|
||||
|
||||
---
|
||||
|
||||
## 2. 完整 JSON 示例
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": "v1",
|
||||
"generated_at": "2026-03-26T10:15:30Z",
|
||||
"run_id": "openclaw-delivery-20260325-101530",
|
||||
"date": "2026-03-25",
|
||||
"candidates": [
|
||||
{
|
||||
"candidate_id": "cand:sha256:xxx",
|
||||
"title": "文章标题",
|
||||
"url": "https://example.com/post",
|
||||
"canonical_url": "https://example.com/post",
|
||||
"published_at": "2026-03-25T09:30:00Z",
|
||||
"author": "作者",
|
||||
"source_name": "来源",
|
||||
"language": "zh-CN",
|
||||
"summary": "2 到 3 句话摘要",
|
||||
"highlights": ["要点1", "要点2", "要点3"],
|
||||
"keywords": ["关键词1", "关键词2", "关键词3", "关键词4", "关键词5"],
|
||||
"topics": ["主题1", "主题2", "主题3"],
|
||||
"category": "观点评论",
|
||||
"worth_keeping": true,
|
||||
"worth_reason": "有长期参考价值",
|
||||
"selection_decision": "review",
|
||||
"selection_reason": "worth_keeping=true but no stronger keep rule matched",
|
||||
"digest_section_hint": "insights",
|
||||
"digest_rank": 60
|
||||
}
|
||||
],
|
||||
"stats": {
|
||||
"total": 1,
|
||||
"keep_total": 0,
|
||||
"review_total": 1,
|
||||
"drop_total": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 字段总览
|
||||
|
||||
| 字段名 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `schema_version` | `string` | 是 | 当前 envelope 的 schema 版本 |
|
||||
| `generated_at` | `string` | 是 | 本批数据的生成时间,ISO 8601 格式 |
|
||||
| `run_id` | `string` | 是 | 本次批量投递的唯一运行标识 |
|
||||
| `date` | `string` | 是 | 本批次所属日期,格式 `YYYY-MM-DD` |
|
||||
| `candidates` | `OpenClawCandidateInput[]` | 是 | 单篇候选内容列表 |
|
||||
| `stats` | `object` | 是 | 批次级统计信息 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 字段详细说明
|
||||
|
||||
### 4.1 `schema_version`
|
||||
|
||||
含义:
|
||||
- 当前批量 envelope 的结构版本
|
||||
|
||||
用途:
|
||||
- 未来字段调整时做兼容处理
|
||||
- 让 OpenClaw 能按版本选择不同解析逻辑
|
||||
|
||||
当前值:
|
||||
- `v1`
|
||||
|
||||
### 4.2 `generated_at`
|
||||
|
||||
含义:
|
||||
- 本批数据的实际生成时间
|
||||
|
||||
格式:
|
||||
- ISO 8601,例如 `2026-03-26T10:15:30Z`
|
||||
|
||||
用途:
|
||||
- 排查数据新旧
|
||||
- 增量处理
|
||||
- 失败重跑和批次比对
|
||||
|
||||
### 4.3 `run_id`
|
||||
|
||||
含义:
|
||||
- 本次投递任务的唯一标识
|
||||
|
||||
用途:
|
||||
- 失败重跑追踪
|
||||
- 批次去重
|
||||
- 运行日志关联
|
||||
|
||||
建议:
|
||||
- 由上游在每次批量生成时唯一产生
|
||||
- 例如:`openclaw-delivery-20260325-101530`
|
||||
|
||||
### 4.4 `date`
|
||||
|
||||
含义:
|
||||
- 本批次所属日期
|
||||
|
||||
格式:
|
||||
- `YYYY-MM-DD`
|
||||
|
||||
用途:
|
||||
- OpenClaw 进行日报归档
|
||||
- 将多次投递映射到同一天的 digest 流程
|
||||
|
||||
### 4.5 `candidates`
|
||||
|
||||
含义:
|
||||
- 单篇候选输入对象列表
|
||||
|
||||
说明:
|
||||
- 数组内每个元素都应满足 `OpenClawCandidateInput` 定义
|
||||
- 单篇字段说明请参考:
|
||||
- `docs/openclaw/openclaw-candidate-input-field-spec.md`
|
||||
|
||||
### 4.6 `stats`
|
||||
|
||||
含义:
|
||||
- 本批次的统计信息
|
||||
|
||||
当前字段包括:
|
||||
- `total`
|
||||
- `keep_total`
|
||||
- `review_total`
|
||||
- `drop_total`
|
||||
|
||||
用途:
|
||||
- OpenClaw 在接收后快速感知这批输入的规模和分布
|
||||
- 便于记录运行状态和对账
|
||||
|
||||
---
|
||||
|
||||
## 5. `stats` 子结构说明
|
||||
|
||||
| 字段名 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `total` | `integer` | 是 | candidate 总数 |
|
||||
| `keep_total` | `integer` | 是 | `selection_decision=keep` 的数量 |
|
||||
| `review_total` | `integer` | 是 | `selection_decision=review` 的数量 |
|
||||
| `drop_total` | `integer` | 是 | `selection_decision=drop` 的数量 |
|
||||
|
||||
说明:
|
||||
- 这些统计值由上游根据 `candidates[]` 自动汇总
|
||||
- OpenClaw 可以直接信任,也可以再次校验
|
||||
|
||||
---
|
||||
|
||||
## 6. 推荐消费方式
|
||||
|
||||
建议 OpenClaw 的批处理逻辑按以下顺序进行:
|
||||
|
||||
1. 先读取 `schema_version`
|
||||
- 选择对应版本的解析逻辑
|
||||
2. 再读取 `generated_at`、`run_id` 和 `date`
|
||||
- 建立本次批处理上下文
|
||||
3. 再读取 `stats`
|
||||
- 快速判断这批输入规模与分布
|
||||
4. 最后逐条消费 `candidates[]`
|
||||
- 去重
|
||||
- 聚类
|
||||
- 分栏目
|
||||
- 排序
|
||||
- 产生日报和 review 清单
|
||||
|
||||
---
|
||||
|
||||
## 7. 当前不会放入 envelope 的字段
|
||||
|
||||
当前 envelope 不会额外放入:
|
||||
|
||||
- 完整内部候选记录列表
|
||||
- 人工确认状态列表
|
||||
- 知识库入库状态列表
|
||||
- 执行日志文本
|
||||
|
||||
这些都属于其他层的对象,不应混进上游投递协议。
|
||||
|
||||
---
|
||||
|
||||
## 8. 一句话结论
|
||||
|
||||
`OpenClawDeliveryPayload` 是“给 OpenClaw 的批量投递对象”:它用 `schema_version`、`generated_at`、`run_id`、`date`、`stats` 管理批次上下文,用 `candidates[]` 承载真正的单篇候选输入。
|
||||
Reference in New Issue
Block a user