Files
planet/docs/technical/zh/earth-news-sources.md
linkong 3265d22af5
Some checks failed
ci / backend (push) Has been cancelled
ci / frontend (push) Has been cancelled
release / images (push) Has been cancelled
ci / delivery (push) Has been cancelled
release: bump version to 0.71.1
2026-06-26 17:34:19 +08:00

18 KiB
Raw Blame History

Earth 新闻源配置

Earth 态势新闻使用 /api/v1/news/earth-feed 输出给前端。新闻源配置存放在 SystemSetting.category = "earth_news_sources";没有数据库配置时,后端使用内置默认源作为 fallback seed。

默认源

默认源包含四类:

  • 新闻源BBC World、DW Top Stories、CNBC Business、BBC Business、Guardian Business、NPR Business、MarketWatch、TechCrunch、Retail Dive、PR Newswire Retail、36氪、亿邦动力、国家统计局数据发布。
  • 行业洞察源McKinsey Retail、Deloitte Retail。
  • 官方数据源国家统计局数据发布、US Census Retail / E-Commerce、商务数据中心、商务部电商动态、电商物流指数。
  • 线索源BusinessWire Electronic CommerceGoogle News 作为一个聚合 source下面挂 global / americas / europe / middle-east-africa / asia-pacific 五个区域 Feed 子项。

配置型数据源默认保留在 Admin 配置中,但若不是稳定 RSS/Atom则默认不参与自动抓取。管理员可以在 Earth 内容 -> 新闻源 中改成可抓取 RSS、启用或禁用。

来源 类型 默认状态 默认主类型 主要标签 用途
BBC World RSS 启用 政治 official_media, global 全球公共新闻基线
DW Top Stories RSS 启用 政治 official_media, europe 欧洲与国际新闻基线
CNBC Business RSS 启用 商业 business_news, us, global 国际商业新闻
BBC Business / Guardian Business / NPR Business / MarketWatch RSS 启用 商业 / 金融 business_news, finance 英美商业与金融基线
TechCrunch / Retail Dive / PR Newswire Retail RSS 启用 科技 / 商业 business_news, ecommerce, retail, press_release 科技、电商、零售和企业公告
36氪 RSS 启用 商业 business_news, ecommerce, china 国内商业、创投和快讯;主页是 https://www.36kr.com/Feed 信息页是 https://www.36kr.com/rss-centerFeed 子项是综合资讯、文章资讯、最新快讯、动态内容
亿邦动力 RSS 启用 电商 ecommerce, business_news, china, retail 国内电商行业新闻;主页是 https://www.ebrun.com/Feed 信息页是 https://www.ebrun.com/rss/Feed 子项是 B2C、B2B、零售、O2O、服务、数据、政策 XML
国家统计局数据发布 RSS 启用 电商 official_data, ecommerce, retail, china 官方数据发布 RSS社零和网上零售条目由分类/重要度规则识别
Google News Aggregated 启用 政治 aggregated, low_stability 一个聚合 sourceFeed 子项为全球、美洲、欧洲、中东与非洲、亚太区域兜底 RSS优先级低于真实 RSS
BusinessWire Electronic Commerce Reference 禁用 电商 press_release, ecommerce, low_stability 企业公告线索
McKinsey Retail Insights Reference 禁用 商业 industry_insight, retail 零售行业洞察
Deloitte Retail Reference 禁用 商业 industry_insight, retail 零售行业洞察
US Census Retail / E-Commerce Reference 禁用 电商 official_data, ecommerce, retail, us 美国零售和电商官方数据
商务数据中心 Reference 禁用 商业 official_data, china 国内商务数据
商务部电商动态 Reference 禁用 电商 official_data, ecommerce, china 国内电商政策与动态
电商物流指数 Reference 禁用 电商 official_data, ecommerce, logistics, china 物流履约与电商景气度

Reference 源表示参考链接/未来采集器线索,只记录官网、报告页或数据页,不参与 RSS/Atom 抓取。这样可以把商业与官方数据源先纳入后台治理,同时避免不可抓取页面拖垮新闻 feed。

新闻源模型是两层结构:

  • source 表示来源品牌或聚合器,例如 36氪、亿邦动力、Google News、BBC。
  • homepage_url 表示来源官网、栏目页或报告页。
  • feed_directory_url 表示 Feed 信息页,也就是 RSS 订阅中心或 Feed 聚合页,只用于人工查看,不参与抓取。
  • feeds 表示该来源下真正抓取的 RSS、Atom 或 Aggregated 子项。每个 Feed 子项都有 id / name / url / type / enabled / default_category / tags / priority

