11 KiB
Summary Core Interface 设计草案
1. 文档目的
本文档用于定义 summary-core 的输入输出接口,目标是把“页面摘要能力”从概念讨论收敛成一套稳定、可复用、可封装的数据接口。
这份文档不限定实现语言,也不限定它最终通过 CLI、HTTP、MCP 还是 Skill 暴露,只关注能力边界和数据契约。
2. 角色定位
summary-core 是阅读流系统中的摘要内核,负责把候选内容转换成可进入过滤、入库和推送阶段的标准化内容对象。
它在整条链路中的位置是:
RSS 聚合 / 页面抓取 -> summary-core -> rule-engine -> sink -> push
它的职责是:
- 接收一个候选内容对象或与之等价的输入
- 获取正文或补全正文
- 抽取正文纯文本
- 生成结构化摘要
- 输出标准化的
document对象或与之兼容的结果
它不负责:
- 维护 RSS 订阅源
- 执行规则过滤
- 写入知识库
- 执行消息推送
- 负责编排整个自动化流程
3. 设计原则
3.1 输入以 item 为主,补充字段为辅
summary-core 的标准输入应优先基于 item,这样可以和上游采集层稳定衔接。
但为了适配不同调用方式,也允许附带额外输入:
raw_htmlrss_contentuser_profilesummary_style
3.2 输出以 document 为中心
summary-core 的输出应该尽量直接映射到 document,而不是返回一段松散文本。
这样后续的规则引擎、知识库入库和推送层都可以稳定消费。
3.3 失败也要结构化表达
正文抓取失败、内容过短、抽取结果异常、疑似付费墙等情况,不能只返回报错字符串,应该返回结构化错误或状态标志。
3.4 同一套数据契约服务多种封装方式
不管未来是:
- 本地 CLI
- HTTP API
- MCP tool
- OpenClaw Skill
都应尽量复用同一套输入输出 schema,而不是每个入口都定义一套不同的数据格式。
4. 处理阶段拆分
summary-core 内部建议拆成以下几个阶段:
- 输入标准化
- 正文获取
- 正文抽取
- 摘要生成
- 质量标记
- 输出映射
4.1 输入标准化
目标:
- 统一不同调用来源的数据结构
- 优先使用
item - 补齐缺失字段
4.2 正文获取
目标:
- 优先使用上游已提供的
raw_content - 若内容不足,再根据
url回源抓取页面 - 如有
raw_html,优先直接使用
4.3 正文抽取
目标:
- 从 HTML 或富文本中抽取正文
- 生成稳定的纯文本内容
- 识别是否正文过短、被截断或包含大量噪音
4.4 摘要生成
目标:
- 基于正文生成结构化摘要
- 输出摘要、高亮点、关键词、主题和评分
- 保证结构化输出稳定,不允许自由散文式结果
4.5 质量标记
目标:
- 判断是否存在付费墙、截断、低信息密度等问题
- 为后续过滤器提供可用标志位
4.6 输出映射
目标:
- 将摘要结果映射为标准
document - 保持与上游
item的可追溯关系
5. 输入模型
5.1 标准输入结构
建议标准输入命名为 SummaryInput。
{
"item": {
"item_id": "sha256:xxx",
"source_id": "my-blog",
"title": "文章标题",
"url": "https://example.com/post/1",
"published_at": "2026-03-23T08:00:00Z",
"raw_summary": "RSS 摘要",
"raw_content": "RSS 正文片段",
"content_kind": "article",
"language": "zh"
},
"raw_html": "<html>...</html>",
"rss_content": "RSS 提供的正文内容",
"user_profile": {
"interests": ["AI", "workflow"],
"languages": ["zh", "en"]
},
"summary_style": "default"
}
5.2 输入字段说明
-
item- 标准主输入
- 推荐必填
-
raw_html- 可选
- 当调用方已经抓到网页 HTML 时可直接传入,避免重复抓取
-
rss_content- 可选
- 当调用方希望优先使用 RSS 正文时可单独传入
-
user_profile- 可选
- 用于后续个性化摘要、主题提取或兴趣打分
- 第一阶段可以不启用,但接口层建议预留
-
summary_style- 可选
- 用于控制摘要策略,例如
default、brief、detailed、bullet
5.3 最小可用输入
第一阶段建议只要求:
{
"item": {
"item_id": "sha256:xxx",
"title": "文章标题",
"url": "https://example.com/post/1",
"raw_summary": "RSS 摘要",
"raw_content": ""
}
}
6. 输出模型
6.1 标准输出结构
建议标准输出命名为 SummaryOutput。
{
"success": true,
"document": {
"document_id": "sha256:yyy",
"item_id": "sha256:xxx",
"source_id": "my-blog",
"url": "https://example.com/post/1",
"title": "文章标题",
"author": "作者",
"published_at": "2026-03-23T08:00:00Z",
"language": "zh",
"content_kind": "article",
"plain_text": "抽取后的正文",
"summary": "3-5句摘要",
"highlights": ["要点1", "要点2", "要点3"],
"keywords": ["rss", "mcp"],
"topics": ["workflow", "knowledge-base"],
"scores": {
"relevance": 0.91,
"novelty": 0.72,
"readability": 0.84
},
"quality_flags": {
"is_paywalled": false,
"is_truncated": false,
"is_low_content": false
},
"pipeline_state": "summarized"
},
"debug": {
"content_source": "fetched_html",
"extractor": "trafilatura",
"model": "summary-model-name"
},
"warnings": []
}
6.2 输出字段说明
-
success- 是否成功完成摘要流程
-
document- 标准输出主体
- 结构应尽量与
documentschema 对齐
-
debug- 可选
- 记录本次实际用了什么正文来源、抽取器和模型
- 便于后续排查问题
-
warnings- 可选
- 用于记录非致命异常,例如正文过短、内容疑似截断、元信息缺失
6.3 最小可用输出
{
"success": true,
"document": {
"document_id": "sha256:yyy",
"item_id": "sha256:xxx",
"title": "文章标题",
"url": "https://example.com/post/1",
"plain_text": "正文",
"summary": "3-5句摘要",
"highlights": ["点1", "点2"],
"scores": {
"relevance": 0.9
},
"pipeline_state": "summarized"
},
"warnings": []
}
7. 错误模型
7.1 为什么要有独立错误模型
如果 summary-core 只在失败时返回字符串错误,会导致:
- 上层流程难以判断是否应该重试
- 过滤器和编排层难以做自动决策
- MCP 或 Skill 封装时难以标准化输出
因此建议引入结构化错误模型。
7.2 建议错误结构
{
"success": false,
"error": {
"code": "CONTENT_FETCH_FAILED",
"message": "Failed to fetch article content",
"retryable": true,
"stage": "fetch",
"details": {
"url": "https://example.com/post/1"
}
},
"warnings": []
}
7.3 建议错误码
INVALID_INPUTCONTENT_FETCH_FAILEDCONTENT_EXTRACTION_FAILEDCONTENT_TOO_SHORTPAYWALL_DETECTEDSUMMARY_GENERATION_FAILEDUNSUPPORTED_CONTENT_KINDUNKNOWN_ERROR
7.4 建议错误字段
-
code- 机器可识别错误码
-
message- 人类可读错误信息
-
retryable- 是否建议重试
-
stage- 出错阶段,例如
normalize、fetch、extract、summarize
- 出错阶段,例如
-
details- 补充调试信息
8. 内容来源优先级策略
为了保证 summary-core 在不同输入条件下行为稳定,建议明确正文来源优先级。
推荐顺序:
raw_htmlitem.raw_contentrss_content- 根据
item.url回源抓取
解释:
- 如果调用方已经传入
raw_html,优先直接用,避免重复请求 - 如果 RSS 已经提供了高质量正文,可优先利用
- 如果 RSS 内容不足,再回源抓页面
这一策略需要在实现阶段进一步细化,例如通过长度阈值判断是否需要回源抓取。
9. 与 document schema 的关系
summary-core 的输出不应另起炉灶,而应尽量直接映射到 document。
建议遵守以下原则:
SummaryOutput.document与documentschema 保持高度一致summary-core只负责生成document,不负责直接写入知识库- 上游保留
item_id和source_id,确保可追溯
这样做的好处是:
- 下游过滤器只需要消费
document - 存储层无需理解摘要实现细节
- MCP 封装和 CLI 调用都可以复用同一结果结构
10. 调用方式兼容性
同一套接口建议兼容以下几种封装方式:
10.1 CLI
适合:
- 本地验证
- 单条 URL 调试
- 批处理脚本调用
建议形式:
summary-core input.jsonsummary-core --url https://example.com/post/1
10.2 HTTP API
适合:
- 被其他服务调用
- 作为统一后端能力暴露
建议形式:
POST /summarize
10.3 MCP Tool
适合:
- 给 OpenClaw、ChatGPT、Claude 等 Agent 调用
建议形式:
summarize_itemsummarize_url
10.4 Skill
适合:
- 让 Agent 在上下文中决定是否调用摘要流程
- 与其他工具组合编排
结论:
接口 schema 应保持统一,不因为调用方式不同而拆成不同语义模型。
11. 当前阶段的最小可用接口
第一阶段建议只实现一个最小接口:
输入:
{
"item": {
"item_id": "sha256:xxx",
"title": "文章标题",
"url": "https://example.com/post/1",
"raw_summary": "RSS 摘要",
"raw_content": ""
}
}
输出:
{
"success": true,
"document": {
"document_id": "sha256:yyy",
"item_id": "sha256:xxx",
"title": "文章标题",
"url": "https://example.com/post/1",
"plain_text": "正文",
"summary": "3-5句摘要",
"highlights": ["点1", "点2"],
"scores": {
"relevance": 0.9
},
"pipeline_state": "summarized"
},
"warnings": []
}
这个阶段先不要求:
- 个性化摘要
- 多风格摘要模板
- 批量接口
- 复杂质量评分
- 高级缓存策略
12. 后续可继续讨论的问题
SummaryInput是否必须包含完整item,还是允许只传 URLsummary_style是否应该在第一阶段就进入 schemadebug字段是否应面向开发环境可选开启- 错误码是否需要更细分成抓取类、抽取类、模型类
plain_text是否需要附带 token 数、字数等统计信息SummaryOutput是否需要保留原始抽取文本和最终摘要之间的映射信息
13. 当前阶段的一句话结论
当前阶段最合理的做法是先固定 summary-core 的统一输入输出契约,让它稳定接收 item,稳定产出 document,再在此基础上封装 CLI、MCP 和 Skill。