コピペなしでAIがRubyをデバッグ!girb-mcpをリリースしました

girb-mcpとは?

girb-mcp は、LLMエージェントが実行中のRubyプロセスにアクセスするためのMCPサーバーです。

girb-mcp

MCP (Model Context Protocol) に対応したクライアントであれば何でも使えます。Claude Code、Gemini CLIで動作確認済みです。

例えばこんな感じで、エージェントに「バグを調査して」と伝えるだけで、実際にリクエストを投げて実行時の状態を確認し、原因を特定してくれます。

あなた: ユーザー一覧ページが500エラーになるので、デバッグセッションに入って原因を調べて

エージェント: コントローラにブレークポイントを設定してリクエストを送りました。
            停止地点で変数を確認したところ、@usersの中にnameがnilのレコードが
            1件混ざっています(User ID: 42)。
            ビューでuser.name.uppercaseを呼んでいるため、ここでNoMethodErrorが
            発生しています。

コードを読むだけではわからない「実行時に何が起きているか」を確認できるのがポイントです。

実際に動作する様子はこちらの動画をご覧ください。

youtu.be

girbとの違い

先日リリースしたgirbはIRBやRails console上で人間が対話的にAIを呼び出すツールでした。

girb-mcpは同じ「実行中のRubyプロセスのコンテキストにアクセスする」というアプローチを、LLMエージェント向けに提供するものです。

girb girb-mcp
使う人 人間(IRB上で対話) LLMエージェント(MCP経由)
インターフェース REPL上のコマンド MCPツール呼び出し
動かし方 girb or binding.girb MCPクライアントの設定に追加

girbが「人間がAIの力を借りてデバッグする」ツールなら、girb-mcpは「AIが自律的にデバッグする」ためのツールです。

既存のMCPサーバーとの違い

Ruby/Rails向けのMCPサーバーはすでにいくつかありますが、それらは静的解析やアプリケーションレベルのAPI(DBクエリ、ルーティング確認など)がメインです。

girb-mcpはdebug gem経由で実行中のRubyプロセスに接続し、その実行時状態をエージェントに公開します。

Agent → connect(host: "localhost", port: 12345)
Agent → get_context()
  → ローカル変数、インスタンス変数、コールスタック
Agent → evaluate_code(code: "user.valid?")
  → false
Agent → evaluate_code(code: "user.errors.full_messages")
  → ["Email can't be blank"]
Agent → continue_execution()

「この変数が今何の値を持っているか」「user.valid?の結果は何か」を実際に評価して返せるのが静的解析との決定的な違いです。
Rubyのような動的な言語では、コードを読むだけではわからないバグが多いので、このアプローチは特に有効だと考えています。

仕組み

  1. debug gem(rdbg --open)が対象Rubyプロセスにソケットを公開
  2. girb-mcpがそのソケットにdebug gemのプロトコルで接続
  3. MCPクライアントからのツール呼び出しがデバッガコマンドに変換され、結果が返される

MCPはAnthropicが策定したオープン標準で、LLMと外部ツールを繋ぐためのプロトコルです。girb-mcpはmcp gemを使ってこの仕様に準拠しているので、MCPに対応したクライアントであれば何でも利用できます。

できること

調査ツール

ツール 説明
evaluate_code 停止中のbindingでRubyコードを実行
inspect_object オブジェクトのクラス・値・インスタンス変数を取得
get_context ローカル変数・インスタンス変数・コールスタック・ブレークポイントを一括取得
get_source メソッドまたはクラスのソースコードを取得

実行制御

ツール 説明
set_breakpoint 行・メソッド・例外クラスでブレークポイント設定
continue_execution 次のブレークポイントまたは終了まで実行を再開
step / next / finish ステップイン・ステップオーバー・メソッド終了まで実行

Railsサポート

Railsプロセスを検出すると自動的にRails用ツールが追加されます。

ツール 説明
rails_info アプリ名・Railsバージョン・環境・DB情報を表示
rails_routes ルーティング一覧をフィルタ付きで表示
rails_model モデルのカラム・アソシエーション・バリデーション・enumを表示
trigger_request デバッグ中のRailsアプリにHTTPリクエストを送信

trigger_requestはPOSTなどのリクエストでCSRF保護を自動的に一時無効化してくれるので、トークンを気にせずリクエストを投げられます。

デバッグだけじゃない!AIコーディングの「次の一歩」

AIに実装を頼むと、テストも一緒に書いてくれます。テストも通ります。でも、そのテストって本当に正しいんでしょうか?