后端会遍历同一 source 下所有启用的 Feed 子项,逐个抓取、合并去重,并把单个子项的检测结果写入 health.feed_results。这不是“备用地址”逻辑36氪的四个订阅地址、亿邦的多个分类 XML、Google News 的五个区域 RSS 都可以同时启用,并且每个 Feed 可以单独配置默认新闻类型和启用状态。HTML 订阅中心或聚合页只能放在 feed_directory_url,不能放进 Feed 地址。默认启用的可抓 Feed 已逐项连通性检测RSS/Atom/Aggregated Feed 必须解析到条目Reference 源只保留参考地址和后续采集器线索。

当前仍保留为 Reference 的项不是“坏源”,而是没有找到稳定、可直接消费的 RSS/Atom

  • BusinessWire 官方说明支持可定制 RSS/Atom但公开页面未暴露稳定行业 feed URL当前保留电子商务行业页作为公告线索。
  • McKinsey / Deloitte 的零售洞察页是报告和文章集合,不是公开 RSS。
  • US Census 的 press release RSS 可访问但条目链接为空Quarterly E-Commerce 页面保留为官方数据参考链接。
  • 商务部数据、电商物流指数目前未找到稳定 RSS后续应做专用 collector 或人工配置可抓 feed。

源属性标签与新闻类型

新闻源有 source_tags,在 Admin 中显示为“源属性标签”。它用于描述 source 的属性,不是媒体来源名,也不是新闻条目的内容类型。例如:

  • official_data:官方数据
  • business_news:商业新闻
  • ecommerce:电商
  • finance:金融
  • retail:零售
  • logistics:物流
  • industry_insight:行业洞察
  • press_release:企业公告
  • chinaglobalus
  • aggregatedlow_stability

单条新闻有一个主类型 category,默认类型包括:政治、商业、电商、金融、体育、科技、军事、灾害、能源、社会、文化、其他。item_tags 是条目级补充标签例如跨境电商、直播电商、零售数据、物流履约、平台治理、AI、半导体、选举、油价、足球、供应链。

主类型优先由规则引擎根据标题、摘要、来源名打分生成;规则未命中时优先使用 Feed 子项的默认类型,再回退 source 默认类型。AI enrichment 不阻塞新闻展示。

重要度

每条新闻输出:

  • importance_score
  • importance_level
  • importance_reasons
  • market_impact

官方数据源、电商指标、平台型公司、量化指标会提高重要度;企业公告基础权重较低,只有命中大平台、金额、并购、监管等信号时提升。

重要度等级固定为:low 034、medium 3559、high 6079、critical 80100。分类、重要度和 Breaking 的计算集中在 earth_news_classification.py;分类 key 和标签仍可配置,重要度与 Breaking 协议状态使用统一枚举,数据库和 API 继续保存兼容的小写字符串。

配置与缓存

GET /api/v1/earth/news-sources 返回默认或已保存配置。PUT /api/v1/earth/news-sources 保存配置并递增 cache_version,同时清理进程内 region cache。POST /api/v1/earth/news-sources/reset 恢复默认源。POST /api/v1/earth/news-sources/test 只测试单个 RSS/Atom/Aggregated 源,不写入新闻表。

手动新闻内容

手动新闻是内容管理能力,不是 RSS 源配置。Admin 入口是 智能星球内容 -> 新闻内容,左栏按 RSS 来源和手动新闻组聚合;进入手动组详情后可以按条添加新闻或上传 JSON 数组批量导入。手动新闻写入 earth_news_items,并标记 feed_type/source_type = manual;前台展示文案是“手动添加”。它不参与 RSS 连通性测试,也不会进入 RSS 抓取流程。

手动新闻采用“先展示,再精修”的策略:

  1. 保存后立即写入 earth_news_items
  2. 没有人工坐标时使用所选区域锚点,verified=false
  3. 有人工坐标时使用 location_source=manual_locationverified=true,后续 AI 精修不会覆盖该坐标。
  4. 创建或重新处理后进入新闻增强队列后台补清洗、翻译、分类、重要度、Breaking 和目标位置推断。
  5. 精修完成后更新同一条新闻,并通过 Earth news reload / patch 让前端无感替换。

后台接口挂在 /api/v1/earth/news-items

  • GET /earth/news-groups:返回 RSS 虚拟来源组和手动新闻组。
  • POST /earth/news-groups:新建手动新闻组。
  • PUT /earth/news-groups/{group_id}:重命名手动新闻组,并同步组内新闻 meta。
  • GET /earth/news-items:分页查询 RSS 与手动新闻,支持来源类型、区域、类型和状态过滤。
  • POST /earth/news-items:新增一条手动新闻。
  • POST /earth/news-items/import:上传 JSON 数组批量导入,group_id 指定当前手动新闻组。
  • PUT /earth/news-items/{id}编辑手动新闻RSS 新闻只读。
  • DELETE /earth/news-items/{id}:删除手动新闻,并触发 Earth 新闻重载。
  • POST /earth/news-items/{id}/reprocess:重新进入清洗、翻译和定位队列。

