spacevision

ガジェット好きのアマチュアサイクルフォトグラファー

X運用AIエージェント作成中。ローカルLLMとX API v2で詰まった一日

Codexで「AI編集部」を作ってブログを動かす日々の延長で、Xにも同じ思想を入れたくなった。

ブログは、企画、調査、下書き、編集、公開準備に分けると扱いやすくなる。ではXも同じように、情報収集、投稿候補の生成、通知、人間の確認、投稿という流れに分けられないだろうか。

そう思って、@spacevision のX運用にAIエージェントを組み始めた。

最初の目標は、X Premiumの収益化要件に向けて、毎日続けられる運用を作ることだ。AIに発信を丸投げしたいわけではない。毎日ニュースを拾い、考え、投稿候補を作るところまでの重さを少し軽くしたい。

X公式ヘルプでは、Creator Revenue Sharingの参加条件として、Premium等の加入、過去3か月で500万 organic impressions、500 verified followersなどが示されている。さらに報酬計算では、Verified Home Timeline impressionsが影響する要素として説明されている。

500万impを90日で割ると、1日あたり約55,000imp。Verified followersは500人がひとつの線になる。気合いだけで届く数字ではない。毎日、無理なく回せる仕組みが必要だ。

そこで、ローカルPCで動く半自動運用エージェントを作った。1日でかなり進んだ。うまくいったところもあるし、X API v2で何度も足止めされたところもある。忘れないうちに記録しておく。

作ったもの

全体の流れはこうだ。

X運用AIエージェントの構成図 RSS収集から投稿までの流れ。最後の投稿判断は自分で残す。※イメージイラスト

夜のRSS収集(27ソース、約488件/日)
  → 直近30時間フィルタ(35件前後に圧縮)
  → 3カテゴリ別 Top10 でDigest生成
  → ローカルLLMで「問いかけ型」の投稿候補を5〜8本生成
  → LINE通知(Digest + 投稿候補リスト)
  → 私が良いものをタップ投稿

毎日21:30にWindows タスクスケジューラから起動する。自宅でPCを使っている時間帯に合わせた。最初からクラウドに置いて完全自動化するより、まずは自分の生活リズムの中で回ることを優先した。(このあたりは、いかにも個人運用らしい。)

技術スタックは次のとおり。

  • Python 3.12
  • feedparser / requests / beautifulsoup4 / PyYAML / dateutil
  • ローカルLLM: Ollama + Gemma 4 26B MoE
  • 通知: LINE Messaging API
  • 投稿自動化: tweepy + X API v2
  • Webhook受信: Flask
  • 外部公開: Tailscale Funnel

ポイントは、投稿候補の生成をローカルで完結させることだ。API課金を気にしなくてよいし、文体プロンプトを何度も試せる。個人のX運用では、この「気軽に失敗できる」ことがかなり大きい。

Gemma 4は2026年4月にGoogleが発表したオープンモデルで、26B MoEと31B Denseなどが用意されている。公式記事ではApache 2.0 licenseで提供され、26BモデルはArena AI text leaderboardで#6と紹介されている。手元ではRTX 5070 Ti 16GB、RAM 64GBの環境で、Q4量子化なら十分実用的に動いた。

LINE通知に投稿候補が届く画面イメージ LINEにDigestと投稿候補を送る。※イメージイラスト

ライターAgentの文体を決める

投稿候補のメインパターンは「問いかけ型」に絞った。

Xでは、ただ情報を流すだけだと会話が生まれにくい。アルゴリズムの細かい重みは時期によって変わるし、外から完全に分かるものでもない。ただ、返信や会話が重要視される傾向はある。収益化を目標にするなら、ニュース紹介で終わらせず、読んだ人が自分の意見を返しやすい形にする必要がある。

そこで、文体ルールはかなり強めにした。

  • 常体で書く
  • 自称は「私」
  • 100〜140字
  • 絵文字なし
  • ハッシュタグなし
  • 本文に外部URLなし
  • 最後は問いかけで終える