AIが書いたテストは「AIが理解した仕様」を検証しているだけです。ユーザーが意図した動作を検証しているとは限りません。テストが通っているのに、実際に動かしてみたら思ってたのと違う。これはAIコーディングあるあるだと思います。

girb-mcpを使うと、テストの先にもう一歩踏み込めます。

  1. AIが実装を書く
  2. AIがテストを書いて通す
  3. girb-mcpで実際にアプリを動かして、意図通りの振る舞いをするか確認する

例えば「管理者だけが記事を削除できること」を実装させたとして、テストが通った後に実際にDELETEリクエストを投げて、一般ユーザーでは403が返ること、管理者では削除されることを実際の動作で確認できます。

これまでは「テストは通ったので、あとは人間が動作確認してね」で終わっていたところを、動作確認までAIに任せられるようになります。人間は最後に動くものを見て判断するだけです。

インストールと設定

gemをインストールします。

gem install girb-mcp

MCPクライアントの設定にgirb-mcpを追加します。

Claude Codeの場合~/.claude/settings.json

{
  "mcpServers": {
    "girb-mcp": {
      "command": "girb-mcp",
      "args": []
    }
  }
}

Gemini CLIの場合~/.gemini/settings.json

{
  "mcpServers": {
    "girb-mcp": {
      "command": "girb-mcp",
      "args": []
    }
  }
}

他のMCPクライアントでも、STDIOトランスポートに対応していれば同様の設定で利用できます。
Bundler経由の場合はcommandbundleargs["exec", "girb-mcp"]に変更してください。

Ruby >= 3.2.0 が必要です。

使ってみる

Rubyスクリプトのデバッグ

rdbg --open --port=12345 my_script.rb

あとはエージェントに頼むだけ。

「デバッグセッションに接続して現在の状態を見せて」

run_scriptツールがあるのでRubyスクリプトの起動自体をエージェントに任せることも可能です。

Railsアプリのデバッグ

girb-mcpにはRailsサーバーをデバッグモードで起動するコマンドも付属しています。

girb-rails    # RUBY_DEBUG_OPEN=true bin/rails server と同等

エージェントにこう伝えます。

「app/controllers/users_controller.rbの15行目にブレークポイントを設定して、/users/1にGETリクエストを送って」

ブレークポイント設定 → リクエスト送信 → 停止した地点で変数を調査、という一連の流れをエージェントが自動で行います。

Docker内のプロセスにも対応

TCP接続またはUnixソケットのボリュームマウントでDocker内のRubyプロセスにも接続できます。TCP経由の場合、ローカルにソースコードがなくてもコンテナ内のファイルを閲覧・読み取りできます。

セキュリティについて

いくつか注意点があります。

  • evaluate_codeは任意のRubyコードを実行できます。 ただしファイル操作やシステムコマンドなどの危険な操作はLLMエージェント側のポリシーで制限されています。girb-mcpはあくまで「デバッガの窓口」であり、エージェント側のガードレールと組み合わせて使うことを前提としています。
  • debug gemには認証機能がありません。 TCPでデバッグポートを公開する場合は127.0.0.1にバインドするなど、アクセスを制限してください。
  • 本番環境では使わないでください。 開発・デバッグ用途のツールです。

girbファミリー

girb-mcpはgirbファミリーの一員です。

  • girb — AI搭載IRBアシスタント(対話型、人間向け)
  • girb-mcp — LLMエージェント向けMCPサーバー(プログラマティック、エージェント向け)
  • girb-ruby_llm — ruby_llm経由のLLMプロバイダー
  • girb-gemini — Gemini API経由のLLMプロバイダー

フィードバック募集中

girb-mcpはまだ発展途上です。使ってみて気づいたことがあれば、ぜひ教えてください。

「ここが使いにくい」「こんな機能がほしい」など、どんな意見でも歓迎です!

Rubyと自然言語で対話しよう!girbをリリースしました

girbとは?

girb(Generative IRB)はIRBRails console・debuggerにAIエージェントを統合するgemです。

girb

例えばこんな感じで、IRB上でAIを呼び出して実装やデバッグを行わせることができます。 youtu.be

いろんな場所で動く

Rails consoleでも動作します。ActiveRecordモデルの情報を理解した上で回答してくれます。

youtu.be

コード内のdebuggerbinding.girbからでも呼び出せます。

youtu.be

実行中のコンテキストを持つ

