こんにちは!ヤプリの iOS グループでテックリードをしている三宅 (@tsushi130) です。
ヤプリでは日々 900 近くのアプリをビルドしています。 そんなビルド作業は「申請チーム」が Build Bot という名前の Slack App を利用して行っていただいており、ほとんどが自動化されています。
ビルドの詳細については少し前ですが、こちらの ↓ iOSDC 2020 での発表にて詳しく解説されているので、気になる方は是非ご覧ください。
課題
ビルドの仕組みが自動化されているものの、多様なアプリのビルドでは、少しのパラメータが異なっていたり、情報が足りない場合などにエラーで正常に作業が完了しないこともあります。
Bitrise を利用してビルド処理を行っており、エラーが発生すると JIRA のチケットへの通知と Slack への通知が行われますが、全てのエラーが分かりやすく誰でも理解できる状態であるとは限りません。
Bitrise の閲覧権限を持たない非エンジニアでは、エラーの原因を特定するのが困難なので、そういったエラーが発生した場合には iOS チームへエスカレーションしていただいております。
エスカレーションを受けた iOS チームは、Bitrise のエラーログから原因を特定して、修正や足りていない必要作業などを行って再度ビルドを実行します。
依頼を受けたエンジニアは、他の作業によって即時確認できない場合や、エスカレーションが溜まってしまって確認が遅れてしまう場合もあり、双方負荷が高いです。
中には Bitrise のエラーログを確認することでパッと分かるものもあるのですが、今回は「エラーの原因を特定するのが困難」という環境を汎用的にシューティングするために、Bitrise MCP と Atlassian MCP に接続した AI エージェントへ Slack からアクセスできるようにすることで、エラー原因の特定から再ビルドまでを自己完結しやすいような改善の取り組みを行ってみました。
利用した MCP
ビルドログの詳細情報へアクセスするために Bitrise MCP を、JIRA やコンフルからチケットの情報やビルドの仕組みに関するドキュメントへアクセスするために Atlassian MCP を利用しました。
中には非公式の MCP なども公開されているので、利用する場合には精査しながら慎重に選択することをオススメします。
AI エージェントの実装
LangGraph の ReAct (Reasoning and Acting) を利用して TypeScript で実装しました。(ちなみに Swift 版は LangChain ならあるようです)
実装時には以下のドキュメントが非常に参考になります。
全てに触れると長くなってしまうのでポイントだけ触れようと思うのですが、全体のざっくりとした構成としては以下の通りです。
- StateGraph
- 以下のノードを追加したグラフ
- Reasoning
- 与えられた課題を推論する
- Planning
- 推論を元にタスクを生成する
- Execution
- タスクを実行する
- Evaluation
- ユーザーの示すゴールを満たすか、実行結果を評価する
- MCP Tool Manager
- 各 Tool や MCPClient を管理する
- SlackClient
- AI エージェントに Slack からアクセスできるように Socket で接続する
conditionalEdge で現在の状態を見ながら、どのノードに遷移するか、あるいは終了するかを判定しています。 推論 → 計画 → 実行 → 評価 のサイクルをユーザーの示すゴールを満たすまでループさせ、自律的にタスクを遂行させる動きを実装しています。
今回の実装で参考にしたドキュメントは以下の通りです。
StateGraph の設計において参考にしました。 blog.langchain.com
Building Effective AI Agents という Anthropic が公開しているドキュメントで、回答の質を高めたり、タスクの評価のために Evaluator-Optimizer Workflow を参考にしました。 www.anthropic.com
工夫した点としては、「Knowledges」という知識を AI エージェントに事前に理解させる仕組みを入れて、毎回同じような指示を記述したプロンプトを作成するコストを軽減しながらも、回答の質を下げずに無駄な LLM・ツール呼び出しを抑制することができました。
また MCP については今後拡張しやすくするために、他の AI エージェントの mcp.json に沿ってほとんどそのままコピーできるように同じ設計にしました。
一部 exclude_tools
という項目を追加しており、AI エージェント経由で破壊的な変更が行われないようにツールを制限できるようにしています。
{ "mcpServers": { "bitrise": { "command": "uvx", "env": { "BITRISE_TOKEN": "***" }, "args": [ "--from", "git+https://github.com/bitrise-io/bitrise-mcp@v1.0.0", "bitrise-mcp" ], "exclude_tools": [] }, "atlassian": { "command": "npx", "args": [ "-y", "mcp-remote", "https://mcp.atlassian.com/v1/sse" ], "exclude_tools": [] } } }
上記の構造に沿った MCP Server の Config を Json から初期化して、各 MCPClient のインスタンスを作っています。
MCPClient は基本的に MCP の仕様に沿って実装を行えばよいですが、直接 MCP へリクエストを送ってデバッグする方法もあるので、必要に応じて利用すると良さそうです。
MCPの動作確認やデバッグにはPostmanを使おう #AI - Qiita
MCP 関連の実装については以下を参考にしながら実装しました。
Introduction - Model Context Protocol
今回は最低限必要な
- initialize
- notifications/initialized
- tools/list
- tools/call
辺りを実装しています。これらの実装でノード間でステートフルに、リクエストに対する回答を自律的に思考しながらタスクを遂行できるようになりました!
成果物
絶妙に Markdown が反映されないなど、少しうまくいかないこともあるので改善の余地ありですが、概ね良さそう・・・!
最後に
ノード間で扱う State の設計も非常に重要で、各ノード のコンテキストが集約されてしまうことで複雑化しがちです。ドメインごとに StateGraph を分割することである程度軽減できそうではありつつ、この辺りは知見が欲しいと感じました。プロンプトによって精度も大きく異なり、割と試行錯誤でした。
エンジニアは環境を構築して Claude Code や Cursor などから AI を利用していますが、非エンジニアにとっては敷居が高いと思います。慣れ親しんだ Slack から気軽にアクセスできると色々なアプリケーションを横断しなくて良くなる点は、誰にでも使い勝手が良さそうでした!
ヤプリのビルドの仕組みでいうと、ビルドシステムの MCP Server を実装して AI エージェントから接続することで自律的にトライアンドエラーさせたりできそう?など、色々改善のアイディアが膨らみます💭 iOS Agent という抽象度の高い名前にしてしまったのですが、汎用的に利用できる AI エージェントにできそうなので、ビルドエラー以外の領域にも広げられそうです。
実はまだ検証的にチームで動かしている段階で実導入には至っていないのですが、まずは触って動かせるものを作るところまでできたので、使って貰いながら徐々にブラッシュアップしていけたらと思います💪🏻