最初は「撮影者視点を必ず入れる」とプロンプトに書いた。すると、機材レビューでも、選手のnoteでも、全部が「写真家として見ると」という口調になってしまった。

これは無理があった。

私はアマチュアサイクルフォトグラファーではあるけれど、すべての話題を写真目線で見るわけではない。ロードバイク好きとして反応することもあれば、観戦好きとして見ることもある。AIに肩書きを強く渡しすぎると、人間の幅が狭くなる。

そこでプロフィールを「ロードバイク好き・観戦好き」を主軸に書き直した。すると、機材記事には機材好きとして、レース速報には観戦者として、写真の話題には撮影者として反応するようになった。

実際に出てきた候補のひとつがこれだ。

プロロゴの最新サドル「Choice」のインプレッションは非常に参考になる。現代のレーシングサドルは、単に柔らかいだけでなく、剛性やサポート性も高まっていると改めて感じた。自分の体格や走行スタイルに対して、このモデルは本当に最適なのか。

まだ少し硬い。でも悪くない。少なくとも「AIが雑に要約しました」という感じではなく、自分の関心に寄せた問いかけにはなっている。ここまで来ると、投稿候補としては十分たたき台になる。

X API v2で詰まった

ここからが本題だ。

X API v2周りで、何度も詰まった。同じ症状に当たる人もいると思うので、手元で起きたことを整理しておく。

罠1: App is not attached to a Project

POST /2/tweets を叩くと、403 Forbiddenが返ってきた。

When authenticating requests to the Twitter API v2 endpoints,
you must use keys and tokens from a Twitter developer App
that is attached to a Project.

X公式ドキュメントにも、X API v2 endpointsを使うにはProjectに関連付いたAppのkeys/tokensが必要、と書かれている。古いStandalone Appのままだと、Tokenが正しく見えても通らない。

対処は、Developer PortalでAppをProjectに関連付けるか、Projectの中で新しくAppを作ることになる。

X API v2のProject紐付けエラーの説明イメージ 403 Forbiddenで詰まったときの確認ポイント。※イメージイラスト

罠2: ghost association

次にハマったのが、Standalone AppをProjectに移動したあとの状態だ。

画面上ではProject内にAppが表示されている。ところが /2/users/me を叩くと、まだProjectにattachedされていないという403が返る。さらに「移動」ボタンを押すと、逆にStandalone側へ戻されそうに見える。

UIとバックエンドの状態が食い違っているように見えた。私はこれを、ひとまずghost associationと呼んでいる。

公式仕様としてそういう言葉があるわけではない。ただ、手元ではこの状態から復旧できなかった。結局、古いAppを削除し、新しい名前で作り直す方向に切り替えた。Project作成フローの中で続けてAppを作るほうが、状態がきれいに見えた。

罠3: User authentication settingsが見つけにくい

Appを作ってSettingsタブを開くと、「User authentication settings (DEPRECATED)」のような表示が出てくる。OAuth 1.0aの設定がどこにあるのか分かりにくい。

XはOAuth 2.0への移行を進めている。公式ドキュメントでも、新しいプロジェクトにはOAuth 2.0が推奨されている。一方で、手元のtweepy実装ではOAuth 1.0aのAccess Token & Secretを使って投稿しようとしていた。

その場合、App permissionsをRead and writeにする必要がある。Read onlyのままでは投稿できない。

画面上のEditボタンが見つからない場合は、シークレットモードでログインし直す、ブラウザを変える、時間を置く、という泥臭い確認になる。Developer PortalのUIは変わることがあるので、ここは最新画面を見ながら進めるしかない。

罠4: 1日3App制限

ProjectやAppを何度か作り直していたら、ついにこのエラーが出た。

Your daily allowance of 3 new Apps has been reached.
Wait 24 hours before creating another.