girbはファイル、変数、定数、メソッドの定義にアクセスし、現在のプログラムの状態を確実に把握できます。
Claude Codeなどとの違いとして、実行中のプログラムのコンテキストを取得できるのが強みです。これはRubyのような動的な言語のデバッグで特に有効なアプローチと考えています。
また、REPL上で実行されたコードと会話の履歴を記憶しているため、試したコードや発生したエラーに対して自然な流れで質問・指示をすることができます。

デバッグの自動化

girbはAIエージェントです。1往復の会話だけでなく、自律的にタスクを進めることができます。
つまり、debuggerbinding.girbで呼び出した後、ブレークポイントの設置やnextなどのデバッグコマンドを駆使して自動でデバッグを進めることができます。
一度の実行で解決できない場合、記憶の永続化オプションを有効にすればセッションが切れても記憶が途切れなくなります。
例えば10行目で『5行目のメソッド内で状態を調査するべきだった』と気づいたら、次回実行時にはその記憶を引き継いで5行目のメソッドの調査を行うことができます。

対応しているLLM

  • girb-ruby_llm: OpenAI, Anthropic, Gemini, Bedrock, Ollama など
  • girb-gemini: Google Gemini専用(Google検索機能に対応)

プロバイダー gemを変更してお好みのプロバイダー、LLMを選べます。
カスタムプロバイダー gemを作ることでどんなLLMでも対応することができます。

インストールと設定

gemをインストールします。

gem install girb girb-ruby_llm

.girbrcに設定を書きます。

require 'girb-ruby_llm'

Girb.configure do |c|
  c.provider = Girb::Providers::RubyLlm.new(model: 'gemini-2.5-flash')
end

APIキーを環境変数に設定して起動します。

export GEMINI_API_KEY="your-api-key"
girb

詳しくはREADMEを参照してください。

使い方

コマンド 説明
qq 質問 AIに質問する
Ctrl+Space 現在の入力をAIに送る
binding.girb コード内からAI付きIRBを起動
debugger debug gemと連携してAIデバッグを開始

自律的に動いている最中でも、Ctrl+Cでいつでも中断できます。

フィードバック募集中

girbはまだ発展途上です。使ってみて気づいたことがあれば、ぜひ教えてください。

「ここが使いにくい」「こんな機能がほしい」など、どんな意見でも歓迎です!

Ano Newsクローズのお知らせ

突然ですが、AnoNewsをサービス終了しました。

(※ AnoNewsについてはリリース時の記事をご覧ください)

約2ヶ月という短い期間の運営となりましたが、その中でも多くの学びと経験を得ることができました。 使っていただいた方、ご意見・ご感想をくださった方々へ感謝を伝えたいです。

お知らせとしては以上となるのですが、せっかくなのでサービス終了の理由や運用してみた感想など書いていきたいと思います。

使用技術

Rails 8 / Hotwire / PostgreSQL / Redis(ActionCable) / Fly.io / Google OAuth / Gemini API / 自作gem(ruby-gemini-api)

サービス終了の理由

まずサービス終了の理由ですが、一つは運用を通じた技術検証が十分にできたことです。

AnoNewsは社会的な課題(ニュースが忘れられてしまう)に着目したサービスでしたが、この課題を解決するには個人プロジェクトとして規模感が合わない、というのが私の出した結論です。単純に集客力が足りないのもありますが、公開された記事をわざわざ修正してくれる、検証してくれるユーザーがいなければ成り立たない、というのがサービスの設計として難しいと感じました。

第2の理由としては、想定以上にサーバー代がかかったことです。appサーバ、DBサーバ、SolidQueueサーバにクラウドストレージ、それぞれをproductionとstagingに作ったところ月々60ドル程度のランニングコストとなりました。ソートボタン連打や複数ユーザーの同時AI記事生成といったケースを考え、負荷対策として少し良いスペックのマシンを借りていたのですが、個人プロジェクトとしては見直しが必要でした。

逆にLLMの費用は(ユーザーが少ないので)全然大丈夫でした。

学び

導線設計の重要性

サービスの強みとして「AI記事生成がとにかく面白い」と考えていたのですが、実際に作ったものは「ログインしてから投稿メニューを押して、AI記事生成を押して、気になるニュースのURLを入力すると生成される」というものでした。初見のユーザーが楽しいところに辿り着くまでの道のりが長すぎました。

次に活かすこと: サービスの一番面白い部分は、最短導線で体験できるようにする。

ユーザーでいなければいけない問題

私自身も記事を書き、投稿された記事を読み、修正したり、いいねしたり、1ユーザーとして活動しました。しかし、新規ユーザーがいないため毎日自力で投稿・巡回することが義務化されました。これは持続可能ではないと気づきました。

