0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

自分の論文を"種"に、OpenAlexで繋がる論文を掘る「Paper Loop」——Phase 0の検証設計と、Grok Botの使い道

0
Posted at

対象読者:研究成果を発信につなげたい研究者・エンジニア。AIエージェントを開発フローに入れたい人
読了時間:約12分
最終確認日:2026年9月20日


この記事のポイント(3行要約)

  • 自著の論文2本を起点に、OpenAlex API(無料・キー不要)で「引用した/された/関連する」論文を取り、そのうちCC系ライセンスのものだけを記事化候補にする——これがPaper Loopの骨格
  • Phase 0は「取れるかどうかの検証」だけ。DBもUIも触らない、本文も取らない、出力は件数と要点だけ(count-only)。この制約が後の自動化を安全にする
  • Grok Botの出番は「APIで取れないもの」。JS描画後の出版社ページでライセンス表示を目視確認する、週1で新規被引用を巡回する——この2つに絞る

⚠️ 大事な前置き

本記事は、筆者が自分のポートフォリオサイト(Next.js/Vercel/Supabase東京リージョン)で進めている研究発信の自動化について、Phase 0(検証段階)の設計を公開するものです。スクリプトは設計と骨子を示しており、実行結果は今後の記事で報告します。OpenAlexのAPI仕様は変わることがあるため、公式ドキュメントを確認してください。研究成果については「候補として提示した」と書き、「AIが発見した」とは書きません。教育開発・研究案件の関係先、未公開データ、患者情報は扱いません。


🔰 まず用語の早見表

  • OpenAlex:論文・著者・機関のメタデータを無料公開しているデータベース。APIキー不要(メールアドレスを付けると優先レーンに入れる)
  • DOI:論文の固有ID。10.3390/... のような形式
  • cited_by:その論文を引用している論文(後から出た論文)
  • references:その論文が引用した論文(先に出た論文)
  • related_works:OpenAlexが内容の近さで結びつけた論文
  • OA(オープンアクセス):無料で読める論文。oa_status で gold/green/hybrid/bronze/closed に分かれる
  • CC BY/CC BY-SA/CC0:再利用を許すライセンス。記事で図や要約を使うときの根拠になる
  • count-only:件数と要点だけ出力し、生データを吐かない設計。fail-closedの原則の一つ
  • Grok Bot:クラウドPCでブラウザを操作するAIエージェント。今回は「画面を見る係」

1. 🔰 Paper Loopとは何か

🔰 たとえ話: 自分の論文を1本の木だとします。その木を引用した論文は「枝」、自分が引用した論文は「根」、似た論文は「隣の木」。Paper Loopは、この森を機械的に歩いて、「読んでよい・紹介してよい木」だけに印をつける仕組みです。

流れは4段階です。

  1. :自著の論文(DOI)
  2. 探索:OpenAlexで cited_by/references/related_works を取る
  3. 選別:OAかつCC系ライセンスのものだけ残す
  4. 記事化:残った論文を「自分の研究との関係」という切り口で紹介する

今回のPhase 0は、2の「取れるか」と3の「何件残るか」を確かめるだけです。記事は書きません。


2. 🔧 Phase 0の設計:安全境界を先に決める

自動化は「できること」より「やらないこと」から決めます。

やらないこと(fail-closed)

  • DBを書かない、UIを変えない。単体スクリプト1本で完結
  • 本文を取らない。OpenAlexのメタデータだけ。PDFのURLが返ってきても開かない
  • 生データを吐かない。標準出力は件数と、候補の doi/title/oa_status/license だけ
  • ライセンス不明は「候補」に数えない。skip として別に数える
  • APIの結果をそのまま信じない。ライセンス表示は後で人間(またはGrok Bot)が出版社ページで確認

入力(種)

識別子 状態
Proteomes 2026 10.3390/proteomes14030036 DOIあり
SciEnggJ 2024;17:202-244 DOI不明 まずCrossref/OpenAlexでタイトル検索して解決