これは公式ドキュメント内では確認できていないが、実際にDeveloper Portalで表示された。1日に何度も作り直す前提で試行錯誤していると、ここで止まる。

X API周りは、詰まったら作り直せばいい、という考え方だと危ない。作り直し回数にも上限がある前提で、手順をメモしながら進めたほうがいい。

罠5: TokenのPermission

Read and writeに変更しても、変更前に発行したAccess Tokenは古い権限のままだ。

X公式ドキュメントにも、permission変更後は再認可して新しいtokenを得る必要がある、と書かれている。これは本当に引っかかりやすい。

設定を変えたら、Access Token & SecretをRegenerateする。OAuth 2.0の場合も、scopeが変わったら取り直す。ここを忘れると、画面上はRead and writeなのにAPIでは書き込めない、という状態になる。

Intent URLでしのぐ

X API側が24時間ロックされたので、完全自動投稿はいったん明日以降に回すことにした。

その代わり、Web Intent URLを使った「ほぼ自動」に切り替えた。

LINE通知の各候補メッセージの末尾に、X公式のIntent URLを付ける。

https://x.com/intent/tweet?text=<本文をURLエンコード>

スマホのLINEでこのリンクをタップすると、Xアプリの投稿画面が本文入りで開く。私はそこで内容を見て、「ポスト」ボタンを押すだけだ。コピペはいらない。実質タップ2回で済む。

これはかなり良かった。

API課金は不要。認証情報も不要。X APIのProjectやToken設定に左右されない。なにより、最後に自分の目で見る時間が残る。

完全自動投稿は便利だが、誤投稿したときのリスクも大きい。Xは凍結や制限のリスクもあるし、AIが作った投稿をそのまま流すのは、自分の発信としても少し怖い。今の段階では、Intent URLを使った半自動運用で十分だと思った。

たぶん、この「十分だ」と思えるところが大事なのだと思う。自動化は、できるところまで進めると楽しい。でも、全部を自動にしなくても運用は軽くなる。

今日の学び

ローカルLLMの日本語生成は、かなり実用域に入っている。Gemma 4 26B MoEは、文体ルールもかなり聞く。もちろん一発で完璧にはならないが、投稿候補を出す相棒としては十分だ。

一方で、X APIは思った以上に手強い。Project、Standalone App、OAuth 1.0a、OAuth 2.0、Tokenの権限、Developer PortalのUI。ひとつずつは理解できるのだが、画面上の状態とAPIの返答が食い違うと、一気に迷路になる。

そして、半自動運用は完全自動より安全だ。

AIが候補を出す。私は最後に見る。良ければ投稿する。少し違えば直す。ダメなら捨てる。

このくらいの距離感が、個人の発信には合っている気がする。AIに任せるのではなく、AIで毎日の入口を軽くする。ブログのAI編集部と同じ考え方だ。

実際、この作業を進めたあと、ブログ側のAI編集部も少し体制を変えた。Ollama + Gemma 4を、Codexに渡す前の前処理エンジンとして使う。RSSや長いメモ、X投稿候補の量産はローカルLLMで軽くして、Codexは編集長として検査、統合、公開準備に集中させる。今回のX運用AIエージェントは、そのままブログ運用の設計にも返ってきた。

結局、発信は自分のものだ。だからこそ、楽に続けるための道具は欲しい。でも、最後に押すボタンは自分で押したい。

次にやること

24時間後に、X APIのクリーンな再構築を試す。

それと並行して、次を進める。

  • Premium Analyticsで、Verified followersとimpressionsの現状を確認する
  • 90日目標に対するKPIギャップを見える化する
  • 数日運用して、投稿候補の文体とトーンを調整する
  • 大きめのPremiumアカウントに対する返信候補生成Agentを作る

X Premium収益化への90日は、短いようで長い。ロードバイクと同じで、最初から完璧なフォームで走れるわけではない。走りながら、少しずつ整えていく。

主要リンク