News Search API でモーニングブリーフィングエージェントを作る

創業者・PM・アナリストが朝 8 時に欲しいのは同じもの:昨夜何が変わったかの精製サマリ。News Search API + LLM + cron があれば、午後一番で出荷できる。
要点
- •構成:cron → News Search → 注目記事を URL Extract → LLM が要約 → Slack 投稿。
- •<code>start_date = 昨日</code> で鮮度、<code>country_code</code> で地域を制御。
- •並列で複数 News Search を呼んでトピック別に分割、LLM がマージ・重複排除。
- •総コストはトピックあたり 15 credits/日 + LLM トークン。5 トピックでも標準価格 $0.10/日 以下。
「使えるブリーフィング」の形
モーニングブリーフィングエージェントは 1 つの問いに答えるべき:「昨夜知っておくべき変化は何か?」見出しを羅列するだけでは RSS と同じで 1 週間でミュートされる。残るのは:5 行の要点、リンク付き、トピック別、ユーザーの語り口。
これを小さなパイプラインに分解:
- 取得:N トピックの最近のニュース — News Search API。
- 抽出:モデルが引用したいリンクの本文 — URL Extract API。
- 要約 + クラスタリング:好みの LLM。
- 配信:Slack / Email / Notion など既存チャンネル。
- スケジュール:cron — Vercel Cron、GitHub Actions、n8n 等。
Step 1:トピックを選ぶ
3〜6 トピックで十分。12 トピックのブリーフィングはスクロールで飛ばされる。例:
- B2B SaaS 創業者:「AI 資金調達」「OpenAI / Anthropic 動向」「競合動向」。
- 金融アナリスト:「FOMC と Treasury」「半導体サプライチェーン」「特定 ticker」。
- ヘルスケア PM:「FDA 承認」「臨床試験読み出し」「保険償還変更」。
Step 2:原信号を取る
トピックごとに並列で News Search を 1 回呼ぶ。鮮度は start_date で:
from datetime import date, timedelta
import asyncio, aiohttp
KEY = "pk_yourkey"
TOPICS = [
"AI agent infrastructure funding",
"OpenAI Anthropic Google new releases",
"RAG and LLM tool calling research",
]
async def fetch_topic(session, q):
yesterday = (date.today() - timedelta(days=1)).isoformat()
async with session.post(
"https://www.apipick.com/api/search/news",
headers={"x-api-key": KEY},
json={"query": q, "start_date": yesterday},
) as r:
return q, await r.json()
async def fetch_all():
async with aiohttp.ClientSession() as s:
return await asyncio.gather(*[fetch_topic(s, q) for q in TOPICS])各呼び出しは ranked 見出し最大 5 件(num_results で 10 まで)。3 トピックで 1 日 3 × 15 = 45 credits、$5 / 5,000 換算で約 $0.045/日。News API は日次総コストでは小さい — メインは LLM。
Step 3:選択的に本文を抽出
すべての記事の本文は要らない — モデルが詳しく引用しそうなものだけ。簡単なヒューリスティック:トピックごとに上位 2 件を抽出。API Pick なら 1 回のバッチ呼び出し:
import requests
urls = [r["url"] for topic, payload in results for r in payload["results"][:2]]
extracted = requests.post(
"https://www.apipick.com/api/extract",
headers={"x-api-key": KEY},
json={"urls": urls, "extract_effort": "auto"},
).json()URL 1 件 2 credits、3 トピックブリーフィングなら抽出ステップは 1 日約 12 credits。
Step 4:要約プロンプト
プロンプトがブリーフィングの「声」を決める。出発点:
You are an assistant that writes a morning briefing in <Sarah's> voice:
direct, no fluff, no marketing language.
Input: a JSON list of {topic, headlines, extracted_bodies}.
Output rules:
- 1 short paragraph per topic, max 60 words.
- Each paragraph ends with up to 3 inline source links.
- If a topic has fewer than 2 substantive stories overnight, omit it.
- If the entire briefing has fewer than 2 substantive topics, output the
literal token SKIP and nothing else.
- Never editorialise. Quote facts and figures verbatim from the sources.
Output format: Slack-flavoured markdown.「低シグナルなら SKIP」が単独で ROI 最高のルール。これがブリーフィングがミュートされない根本理由。
Step 5:配信とスケジュール
Python cron 全体で 80 行未満。Slack 投稿:
if briefing.strip() == "SKIP":
return
requests.post(
SLACK_WEBHOOK_URL,
json={"text": briefing, "username": "Morning Briefing", "icon_emoji": ":sunrise:"},
)Vercel Cron(vercel.json)、GitHub Actions、AWS EventBridge、n8n でスケジュール。あなたのタイムゾーン 7:45 で実行 — 8 時に座ったときには既に届いているように。
n8n でノーコード派
- Schedule trigger:毎日 7:45(ユーザーTZ)。
- HTTP Request ノード(トピックごと 1 つ):POST
/api/search/news、start_date= 昨日。 - Merge:トピック結果を結合。
- HTTP Request:
/api/extract。 - OpenAI / Anthropic:要約プロンプト実行。
- If:出力が SKIP でないか確認。
- Slack:投稿。
本番で気をつけること
- トピック漂流。「AI agents」のような広いクエリは 6 ヶ月で曖昧になる — インデックスは育つがブリーフィングは具体的なまま。クエリは四半期に 1 度引き締める。
- 日跨ぎ重複。前日の URL リストをモデルに渡し「このリストの記事は再カバーしない」と指示。
- 静かな週末。SKIP ルールが既に処理する。日次のチェックインをブリーフィングに依存しないこと。
反復、出して終わりにしない
最初の 1 週間は毎朝ブリーフィングを読む。モデルが嘘をついた、誤分類した、見落とした箇所をメモ。プロンプトを更新。1 週間後にはブリーフィングが習慣になる — そしてあなたは約 80 行のコードと 3 回の API 呼び出しで動くエージェントを作ったことになる。
よくある質問
Google News や RSS アグリゲーターでよくない?
それでもいい — ただし退屈な部分(クラスタリング、重複排除、要約、本文を書く)が残る。エージェントは LLM でその部分を片付ける。RSS は見出しを返し、エージェントは「これがなぜ重要か」を出典リンク付きで返す。
News Search API の鮮度は?
主要メディアをほぼリアルタイムにインデックス。前 24 時間をカバーする朝 8 時のブリーフィングなら start_date を昨日に。1 時間ごとの速報ボットなら start_date を今日に、前回結果に対して重複排除する。
今日特に話すことがない場合は?
プロンプトに書き込む:「If fewer than 3 substantive stories changed overnight, return SKIP.」cron は SKIP を尊重して投稿しない。ブリーフィング疲れは Slack チャンネルがミュートされる最速の道。
n8n なしでも動く?
可。下の 30 行 Python スクリプト + cron で十分。n8n はビジュアルデバッグと Slack 統合に便利だが必須ではない。
同じ記事が複数トピックで重複要約されないようにするには?
同じ実行内で先行クエリで使った URL をモデルに渡し、「このリストの URL は再言及しないこと」と指示する。あるいは多トピックを 1 回検索でまとめてモデルに分けさせる。後者の方が安い。
この記事で使われている API
API Pick の CEO。AI エージェントと LLM ワークフロー向けの本番運用可能な API について執筆。