記事にしたいニュース、追いかけたいニュースがあるからサービスを使うはずが、サービスを使うためにニュースを探すことになったのです。負担を減らすために扱うニュースの候補を自動ピックアップするスクリプトを作ったりしましたが、本末転倒だと感じました。

次に活かすこと: 自分自身が「義務」ではなく「使いたい」と思えるサービスを作る。コールドスタート問題の解決策は、運営の努力ではなく仕組みで担保する。

良かったこと

技術的知見がたくさん得られた

触ったことのない技術、実装したことのない機能をたくさん触ることができました。Google認証、ポーリングによる通知、WebSocketによるリアルタイムなスコア加算など、自分が「こういう風にしたい」を実現するための様々な技術に触れられたのはとても良い体験でした。

監視やオブザーバビリティなど、普段あまり意識したことがなかった概念に触れられたのも良かったと思います。

自作gemをちゃんと使えた

公開しているruby-gemini-api gemをサービス内で活用したため、実際の使い心地を体験できました。不足している機能もわかったため、gemのメンテナンスも並行して行うことができました。

感想

作ってみて良かったです。サービス運用は大変だなとも思いました。

だいたい1ヶ月くらいで完成させたのですが、寝食を忘れて開発していました。とても楽しかったです。

また何か面白いものを作りたいと思います。

AIでストリートファイターを実況する技術

AIに格ゲー実況させたい

AI Tuberというものが気になってます。
AIが感想をコメントしながら格闘ゲームをしている姿が見てみたいです。
しかし、格闘ゲームをプレイするにはリアルタイムな応答性が必要です。
現時点で格闘ゲームをLLM、VLMにプレイさせるのは難しいですが、人間やCPUがプレイした動画にあたかもAI自身がプレイしたかのようなコメントを入れることは可能なのでは?と考え、実験してみました。

今回の対象ソフトはストリートファイターVです。

実況コメントするには盤面の変化を適切に捉え、喜怒哀楽を表現しなくてはなりませんがうまくいくのでしょうか?

マルチモーダルモデルに放り込む

まず思いつくのが動画をマルチモーダルなモデルに入力し、キャラ設定を渡してコメントさせる手法。
実はgemini-2.5-proが出たあたりで一度実験したのですが、自キャラと対戦相手の区別が付かないという問題がありました。
gemini-3-proが出た今なら何とかなるんじゃないの?というのが今回再実験を始めたきっかけでもあります。

結果

gemini-3-proでも敵味方の区別に失敗します。自キャラに必殺技が当たって大喜びする様子を見るのはなんとも悲しい気持ちになります。

失敗の原因分析:

  • 動画全体を渡すと、VLMは「どの瞬間を見ればいいか」がわからない
  • 格闘ゲームは1秒間に何度も状況が変わるため、漠然と見せても正確な判断ができない
  • 「P1が攻撃した」「P2が攻撃した」の区別は、VLMには判断が難しい

ゲージを見ろ

次の作戦として、マルチモーダルなモデルに体力ゲージだけを注視させます。
まずは体力ゲージの推移ログを作り、ログと試合動画を見比べながらコメントをさせる作戦です。
これならVLMの役割がシンプルになるので成功しそうです。

結果

これも失敗。
ゲージだけ注視しろと言っても無視したり、ゲージから正確な割合を判定できないという問題がありました。

失敗の原因分析:

  • VLMは「ゲージが何%か」を正確に読み取るのが苦手
  • プロンプトで「ゲージだけ見ろ」と言っても、画面全体を見てしまう

体力のログは自力で作る(フェーズ1)

体力ゲージのログを取るだけならVLMじゃなくてもできます。
OpenCVという画像処理ライブラリを使い、体力ゲージの様子を100ms単位でログに出力させます。

工夫したポイント:

  • 体力ゲージは「赤→黒」でダメージが確定する仕様を考慮
  • キャラクターがジャンプするとゲージが隠れる問題→前フレームの値を維持
  • ラウンド開始時の発光演出→異常値として除外
  • 体力は増えないという制約を利用したノイズ除去

結果

これはうまくいきました。 キャラクターがジャンプすると体力ゲージが隠れたり、ラウンド開始時の発光など、イレギュラーなイベントもありましたが、「体力ゲージは増えない」、「赤→黒でダメージが確定する」など細かい仕様を加えることで、ある程度正確なログが取れています。 この体力ログ生成はフェーズ1として採用します。

