我用 AI 构建了实时 HackerNews 趋势雷达(并且它会自行运行)
I’m happy to translate the article for you, but I’ll need the full text of the post (the paragraphs, headings, lists, etc.) in order to do so. Could you please paste the content you’d like translated (excluding the source link you’ve already provided)? Once I have the article text, I’ll translate it into Simplified Chinese while preserving the original formatting, markdown syntax, and technical terms.
Source: …
每天,HackerNews 静静地决定开发者世界接下来会关注什么。
但如果你不是整天 doom‑scrolling(刷屏),就会错过真正的信号:哪些话题正在真正起飞,遍布各个帖子和深层评论链。
于是,我在其之上构建了一个 实时“趋势雷达”:
-
持续获取最新的 HN 文章和评论
-
使用 LLM 提取结构化话题(公司、工具、模型、技术术语)
-
将所有数据流入 Postgres,便于即时查询,例如:
- “现在 HN 上有什么趋势?”
- “今天哪些帖子在为 Claude / LangChain / Rust 推波助澜?”
所有这些都以 声明式 CocoIndex 流程 运行,具备增量同步、LLM 驱动的抽取以及简易查询处理器。
在本文中,你将看到它的端到端实现,以及如何 fork 它来追踪任何社区(Reddit、X、Discord、内部 Slack 等)。
为什么 HN 是金矿(如果你能结构化它)
HackerNews 是以下早期信号中最强的之一:
- 开发者实际尝试的新工具和框架
- 哪些 AI 模型/产品正在获得关注度
- 评论中的真实情绪和反馈
- 新兴创业公司和可能在 6‑12 个月内爆发的冷门库
但原始的 HN 存在三个问题:
- 线程嘈杂,评论层级混乱
- 除了自由文本外,没有“主题”概念
- 没有内置方式来询问:“整个信息流中有什么趋势?”
CocoIndex 中的 HackerNews Trending Topics 示例本质上是:“将 HN 转变为结构化、持续更新的主题索引,供 AI 代理和仪表盘在毫秒级查询。”
架构:从 HN 火焰流到可查询的话题
在高层次上,管道如下所示:
HackerNews API
↓
HackerNewsConnector (Custom Source)
├─ list() → thread IDs + updated_at
├─ get_value() → full threads + comments
└─ provides_ordinal() → enables incremental sync
↓
CocoIndex Flow
├─ LLM topic extraction on threads + comments
├─ message_index collector (content)
└─ topic_index collector (topics)
↓
Postgres
├─ hn_messages
└─ hn_topics
↓
Query Handlers
├─ search_by_topic("Claude")
├─ get_trending_topics(limit=20)
└─ get_threads_for_topic("Rust")
核心思想: 将发现(discovery)与获取(fetching)分离。
list()调用 HN Algolia 搜索 API,获取轻量级元数据:线程 ID +updated_at时间戳。get_value()只对updated_at发生变化的线程运行,从 items API 获取完整内容 + 评论。- 序号(时间戳)让 CocoIndex 跳过所有未改变的内容,使后续同步的 API 调用减少超过 90 %。
这使得在 30 秒轮询间隔 的“实时模式”成为可能,而不会耗尽 API 配额或钱包。
步骤 1:将 HackerNews 打造成一等增量数据源
首先,定义 线程和评论的数据模型。
class _HackerNewsThreadKey(NamedTuple):
thread_id: str
@dataclasses.dataclass
class _HackerNewsComment:
id: str
author: str | None
text: str | None
created_at: datetime | None
@dataclasses.dataclass
class _HackerNewsThread:
author: str | None
text: str
url: str | None
created_at: datetime | None
comments: list[_HackerNewsComment]
然后声明一个 SourceSpec,用于配置如何查询 HN:
class HackerNewsSource(SourceSpec):
"""Source spec for HackerNews API."""
tag: str | None = None # e.g. "story"
max_results: int = 100 # hits per poll
自定义源连接器将该规范映射为实际的 HTTP 调用:
list()→ 调用https://hn.algolia.com/api/v1/search_by_date,参数hitsPerPage=max_results,产生以线程 ID 为键、以updated_at为序号的PartialSourceRow对象。get_value()→ 调用https://hn.algolia.com/api/v1/items/{thread_id},并将完整的线程及其嵌套评论解析为_HackerNewsThread和_HackerNewsComment。provides_ordinal()→ 返回True,让 CocoIndex 能进行增量同步。
CocoIndex 负责处理最难的部分:跟踪序号并在每次同步时仅重新拉取已更改的行。
步骤 2:使用 LLM 从每个线程和评论中抽取话题
源进入流后,真正有趣的部分开始了:语义增强。
定义一个最小的 Topic 类型,由 LLM 填充:
@dataclasses.dataclass
class Topic:
"""
A single topic extracted from text:
- products, tools, frameworks
- people, companies
- domains (e.g. "vector search", "fintech")
"""
topic: str
在流中,每个线程的主题通过单一声明式转换提取:
with data_scope["threads"].row() as thread:
thread["topics"] = thread["text"].transform(
cocoindex.functions.ExtractByLlm(
llm_spec=cocoindex.LlmSpec(
api_type=cocoindex.LlmApiType.OPENAI,
model="gpt-4o-mini",
),
output_type=list[Topic],
)
)
对评论执行相同操作:
with thread["comments"].row() as comment:
comment["topics"] = comment["text"].transform(
cocoindex.functions.ExtractByLlm(
llm_spec=cocoindex.LlmSpec(
api_type=cocoindex.LlmApiType.OPENAI,
model="gpt-4o-mini",
),
output_type=list[Topic],
)
)
在幕后,CocoIndex:
- 使用结构化提示调用 LLM,并强制
output_type=list[Topic] - 将杂乱的自由文本规范化为一致的话题字符串
- 将其视为另一列加入到数据集中
Source: …
your flow instance, ready to be persisted to Postgres and queried instantly.
Instead of a Separate Glue Script
这就是把 HN 从“纯文本”转化为 AI 代理或 SQL 查询能够 推理 的内容的关键。
Step 3: Indexing Into Postgres for Fast Topic Queries
所有结构化数据被收集到两个逻辑索引中:
| 索引 | 内容 |
|---|---|
message_index | 包含原始文本和元数据的线程 + 评论 |
topic_index | 与消息关联的单独主题 |
收集器只需声明一次,然后导出到 Postgres:
message_index = data_scope.add_collector()
topic_index = data_scope.add_collector()
message_index.export(
"hn_messages",
cocoindex.targets.Postgres(),
primary_key_fields=["id"],
)
topic_index.export(
"hn_topics",
cocoindex.targets.Postgres(),
primary_key_fields=["topic", "message_id"],
)
现在你拥有了两张可以通过 SQL 或 CocoIndex 查询处理器操作的表:
hn_messages– 全文搜索、内容分析、作者统计hn_topics– 主题层面的分析、趋势追踪、每个主题的线程排名
Step 4: Query Handlers – From “Cool Pipeline” to Real Product
这一步标志着项目不再是单纯的 ETL 演示,而是可以真正交付的产品。
search_by_topic(topic): “显示所有 Claude 的提及”
@hackernews_trending_topics_flow.query_handler()
def search_by_topic(topic: str) -> cocoindex.QueryOutput:
topic_table = cocoindex.utils.get_target_default_name(
hackernews_trending_topics_flow, "hn_topics"
)
message_table = cocoindex.utils.get_target_default_name(
hackernews_trending_topics_flow, "hn_messages"
)
with connection_pool().connection() as conn:
with conn.cursor() as cur:
cur.execute(
f"""
SELECT m.id, m.thread_id, m.author, m.content_type,
m.text, m.created_at, t.topic
FROM {topic_table} t
JOIN {message_table} m ON t.message_id = m.id
WHERE LOWER(t.topic) LIKE LOWER(%s)
ORDER BY m.created_at DESC
""",
(f"%{topic}%",),
)
results = [
{
"id": row[0],
"url": f"https://news.ycombinator.com/item?id={row[1]}",
"author": row[2],
"type": row[3],
"text": row[4],
"created_at": row[5].isoformat(),
"topic": row[6],
}
for row in cur.fetchall()
]
return cocoindex.QueryOutput(results=results)
在 CLI 中运行:
cocoindex query main.py search_by_topic --topic "Claude"
你会收到一个整洁的 JSON 响应,包含 URL、作者、时间戳以及出现该主题的内容片段。
get_threads_for_topic(topic): 按主题分数对线程进行排名
并非所有提及都同等重要:
- 如果 “Rust” 出现在 线程标题 中,则为 主要 讨论。
- 如果它埋在评论里,则为 次要 提及。
get_threads_for_topic 使用加权评分模型,优先展示主题居中的线程。
get_trending_topics(limit=20): 实际的趋势雷达
该端点为仪表盘和代理提供数据。它会返回类似下面的列表:
[
"Claude 3.7 Sonnet",
"OpenAI o4-mini",
"LangChain",
"Modal",
…
]
每个主题都包含其分数、最新提及时间以及讨论该主题的热门线程。
你可以将其接入:
- 实时仪表盘,显示 “最近 N 小时的前 20 大主题”
- Slack 机器人,每日推送 “HN 上的热点趋势” 摘要
- 监控内部研究代理,捕捉 HN 上的最新动向
与您的技术栈相关的信号
实时运行
一旦流程定义完成,保持实时运行只需一行命令:
# On‑demand refresh
cocoindex update main
# Live mode: keeps polling HN and updating indexes
cocoindex update -L main
CocoIndex 负责:
- 每 30 秒轮询 HN(可配置)
- 增量同步仅有更改的线程
- 仅在需要时重新运行 LLM 提取
- 导出到 Postgres 并暴露查询处理器
用于调试,CocoInsight 让您可以在 UI 中探索流程、查看血缘并尝试查询:
cocoindex server -ci main
# Then open: https://cocoindex.io/cocoinsight
您可以在此基础上构建的内容(超越 “Just HN”)
| Extension | Idea |
|---|---|
| 跨社区趋势追踪 | 将 Reddit 子版块、X 列表、Discord 频道、内部 Slack 等作为额外来源;对它们的主题进行归一化,以观察想法的传播路径。 |
| 情感感知趋势分析 | 在主题旁加入基于 LLM 的情感提取步骤;不仅跟踪 什么 正在流行,还要跟踪开发者是 喜欢 还是 讨厌。 |
| 影响者与关键贡献者映射 | 使用 author 字段查看谁发起重要讨论,以及谁的评论推动了对话的进展。 |
| 持续知识图谱 | 将主题视为节点,线程视为边,构建一个由真实讨论链接的工具、公司和人物的图谱。 |
| 实时 AI 研究代理 | 将代理指向基于 Postgres 的索引,让它回答诸如以下问题: • “本周人们正在实验的顶级新向量数据库有哪些?” • “哪些 AI 评估框架正在获得关注?” |
如果你身处数据、基础设施或 AI 领域,这基本上是 一个可自我更新的 HN 信号层,供你的工具和代理查询。
想自己动手试试吗?
您可以在下面链接的仓库中找到完整可运行的示例(包括流定义、Docker 设置和快速启动脚本)。
GitHub – hackernews‑trending‑topics‑cocoindex
祝您玩得开心!
概览
在官方的 HackerNews Trending Topics 示例 中,探索 ding flow definition、自定义源、查询处理程序以及 Postgres 导出,查看 CocoIndex 文档和其 GitHub 仓库。
如果你最终
- 将其指向不同的社区
- 添加嵌入、RAG 或情感分析
- 将其接入真实产品或代理
…一定要分享回来!
这个模式最酷的地方在于,你只需要极少的代码,就能从“原始社区噪声”转变为 实时、可查询的趋势雷达。