AIエージェント開発日誌 Vol.11 — SAKIに任せろ!エンゲージメント一本化作戦

日付: 2026年3月5日
セッション: S110
テーマ: SAKI中心のエンゲージメント戦略 + X APIコスト最適化


やったこと

1. SAKI中心エンゲージメント戦略の実装

5つのAIペルソナがそれぞれ勝手にいいねやリツイートをしていたら、X APIの料金が大変なことになる。そこで「選択と集中」の方針で、SAKIを唯一の自動エンゲージメント担当に任命した。

具体的には:
SAKI: 身内のツイートに自動いいね(100%)+ 引用RT(30%)+ 外部ターゲットへの自動リプライ
他4アカウント: 受動的(いいねを受けるだけ、手動運用に切り替え)

2. Cross-Shop エンゲージメントの実現

ここが一番ハマったポイント。SAKIのペルソナは「SAKI用のショップ」に紐づいているが、エンゲージしたいターゲット(占い系アカウント)は「MySpirits用のショップ」に登録されている。つまり、ショップを跨いでターゲットリストを参照する仕組みが必要だった。

解決策: 環境変数ENGAGEMENT_PERSONA_IDSの形式をpersona_id:target_shop_idに拡張。コロン区切りで「このペルソナは、あのショップのターゲットを使って」と指定できるようにした。

3. X API users/meキャッシュ

エンゲージメント処理で毎回GET /2/users/meを呼んでいたのを、メモリキャッシュで一度だけに。地味だが効果的なコスト削減。


やらかしたこと

バグ修正7連発

テスト実行→エラー→修正→デプロイ→テスト…を7回繰り返した。一つ直すと次のエラーが出る、いわゆる「玉ねぎ剥き」状態。

  1. 変数名ミス: persona_idspersona_entriesに変更したのに、レスポンス生成部分で旧名を参照 → NameError
  2. 存在しないカラム: is_activereply_restrictioninteraction_countがtarget_accountsテーブルに実は存在しなかった
  3. 存在しないテーブル: engagement_followsテーブルのDDLが未実行だった(S107で設計だけして放置)
  4. PostgREST NULLの罠: .neq("column", "value")はNULL行を含めない。PostgreSQLの三値論理に毎回やられる
  5. Cross-shop参照: ターゲット取得はMySpiritsのshop_idを使うが、内部関数に渡し忘れ

教訓

デプロイ前にローカルテストしろ。 毎回Cloud Runにデプロイして本番で確認するのは時間の無駄。ただし今回はローカルに環境変数がなくてSupabase接続できなかったので仕方ない面もある。テスト環境の整備が課題。


教訓

1. PostgRESTのNULL挙動は毎回確認しろ

PostgreSQLではcolumn != 'value'はNULLの行を返さない。これは何度目だ。PostgRESTフィルタを使う前に「NULLの行がどうなるか」を必ず考えること。安全策はPython側でフィルタリングすること。

2. DDLは設計と同時に実行確認しろ

S107で設計したengagement_followsテーブルが3セッション放置されていた。設計書にDDLを書くだけでは不十分。「実行済み」チェックボックスを設計書に入れるべき。

3. 「選択と集中」はコードにも適用される

5ペルソナ全員を自動化するより、1ペルソナに集中した方がデバッグもコスト管理も楽。人間のマーケティング戦略がそのままシステム設計に反映された好例。


エージェントとのやりとりで気づいたこと

今回はユーザー(サヨン)が「阿蘭自体のアカウントを動かすんじゃなくて、SAKIを使って阿蘭に集客する作戦」と明確に戦略を示してくれたおかげで、実装方針がブレなかった。

技術的には可能でも、ビジネス戦略を理解していないと正しい実装はできない。「全ペルソナ均等に自動化」と「1ペルソナに集中」では、コードの構造が全く違う。

Cloud Runへの7回連続デプロイは反省点。各デプロイに3-4分かかるので、合計30分近くがデプロイ待ちに消えた。次回からは可能な限りローカルテスト環境を整備したい。


数字で見るS110

指標
コミット数 9(x-growth)
修正バグ数 7
Cloud Runデプロイ回数 8
テスト成功 mutual-boost ✓, 外部engagement ✓
生成されたリプライ 「占い好きとしてはワクワクします」(by SAKI → @uranainoaika)