JSON 导入首版只支持数组:

[
  {
    "title": "必填标题",
    "summary": "可选摘要",
    "content": "可选正文",
    "url": "https://example.com/story",
    "source": "手动添加",
    "region": "global",
    "published_at": "2026-05-15T03:00:00Z",
    "category": "business",
    "tags": ["manual", "analysis"],
    "location": {
      "label": "北京市, 中国",
      "latitude": 39.9057,
      "longitude": 116.3913
    }
  }
]

重复导入使用稳定 ID 去重ID 由标题、发布时间、URL 和来源生成,格式为 manual:{hash}。同一条手动新闻再次导入会更新原记录,不会重复出现在 EarthFeed。

Feed 查询与类型过滤

星球端和 UE 端统一使用 GET /api/v1/news/earth-feed 获取新闻。接口支持服务端过滤,不要求客户端拿全量列表后自行筛选。

  • lat / lon:按当前视角推断区域,适合 Web 星球端。
  • region:显式指定区域,适合 UE 端或服务端集成;可选值包括 globalamericaseuropeasia-pacificmiddle-east-africaglobal 是全局聚合视图,会展示所有区域来源;其它区域只展示该区域和 global 来源。
  • categories:逗号分隔的新闻类型 key例如 business,ecommerce。全选时可以不传。
  • locale:展示语言,支持 zh-CNen-US,默认 zh-CN。中文 RSS 会以中文原文入库,并由后台补 en-US;英文 RSS 则由后台补 zh-CN

示例:

GET /api/v1/news/earth-feed?region=europe&categories=business,ecommerce
GET /api/v1/news/earth-feed?lat=48&lon=10&categories=technology
GET /api/v1/news/earth-feed?region=global&categories=business,ecommerce&locale=zh-CN

非法新闻类型或语言会返回 422,响应中包含允许值。响应体会带 filters,用于确认后端实际应用的区域、类型和语言过滤。itemscruise_items 使用同一套类型过滤规则。

Web 星球端的新闻类型按钮只保存当前浏览器的显示偏好偏好变化后会重新请求接口。UE 端应直接把类型选择拼到 categories 参数里,不需要再做主过滤。

未指定 sources 时,服务层会优先选择当前 locale 已有可展示标题和摘要的新闻,并从当前启用来源补齐候选后做来源轮转,避免一个来源的最新待处理条目占满默认 12 条。指定 sources 时保持精确来源过滤,不做跨来源补齐。数据库查询层只负责区域、类型、来源和排序条件,不包含语言展示策略。

源测试只证明当前 RSS/Atom/XML 能解析到条目,不等于这些条目已经入库展示。展示链路还会检查区域、类型过滤和数据库新鲜度。保存或重置新闻源会递增配置版本并清理缓存;如果当前启用的 Feed 子项在库里没有近期条目,下一次 earth-feed 请求会补抓,避免新启用的 36氪、亿邦被旧 Google News 缓存挡住。

区域均衡与异步精修

earth_news_items 是 EarthFeed 的当前状态表。接口在没有显式 sources 过滤时会先按 Breaking、区域、发布时间排序再做区域轮转避免亚太或任一高频来源把全球视图和巡航队列全部占满。默认区域顺序是美洲、欧洲、中东与非洲、亚太、全球未知区域只在已知区域之后参与轮转。区域视图仍遵守“当前区域 + global”的规则不会把其它区域混进区域面板。

itemscruise_items 都会进入目标位置与本地化精修队列,但前端不能等 AI 完成后再展示。标题或摘要没有目标语言翻译时Web Earth 先显示原始 title / summary避免卡片出现“新闻汉化中”而实际内容已经可读。后台完成翻译、分类、Breaking 或目标坐标后,会更新同一条 earth_news_items 并通过 Earth news reload / patch 刷新前端。

目标位置队列使用 Redis Streams 两级队列:

  • earth_news:target_location:priority:当前可见 itemscruise_items 的优先精修任务,短 TTL 去重。
  • earth_news:target_location:jobs:普通后台精修任务,长 TTL 去重。

Worker 总是先处理优先队列再处理普通队列pending 消息超过空闲阈值会被 reclaim单条 AI 任务有超时保护,失败后进入重试或 dead letter。这样即使历史普通队列有大量 backlog当前打开的欧洲、美洲等区域新闻也不会被长队列饿死。

Breaking News 插队

