TechBlog一覧へ
AIエージェント 2026年4月28日

RedmineをAIチームのメッセージキューとして使う設計にした理由

XECIN Redmineアーキテクチャチーム統合自動化

AIエージェントをチームに統合するとき、最初に直面するのは「どのツールをハブにするか」という問いです。

私たちが最初に試みたのはSlackでした。エージェントにSlack botを持たせて、チャンネルにメッセージを投稿させる形です。直感的に「会話できる」感じがして良さそうに思えましたが、実際に動かしてみると問題が出てきました。

Slackをハブにしたときの失敗

Slackのスレッドは状態を持ちません。ボットがメッセージを投稿しても、「このタスクが完了したのか、まだ処理中なのか」を別の仕組みで管理する必要が生まれる。結局、Slackの隣にタスク管理のスプレッドシートを置くことになって、二重管理が始まりました。

GitHub Issuesも検討しました。APIが整備されていてエージェントとの相性は良い。でも既存チームはGitHub Issuesを使っておらず、人間のタスクはRedmineで管理されている。「AIのタスクだけGitHub」という分断が生まれると、人間がどこを見ればよいか分からなくなると考えました。

結局、既存のRedmineをそのまま使うことにしました。

ステータス遷移をAIとのプロトコルとして使う

Redmineの強みはステータス遷移が明示的に定義できる点です。私たちはAI専用のステータスを追加しました。

ステータス意味
AI処理待ちエージェントが拾うキュー
AI処理中エージェントが処理中
AIハンドオーバーセッション切れで次のエージェントへ
AI処理完了エージェントの処理が終わった
AIレビュー待ち人間の判断が必要

エージェントはRedmine APIでチケットを取得し、処理を開始するときに「AI処理中」へ更新、完了したら「AI処理完了」へ更新します。人間は「AI処理完了」のチケット一覧を確認するだけでよい。

これはメッセージキューのプロデューサー・コンシューマーパターンと同じです。人間がチケットを作成(エンキュー)し、エージェントが取得して処理(デキュー)する。Redmineのステータス遷移がキューの状態管理を担っています。

# エージェントがキューからタスクを取得する例
# 改善の余地あり: エラー時のリトライとバックオフが未実装
def fetch_next_task(redmine_client):
    issues = redmine_client.issue.filter(
        assigned_to_id="me",
        status_id=STATUS_AI_WAITING,
        sort="priority:desc,id:asc",
        limit=1
    )
    return issues[0] if issues else None

チケット履歴が監査ログになる

予想外に重宝しているのが、チケットのジャーナル(コメント履歴)です。エージェントは作業の各ステップでRedmineにコメントを残すようにしています。

### 作業記録: 手順2 完了
- 結果: src/content/news/ に記事ファイルを作成
- 変更点: 2026-04-28-ai-employee-redmine-queue.mdx を新規作成
- コミット: abc1234
- 次の手順への申し送り: GitHub PRの作成に進む

「AIが何をしたか」が後から追跡できる。これが運用を考えると非常に重要です。何か問題が起きたとき、Slackのログを遡るよりもチケット履歴を確認する方がはるかに速い。タスクの依頼から完了まで、人間とAIのやりとりが1つのチケットに集約されます。

既存チームのワークフローを変えずに追加できた本当の理由

正直なところ、これが一番大きかったと考えています。

人間のチームはRedmineを使い続けながら、AIエージェントを「AI処理待ち担当」として追加するだけで済みます。既存のチケット作成フローを変える必要がない。「AIに任せたいタスクは担当者をAIにして、ステータスをAI処理待ちにする」というルールだけ覚えれば動き始めます。

新しいツールの学習コストも、移行コストも発生しません。RedmineとAIエージェントが同じ言語(チケットとステータス)で会話している、というイメージです。

# エージェントが完了時にステータスを更新する処理
def complete_task(redmine_client, issue_id, completion_notes):
    redmine_client.issue.update(
        issue_id,
        status_id=STATUS_AI_COMPLETE,
        notes=completion_notes
    )

落とし穴とSlack通知を後から追加した経緯

ただ、完全に問題がなかったわけではありません。最初の設計では「AI処理完了になったチケットをRedmineで確認する」という運用を想定していたのですが、人間がRedmineを常時監視するのは現実的ではなかった。

処理が完了してもしばらく誰も気づかない、という状況が続きました。結果として、「AI処理完了」に遷移したタイミングでWebhookを使ってSlack通知を飛ばす仕組みを後から追加しています。確認のきっかけはSlack、詳細はRedmineで確認——という役割分担に落ち着きました。

ここは設計時に見落としていた点で、今思えば最初から入れておくべきでした。ドキュメントにはこう書いてあるけど、という話ではなく、単純に「人間がどう動くか」の想定が甘かったというだけです。

振り返って

Redmineをメッセージキューとして使うという発想は、最初は「既存ツールの流用」という妥協の産物でした。でも実際に動かしてみると、ステータス遷移による状態管理と、チケット履歴による監査ログが、AIエージェントとの統合に思いのほかフィットしていると感じています。

今後は、AIエージェントが処理できないと判断したタスクの自動エスカレーションや、複数エージェントが並列でタスクを処理するときの競合防止など、もう少し込み入った使い方も試していきたいと考えています。完成した設計ではありませんが、現時点での判断として公開します。