一眼看完
这套东西怎么切的
填不出来填 null,绝不编
entities / hero / news_type…
存进 doc jsonb
模板由代码按规则推
👆 Jeff 2026-08-13 定的切法。好处不是好看:换版式不用重跑 AI, 出错能定位到「哪个字段填错了」,闸门能逐字段查。
0. 一句话结论
能做,而且噱头不在「AI 写新闻」——那玩意儿满大街都是。 噱头在它长在聊天软件里(读完一条能直接甩进群里吵)和订阅制(你自己挑类别,不靠推荐算法猜)。
真正会决定生死的不是技术,是三件事:版权、配图、防幻觉。 这三件在下面各有一节。
0.1 这套东西到底是什么(Jeff 2026-08-13 定的形态)
Jeff 原话:「不要把它设计成『AI 帮新闻排版』,而是做成一个 AI News Studio + 群内新闻阅读器。 AI 负责当编辑,不负责乱画版面;排版引擎负责把 AI 的编辑决定变成漂亮且稳定的视觉。这两层一定要分开。」
四句话说清它和「新闻 app」的区别:
| 普通新闻 app | HOOP NOW | |
|---|---|---|
| 你在哪读 | 打开一个 app | 就在群里,读完能直接吵 |
| 读多久 | 一篇长文 | 三层:3 秒 / 10 秒 / 为什么重要(§3.0) |
| 一条新闻几张卡 | 一张 | 两张 —— 第二张是「为什么大家在讨论」(§3.5.3) |
| 你能做什么 | 👍❤️😂 | Explain / Ask AI / Discuss / Save / Follow(§3.9) |
⚠️ Jeff 那句必须刻在墙上的话:「漂亮是第二重要,新闻不失真才是第一重要。」 他给的例子:Reuters 报「Anthropic 据消息人士称正在洽谈收购 Decart AI,规模约 60 亿美元」—— AI 不许把标题写成「Anthropic 60 亿美元收购 Decart」,因为交易还没完成。 「据报道 / 洽谈 / 已完成」这几级必须原样保住。这条已经做成闸门 7(§3.6),不是靠提示词求它。
2.1 噱头在哪 —— 老实说
不在这儿: 「AI 每天写新闻」。这个 2026 年已经不稀奇,Apple 都做了(还翻车了)。
在这两条:
- 读完能立刻吵起来。 今日头条要你看完再去别处聊;我们的新闻本身就在聊天软件里 —— 一条金价新闻,长按甩进群、直接开投票「买不买」。别人要复制这个,得先有一个 IM。
- 订阅,不是喂你。 头条靠推荐算法猜你想看,越猜越窄;我们是你自己挑类别,每天固定几条。 在信息过载的今天,「少而准」反而是卖点。
⚠️ 一句实话:广度上打不过今日头条,别往那儿比。 我们赢在小、准、能社交。 Artifact 的教训就是:别做一个「又一个新闻 app」。
2.2 判据:什么算「高质量」(可测)
「高质量」不能停在形容词。定义成可测的:
| 指标 | 怎么量 | 及格线(建议,待拍板) |
|---|---|---|
| 来源可溯率 | 有原文链接且链接可达的条数 / 总条数 | 100%,低于就不发 |
| 事实锚定率 | 每条里的具体数字/人名/时间,能在源文本里找到的比例 | ≥ 95% |
| 重复率 | 同一天同一类里,讲同一件事的条数 | ≤ 1 |
| 时效 | 从源发布到我们推送的中位时长 | < 6 小时 |
| 打开率 | 推送 → 打开的比例 | 建立基线后再定 |
| 投诉/纠错数 | 用户报错条数 / 周 | 单条纠错 1 小时内能下架 |
3.1 分类怎么切
⚠️ 这一节有一处 Jeff 前后给了两套,我不替他合并,摆出来等他定(见 §6 第 9 条)。
Jeff 08-13 最新那段给的是五类(HOOP NOW 进群后那一行):
| 类别 | 为什么 |
|---|---|
| 🌍 World | 大盘子,人人有兴趣 |
| 💼 Business | 源规整、事实性强,数字类最容易验证 |
| 🤖 AI | 我们自己的读者最关心;Jeff 举的例子(Anthropic / Decart)就在这类 |
| ⚽ Sport | 高频、情绪强,天生适合甩进群吵 |
| 🎬 Entertainment | 用户面广 |
他更早那条语音点的是:财经、黄金、娱乐 + 我加的本地(马新)。
我的建议(要他一句话):在五类基础上加第六类 🇲🇾 Local(马新)。 理由:World/Business/AI/Sport/Entertainment 这五类,Apple News 和 Google News 都有, 而且比我们全;唯独马新本地新闻大平台覆盖薄 —— 那才是我们真能赢的一块。 黄金可以并进 Business,不单开一类。
⚠️ 类别数直接乘成本(见 §4):五类比四类贵 25%,六类贵 50%。 但绝对值很小($12 → $18 一个月),这一刀该按产品定,不该按成本定。
3.2 时区与节奏
- 时区一律
Asia/Kuala_Lumpur(UTC+8),和新加坡同一时区,不做多时区。 - 每类每天跑一次,清晨出稿。建议 06:30 生成 → 07:30 推送(赶上班前那一眼)。
- ⚠️ 待拍板:财经/黄金要不要加一次收盘后(比如 18:00)。加了成本翻倍。
1. 调研:外面是怎么做的,以及谁摔死了
1.1 Artifact —— Instagram 创始人做的 AI 新闻 app,做死了
这是最值得看的一个,因为他们做的事和我们要做的几乎一模一样,而且人、钱、技术都不缺。
- Kevin Systrom 2024 年 1 月宣布关停,app 2024 年 4 月正式下线。
- 官方理由(Systrom 原话):"the market opportunity isn't big enough to warrant continued investment" —— 「我们做出了一个核心用户很爱的东西,但市场盘子不够大。」
- 数字很难看:2023 年 2 月上线以来总下载 444,000,而且大部分集中在发布那几天,之后月下载量断崖。
- 地域极度失衡:美国占 44%,其他任何一个国家都不超过 4%。
- 2024 年 3 月,Yahoo 收购了它的个性化/推荐技术,并入 Yahoo News。
这对我们的三条启示(这是本节最重要的部分):
- 「单独一个新闻 App」是个坏生意 —— 用户手机里已经有 Apple News / Google News, 再装一个次要新闻 app 的动力很弱。⚠️ 而我们不是要做单独的 app,我们是长在 HOOP 里的一个小程序 —— 这恰好绕开了 Artifact 的死因。这是我们和它最大的结构性差别,不是运气。
- 他们的技术值钱,产品不值钱 —— Yahoo 买的是推荐引擎,不是那个 app。 说明「AI 处理新闻」这件事本身有价值,但要挂在一个已经有用户的地方。
- 留存比下载重要得多。 发布那几天冲一波然后掉光,是这类产品的标准死法。
来源: - TechCrunch — What happened to Artifact? - Mediagazer — Systrom 关停声明 - Failory — Why Artifact Failed - TechCrunch — Yahoo 收购 Artifact 技术
1.2 Apple 的翻车 —— AI 摘新闻编造标题,被 BBC 投诉到下架
这一节直接决定我们的「审核闸门」怎么设计,请当成必读。
Apple 在 iOS 18 的 Apple Intelligence 里加了「通知摘要」,把新闻 app 的推送自动缩写。结果:
- 把 BBC 的推送摘成 「Luigi Mangione 开枪自杀」 —— 事实是他活着且在羁押中。
- 摘出 「Luke Littler 赢得 PDC 世界飞镖锦标赛」 —— 比赛还没开始。
- 摘出 「Rafael Nadal 出柜」 —— 无中生有。
- 把《纽约时报》三篇文章缩成一条推送,称 「以色列总理内塔尼亚胡被捕」 —— 没这回事。
结果:2025 年 1 月,Apple 在 iOS 18.3 beta 里把新闻/娱乐类 app 的 AI 摘要功能整个关掉。 是 Apple 这种体量的公司,做的还只是「把已有文字缩短」这种最保守的任务。
⚠️ 我们要做的比这难得多 —— Apple 只是摘,我们是写。 Apple 用的还是原文做输入,而幻觉照样发生。
给我们的判据: - 「AI 只是摘要,所以不会编」是错的。 摘要照样编,而且编得像真的。 - 出事的成本不对称:一百条对的没人夸,一条编的能上新闻。 - 必须有「关掉」这个开关 —— Apple 的处理方式就是整个功能下架。我们要能做到同样的事(见 §5.5)。
来源: - CNN — Apple pulls AI-generated notifications for news - Axios — Apple pauses AI-generated news alerts - Daring Fireball — BBC 那几条的细节 - CBC — 报道汇总
1.3 配图 —— Unsplash / Pexels 到底能不能用
结论:Pexels 可以,Unsplash 有两个坑,而两家都有一个共同的大坑。
| Pexels | Unsplash | |
|---|---|---|
| 免费商用 | ✅ 允许,不强制署名(但用 API 时其指引要求链回 Pexels) | ✅ 授予不可撤销、非独占、全球范围的使用许可,可商用 |
| 用 API 时 | 指引要求链回 | ⚠️ 署名是强制的,不是「鼓励」——写在 API 服务条款里 |
| 致命限制 | — | ⚠️ 不得汇编图片去复制或与 Unsplash 竞争的服务 |
⚠️ 两家共同的大坑,而且这条对新闻最致命: 它们都不保证「肖像授权(model release)」。 只要图里有可辨认的真人,拿去做商业/宣传性质的使用,通常需要本人书面同意 —— 而这两家都不提供。
对新闻场景的实际含义: - 拿一张「路人甲在街上走」的图去配一条犯罪新闻 = 在暗示这个路人是嫌疑人。这是实打实的诉讼风险,不是理论风险。 - 所以:有人脸的图,一律不许自动配到新闻上。 这条要做成流水线里的硬闸门,不是靠提示词。
AI 生图当新闻配图,风险更大(这条是判断,不是查到的条文,标明): 真人肖像、灾难/战争场景、看起来像「现场照片」的合成图 —— 一旦被当成真实影像传播, 性质就从「配图不当」升级成「伪造新闻图片」。
⚠️ 建议(要 Jeff 拍板):新闻配图只用抽象/示意图(图表、色块、图标、纯风景), 永不生成或使用「看起来像新闻现场」的图。宁可难看,不可惹祸。
来源: - Pexels Terms of Service - Unsplash — 能否用于个人或商业项目 - LicenseOrg — Unsplash 署名在 API 下是强制的 - LicenseOrg — 免费图库的授权陷阱(含 model release)
1.4 版权:马来西亚 / 新加坡的实际法条
我们用户主要在马新,所以先查这两地,没有拿欧美的先例硬套。
马来西亚 —— 《Copyright Act 1987》(Act 332)。合理使用(fair dealing)看四个因素: 1. 使用的目的和性质(商业性 vs 非营利教育) 2. 被使用作品的性质 3. 使用部分的数量和实质性(相对于整部作品) 4. 对该作品潜在市场或价值的影响
新加坡 —— 新《Copyright Act 2021》,2021 年 11 月 21 日生效。 把这一条从 "fair dealing" 改名为 "fair use",并删掉了原来的第五个因素 (「能否以通常商业价格取得该作品」)。马新两地的合理使用四因素是同一套。
⚠️ 这对我们的含义,说实话: 四因素里,第 1 条(商业性)和第 4 条(是否影响原作市场)对我们都不利 —— 我们是商业产品,而且「让人不必去点原文」正是替代原作市场。
所以我的建议不是「靠合理使用抗辩」,而是根本别走到需要抗辩那一步: - 只取标题 + 极短事实性摘要,改写而非搬运; - 每条必须显著带原文链接和出处,把流量送回去而不是截留; - 绝不整篇转载,绝不做「不用点进去就看完」的长摘要。
⚠️ 这条我做不了法律结论,只能给出风险姿态。上线前建议找一次本地律师看条款 —— 这是要 Jeff 拍板的事。
来源: - Laws of Malaysia — Copyright Act 1987 (PDF) - Lexology — 新加坡新著作权法十大变化 - infojustice — Copyright Act 2021 的 fair use 修订 - Wikipedia — Copyright law of Malaysia
1.5 没查到 / 没查透的(诚实标注)
以下几项我没有查到可靠一手来源,不编:
- AP / Reuters / AFP 的授权价位 —— 公开网页查不到报价,这类都是一对一谈。要报价得直接联系他们。
- NewsAPI / GDELT 的商用条款细则 —— 没逐条读过它们的 ToS,不敢下结论。
- AI 生图的单张成本 —— 我们自己那条生图管线的单价我没现查,§4 的成本表里留空标注。
- Semafor Signals / Channel 1 AI 的内部分工 —— 没找到可靠的一手说明。
3.0 🧱 新闻框架 —— AI 编辑部和排版之间的唯一契约(Jeff 2026-08-13 定的第一步)
Jeff 原话:「新闻分两部分:AI 负责编辑,定新闻的框架,框架用 JSON 存…… 这个框架是我们第一步要做的。」
这一刀比「AI 写文章 → 排版渲染文章」狠得多,值得先说清好在哪:
| 「AI 写一篇稿子」 | 「AI 填一张表」(Jeff 这版) | |
|---|---|---|
| 排版怎么知道重点 | 得去猜哪句是重点 | 重点是字段,不用猜 |
| 换版式 | 要重跑 AI | 不用碰 AI,同一份 JSON 换个模板重渲 |
| 出错怎么定位 | 「这篇写坏了」 | 「key_numbers[1] 填错了」 |
| 闸门怎么查 | 拿正则去捞文章里的数字 | 逐字段查,查得动(§3.6) |
| 双语 | 翻译整篇 | 只翻三个字段 |
判据:排版层永远不许去读 body 猜结构。 它要的每样东西,框架里都得有一个字段。
⚠️ importance 我建议用 1-5 整数,不用 8.7/10(原方案给的刻度)。
模型给不出稳定的 8.7 和 8.6 的差别 —— 换个 prompt、换个批次就变。
假精度的坏处不是"不够准",是你会拿它去排序,而它其实是噪音。
1-5 整数(或者干脆 breaking / big / normal 三档)反而稳。这条待 Jeff 拍板(§6 第 12 条)。
框架长什么样(v1)
{
"schema_version": 1, // 框架会变;旧稿要还能渲染,靠这个
"id": "uuid",
"run_date": "2026-08-14",
"category": "finance", // finance | gold | entertainment | local
"lang": "en", // 每种语言一份 doc,不在一份里塞两套
// —— 这条是什么新闻 ——
"news_type": "big_story", // 见下表,决定版式的主变量
"importance": 4, // ⚠️ 见下方「假精度」那条:建议 1-5 整数,不用 8.7/10
"status": "developing", // developing | confirmed —— 版面上要显示
"fact_level": "reported_talks", // ⚠️ 事实层级,见 §3.6 闸门 7,**不许被升级**
// —— 三层阅读(Jeff 08-13 加的,这是产品的核心手感) ——
"layer1_3s": "Anthropic 据报洽谈约 US$6B 收购 Decart AI", // 3 秒看到 · ≤ 60 字符
"layer2_10s": "Claude 开发商 Anthropic 正在讨论收购 Nvidia 支持的 AI startup Decart AI。若交易达成,规模可能约 60 亿美元。",
"layer3_why": "如果交易完成,意味着 Anthropic 正进一步扩张 AI 基础设施和技术能力。", // 为什么重要
"subheadline": "Reportedly in talks to acquire Decart AI", // ≤ 90 字符,可为 null
"body_blocks": [ // 点进去那条 Story 的正文;列表页只用上面三层
{"type": "para", "text": "……"},
{"type": "bullet", "items": ["……", "……"]},
{"type": "quote", "text": "……", "speaker": "Anwar Ibrahim", "source_ref": 0}
],
// —— 第二张卡(Jeff 08-13 加:同一则新闻,AI 自动创造第二张) ——
"second_card": { // 可为 null;不硬凑
"kind": "why_talking", // why_talking | what_it_means | bull_vs_bear
"title": "WHY PEOPLE ARE TALKING ABOUT THIS",
"points": ["……", "……"],
"bull": null, "bear": null // kind = bull_vs_bear 时才填这两个
},
// —— 事实锚点(防幻觉的主力) ——
"key_numbers": [
{"label": "Gold spot", "value": 2401.50, "unit": "USD/oz",
"change": 1.8, "change_unit": "%", "direction": "up",
"as_of": "2026-08-14T09:00:00+08:00", "source_ref": 0}
],
"entities": [
{"name": "Bank Negara Malaysia", "type": "org"}, // person|org|place|ticker|event
{"name": "Kuala Lumpur", "type": "place"}
],
"location": {"country": "MY", "city": "Kuala Lumpur", "scope": "national"},
// —— 判断类(必须和事实类分开存) ——
"sentiment": {"tone": "positive", "score": 0.62, "subject": "gold market"},
"credibility": {"score": 88, "source_count": 3, "top_tier": true,
"corroborated": true, "method": "computed_v1"},
// —— 版面 ——
"hero": {"kind": "chart", "chart": {"series": "XAUUSD", "window": "1M"},
"image_url": null, "credit": null, "alt": "Gold price, past month"},
"layout": {"template": "hero_number", "picked_by": "rules_v1"}, // ⚠️ 不是 AI 挑的
// —— 出处与留证 ——
"sources": [
{"publisher": "Reuters", "url": "https://…", "published_at": "…", "item_id": "uuid"}
],
"gates": {"…": "闸门逐项结果,见 §3.6"}
}
news_type 全表(这一栏决定版式)
这一栏和 §3.5 的八种母版一一对应 —— 一个名字管到底,不要「新闻类型」和「版式」两套词 (两套词就要一张手工对照表,一写就腐,铁律 23)。
| 值 | 什么时候用 | 它必须有 | MVP |
|---|---|---|---|
breaking |
突发 / 重大事件 | location 或 entities ≥ 1 |
✅ |
big_story |
重要 / 影响深远 | key_numbers ≥ 1 或 hero |
✅ |
normal |
日常 / 一般性新闻 | — | ✅ |
data |
含数据 / 讲趋势 | key_numbers ≥ 1 |
✅ |
explainer |
需要解释 / 背景知识 | body_blocks 里 ≥ 3 段 |
✅ |
quote |
名人发言 / 官方声明 | body_blocks 里有 quote |
— |
timeline |
事件发展过程 / 时间线 | timeline[] ≥ 3 项 |
— |
multi |
简报 / 多条新闻一览 | 引用 ≥ 3 条别的 article | — |
⚠️ MVP 那一栏是 Jeff 定的:「我甚至不会先做 100 种新闻。先做 Breaking / Big Story / Normal / Data / Explainer 五种,把这五种做到非常漂亮,再让 AI 自动选择。」
⚠️ 三条硬规矩(这三条是这份框架真正值钱的地方)
① AI 在闭集里选版式,代码验它选得合不合法。
⚠️ 这一条我改过。 我原来写的是「版式由代码推出来,AI 一个字都不许决定」。 Jeff 08-13 那段说的是「AI 判断新闻 → AI 选择视觉语言 → 排版引擎生成, 这才会看起来像 AI 在设计」「AI 负责审美决定,Renderer 负责精准执行」。 他是对的,而我那条太紧了 —— 全靠规则推,出来的东西一辈子长一个样, 那就不是「AI 在设计」,是「模板套娃」。
改成两半,各管各的:
- AI 有审美决定权,但只能在 §3.5 那 8 个母版里选一个(闭集,不许自由发挥画图)。
- 代码当守门员:选中的母版声明了它要哪些字段(见 §3.0 news_type 全表),
字段不齐 → 驳回,自动降到能满足的那个;全不满足 → 落 normal(兜底,不许没有)。
驳回要记进 gate_report,别静默改掉 —— 静默降级会让人以为 AI 选得很准。
判据:AI 挑的是「哪种视觉语言」,不是「这里字号多大、留白多少」。 后者永远归 Renderer —— 那才是「今天很漂亮明天很丑」的根源(Jeff 原话)。
② 填不出来就填 null,绝不许编。
框架里没有一个字段是"必须编一个出来"的(除了 headline/summary)。
key_numbers 里每个数字必须带 source_ref,指向 sources 里的第几条 ——
指不出出处的数字,不许进框架。这一条把「事实锚定率 ≥ 95%」(§2.2)从口号变成可查的。
③ credibility 不许让写稿那个模型自己打。
自己给自己打分永远是高分。P0 用算的(method: "computed_v1"):
源的层级(通讯社/官媒/自媒体)× 印证条数(几家独立报了同一件事)× 有没有官方一手来源。
要上模型打分,也得是另一个调用、看不到写稿过程。
存哪儿
news_articles 的正文部分整份存 jsonb,不再拆成 headline/body 两列:
news_articles
…
doc jsonb -- ⬅️ 上面那份框架,整份存
schema_version int -- 冗余出来做索引和迁移
headline text GENERATED -- 从 doc 生成,只为了列表页查得快
news_type text GENERATED
importance int GENERATED
INDEX (category_key, run_date, importance DESC)
为什么 headline 用 generated 而不是各存一份: 手抄一份就会腐(铁律 23)。
真相只有 doc 一处,索引列是它的投影,不是副本。
⚠️ 待 Jeff 拍板(这份框架本身): 上面这些字段够不够、有没有多余的。我建议 v1 就到这里,先跑起来再加 —— 字段一旦发出去就有旧稿在用它,加容易删难。
3.5 News Design System —— 八种母版(Jeff 08-13 出了版式库图)
Jeff 原话:「我反而不建议每一则新闻都叫 AI 自由发挥画一张图。因为那会发生一个问题: 今天很漂亮,明天很丑;这一篇像杂志,下一篇像海报;整个 HOOP 里面完全没有品牌语言。 应该建立一个 News Design System:只给 AI 6-8 种非常高级的母版,但每种母版内部可以自动变化。」
「一套 template 重复 100 次」和「AI 每次自由发挥」都不对。 中间那条路是: 母版是闭集(8 个),母版内部按内容自动变化(字号、图 crop、留白、数字位置这些归 Renderer)。
| # | 母版 | 什么新闻用它 | 版面长什么样 | MVP |
|---|---|---|---|---|
| 01 | BREAKING | 突发 / 重大事件 | 超大标题 + 强视觉,红标 | ✅ |
| 02 | BIG STORY | 重要 / 影响深远 | 大图 + Headline + Key Fact 三小格 | ✅ |
| 03 | NORMAL | 日常 / 一般性 | 左图右文 + 简短摘要 | ✅ |
| 04 | DATA | 含数据 / 讲趋势 | 大数字 + 图表 | ✅ |
| 05 | EXPLAINER | 需要解释 / 背景 | 3 张解释卡(①②③) | ✅ |
| 06 | QUOTE | 名人发言 / 官方声明 | 人物照 + 引号 + 一句话 | — |
| 07 | TIMELINE | 事件发展过程 | 时间轴 | — |
| 08 | MULTI-NEWS | 简报 / 多条一览 | 2×2 瀑布流「今日要闻速览」 | — |
MVP 先做前五种,做到非常漂亮(Jeff 定的),后三种留到 P2。
📐 母版必须按聊天气泡的真实宽度设计,不是按网页宽度
从 app/lib/screens/chat_screen.dart 量的真实约束(不是估的):
图文气泡 屏宽 × 0.76,纯媒体气泡 屏宽 × 0.86。
| 机型 | 图文气泡最宽 | 纯媒体气泡最宽 |
|---|---|---|
| iPhone 16 Pro Max | 334 pt | 378 pt |
| iPhone 15/16 标准 | 299 pt | 338 pt |
| iPhone SE / mini | 285 pt ← 按这个设计 | 322 pt |
⚠️ 判据:新闻卡要在 285 pt 宽也不崩。 拿「展示网页」的尺寸做出来的母版,
塞进聊天窗口一定要重做一遍 —— 大数字会撑破、三栏会挤成一坨。
Data 母版那个「大数字」尤其危险:$6B 没事,RM 1,234,567 就要换行策略。
3.5.1 为什么必须 LLM → Design JSON → Renderer,而不是 LLM → PNG
Jeff:「你的绘图软件拿这些数据,自动决定字号、字重、图片 crop、留白、渐变、卡片高度、 数字位置、logo 位置。AI 负责审美决定,Renderer 负责精准执行。」
LLM → 直接出 PNG |
LLM → Design JSON → Renderer |
|
|---|---|---|
| 稳定性 | 每张都在赌 | 同样输入永远同样版面 |
| 改品牌色/字体 | 全部重画 | 改 Renderer 一处,历史全变 |
| 能不能测 | 不能 | 能 golden(版式坏了是代码 bug) |
| 成本 | 每张都要生图 | 几乎为零 |
| 出错 | 「这张丑」 | 「key_number 太长撑破了」 |
3.5.2 点进去是一条 Story,不是一篇文章
Jeff 给的骨架(封面卡只是入口):
01 — What happened 一句话
02 — The number $6B ← 一个巨大数字
03 — Who is Decart? 小解释
04 — Why it matters AI 解读
05 — Source Reuters 原始报道
这五段直接对上框架里的字段:layer1_3s / key_numbers[0] / body_blocks /
layer3_why / sources[0] —— 没有一段需要 Renderer 去猜。
3.5.3 第二张卡(Jeff 08-13 加的,我原来完全没有)
「同一则新闻,AI 自动创造第二张卡。第一张是 WHAT HAPPENED, 第二张不是重复新闻,而是 WHY PEOPLE ARE TALKING ABOUT THIS / WHAT THIS MEANS / BULL vs BEAR。这样『新闻』开始变成一种可以刷的内容产品。」
框架里对应 second_card(§3.0)。三条实现纪律:
- 允许为
null—— 没话说就别硬凑第二张,凑出来的就是废话卡。 bull_vs_bear只给财经/市场类,而且正反两面都要有source_ref—— 否则它就是「AI 的看法」,那是评论不是新闻。- 第二张卡同样要过闸门(§3.6):它更容易编,因为它天生是「解读」。
⚠️ bull_vs_bear 有合规风险,原方案没提到,这里补上(2026-08-13 我评审时发现):
自动生成「看多 vs 看空」就是在给投资意见,马新对投资建议有牌照门槛。三条硬要求:
1. 正反两面都必须有 source_ref —— 是「谁说的」,不是「AI 觉得」;
2. 卡上硬标「非投资建议」,不是藏在设置里的免责声明;
3. 不许出现买/卖倾向动词(建议买入/应该减仓/值得上车…)—— 做成词表闸门,和闸门 7 一个做法。
判据:我们是「转述别人的多空看法」,不是「我们看多」。 这两件事在法律上不是一回事。
表关系图
👇 这张图不是画的,是从下面那段 schema 里解析出来生成的 —— 加一张表、改一个 FK,图会自己跟着变(手抄一张就会腐,铁律 23)。绿箭头 = 外键指向,虚线框 = 外部表。
3.3 数据表(字段级)
HOOP 用 Postgres + UUIDv7。迁移号要从
backend/migrations/LEDGER.md取一个,取完立刻 +1 写回 —— 本图纸阶段不占号、不写迁移文件。
news_sources -- 我们订了哪些源
id uuid PK
name text -- 「Reuters 商品」
kind text -- 'rss' | 'api'
url text
category_key text -- 冗余:这个源主要喂哪一类
publisher text -- 出处署名,发到用户面前的那个名字
enabled bool default true
last_ok_at timestamptz -- 上次成功抓取;监控用
last_error text
created_at timestamptz
news_categories -- 类别
key text PK -- 'finance' | 'gold' | 'entertainment' | 'local'
name_en text
name_zh text
sort_order int
enabled bool default true
news_items -- 抓回来的原始条目(未加工)
id uuid PK
source_id uuid FK -> news_sources
external_id text -- 源自己的 guid;去重用
title text
summary text -- 源给的摘要,不是我们写的
url text -- 原文链接
published_at timestamptz
fetched_at timestamptz
cluster_id uuid NULL -- 聚类后回填:同一事件的多条指向同一个
UNIQUE (source_id, external_id)
news_articles -- 我们生成的稿件(全平台共享,不分用户)
id uuid PK
category_key text FK -> news_categories
run_date date -- 哪一天那一跑
doc jsonb -- ⬅️ §3.0 那份新闻框架,整份存;正文的唯一真相
schema_version int -- 冗余出来做索引和迁移
headline text GENERATED -- 从 doc 投影,只为列表页查得快,不是副本
news_type text GENERATED
importance int GENERATED
status text -- 'draft'|'passed'|'blocked'|'published'|'retracted'
gate_report jsonb -- 闸门逐项结果,留证
model_id text -- 哪个模型写的
token_in int
token_out int
created_at timestamptz
published_at timestamptz NULL
retracted_at timestamptz NULL
retract_reason text NULL
INDEX (category_key, run_date, importance DESC)
news_article_sources -- 一条稿件用了哪些源(多对多),防幻觉的锚
article_id uuid FK -> news_articles
item_id uuid FK -> news_items
PRIMARY KEY (article_id, item_id)
news_subscriptions -- 谁订了哪一类
user_id uuid FK -> users
category_key text FK -> news_categories
created_at timestamptz
PRIMARY KEY (user_id, category_key)
news_deliveries -- 推送记录(幂等 + 可回溯)
id uuid PK
user_id uuid FK -> users
article_id uuid FK -> news_articles
delivered_at timestamptz
opened_at timestamptz NULL
UNIQUE (user_id, article_id) -- ⚠️ 这个唯一键就是防重复推送的全部保证
⚠️ 两个设计要点,别改:
1. news_articles 里没有 user_id —— 稿件是全平台共享的。这是成本能不能扛住的关键(§4)。
2. news_article_sources 是必须的,不是可选的 —— 没有它,「每条都有出处」就是一句口号。
每天那一跑
7 道闸门
任何一项不过 → blocked,当天这条不发。⚠️ 这几关必须是代码,不是提示词。
news_article_sources 至少一行,且链接可达fact_level 与源一致;源写「洽谈/据报道」,稿子里不许出现「已收购/达成」3.6 审核闸门(这是整套里最重要的一段)
每一条稿件在发布前,必须逐项过下面这几关。任何一项不过 → blocked,当天这条不发。
⚠️ 闸门 7 是 Jeff 2026-08-13 点名要的,他的原例:Reuters 报「Anthropic 正在洽谈收购 Decart AI」→ AI 不许把标题写成「Anthropic 60 亿美元收购 Decart」,交易还没完成。 怎么做成代码而不是提示词:
fact_level 五级(从弱到强):
rumor(传闻) < reported_talks(据报道洽谈) < confirmed_talks(双方证实在谈)
< agreed(已达成协议) < completed(已完成)
判法:① AI 填的 fact_level,必须能在源文本里找到对应措辞(in talks / reportedly / agreed…)
② 三层阅读 + headline 里,不许出现比 fact_level 更强的动词
—— 维护一张「更强动词」词表(收购/完成/达成 vs 洽谈/据报道),命中就 blocked
③ status = developing 时,版面上**必须**显示「Developing」角标
⚠️ 闸门 2 和 3 是「防 Apple 那一类翻车」的核心 —— Apple 那几条编造的共同点就是 摘要里出现了源文本中没有的事实(自杀、夺冠、出柜、被捕)。
⚠️ 这几关必须是代码,不是提示词。 「求模型别编」不是闸门;在源文本里 grep 得到才算数。
📌 Jeff 那一刀让闸门 2 从"能做"变成"好做":数字不再是从一坨正文里正则捞出来的,
而是 key_numbers[] 里一个一个躺着的,每个还自带 source_ref 指到哪条源。
所以闸门 2 变成:遍历 key_numbers,拿 value 去 sources[source_ref] 的原文里找,
找不到就 blocked —— 精确到"是第几个数字错了",不是"这篇有问题"。
闸门 3 同理走 entities[]。这是内容与排版分家顺带买一送一的好处。
3.7 人在哪一环 —— 全自动 ≠ 无人把关
Jeff 要的是「全自动化」。全自动可以,但必须答出这三个问题:
| 问题 | 答案 |
|---|---|
| 谁能停? | 每类都有 enabled 开关;一键关掉某类当天推送 |
| 出事怎么撤? | status = 'retracted' + retracted_at + 原因;已推送的要能撤 |
| 多久能撤? | 目标:发现到下架 < 1 小时(见 §2.2) |
⚠️ 撤稿这条路必须在 P0 就通 —— Apple 的教训是:出事时你需要的是一个开关,不是一次发版。
3.8 失败与降级 —— 宁可不发,不发旧的
| 挂了什么 | 怎么办 |
|---|---|
| 某个源挂了 | 跳过它,用其余的源照常出;记 last_error |
| 一整类的源全挂 | 这一类今天不发。 不发比发错好 |
| 模型挂了 / 超时 | 重试 2 次(退避)→ 仍失败则该类不发 |
| 闸门不过 | 该条不发;若整类都不过 → 该类不发 |
| 发旧的? | ❌ 绝不。 新闻发旧的比不发更糟 —— 用户会以为那是今天的事 |
判据一句话:这套东西「安静地没发」是可接受的,「发错」不可接受。
3.9 群里的动作条 —— 新闻 → 群 → AI → 讨论(Jeff:这比排得漂亮重要得多)
Jeff 原话:「用户下面不是只有 👍❤️😂,而可以有 Explain / Ask AI / Discuss / Save / Follow。 用户点 Ask AI 就可以直接问『这会不会威胁 Nvidia?』然后在这条新闻下面直接和 AI 聊。 这就非常 HOOP 了 —— 不是『新闻 app → 看新闻』,而是『新闻 → 群 → AI → 讨论』。 这个我觉得比单纯把新闻排得漂亮重要得多。」
我同意,而且这条是护城河本身:排版谁都能抄,「新闻长在一个有群的 IM 里」抄不走(§2.1)。
| 动作 | 干什么 | 落在哪 | 难度 |
|---|---|---|---|
| Explain | 就这条新闻,给一段更浅的解释 | 复用 layer3_why + 追加一次调用 |
低 |
| Ask AI | 在这条新闻下面直接问 | 起一条带上下文的 AI 回复,上下文 = 这条 doc + 源文本 | 中 |
| Discuss | 把这条甩进群,开一条讨论 | 复用已有的转发 + 群消息 | 低(地基已有) |
| Save | 收藏 | 一张 news_saves 表 |
低 |
| Follow | 追这条线后续 | 跟 cluster_id 走,有后续就推 |
中 |
⚠️ 三条设计纪律(不写清楚会出事):
- Ask AI 的上下文只有「这条 doc + 它的源文本」 —— 不许它带着整个互联网的记忆来答。 否则用户问「这会不会威胁 Nvidia」,它会拿训练里的旧事实回答,而那些没过我们的闸门。
- AI 的回答必须视觉上和新闻正文区分开,并标「这是 AI 的看法,不是报道」。 Apple 那次翻车(§1.2)就是用户分不清哪句是新闻、哪句是 AI 生成的。
- 群里问的,群里能看见 —— Ask AI 的问答落在那条新闻下面,不是私聊; 否则同一个问题群里五个人各问一遍,五份成本、五个答案。
4. 成本(按现价算,标了查询日期)
价格查询日期 2026-08-13,来源 = claude-api skill 的模型价目表(缓存日期 2026-06-24):
| 模型 | 输入 $/1M tok | 输出 $/1M tok |
|---|---|---|
Claude Opus 5 (claude-opus-5) |
$5.00 | $25.00 |
Claude Sonnet 5 (claude-sonnet-5) |
$3.00(introductory $2.00,到 2026-08-31) | $15.00(intro $10.00) |
Claude Haiku 4.5 (claude-haiku-4-5) |
$1.00 | $5.00 |
假设(明写,方便你改): - 4 个类别,每类每天跑 1 次 - 每跑一次:输入 ≈ 20,000 tok(源摘要 + 提示词),输出 ≈ 6,000 tok(5 条 × 约 1,200 tok)
每月成本(30 天):
| 模型 | 每类每天 | 4 类每天 | 每月 |
|---|---|---|---|
| Haiku 4.5 | $0.020 + $0.030 = $0.05 | $0.20 | ≈ $6 |
| Sonnet 5(intro 价) | $0.040 + $0.060 = $0.10 | $0.40 | ≈ $12 |
| Sonnet 5(标准价) | $0.060 + $0.090 = $0.15 | $0.60 | ≈ $18 |
| Opus 5 | $0.100 + $0.150 = $0.25 | $1.00 | ≈ $30 |
⚠️ 三个必须看懂的点:
- 文本成本低到可以忽略。 就算全用 Opus 5,一个月也就 30 美金上下。 真正的成本变量是「类别数 × 每天跑几次」,不是模型档次。 加到 10 类、一天跑 2 次 → 直接 ×5。
- 成本和用户数无关 —— 因为稿件是共享的(§3.3)。 ⚠️ 如果哪天有人提议「给每个用户单独生成」,那一刻成本就从「和类别数成正比」变成「和用户数成正比」。这是这个产品最经典的死法。
- 配图成本没算进去 —— 我没现查我们那条生图管线的单价。⚠️ 待补。 若一天 20 张图,这一项很可能比文字贵。
建议:P0 用 Sonnet 5 起步(质量够、便宜),把 Opus 5 留给「财经/黄金」这类出错代价高的类别。 ⚠️ 这条是建议,待 Jeff 拍板。
5. 分阶段
P0 —— 最小能跑通(验收:一条真新闻,端到端出现在手机上)
- 第 0 件事:把 §3.0 那份框架落成真 schema(Jeff 定的第一步)——
JSON Schema 一份 + Go struct 一份,两边由同一份生成,不许手抄两份(铁律 23)。
模板挑选那个规则函数先写测试:给一份 doc,断言它挑中哪个模板;字段全缺时必须落到
plain。 - 五种母版做到非常漂亮(Breaking / Big Story / Normal / Data / Explainer)—— Jeff 定的:「我甚至不会先做 100 种新闻。」剩下三种(Quote / Timeline / Multi)留 P2。 ⚠️ Renderer 先于 AI 做:五种母版拿手写的假数据先渲染出来给 Jeff 看, 他点头了再接 AI —— 否则会拿「AI 写得不好」去解释「版式不好看」,两个问题搅在一起。
- 类别每天 1 次、只用 RSS 源(几类等 §6 第 9 条拍板)
- 表:
news_sources/news_categories/news_items/news_articles/news_article_sources - 闸门:1(有出处)+ 2(数字锚定)+ 5(长度)+ 7(事实层级不许升级) 四关先上 ⚠️ 闸门 7 进 P0 不进 P1 —— Jeff 那句「新闻不失真才是第一重要」说的就是它
- 三层阅读要全(3 秒 / 10 秒 / 为什么重要);第二张卡不进 P0(它更容易编)
- 不配图(先跑通文字,图是第二难的问题)
- 撤稿开关必须通
- 验收:同一条新闻,源里能查到出处;闸门故意喂一条编的进去,必须红; 再喂一条「源写洽谈、稿子写已收购」的,闸门 7 必须红
P1 —— 订阅与推送
news_subscriptions/news_deliveries- App 里的订阅界面 + 每天推送
- 闸门补齐 3(专名)、4(无人脸)、6(单源孤证)
- 群里的动作条(§3.9):先上 Discuss + Save(地基已有),Ask AI 也放这一档 —— Jeff 说它比排得漂亮重要得多,不该等到 P2
- 第二张卡(why_talking / what_it_means)——
bull_vs_bear留到有财经类再说 - 验收:同一条稿件推给 100 个订阅者,
news_deliveries不能有重复行; Ask AI 的回答在视觉上和报道正文分得开,并标了「这是 AI 的看法」
P2 —— 配图与社交
- 配图(抽象图为主)+ 人脸闸门(闸门 4)
- 「甩进群 + 一键开投票」 ←—— 这是噱头本体,别拖到最后
- 指标看板(§2.2 那张表)
⚠️ 我个人建议把 P2 的「甩进群」提前到 P1 —— 那才是我们和今日头条的差别; 纯看新闻的部分,我们本来就不占优。这条要 Jeff 拍板。
要你拍板的 13 条
news_type、status、body_blocks、entities、schema_versionimportance 用 1-5 整数还是 8.7/10 一位小数6. ⚠️ 要 Jeff 拍板的(我没有替你决定)
7. 这份图纸没做的事(边界)
- ❌ 小程序平台的任何设计 —— 归 Fable(Jeff 2026-08-13 明确)
- ❌ 任何代码、迁移文件、迁移号
- ❌ 部署与发版
写于 2026-08-13 · Vega(平台架构/接缝线) 下一步:等 Jeff 看完 §6 那几条,拍完板再谈动手。