2本目が重要です。地域誌・新興誌はOpenAlexに載っていないことがあり、「載っているか」自体が検証項目です。

出力(種ごとの表)

cited_by references related うちOA うちCC系 skip
Proteomes n n n n n n
SciEnggJ n n n n n n

最後に「分かった事実」を3行で要約して終わり。


3. 💻 スクリプトの骨子(scripts/openalex-probe.mjs)

⚠️ 以下は設計段階の骨子です。実行結果は次の記事で報告します。OpenAlexのエンドポイント仕様は公式(https://docs.openalex.org/)で確認してください。

// scripts/openalex-probe.mjs — Phase 0: 検証のみ。DB・UI・本文に触れない。
const BASE = "https://api.openalex.org";
const MAILTO = process.env.OPENALEX_MAILTO ?? ""; // 任意。優先レーン用
const CC = new Set(["cc-by", "cc-by-sa", "cc0"]);

const seeds = [
  { label: "Proteomes 2026", doi: "10.3390/proteomes14030036" },
  { label: "SciEnggJ 2024", doi: null, title: "(ここに論文タイトル)" },
];

async function get(path, params = {}) {
  const url = new URL(BASE + path);
  for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
  if (MAILTO) url.searchParams.set("mailto", MAILTO);
  const r = await fetch(url);
  if (!r.ok) throw new Error(`${r.status} ${url}`);
  return r.json();
}

// DOI → OpenAlex Work。DOI不明ならタイトル検索で解決(先頭1件のみ、要人間確認)
async function resolveSeed(seed) {
  if (seed.doi) return get(`/works/https://doi.org/${seed.doi}`);
  const res = await get("/works", { search: seed.title, "per-page": 3 });
  return res.results[0] ?? null;
}

// 複数IDをまとめて取得(メタデータのみ)。OpenAlexのORフィルタ上限に合わせて分割
async function fetchWorks(ids) {
  const out = [];
  for (let i = 0; i < ids.length; i += 50) {
    const chunk = ids.slice(i, i + 50).map((id) => id.split("/").pop()).join("|");
    const res = await get("/works", {
      filter: `openalex_id:${chunk}`,
      select: "id,doi,title,open_access,best_oa_location",
      "per-page": 50,
    });
    out.push(...res.results);
  }
  return out;
}

async function citedBy(workId) {
  const res = await get("/works", {
    filter: `cites:${workId.split("/").pop()}`,
    select: "id,doi,title,open_access,best_oa_location",
    "per-page": 200,
  });
  return res.results;
}

function tally(works) {
  let oa = 0, cc = 0, skip = 0;
  for (const w of works) {
    const isOA = w.open_access?.is_oa === true;
    const lic = w.best_oa_location?.license ?? null;
    if (isOA) oa++;
    if (lic === null) skip++;
    else if (CC.has(lic.toLowerCase())) cc++;
  }
  return { total: works.length, oa, cc, skip };
}

for (const seed of seeds) {
  const work = await resolveSeed(seed);
  if (!work) { console.log(`${seed.label}: OpenAlexに未収載`); continue; }

  const cited = await citedBy(work.id);
  const refs = await fetchWorks(work.referenced_works ?? []);
  const related = await fetchWorks(work.related_works ?? []);
  const all = [...cited, ...refs, ...related];

  // 件数と要点だけ出す(count-only)。生の本文・著者・抄録は出力しない
  console.log(`\n== ${seed.label} (${work.doi ?? "no DOI"}) ==`);
  console.table({
    cited_by: tally(cited),
    references: tally(refs),
    related: tally(related),
    all: tally(all),
  });
  for (const w of all.filter((w) => CC.has((w.best_oa_location?.license ?? "").toLowerCase())))
    console.log("  candidate:", w.doi, "|", w.title, "|", w.open_access?.oa_status, "|", w.best_oa_location?.license);
}

設計上のポイント

  • select でフィールドを絞る。取らなければ漏れない
  • cites: フィルタで被引用を取る。referenced_worksrelated_works はIDの配列で返るので、まとめて再取得
  • タイトル検索の結果は先頭1件を"仮"として扱い、人間が確認する。ここを自動で確定させない
  • 200件を超える被引用は今回のPhase 0では切る(自著の規模なら足りる想定。超えたら要ページング)

4. 🤖 Grok Botの使い道:APIで取れないものだけ

ここが本記事の主題です。Paper Loopの大半はAPIで済みます。ではGrok Botは何をするのか。「ブラウザで見ないと分からないこと」だけです。

使い道①:ライセンス表示の目視確認

OpenAlexの license フィールドは、出版社が機械可読で出している情報の写しです。欠けていたり、古かったりします。記事で「CC BYなので図を引用します」と書く前に、出版社ページに実際に表示されているライセンスを見る必要があります。

出版社ページの多くはJavaScriptで描画され、コードを読むAIには見えません。Grok Botはブラウザで開いてスクリーンショットを撮れます。

【Grok Bot への依頼】
Slackの #paper-loop に貼ったDOIのリスト(最大10件)について、
各DOIのランディングページを開き、
ライセンス表記(CC BY / CC BY-SA / CC0 / その他 / 表示なし)を
スクリーンショット付きで #paper-loop-report に報告して。
PDFは開かない。本文は読まない。ダウンロードしない。

使い道②:週1の被引用巡回

「自分の論文が新しく引用されたか」を毎週見るのは、人間がやると忘れます。Grok BotのRoutineに任せます。

【Routine:毎週月曜 8:00】
scripts/openalex-probe.mjs の実行結果(#paper-loop-report に貼られた表)と
先週の表を比べ、cited_by が増えていれば増分のDOIとタイトルだけ報告。
増えていなければ「変化なし」の1行だけ。

⚠️ スクリプトの実行そのものはCodexかローカルで行います。Grok BotのクラウドPCにリポジトリを置く必要はありません。Botが読むのはSlackに貼られた出力だけです。

使い道③:未収載誌の「載っているか」確認

SciEnggJのようにOpenAlexに載っていない可能性がある誌は、誌のサイトでDOIの有無・掲載ページ・ライセンス表記を直接見る必要があります。これもブラウザの仕事です。

使い道ではないこと

  • スクリプトを書く・直す:CodexかClaude Codeの仕事
  • どの論文を記事にするか決める:人間の仕事
  • 論文本文を要約する:Phase 0では誰もやらない。本文を取らないのが境界
  • DBに書く・UIに出す:Phase 1以降。しかもGrok Botではなく、レビューを通したコードで

Grok Botに渡さないもの

  • リポジトリの .env、Supabaseの接続情報、Vercelのトークン
  • /members(会員エリア)のログイン
  • 未発表の原稿、投稿中の論文、共同研究者の個人情報

Grok Botのクラウド PCは、そのユーザーの全Botで共有されます。置くのは「Slackに貼ったDOIのリスト」だけで足ります。


5. 🔗 全体の分業(誰が何をやるか)

工程 担当 理由
仕様(PAPER_LOOP_SPEC.md)の維持 人間+Claude 境界の判断は人間、文書化はClaude
スクリプト実装 Codex 実働コード
実行とcount-only出力 ローカル or Codex リポジトリがある場所で
出版社ページのライセンス目視 Grok Bot JS描画後の画面を見る
週次の被引用巡回 Grok Bot 常駐・定期
記事化する論文の選定 人間 判断
記事の下書き Claude 長文と整合性
公開 人間 ゲート

AIがAIを直接呼ぶ箇所はありません。つなぎ目はSlackの #paper-loop#paper-loop-report、それとGitHubのPRだけです。


6. 💬 こんな会話、ありませんか

研究者A「自分の論文が引用されてるか、Google Scholarのアラートでいいんじゃない?」

研究者B「アラートは"来た"までしか分からない。OAかどうか、CC BYかどうかまで機械で分けたい。そこまで分かれば記事にしていい論文が自動で絞れる」

研究者A「で、Grok Botは何するの?」

研究者B「APIが言ってるライセンスを、出版社のページで本当にそうか見てもらう。あと週1で増分を見張ってもらう。それだけ」

研究者A「それだけ?」

研究者B「それだけに絞るから、Botに何も預けなくて済む」


7. 🎨 補足:報告画面を作るなら、どのデザイン基準を使うか

Phase 1以降で件数の推移をダッシュボードにするなら、筆者はデザインの基準を用途で使い分けています。

AIに画面を作らせるときは、「オシャレにして」ではなく「デジタル庁デザインシステムのテーブルとタグに従って」と基準を指定すると、出力が安定します。普段使っているアプリで「これはいい」と思ったら、なぜそう思ったかを言葉にしておく。それがそのままAIへの指示になります。


✅ Phase 0 チェックリスト

  • scripts/openalex-probe.mjs は単体で動き、DB・UIに触れない
  • 本文・PDF・抄録を取得していない(select で絞っている)
  • 出力は件数と doi/title/oa_status/license だけ
  • ライセンス不明は skip として別集計
  • SciEnggJ のタイトル検索結果は人間が確認してから確定
  • Grok Botに渡すのはSlackに貼ったDOIリストのみ。.env・リポジトリ・会員エリアは渡さない
  • Grok Botのライセンス目視は「PDFを開かない・本文を読まない・ダウンロードしない」を依頼文に明記
  • 実行後、「分かった事実」を3行で記録

まとめ:いちばん大事なことを、もう一度

  1. Paper Loopは「自著→繋がる論文→CC系だけ→記事化」。Phase 0は取れるかの検証だけ
  2. 安全境界は「DB・UIを触らない、本文を取らない、count-only、不明はskip」
  3. Grok Botの使い道はライセンスの目視確認と週次巡回の2つだけ。スクリプト・選定・記事化は別の担当
  4. Grok Botに預けるのはSlackのDOIリストだけ。認証情報・リポジトリ・会員エリアは渡さない
  5. AIがAIを呼ばない。つなぎ目はSlackとGitHubの2本

今夜やる1つのこと: docs/PAPER_LOOP_SPEC.md の §7(安全境界)に「Grok Botに渡してよいもの/渡さないもの」を3行足す。スクリプトより先に、境界を書く。


⚠️ 免責

本記事は2026年9月20日時点の設計であり、スクリプトは検証前の骨子です。OpenAlexのAPI仕様・レート制限・フィールド名は変更されることがあります。ライセンスの最終判断は出版社の表示と各ライセンスの条文に基づいて行い、本記事の記述を根拠にしないでください。研究成果の記述は「候補として提示した」の範囲に留めています。筆者は、本記事の内容を実際の業務や研究で使われたことに起因するいかなる損害についても責任を負いません。


出典・参考資料

OpenAlex/Crossref

Grok Bot

デザイン基準

筆者の関連記事


著者プロフィール

臨床工学技士 × AIエンジニア / 11年間、病院の医療機器の現場に立ち続けてきました。
いまはAIエンジニアとしても活動しながら、酪農学園大学の研究生として論文博士の取得を目指しています。
研究テーマの主軸は遺伝子医療の未来。そのうえで、医療現場と地続きにある病院のIT・サイバーセキュリティ・医療AI導入についても、現場で起きている課題と一次情報を突き合わせながら調べ続けています。

質問・誤りの指摘・「うちではこうしている」という事例の共有、いつでも歓迎します。

X:@endoh_taichi
Qiita:@TaichiEndoh

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?