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で何度も足止めされたところもある。忘れないうちに記録しておく。
作ったもの
全体の流れはこうだ。
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に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を作ることになる。
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日は、短いようで長い。ロードバイクと同じで、最初から完璧なフォームで走れるわけではない。走りながら、少しずつ整えていく。