ダメージイベント抽出(フェーズ2)

体力の推移ログから、実際にダメージが発生したタイミングを抽出します。
これにより100ms単位で存在していたログを圧縮します。

  • Phase1の体力ログ(100ms単位)を読み込み
  • 体力の減少を検出してダメージイベントに変換
  • 500ms以内の連続ダメージは1イベントにマージ
  • イベントタイプを分類(p1_damage, p2_damage, exchange, ko, round_start)

結果

timestamp_ms,event_type,target,damage,p1_health,p2_health
7500,round_start,-,0,100,100
11600,p2_damage,p2,3.2,100,96.8
12300,p1_damage,p1,2.1,97.9,96.8
...

ダメージが発生したタイミングをまとめた、タイムラインの作成に成功しました。

具体的な試合内容を記録する(フェーズ3)

タイムラインからはダメージが入ったタイミングとダメージ量が読み取れます。
また、ダメージが入っていない時間からは読みあい、牽制などで試合が硬直していたことが読み取れます。
VLMにはタイムライン上の各イベントが、具体的にどのような内容だったかを確認させ、より具体的な試合内容を記録させます。

フレーム抽出方式

動画全体を渡すのではなく、各イベントのタイムスタンプ周辺の5フレーム(0.5秒間)だけを画像として抽出してVLMに渡します。

この方式のメリット:

  • VLMが「どの瞬間を見ればいいか」が明確になる
  • 処理時間の短縮(動画全体を処理する必要がない)
  • 攻撃の前後を見ることで、何が起きたかを判断。

イベントの判定にも体力のログを使う

体力のログから判定できることはそちらで判定し、VLMは視覚的な特徴のみを担当させました。

判定項目 担当 理由
誰が攻撃したか CV 体力が減った側が被弾者
コンボかどうか CV イベント間隔で判定可能
ダメージ量 CV 体力の差分から計算
投げか打撃か VLM 視覚的な判断が必要
飛び道具か VLM 視覚的な判断が必要
対空か VLM 視覚的な判断が必要

様子見イベントの挿入

イベント間の空白時間が長いと、実況が沈黙してしまいます。これを解決するため、3秒以上の空白時間に「様子見」イベントを挿入します。

結果

タイムラインを渡したおかげで、VLMが敵味方を間違えることがなく、試合の詳しい情報を取得できました。

フェーズ3の出力例:

timestamp_ms,time,situation,emotion,intensity,attacker,is_p1_attacking
7500,7.5,ラウンド開始,緊張,medium,,
11600,11.6,牽制ヒット,淡々,low,p1,True
45600,45.6,コンボ被弾開始,悔しさ,high,p2,False
51500,51.5,コンボ開始,興奮,high,p1,True
70900,70.9,KO勝利,歓喜,high,p1,True

コメントを付ける(フェーズ4)

具体的なイベントを記録したタイムラインができました。
次は、タイムライン上のイベントごとにLLMに適切なコメントをさせます。
コメントの内容はキャラ付け次第になります。今回はお嬢様系実況者という設定でコメントしてもらいました。

発話時間に基づく文字数制限

コメントとコメントの間隔が短いと、発話が終わる前に次のコメントが始まってしまいます。これを防ぐため、次のイベントまでの時間から最大文字数を計算します。

CHARS_PER_SECOND = 5  # 日本語の発話速度(余裕を持たせた値)

for scene in scenes:
    gap_sec = next_event_time - scene_time
    max_chars = max(3, min(25, int(gap_sec * CHARS_PER_SECOND)))
    scene['max_chars'] = max_chars

プロンプトでの指示はこのようになります

[11.6秒] 【自分が攻撃】 牽制ヒット (感情: 淡々, 次まで0.7秒, 最大3文字)
[12.3秒] 【相手が攻撃】 被弾 (感情: 焦り, 次まで2.9秒, 最大14文字)

キャラクター設定のカスタマイズ

今回実験したキャラクター設定:

1. LLM専門用語キャラ

- 攻撃成功: 「推論的中!」「重み最適!」「loss低下!」
- 被弾: 「勾配爆発!」「NaNエラー!」「過学習!」
- コンボ: 「連鎖推論!」「テンソル全開!」「並列化!」
- ピンチ: 「VRAM残りわずか!」「GPU温度上昇中…」

2. お嬢様キャラ

- 攻撃成功: 「参ります!」「お見事」「華麗に」
- 被弾: 「まあ!」「失礼な!」「無礼な!」
- コンボ: 「舞いますわ!」「優雅に」
- 勝利: 「おほほ、当然の結果ですわ!」

