拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Codex 实战 Skills:用 Skill 自动抓取 20 个 RSS 订阅,并用 AI 自动输出中文摘要(TaoToken 统一 Key 接入版)

1. 为什么我要把 20 个 RSS 源塞进 Codex Skill每天打开阅读器20 多个订阅源堆着上百条未读标题党一堆真正值得看的没几条。我试过用传统 RSS 阅读器加规则过滤但规则写起来比读文章还累而且英文源还得自己翻译。后来我把这件事拆成两步抓取交给脚本理解交给 AI中间用 Codex 的 Skill 机制串起来一次配置就能跑通全流程。Codex 的 Skill 本质上是一个可被 Agent 调用的能力单元你可以把它理解成给 AI 装了一只“手”这只手负责去网上把 RSS 拉回来、把正文洗干净再交给模型生成中文摘要。本文要交付的就是这样一个名为rss_aggregator的 Skill包含config.toml与settings.json的关键字段、20 个 RSS 源的抓取逻辑以及摘要输出的验证动作。适合已经会用命令行、想把手动读 RSS 变成自动流水线的开发者。整条链路里AI 调用是最容易卡住的一环不同模型的 Key 格式不一样切换模型要改代码。我用 TaoToken 的统一 Key 通道来解决这个问题一个 Key 走 OpenAI 兼容接口Skill 里只配一个base_url和api_key换模型不用动业务代码。下面从环境准备开始一步步把这条流水线搭起来。2. TaoToken 前置统一 Key 与接口地址在写 Skill 之前先把 AI 通道准备好。TaoToken 提供的是 OpenAI 兼容的 API 通道也就是说你原来用openaiSDK 写的代码只需要改base_url和api_key两个地方就能接上。对 Skill 这种要长期跑的自动化任务来说统一 Key 的好处是抓取脚本、摘要脚本、后续可能加的翻译脚本全都共用一套凭证不用为每个模型单独维护配置。你需要先拿到一个 API Key。登录官网后进入控制台在 API Keys 页面创建一个新 Key复制出来保存好后面写进config.toml。接口地址固定为https://taotoken.net/api注意这个地址不带任何查询参数直接作为base_url使用。注意Key 只显示一次创建后立刻复制。不要把它硬编码进提交到 Git 的脚本里用环境变量或本地配置文件承载。如果你还没决定用哪个模型可以先去模型对话页面手动试几条 RSS 正文看看摘要质量和速度是否符合预期再决定写进配置的模型名。对于长期跑的编码类或 Agent 类任务Coding Plan 的额度模型通常比按次调用更划算具体可以在控制台里对比。3. 可复制配置config.toml 与 settings.jsonSkill 的配置分两层config.toml管运行参数和 AI 通道settings.json管 RSS 源清单和输出行为。这样拆的好处是换模型只动 toml加订阅源只动 json互不干扰。先看config.toml[llm] base_url https://taotoken.net/api api_key sk-你的TaoToken密钥 model gpt-4o-mini temperature 0.2 max_tokens 600 timeout 30 [fetch] concurrency 5 request_timeout 12 retry_times 2 user_agent Mozilla/5.0 (compatible; RSSAggregatorSkill/1.0) [output] result_file aggregated_results.json max_articles_per_run 20 summary_language zh-CNbase_url指向 TaoToken 的 API 地址api_key填你刚创建的 Key。temperature设 0.2 是为了让摘要稳定不要每次跑出来风格差异太大。concurrency控制并发抓取数5 是个比较稳的值太高容易被源站限流。再看settings.json这里放 20 个 RSS 源{ sources: [ { name: Hacker News, url: https://hnrss.org/frontpage, category: Tech }, { name: Ars Technica, url: https://feeds.arstechnica.com/arstechnica/index, category: Tech }, { name: The Verge, url: https://www.theverge.com/rss/index.xml, category: Tech }, { name: TechCrunch, url: https://techcrunch.com/feed/, category: Business }, { name: InfoQ 中文, url: https://www.infoq.cn/feed, category: Backend }, { name: 阮一峰的网络日志, url: https://www.ruanyifeng.com/blog/atom.xml, category: Frontend }, { name: 酷 壳, url: https://coolshell.cn/feed, category: Backend }, { name: 少数派, url: https://sspai.com/feed, category: Product }, { name: 机器之心, url: https://www.jiqizhixin.com/rss, category: AI }, { name: 量子位, url: https://www.qbitai.com/feed, category: AI }, { name: GitHub Blog, url: https://github.blog/feed/, category: DevOps }, { name: Cloudflare Blog, url: https://blog.cloudflare.com/rss/, category: Security }, { name: AWS News, url: https://aws.amazon.com/blogs/aws/feed/, category: Cloud }, { name: Kubernetes Blog, url: https://kubernetes.io/feed.xml, category: DevOps }, { name: React Blog, url: https://react.dev/rss.xml, category: Frontend }, { name: Vue Blog, url: https://blog.vuejs.org/feed.rss, category: Frontend }, { name: Rust Blog, url: https://blog.rust-lang.org/feed.xml, category: Backend }, { name: Python Insider, url: https://pythoninsider.blogspot.com/feeds/posts/default, category: Backend }, { name: OpenAI Blog, url: https://openai.com/blog/rss.xml, category: AI }, { name: Hugging Face Blog, url: https://huggingface.co/blog/feed.xml, category: AI } ], dedup: { by_url: true, by_title_similarity: 0.9 } }这 20 个源覆盖了 AI、前后端、DevOps、安全、产品几个方向中英文都有。dedup段控制去重策略by_url是基础去重by_title_similarity用标题相似度挡掉不同源转载的同一篇文章。4. 抓取与摘要Skill 主流程代码配置就位后写 Skill 的执行逻辑。核心分三步并发拉取 RSS、用 Readability 提取正文、调用 TaoToken 生成中文摘要。下面这段代码可以直接放进rss_aggregator_skill.pyimport json import tomllib import feedparser import requests from concurrent.futures import ThreadPoolExecutor, as_completed from readability import Document from bs4 import BeautifulSoup from openai import OpenAI with open(config.toml, rb) as f: cfg tomllib.load(f) with open(settings.json, r, encodingutf-8) as f: settings json.load(f) client OpenAI( base_urlcfg[llm][base_url], api_keycfg[llm][api_key], ) HEADERS {User-Agent: cfg[fetch][user_agent]} def fetch_rss(source): try: resp requests.get(source[url], headersHEADERS, timeoutcfg[fetch][request_timeout]) resp.raise_for_status() feed feedparser.parse(resp.content) return source, feed.entries[:5] except Exception as e: print(f[RSS失败] {source[name]}: {e}) return source, [] def extract_content(url): try: resp requests.get(url, headersHEADERS, timeoutcfg[fetch][request_timeout]) resp.raise_for_status() doc Document(resp.text) soup BeautifulSoup(doc.summary(html_partialTrue), html.parser) text soup.get_text(separator\n, stripTrue) return text[:4000] except Exception as e: print(f[正文失败] {url}: {e}) return def summarize(title, content, source_name): prompt f你是技术内容编辑。请对下面文章输出严格 JSON不要 Markdown 代码块。 字段category从 AI/前端/后端/DevOps/安全/产品/其他 中选一个、 keywords3-5 个、summary150 字左右简体中文直击技术要点。 标题{title} 来源{source_name} 正文{content} try: resp client.chat.completions.create( modelcfg[llm][model], messages[{role: user, content: prompt}], temperaturecfg[llm][temperature], max_tokenscfg[llm][max_tokens], ) raw resp.choices[0].message.content.strip() if raw.startswith(): raw raw.strip().lstrip(json).strip() return json.loads(raw) except Exception as e: print(f[摘要失败] {title}: {e}) return {category: 其他, keywords: [], summary: 摘要生成失败}主流程把抓取和摘要串起来控制单次运行的文章数def run(): results [] with ThreadPoolExecutor(max_workerscfg[fetch][concurrency]) as pool: futures [pool.submit(fetch_rss, s) for s in settings[sources]] for fut in as_completed(futures): source, entries fut.result() for entry in entries: if len(results) cfg[output][max_articles_per_run]: break content extract_content(entry.link) if not content: continue meta summarize(entry.title, content, source[name]) results.append({ title: entry.title, source: source[name], url: entry.link, category: meta.get(category, 其他), keywords: meta.get(keywords, []), summary: meta.get(summary, ), }) with open(cfg[output][result_file], w, encodingutf-8) as f: json.dump(results, f, ensure_asciiFalse, indent2) print(f完成共 {len(results)} 篇) return results if __name__ __main__: run()这段代码里base_url和api_key全部从config.toml读取业务逻辑里没有任何硬编码的模型信息。想换模型改 toml 里一行model就行抓取和摘要代码不用动。5. 验证请求跑通并检查输出配置和代码都写好后先做一次小规模验证别一上来就跑满 20 个源。把settings.json里的sources临时只留 2 个max_articles_per_run改成 3然后执行python rss_aggregator_skill.py正常的话你会看到类似输出完成共 3 篇打开aggregated_results.json检查每条记录是否包含title、source、url、category、keywords、summary六个字段摘要是不是中文、有没有明显跑题。如果摘要字段是“摘要生成失败”说明 AI 通道没通先单独验证 Keycurl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-你的密钥 \ -H Content-Type: application/json \ -d {model:gpt-4o-mini,messages:[{role:user,content:回复ok}]}返回里能看到choices字段就说明 Key 和地址都没问题。确认单源跑通后再把 20 个源恢复max_articles_per_run设回 20完整跑一次。第一次全量跑建议观察日志里有没有大量[RSS失败]或[正文失败]有的话按下一节的排查表处理。6. 本篇常见错排查跑这条流水线时报错基本集中在三类网络抓取、正文提取、AI 调用。下面这张表是我实际踩过的坑和对应处理方式。现象可能原因处理方式[RSS失败]大量出现源站限流或 URL 失效降低concurrency逐个 curl 验证 URL[正文失败]但 RSS 正常目标站反爬或正文在 JS 里换用该源的 RSS 全文或跳过该源摘要返回“生成失败”Key 错误或base_url写错用上面的 curl 单独验证通道摘要非中文Prompt 被截断检查max_tokens是否过小同一篇文章重复出现去重未生效确认dedup.by_url为 true检查 URL 是否带追踪参数运行很慢串行抓取或源站响应慢提高concurrency但别超过 8其中最常见的是base_url多写了/v1或少了/api。TaoToken 的接口地址是https://taotoken.net/apiSDK 会自动补全路径你不需要手动加/v1/chat/completions。如果摘要一直失败先去 API Keys 页面确认 Key 状态是否正常再检查config.toml里有没有多余空格。另一个容易忽略的点是readability对某些中文站点提取效果一般正文可能只剩标题。遇到这种情况可以在extract_content里加一个兜底如果提取出的文本长度小于 200 字就直接用 RSS 条目自带的summary字段作为正文虽然信息量少一点但至少能生成摘要。7. 下一步把 Skill 接进你的工作流跑通之后这个 Skill 可以按你的习惯接进不同环节。想每天定时跑用系统计划任务调用python rss_aggregator_skill.py即可想把结果推到手机读aggregated_results.json再调一个推送接口就行。如果你还想让 Agent 在编码时自动调用这个 Skill可以把脚本注册成 Codex 可发现的工具具体接入方式参考接入文档里的 Skill 注册章节。需要长期跑、文章量大的话建议在控制台里看一下 Coding Plan 的额度模型比单次调用更适合这种每天固定消耗的场景。模型选择上摘要任务用轻量模型就够把省下的额度留给更复杂的推理任务。配置骨架已经给全剩下的就是按你的订阅源清单替换settings.json然后让它自己跑起来。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门