我用Claude API搭了一个AI资讯监控机器人,踩了这几个坑才跑稳
我用Claude API搭了一个AI资讯监控机器人,踩了这几个坑才跑稳
上周有人问我每天是怎么跟上AI行业节奏的。
我发了一张Telegram截图给他——密密麻麻的推送消息,每条都有标题、一句话摘要、分类标签和原文链接。他问:这是什么工具?
我说,是我自己搭的。
他问多久搭好的。我说:搭起来只用了一个下午,但让它稳定跑下去花了我两周。
这篇文章,就是那两周踩坑经验的完整复盘。
---
为什么不用现成的工具
不是没试过。
早期我用过几款AI资讯聚合产品,体验都差不多:噪音太多、分类混乱、推荐逻辑不透明。更关键的是,我关注的方向很窄——主要是模型能力进展、API生态动向、国内大厂的产品节奏——但这些工具总想给我推"AI写作"、"AI绘画"、"某某公司融资"。
过滤不掉,就会逐渐失去信任感,最后干脆不看。
另一个动机更私人:我想把推送直接打到Telegram,因为我的信息消费主要在那里。现成工具基本不支持这种定制化输出。
核心诉求说清楚就是三条:
- 定向追踪:只看我关心的几个方向
- 智能摘要:每条资讯一句话说清楚"这条有什么新的"
- 推送到我的地方:Telegram,不是App,不是邮件
这三条用Claude API都能做到。于是就开始搭了。
---
整体架构:先有全局感,再看细节
整个工作流的链路很清晰:
数据源(RSS + 少量爬虫)
↓
内容抓取 & 清洗
↓
URL哈希去重(过滤已处理过的)
↓
Claude API(摘要 + 分类 + 重要性评分)
↓
二次过滤(评分低于阈值的丢弃)
↓
Telegram Bot 推送
↓
本地日志 & 错误告警
技术栈选择上没什么特别:Python为主,RSS解析用feedparser,调度用APScheduler,Telegram推送用python-telegram-bot。
第一,长文本理解能力强。有些源的文章动辄四五千字,我需要它在理解完整语境后再给摘要,而不是只看前几段。
第二,指令遵循稳定。我需要结构化输出(JSON格式),Claude在格式约束方面的一致性比我早期测试的其他方案要好。
整个系统每天定时跑4次,分别在早上7点、中午12点、下午5点、晚上10点。每次处理约50-120条原始条目,最终推送的大概在10-25条之间。
---
踩过的3个坑
这是全文最重要的部分。每个坑我都按"现象 → 排查 → 解法"的顺序说。
坑1:Prompt写得"太聪明"反而输出不稳定
现象:最开始我写了一个"全能Prompt",试图在一次调用里完成所有任务:摘要、分类、重要性评分、提取关键词、判断是否与竞品相关……一共要求输出7个字段的JSON。
前几天跑得挺好。但大概第三天开始,偶尔会出现JSON格式错误——有时候某个字段缺失,有时候直接输出了一段解释性文字而不是JSON,有时候字段顺序乱了导致解析失败。
失败率大概在8%-12%之间,看起来不高,但每天几百次调用累积下来,丢失的内容不少。
排查过程:我把失败的case全部存了下来,发现有一个规律:失败几乎都发生在文章内容比较复杂、或者涉及多个话题的条目上。
问题根源是:我的Prompt在要求模型同时做太多判断,当输入内容本身有歧义时,模型会"想多了",开始在输出里解释自己的判断逻辑,破坏了JSON结构。
解法:拆分任务。把"摘要生成"和"分类+评分"拆成两次调用,每次只做一件事。同时在Prompt里加入更强的格式约束:
system_prompt = """你是一个资讯处理助手。
你的输出必须且只能是合法的JSON格式,不包含任何其他文字。
如果你无法完成任务,请输出:{"error": "无法处理"}
绝对不要输出JSON以外的任何内容。"""
同时把temperature设为0,让输出更确定性。
拆分之后,格式错误率从8%-12%降到了不足1%。
---
坑2:不限速导致Rate Limit集中爆发
现象:搭好之后跑了几天很正常。直到某天早上,系统积压了一批内容(前一天晚上有个大新闻,RSS更新了很多条),早上7点定时任务触发,一次性要处理180多条内容,API调用在几分钟内密集发出,触发了Rate Limit,大量请求失败。
排查过程:看了一下日志,问题很明确:没有做任何限速,所有调用几乎是并发的。Claude API有每分钟请求数和token数的双重限制,批量处理时很容易踩线。
解法:加入队列机制 + 指数退避重试逻辑。核心代码如下:
import time
import random
from anthropic import Anthropic, RateLimitError, APIError
client = Anthropic(
base_url="https://api.884819.xyz", # 兼容官方格式,直接换base_url即可
api_key="your_api_key"
)
def call_claude_with_retry(prompt: str, max_retries: int = 5) -> str:
"""带指数退避重试的Claude API调用"""
for attempt in range(max_retries):
try:
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=512,
temperature=0,
system=SYSTEM_PROMPT,
messages=[{"role": "user", "content": prompt}]
)
return response.content[0].text
except RateLimitError:
if attempt == max_retries - 1:
raise
# 指数退避:1s, 2s, 4s, 8s, 16s,加随机抖动
wait_time = (2 ** attempt) + random.uniform(0, 1)
print(f"Rate limit触发,{wait_time:.1f}秒后重试(第{attempt+1}次)")
time.sleep(wait_time)
except APIError as e:
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt)
return ""
def process_batch(items: list, interval: float = 1.5) -> list:
"""批量处理,每次调用之间强制间隔"""
results = []
for item in items:
result = call_claude_with_retry(item["content"])
results.append(result)
time.sleep(interval) # 固定间隔,避免突发
return results
加了重试逻辑和调用间隔之后,失败率从高峰期的约30%降到了接近0。
💡 如果你还没有Claude API访问权限,或者被地区限制卡住了,我目前用的是 [api.884819.xyz](https://api.884819.xyz) 做中转——接口格式和官方完全兼容,上面的代码直接换一下 base_url 就能跑,不需要改其他任何东西。新用户注册即送体验token,国产模型(Deepseek/千问等)完全免费,按量付费没有月租。
---
坑3:没做去重,同一条新闻反复推送
现象:某天下午,我收到了关于同一个模型发布的3条推送,内容几乎一样,只是来自不同的RSS源。同一件事被摘要了3次,推送了3次。
这不只是体验问题——还造成了不必要的token消耗。
排查过程:问题很简单:我只做了"当次运行内"的去重,但没有跨运行的持久化去重。同一条新闻被不同RSS源收录后,下次定时任务触发,又会被当成新内容处理。
解法:两层去重:
第一层(URL哈希): 对每条内容的URL做MD5,存入本地SQLite。每次处理前先查库,已存在的跳过。import hashlib
import sqlite3
def get_url_hash(url: str) -> str:
return hashlib.md5(url.encode()).hexdigest()
def is_duplicate(url: str, db_path: str = "seen_urls.db") -> bool:
url_hash = get_url_hash(url)
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
cursor.execute(
"CREATE TABLE IF NOT EXISTS seen (hash TEXT PRIMARY KEY, ts INTEGER)"
)
cursor.execute("SELECT 1 FROM seen WHERE hash = ?", (url_hash,))
exists = cursor.fetchone() is not None
if not exists:
import time
cursor.execute(
"INSERT INTO seen VALUES (?, ?)", (url_hash, int(time.time()))
)
conn.commit()
conn.close()
return exists
第二层(标题相似度): 对于不同URL但内容高度相似的情况(转载、洗稿),用标题的简单字符相似度做二次过滤。轻量场景下不需要上向量数据库,difflib.SequenceMatcher就够用:
from difflib import SequenceMatcher
def is_similar_title(new_title: str, recent_titles: list, threshold: float = 0.75) -> bool:
for title in recent_titles:
ratio = SequenceMatcher(None, new_title, title).ratio()
if ratio > threshold:
return True
return False
两层去重加上之后,重复推送问题基本消失。
---
现在跑得最稳的配置
给出关键参数配置清单,可以直接参考:
| 参数 | 推荐值 | 说明 | |temperature | 0 | 结构化输出必须确定性 |
| max_tokens | 512 | 摘要任务够用,控制成本 |
| 调用间隔 | 1.5s | 避免突发Rate Limit |
| 最大重试次数 | 5 | 指数退避,上限约30s |
| 去重窗口 | 7天 | 超过7天的URL哈希清理 |
| 每批处理上限 | 60条 | 单次任务不要太贪 |
| 日志级别 | INFO + 错误单独告警 | 方便排查不刷屏 |
Prompt模板(摘要+分类二合一,当前生产版本):
你是一个AI行业资讯处理助手。
你的输出必须且只能是合法的JSON,不包含任何其他文字。
处理以下文章,输出格式如下:
{
"summary": "一句话摘要,说明这条资讯的核心新意(50字以内)",
"category": "模型进展/产品发布/行业动态/研究论文/其他 中选一个",
"importance": 1-5的整数,5最重要,
"is_relevant": true或false(是否与大模型/AI基础设施相关)
}
文章标题:{{title}}
文章内容:{{content}}
---
跑了两个月,真实效果怎样
几个实际数据(主观估算,非精确统计):
- 每天处理原始条目:约200-400条
- 过滤后实际推送:约20-40条,过滤率约85%-90%
- 重复推送发生率:加去重后接近0
- API调用失败率:加重试后低于1%
- 每天token消耗:约15万-25万token(摘要任务为主)
- 小语种内容处理较差,日文、韩文的AI资讯摘要质量明显下降
- 某几个垂直方向的RSS源不稳定,时不时抓不到内容
- 重要性评分的校准还不够准,有时候一些真正重要的进展被打了低分
这些问题我知道在哪,但还没有排上优先级去修。
---
最后说一句
这套工作流目前只做到了"信息收集+摘要",本质上还是帮我读资讯。
但我最近在想一件事:下一步能不能让它自动判断——哪条动态值得写成一篇文章,并给出初步的选题角度?
也就是说,让Claude不只是帮我读资讯,而是帮我做编辑决策的第一层过滤。
从"信息消费"升级到"内容生产辅助",这个方向我已经有了一些思路。如果这篇的反响还不错,下篇写这个。
---
本文由8848AI原创,转载请注明出处。关注8848AI,带你从零开始学AI。#AI工具 #Claude #自动化工作流 #Python #API开发 #8848AI #AI资讯 #Telegram机器人