他のキャラクター案

  • 株トレーダーAI: 「利確!」「損切り!」「ボラ上昇!」
  • 軍師AI: 「作戦通り」「陽動成功」「撤退せよ」
  • 厨二病AI: 「我が力を解放…」「闇が疼く」
  • 体育会系AI: 「押せ押せ!」「根性!」「気合いだ!」
  • 医療AI: 「バイタル安定」「容態急変!」「オペ成功」

結果

どのキャラ設定でも問題なく機能しました。
ただ、キャラが濃すぎると何を言っているのかわからないことが多くなりますね…

お嬢様キャラの出力例:

timestamp_ms,time,situation,comment,emotion
7500,7.5,ラウンド開始,幕開けですわね。,緊張
15900,15.9,飛び込みヒット,華麗ですわ,喜び
21000,21.0,被弾,きゃっ、失礼な!,焦り
45600,45.6,コンボ被弾開始,無礼な!,悔しさ
51500,51.5,コンボ開始,舞いますわ!,興奮
70900,70.9,KO勝利,おほほ、当然の結果ですわ!,歓喜

動画とコメントを同期表示する

実際のAI Tuberとして稼働するならTTSで音声としてコメントを動画に載せると思いますが、今回はコメントとして同期表示させました。
動画とコメントを指定することで同期表示されるhtmlを用意しました。

パイプライン全体図

これで動画にAIのコメントが表示できます。
ここまでの流れをまとめます。

入力: 試合動画
    ↓
Phase1: 体力ゲージ解析(OpenCV)
  - 100ms単位で体力%を記録
  - ノイズ除去(ジャンプ、発光演出)
    ↓
Phase2: ダメージイベント抽出
  - 体力減少タイミングを検出
  - イベントタイプ分類(damage/exchange/ko)
    ↓
Phase3: シーン解析(VLM: gemini-3-pro-preview)
  - 各イベントの前後5フレーム抽出(-200ms〜+200ms)
  - コンボ判定(CV: 3ヒット以上、1500ms以内)
  - 様子見イベント挿入(3秒以上の空白)
  - 視覚的特徴の判定(投げ/飛び道具/対空)
    ↓
Phase4: コメント生成(LLM: gemini-2.5-flash)
  - キャラクター設定に基づくコメント生成
  - 発話時間に基づく文字数制限(5文字/秒)
  - 攻撃方向に応じた感情表現
    ↓
出力: タイムライン付きコメント(CSV/JSON形式)

完成したもの

最終的に完成した動画がこちら。

youtu.be

そこそこ実況っぽくなっています! リアルタイムにコメントできない、実際にプレイできるわけではない。技の解説もたぶんできない、ということで実用的ではないですが、とりあえずコメントさせることに成功しました。

今後の発展可能性

リアルタイム化への課題

  • 現状: 動画全体を処理してからコメント生成(オフライン処理)
  • 課題: VLM/LLMのレイテンシ(数秒)が格闘ゲームのテンポに合わない
  • 可能性: モデルの進化に期待…

TTS連携

  • VOICEVOXなどのTTSと連携
  • 感情パラメータ(emotion)をTTSの感情制御に活用

まとめ

学んだこと: 1. VLMに全てを任せない: CVで確定できることはCVで処理し、VLMの役割を明確に絞る 2. フレーム抽出が効果的: 動画全体より、特定タイムスタンプのフレームを渡す方が精度が高い 3. 発話時間の考慮: 実況では「何を言うか」だけでなく「どれくらいの長さで言うか」も重要

AI Tuberはある日突然登場するというより、こういった技術の積み重ねで洗練されていくものだと思っています。この記事も何かの役に立てばいいなーと思います。

自作サービスで忘れがちなあれこれ

はじめに

この記事はフィヨルドブートキャンプ Advent Calendar 2025 の9日目の記事です。

昨日の記事はmachidaさんのKaigi on Rails 2025 のデザインをやりました Vol.1 「メインビジュアルの3つの案」でした。


先日自作サービスAno Newsを公開しました。
フィヨルドブートキャンプ卒業から約2年。卒業時に作ったサービスは閉じてしまいましたが、また新たなサービスを立ち上げました。これからコツコツ育てていきたいと思います。

サービスの紹介はリリースブログに任せるとして、この記事ではサービス公開する際に「そういえば忘れてた」「あった方がよかった」となった機能を紹介したいと思います。
これからサービスを公開する方、作ろうという方は参考になるかもしれません。