新闻体系里有三套互不替代的判断:

  • 分类:新闻是什么,例如商业、军事、灾害。
  • 重要度:长期是否值得关注,写入 importance_score / importance_level
  • Breaking:短时间内是否必须插队,写入 location_meta.news_meta.breaking_*

Breaking 不新增表字段,继续保存在 location_meta.news_meta

  • breaking_levelnone / watch / breaking / critical
  • breaking_scoperegional / global
  • breaking_reasons:触发原因。
  • breaking_sourcerules / ai / manual / multi_source
  • breaking_confidence0 到 1。
  • breaking_expires_at:过期时间。

排序由服务端完成,客户端和 UE 不需要自己重排。未过期的 criticalbreakingwatch 会依次排在普通新闻前面;过期后只回到普通排序,不删除新闻,也不改变长期重要度。

breaking_scope = global 的新闻会无视当前区域,进入所有区域的 feedregional 只遵守当前区域加 global 的普通区域规则。接口响应的 filters 会返回 has_breakinghighest_breaking_level,星球端据此给新闻面板和卡片加克制的背景/边框状态。

连通性监测

POST /api/v1/earth/news-sources/test 会测试单个源并把结果写入 earth_news_sources.health[source_id]。实际 RSS/Atom 抓取也会更新同一份健康状态。

健康结果包含:

  • statusokemptyformat_errorhttp_errortimeoutnetwork_errorreference
  • status_codecontent_typeitem_countlatency_mserrorfetched_at
  • feed_results:多 Feed source 的逐 Feed 子项检测结果,包含 feed_idfeed_namefeed_typefeed_url、状态、条数和错误。

常见诊断:

  • 返回 HTML 页面:说明配置 URL 不是 RSS/Atom feed例如把网页中心页当成 feed。
  • HTTP 403通常是 CDN、反爬或源站拒绝抓取。
  • Reference参考链接不参与抓取需要改为 RSS、Atom 或 Aggregated 后才可测试抓取。

Admin 入口是 Earth 内容 -> 新闻源。界面不是整包 JSON 编辑,而是两层:

  • 新闻源:左侧逐个 source 列表支持按启用、停用、参考链接、RSS/Atom/Aggregated、区域和源属性标签筛选右侧编辑当前 source 字段和 Feed 子项列表。
  • 策略规则:保留源属性标签、新闻类型、条目标签规则、默认健康策略等全局规则。高级 JSON 只用于排障,不作为默认编辑路径。

单源表单分为“来源信息”和“Feed 子项”:

  • 来源信息包括名称、ID、区域、主页 URL、Feed 信息页、源类型、启用开关、源属性标签、重要度权重、抓取间隔、超时、失败阈值和熔断开关。
  • Feed 子项包括 Feed ID、名称、真实 Feed URL、类型、启用开关、默认新闻类型、优先级和 Feed 标签。Feed 子项底部的 + 只新增一个前端草稿;保存 source 后才写入配置,取消会销毁草稿。

单源“测试源”会测试当前 source 下全部启用 FeedFeed 子项上的测试按钮只测试当前 Feed。测试请求仍发送到 /api/v1/earth/news-sources/test,但 payload 里只带当前 source 和选中的 Feed 子项。

参考链接会显示“只记录官网、报告页或未来采集器线索,不参与 RSS/Atom 抓取”。它可作为商业或官方数据线索保留在配置中,但启用抓取前必须改成 RSS、Atom 或 Aggregated并提供可抓取的 Feed 地址。

flowchart LR
  Admin["Admin: Earth 内容 / 新闻源"] --> Source["Source 配置"]
  ManualAdmin["Admin: Earth 内容 / 新闻内容"] --> ManualAPI["/api/v1/earth/news-items"]
  Source --> Feed["Feed 子项"]
  Feed --> ConfigAPI["/api/v1/earth/news-sources"]
  ConfigAPI --> Config["SystemSetting: earth_news_sources"]
  ManualAPI --> Store

  Earth["Earth 新闻面板"] --> NewsAPI["/api/v1/news/earth-feed"]
  NewsAPI --> Resolver["Source Resolver"]
  Resolver --> Config
  Resolver --> Cache["Region Feed Cache"]
  Resolver --> Fetcher["RSS / Atom Fetcher"]
  Fetcher --> Parser["Feed Parser"]
  Parser --> Classifier["Classifier: category + item_tags + importance"]
  Classifier --> Store["earth_news_items"]
  Fetcher --> Health["source health"]
  Health --> Config
  Store --> EnrichQueue["Location / Localization Queue"]
  EnrichQueue --> AI["AI Provider"]
  Store --> NewsAPI
  UE["UE Client"] --> NewsAPI