ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于Jev与LLM的三源新闻日报自动化系统实战

基于Jev与LLM的三源新闻日报自动化系统实战 1. 从信息焦虑到日报自动化这个项目到底在解决什么每天早上睁眼第一件事就是刷各种信息流科技新闻、行业动态、社区热帖翻一遍半小时没了真正有价值的内容可能就三五条。更麻烦的是同一个事件在不同来源的报道角度、深度、时效性都不一样靠人肉对比根本不现实。这个项目的出发点很朴素让 Jev 替我完成扫信息流这件事每天定时产出一份三源新闻日报我只需要花五分钟读日报就行。所谓三源指的是从三个不同渠道抓取新闻内容——可以是 RSS 订阅源、公开的新闻 API、或者社区热榜接口。三个来源各有侧重有的偏快、有的偏深、有的偏社区讨论组合起来信息覆盖面比单一来源强得多。而日报则是最终产物一份经过 LLM 筛选、归类、摘要、去重后的结构化文档按主题分块每条附上来源和原文链接。Jev 在这里扮演的角色是调度中枢 智能处理引擎。它负责定时触发抓取任务、调用 LLM 对原始内容做清洗和摘要、把结果按模板渲染成日报、最后推送到指定位置邮件、飞书、本地 Markdown 文件都行。整个链路的核心难点不在抓而在筛和写——怎么让 LLM 在有限的 token 预算内把一堆杂乱信息压缩成一份人愿意读的日报。这个项目适合几类人参考一是每天需要跟踪特定领域动态的从业者比如做投资、做技术选型、做竞品分析的二是想入门 LLM 应用开发但不知道从什么项目练手的开发者这个项目的链路完整但不复杂涉及 API 调用、Prompt 设计、错误处理、定时任务麻雀虽小五脏俱全三是已经在用各种 RSS 阅读器但觉得读不过来的人日报模式本质上是用 LLM 做了一次信息降噪。我自己的使用场景是技术资讯跟踪。以前用 RSS 阅读器订阅了四十多个源每天未读数轻松破千后来干脆不看了。改成三源日报之后每天固定收到一份两三千字的摘要覆盖当天最重要的十几条技术动态阅读压力骤降。下面把整个实现过程拆开讲包括选型理由、踩过的坑、以及几个让日报质量明显提升的调优技巧。2. 三源抓取层的设计为什么不是源越多越好2.1 三个来源的定位差异与互补逻辑很多人第一反应是既然要抓那就多抓几个源信息更全。我一开始也是这么想的接了八个源结果日报里大量重复内容LLM 的 token 消耗翻了三倍摘要质量反而下降——因为模型要在冗余信息里做去重注意力被分散了。后来砍到三个源效果反而最好。三个源的选取原则是定位互补而不是数量堆砌。我最终确定的组合是来源类型定位更新频率内容特征综合新闻 API覆盖广度每小时标题规范、正文完整、有分类标签技术社区热榜社区讨论热度每 6 小时标题口语化、有评论数、反映真实关注度垂直领域 RSS深度与专业性每天长文为主、有作者观点、时效稍慢这三个源覆盖了发生了什么大家在讨论什么专业人士怎么看三个层面。综合新闻 API 保证不漏大事件社区热榜反映真实热度避免被公关稿带偏垂直 RSS 提供深度分析。三者交叉验证日报的信息质量比单一来源高一个档次。提示源的数量控制在 3 到 5 个比较合理。超过 5 个之后去重和排序的逻辑复杂度会急剧上升而信息增益递减明显。2.2 抓取频率与去重策略的配合抓取频率不是越高越好。我最初设的是每 15 分钟抓一次结果同一个事件在一天内被反复抓取日报里出现大量旧闻。后来改成按源设定频率新闻 API 每小时一次社区热榜每 6 小时一次RSS 每天一次。这样既保证时效又避免重复。去重分两层做。第一层是URL 去重用 URL 的规范化形式去掉 utm 参数、统一协议头做哈希存到本地 SQLite 里抓过的直接跳过。第二层是内容相似度去重用标题的 SimHash 做近似匹配阈值设在 0.85 左右——这个值是我试出来的太低会误杀不同事件的相似标题太高则漏掉改头换面的重复报道。import hashlib from simhash import Simhash def url_fingerprint(url): # 去掉常见追踪参数 parsed urlparse(url) clean f{parsed.scheme}://{parsed.netloc}{parsed.path} return hashlib.md5(clean.encode()).hexdigest() def title_similar(a, b, threshold0.85): ha, hb Simhash(a), Simhash(b) distance ha.distance(hb) # Simhash 是 64 位距离越小越相似 return (1 - distance / 64) threshold这里有个细节SimHash 对中文标题的效果不如英文因为中文分词后特征词更少。我的做法是先用 jieba 分词去掉停用词再把关键词拼成字符串做 SimHash。实测下来中文标题的误判率从 15% 降到了 5% 左右。2.3 抓取失败与限流的处理经验公开 API 和 RSS 都有速率限制硬抓会被封。我的处理策略是指数退避 本地缓存。第一次失败等 2 秒重试第二次等 4 秒第三次等 8 秒最多重试三次。如果三次都失败就把这个源标记为临时不可用跳过本轮下一轮再试。本地缓存的作用是兜底。如果某个源连续失败日报里对应板块就用上一次成功抓取的内容填充并标注数据可能滞后。这样至少保证日报不会开天窗。注意抓取时一定要设置合理的 User-Agent 和请求间隔。我见过有人用默认的 python-requests UA 高频抓取结果 IP 被临时封禁排查了半天才发现是 UA 的问题。3. LLM 处理链路token 预算、Prompt 设计与摘要质量3.1 为什么 token 预算是这个项目的第一约束三源抓取下来原始内容轻松超过十万字。如果直接丢给 LLM 做摘要先不说成本光是上下文长度就可能超限——很多模型的单次请求上限是 128K token十万字中文大概对应 15 万 token 左右直接爆掉。我踩过的第一个坑就是没算 token把整天的抓取结果一次性塞进去结果 API 直接返回 400 错误提示超出最大上下文长度。所以整个 LLM 处理链路必须分层做减法。我的方案是三级压缩规则预筛按关键词、来源权重、发布时间做第一轮过滤砍掉明显不相关的内容通常能去掉 60% 到 70%。单条摘要对剩下的每条内容单独调用 LLM 做一句话摘要输出控制在 50 字以内。聚合生成把所有单条摘要按主题聚类再调用一次 LLM 生成最终的日报正文。这样每一级的输入都在可控范围内最终聚合时的输入通常只有几千 token稳定不超限。3.2 单条摘要的 Prompt 怎么写才不废话单条摘要的 Prompt 我改了七八版最终稳定下来的版本是这样的你是一名新闻编辑。请用一句话概括以下内容的核心事实不超过50字。 要求 1. 只陈述事实不加评价 2. 保留关键数字和专有名词 3. 如果内容没有实质信息输出无价值内容 内容{content}关键在最后那条无价值内容的兜底。没有这条的时候模型会对每条内容都硬憋出一句摘要包括那些纯广告、纯水文导致日报里混入垃圾。加上这条之后模型有了拒绝的选项日报的纯净度明显提升。另一个技巧是在 Prompt 里给示例。我放了两条正例和一条反例模型对什么算核心事实的理解会准确很多。示例不用多两三条就够多了反而占 token。3.3 聚合阶段的主题聚类与排序逻辑聚合阶段的核心是先聚类再排序最后生成。聚类我用的是简单的关键词匹配加 LLM 辅助判断——先按预定义的主题标签如AI开源硬件政策做粗分再让 LLM 判断边界模糊的条目该归到哪一类。排序逻辑是三个维度的加权来源权重 × 0.4 时效性 × 0.3 社区热度 × 0.3。来源权重是我手动设的垂直 RSS 给 1.0新闻 API 给 0.8社区热榜给 0.6。时效性按发布时间做指数衰减24 小时前的权重降到 0.3。社区热度用评论数或点赞数归一化。这个加权公式不是拍脑袋定的是我用两周的日报做了 A/B 对比调出来的。最初只用时效性排序结果日报里全是刚发的短讯深度内容被淹没加上来源权重和热度之后日报的信息密度明显提升。4. 日报渲染与推送让输出真正可读4.1 日报模板的结构设计日报最终是一份 Markdown 文档结构固定为四块今日要闻3 到 5 条、分类速览按主题分组的摘要列表、深度推荐1 到 2 篇长文、数据统计抓取条数、去重后条数、各源占比。这个结构是迭代出来的。最初的版本只有分类速览读起来像流水账没有重点。加上今日要闻之后读者可以先看最重要的几条有兴趣再往下翻。深度推荐是后来加的因为发现有些长文被摘要压缩后失去了价值单独拎出来推荐原文更好。模板用 Jinja2 渲染好处是逻辑和展示分离改版式不用动代码。下面是一个简化版的模板片段## 今日要闻 {% for item in highlights %} - **{{ item.title }}** — {{ item.summary }}来源{{ item.source }} {% endfor %} ## 分类速览 {% for category, items in grouped.items() %} ### {{ category }} {% for item in items %} - {{ item.summary }} [原文]({{ item.url }}) {% endfor %} {% endfor %}4.2 推送渠道的选择与踩坑推送渠道我试过三种邮件、飞书机器人、本地文件。邮件最通用但排版容易乱飞书机器人实时性好但消息长度有限制本地文件最灵活但需要自己同步。最终我选的是本地 Markdown 文件 飞书机器人摘要的组合。完整日报写成本地文件方便归档和搜索飞书只推今日要闻部分控制在 500 字以内避免消息被截断。飞书机器人的坑主要在消息格式上。它支持富文本卡片但字段结构比较绕我第一次调的时候消息发出去是空的排查发现是 card 的 schema 写错了。建议先用官方提供的调试工具把卡片结构调通再接入代码。提示推送失败一定要有重试和告警。我有一次飞书 token 过期日报连续三天没推出去直到手动检查才发现。后来加了个简单的告警推送失败时写一条日志到本地文件并在下一次成功推送时附带上次推送失败的提示。4.3 日报质量的自我评估机制日报发出去之后怎么知道质量好不好我加了一个简单的反馈闭环每天日报末尾附一个有用/没用的投票链接读者点完之后数据回写到本地。连续一周没用占比超过 30%就触发一次 Prompt 调优。另外还有一个自动指标摘要压缩比。原始内容总字数除以日报总字数正常在 50:1 到 100:1 之间。如果低于 30:1说明摘要不够精炼如果高于 150:1说明可能漏掉了重要信息。这个指标帮我发现过好几次 Prompt 退化的问题。5. 部署与运维让日报每天准时出现5.1 定时任务的选型与容错定时任务我用的是系统的 cron简单可靠。但 cron 有个问题如果上一次任务还没跑完下一次又触发了会出现并发冲突。我的处理是加文件锁——任务开始时创建一个 lock 文件结束时删除如果 lock 文件存在就跳过本次执行。#!/bin/bash LOCK/tmp/news_daily.lock if [ -f $LOCK ]; then echo 上一次任务还在运行跳过 exit 0 fi touch $LOCK trap rm -f $LOCK EXIT python /path/to/daily.pytrap那行很关键保证即使脚本异常退出lock 文件也会被清理不会导致任务永久卡死。这个坑我踩过有一次脚本因为 API 超时崩了lock 文件没删结果后面几天的任务全部跳过日报断更了三天才发现。5.2 API Key 管理与错误处理项目里涉及多个 API Key新闻 API、LLM API、推送渠道的 token。这些绝对不能硬编码在代码里。我的做法是用.env文件加python-dotenv加载.env加入.gitignore代码里只引用环境变量名。错误处理要区分可重试和不可重试两类。网络超时、限流属于可重试指数退避后重试API Key 无效、请求格式错误属于不可重试直接记录日志并跳过。我见过有人把所有错误都无脑重试结果 Key 失效时疯狂重试把配额耗光了。def call_llm(prompt, max_retries3): for i in range(max_retries): try: resp client.chat(prompt) return resp except RateLimitError: time.sleep(2 ** i) except AuthenticationError: logger.error(API Key 无效跳过本次调用) return None except Exception as e: logger.warning(f未知错误{e}) time.sleep(2 ** i) return None5.3 日志与监控出问题时怎么快速定位日志我分了三层INFO记录每步的正常执行抓取了几条、摘要了几条、推送成功WARNING记录可恢复的异常某个源失败、重试成功ERROR记录需要人工介入的问题Key 失效、连续失败。日志按天切分保留 30 天。排查问题时先看 ERROR再看 WARNING基本能定位到是哪一环出的问题。我遇到过一次日报内容为空的情况查日志发现是抓取层全部返回 0 条再往上查是新闻 API 改了返回格式字段名从articles变成了data。如果没有详细日志这种问题很难快速定位。6. 几个让日报质量明显提升的调优技巧6.1 用负面示例约束 LLM 的输出风格LLM 默认的摘要风格偏新闻联播喜欢用据悉标志着进一步这类词。我在 Prompt 里加了一段负面示例不要使用以下表达 - 据悉、据了解 - 标志着、意味着 - 进一步、持续 - 任何没有信息量的形容词加上之后摘要的废话率明显下降。这个技巧对任何 LLM 摘要任务都适用——与其告诉模型要简洁不如直接列出不要用什么词后者更可操作。6.2 按主题动态调整摘要长度不同类型的新闻合适的摘要长度不一样。政策类新闻需要保留更多细节社区讨论类只需要一句话概括。我的做法是在 Prompt 里根据主题标签动态调整字数上限政策类 80 字技术类 60 字社区类 40 字。这个调整让日报的可读性提升了不少。之前统一 50 字的时候政策类新闻经常被压缩得看不懂社区类又显得啰嗦。6.3 定期回顾与 Prompt 版本管理Prompt 是要迭代的但改了什么、为什么改必须记下来。我用一个简单的 Markdown 文件做 Prompt 版本管理每次修改记录日期、改动内容、改动原因、效果对比。这样当日报质量下降时可以快速回滚到上一个稳定版本。我自己的 Prompt 从 v1 到 v7中间有三次是回滚后重新改的。没有版本管理的话根本记不清哪一版效果最好。6.4 人工抽检与自动化指标结合完全依赖自动指标不够我每周会人工抽检两天的日报看摘要是否准确、分类是否合理、有没有漏掉重要新闻。人工抽检发现的问题往往是自动指标覆盖不到的——比如某条摘要事实性错误压缩比指标完全正常但内容就是错的。抽检的另一个作用是发现新的信息源。有时候日报里某个主题的内容明显偏少说明对应的源覆盖不够需要补充新的源。这个判断只能靠人自动化做不了。7. 这套方案还能怎么扩展三源日报跑顺之后我陆续加了一些扩展。一个是个性化权重根据我点击有用的历史记录动态调整各主题的排序权重让日报越来越贴合我的关注点。另一个是周报聚合把一周的日报再做一次 LLM 聚合生成一份周度回顾适合周末花十分钟快速补课。还有一个方向是多模态。现在日报只处理文本但很多新闻的价值在图表和视频里。下一步想试试把关键图表用 OCR 提取数据让 LLM 结合数据做摘要。这个还在试验阶段效果好的话再单独写一篇。如果你也在做类似的信息聚合项目我的建议是先把单源跑通再加源。我见过太多人一上来就接十个源结果去重和排序逻辑没做好日报里全是重复内容最后项目烂尾。三源是个比较舒服的起点跑顺了再按需扩展比一开始就贪多要靠谱得多。
返回列表