忘れてた機能いろいろ

フォント設定

WEBフォントを使えば、環境によらず統一されたフォントを使うことができます。
AnoNewsはニュースサイトなので、コンテンツ本文は明朝体、見出しにはゴシック体を使うことにしました。
自作サービス作成中、デザインを後回しにしがちですが、適切なフォントを入れるだけで見栄えがよくなります。是非やりましょう。

2重リクエスト対策

例えば記事投稿の確定ボタン。連打すると同じ記事がだだだーっと大量に登録できてしまっていました。
これはフロント側で連打できないようにすることでほとんど解決するのですが、バックエンドでも重複登録を拒否するよう設定することでより安全なシステムになります。

2重リクエストについてはこちらの記事が大変参考になりました。
2重リクエスト完全攻略HANDBOOK / Double Request Handbook - Speaker Deck

退会機能

入り口や中身は一生懸命作るのに、出口は忘れがちです。
サクッとログイン出来て、気に入らなければスパッと退会できるのが理想です。ちゃんと実装しましょう。

OGP

OGPというのはX(Twitter)などのSNSにシェアしたときに表示される、タイトルや画像などの補足情報を表示するための仕組みです。
OGP画像があるとシェアされたときの見栄えがよくなります。シェアボタンがあるようなサービスなら設定しておきましょう。

AnoNewsのOGP画像

ハッシュタグ

シェアボタンからシェアされたときに、自サービス用のハッシュタグをつけておくと検索性がよくなります。
OGPと合わせて設定しておくとよさそうです。

キャッシュ

キャッシュ戦略を考えるのは難しいですが、ヘッダーやメニューなど、動的に更新されない部分のキャッシュなら実装しやすいのではないでしょうか。
AnoNewsでもヘッダーの一部はキャッシュを使うことで表示の高速化を実現しています。

ちゃんと実装してた機能

逆に、「これは最初から入れておいて良かった」という機能も紹介しておきます。

全文検索

後回しにすると面倒そうな機能として全文検索があります。
記事の文章などから任意の文字列を検索するためには索引を作る必要があります。これは文章を作成したタイミングで作るのが一般的です。
サービスリリース後に作る場合、既存の文章の索引を作るという作業が発生してしまいます。
文章を扱うサービスの場合、検索機能は最初からつけておいた方がいいと思います。

エラー追跡・監視

本番環境でエラーが発生したとき、どうやって気づけばいいでしょう?ユーザーの報告がなければ気づけないのでしょうか?
エラーを見逃さないためには、エラー追跡サービスを入れておくと安心です(Sentryなど)。

無料プランでも十分使えます。

まとめ

サービス公開前は機能実装に集中しがちですが、今回紹介したような「地味だけど重要な機能」も忘れずに実装しましょう。

これからサービスを公開する方の参考になれば幸いです!

Ano Newsもぜひ使ってみてください。「あのニュース、どうなった?」という疑問を解決するサービスです。

「あのニュース、どうなった?」を追い続けるサービス「Ano News」をリリースしました

政治家の公約は実現したのか。災害の被災地は復興したのか。企業の謝罪会見の後、本当に改善されたのか。

ニュースは日々生まれますが、「その後」が報じられることは多くありません。選挙が終われば公約の検証は話題にならなくなり、災害報道は時間とともに減っていきます。調べようとしても、情報はバラバラで全体像をつかむのは簡単ではありません。

メディアは速報性に優れていますが、過去のニュースを追い続けることはビジネスモデル上難しいのが現実です。

「あのニュース、どうなった?」

この疑問に答えるためのサービス「Ano News」をリリースしました。

https://ano.news


Ano Newsとは

Ano Newsは、ニュースの「その後」を時系列で追跡する市民ジャーナリズムプラットフォームです。

タイムライン形式でニュースを追跡・深堀り

Ano Newsでは、一つのニューストピックを「タイムライン」として管理します。タイムラインには、出来事を時系列で記録していきます。

たとえば「異次元の少子化対策」というタイムラインには、政策発表から法案成立、実施状況まで、一連の流れがまとまっています。新しい動きがあれば、誰でも続報を追加できます。

タイムラインは「これから」を追うだけではありません。「これまで」の経緯を整理する場でもあります。今話題のニュースがどのような背景で生まれたのか、過去の出来事を遡って理解できます。

誰でも投稿可能

Ano Newsは誰でも参加できるプラットフォームです。

既存のタイムラインに続報を追加することも、新しいタイムラインを作成することもできます。プロの記者でなくても、気になるニュースを追いかけて記録を残せます。

AIでタイムラインを簡単作成

「タイムライン記事を書くのは大変そう」と思うかもしれません。Ano Newsでは、AIを使って簡単にタイムラインを作成できます。

入力するのは2つだけです。

  1. ニュース記事のURL
  2. どのような観点でタイムラインを作りたいか

これだけで、AIが関連情報を収集し、時系列に整理したタイムラインの下書きを生成します。あとは内容を確認して、必要に応じて編集するだけです。


どのように使うのか

読む

タイムライン記事はユーザー登録なしで読めます。

トップページから興味のあるトピックを探してみてください。現在、以下のようなタイムラインが公開されています。

  • 大阪・関西万博 誘致から閉幕までの道のり — 誘致決定から開催、そしてその後まで
  • 八丈島を襲った二つの台風:被害と復旧の記録 — 災害発生から復旧状況までを追跡
  • エンジニア転職市場の変遷 — 業界の変化を時系列で整理

政治、災害、社会問題から、eスポーツやはやぶさ2の状況まで、幅広いジャンルのタイムラインを用意しています。

参加する

記事へのいいね、ブックマーク、タイムラインの作成・編集にはユーザー登録が必要です。Googleアカウントがあれば、すぐに登録できます。

登録すると、以下のことができるようになります。

  • 既存のタイムラインに続報を追加する
  • 新しいタイムラインを作成する
  • AIを使ってタイムラインを生成する(1日3本まで)
  • 気になるタイムラインにいいね・ブックマークする

まずは既存のタイムラインを読んでみて、気になるニュースがあれば続報を追加するところから始めてみてください。


なぜ作ったのか

きっかけは、2025年10月に八丈島を襲った台風22号・23号のニュースでした。

発生直後は多くのメディアが報じましたが、時間が経つにつれて続報が減っています。復旧の状況を知りたくても、まとまった情報はなかなか見つかりません。SNSで細々と発信されている情報を毎日たどって、ようやく現状を把握できる状態が続いています。

Xのおすすめ欄も、興味を持ち続けなければ表示されなくなります。関心が薄れれば、情報も届かなくなる。これはどのニュースにも当てはまる構造的な問題です。

小さな続報でも、タイムラインとして一つのかたまりになれば、ニュースとしての価値が生まれるのではないか。そう考えて、Ano Newsを作りました。

ニュースをもっと身近に、「自分事」として感じられるサービスを目指しています。


今後の展望

現在、「Webデモ」機能をベータ版として公開しています。

Webデモは、市民の力で社会問題を広めるための仕組みです。Ano News内で広告を視聴すると、その収益がプールされます。集まった収益を使って、XやGoogleなどのプラットフォームに意見広告を出稿する、というコンセプトです。

「このニュースをもっと多くの人に知ってほしい」という想いを、広告という形で届ける。新しい市民参加の形を目指しています。

実装時期は未定ですが、ファーストリリース後の反応を見ながら開発を進めていく予定です。


さいごに

Ano Newsは、ニュースの「その後」を市民の手で記録し続けるプラットフォームです。

まずはサイトを訪れて、気になるタイムラインを読んでみてください。そして、追いかけたいニュースがあれば、AIタイムライン生成を試してみてください。ニュース記事のURLと観点を入力するだけで、タイムラインの下書きが作れます。

ご意見・ご感想・バグ報告など、フィードバックを歓迎しています。技術的な観点からのご意見もお待ちしています。

「あのニュース、どうなった?」という疑問を、一緒に追いかけていきましょう。


Order2Postサービス終了のお知らせ

平素よりOrder2Postをご利用いただき、誠にありがとうございます。

この度、Order2Postは2025年11月1日をもちまして、サービスを終了させていただくこととなりました。

サービス終了日時

2025年11月1日(土) 00:00

上記日時をもちまして、すべての機能を停止いたします。 サーバーの停止に伴い、保存されているデータもすべて削除されます。

終了の理由

運営者の都合により、サービスの継続が困難となったため、やむを得ずこのような判断に至りました。 今後は他のプロジェクトに注力していく予定です。

ご利用中の皆様へ

2023年12月のサービス開始以来、Order2Postをご利用いただいた皆様には心より感謝申し上げます。 多くの方にご利用いただくには至りませんでしたが、実際に使っていただけたことは大変励みになりました。

お問い合わせ

ご不明な点がございましたら、以下までご連絡ください。

短い期間ではございましたが、Order2Postをご利用いただき、誠にありがとうございました。