0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【構想編】社内ローカルAIに手足をつける!〜MCP × LangGraphでRedmine・Slackを読み取るAIを作る〜

0
Posted at

はじめに

社内でMacBook Proを1台購入し、ローカルLLMを動かせる環境を用意しました。

せっかく社内ネットワーク内でAIを動かせるなら、RedmineやSlackの情報を参照して、プロジェクトの進捗をまとめてもらいたいところです。

そこで今回は、以下を組み合わせた構成を考えます。

  • ローカルLLM
  • MCP
  • LangGraph

目標は、

「プロジェクトAの進捗どう?」

と聞くだけで、RedmineとSlackを横断して状況をまとめてくれる社内向けAIです。

1. MCPで社内システムに接続する

MCP(Model Context Protocol)は、LLMと外部ツールを接続するためのプロトコルです。

今回の構成は次のようになります。

                 ┌──────────────┐
                 │     LLM      │
                 └──────┬───────┘
                        │
                        │ MCP
                        ▼
                 ┌──────────────┐
                 │  MCP Server  │
                 └──────┬───────┘
                        │
             ┌──────────┴──────────┐
             ▼                     ▼
         ┌────────┐           ┌────────┐
         │ Redmine│           │ Slack  │
         └────────┘           └────────┘

MCP Serverでは、例えば次のようなツールを提供します。

get_issue(issue_id)
search_issues(query)
list_open_issues()

search_messages(query)
get_thread(channel_id, thread_ts)
get_channel_history(channel_id)

LLMはこれらのツールを呼び出し、RedmineやSlackの情報を取得します。

2. 最初は読み取り専用にする

社内データを扱うため、最初のPoCでは読み取り専用にします。

Redmine
├── list_issues       ○
├── get_issue         ○
├── search_issues     ○
├── create_issue      ×
├── update_issue      ×
└── delete_issue      ×

Slack
├── search_messages   ○
├── get_thread        ○
├── get_history       ○
└── send_message      ×

重要なのは、プロンプトで「書き込み禁止」と指示するのではなく、MCP Serverに書き込み用ツールを実装しないことです。

これなら、LLMが誤って判断しても、RedmineやSlackを変更する操作自体を呼び出せません。

3. LangGraphで処理フローを組み立てる

MCPはツールを提供しますが、ツールを呼ぶ順番や、結果をどう処理するかまでは管理しません。

そこでLangGraphを使います。

                    ┌─────────────┐
                    │   User      │
                    └──────┬──────┘
                           ▼
                    ┌─────────────┐
                    │ LangGraph   │
                    │   Agent     │
                    └──────┬──────┘
                           │
                           ▼
                    ┌─────────────┐
                    │    LLM      │
                    │   oMLX      │
                    └──────┬──────┘
                           │
                      Tool Call
                           │
                           ▼
                    ┌─────────────┐
                    │ MCP Client  │
                    └──────┬──────┘
                           │
                           ▼
                    ┌─────────────┐
                    │ MCP Server  │
                    └──────┬──────┘
                           │
                  ┌────────┴────────┐
                  ▼                 ▼
              ┌────────┐        ┌────────┐
              │Redmine │        │ Slack  │
              └────────┘        └────────┘

例えば、次のような処理をGraphとして定義できます。

LLM
 ↓
Redmineを検索
 ↓
結果を整理
 ↓
Slackを検索
 ↓
情報を比較
 ↓
進捗レポートを生成

4. LLMはどうやってツールを知るのか

LLMがMCP Serverを直接知っているわけではありません。

MCP ClientがMCP Serverからツール定義を取得し、それをLangGraph経由でLLMに渡します。

例えば、ツール定義は次のような形式です。

{
  "name": "get_issue",
  "description": "Get a Redmine issue",
  "input_schema": {
    "type": "object",
    "properties": {
      "issue_id": {
        "type": "integer"
      }
    },
    "required": ["issue_id"]
  }
}

LangGraph側では、概念的には次のようにLLMへツールをバインドします。

tools = mcp_client.get_tools()

llm_with_tools = llm.bind_tools(tools)

流れは次のとおりです。

MCP Server
   │
   │ tools/list
   ▼
MCP Client
   │
   │ ツール定義
   ▼
LangGraph
   │
   │ bind_tools()
   ▼
LLM

LLMはRedmine APIやSlack APIを直接扱うのではなく、get_issuesearch_messages といったツールとして認識します。

5. Tool Callの流れ

ユーザーが、

「プロジェクトAの未完了チケットを教えて」

と質問したとします。

LLMは search_issues を使うと判断し、次のようなTool Callを返します。

{
  "name": "search_issues",
  "arguments": {
    "status": "open",
    "project": "project-a"
  }
}

LangGraphはこのTool Callを受け取り、MCP経由でRedmineを検索します。

LLM
 ↓
search_issues
 ↓
MCP Client
 ↓
MCP Server
 ↓
Redmine

取得結果はLLMに戻され、最終的な回答が生成されます。

Redmine
 ↓
MCP Server
 ↓
MCP Client
 ↓
LangGraph
 ↓
LLM
 ↓
回答

6. LangGraphの基本的な構成

Agentの処理は、単純化すると次のようになります。

START
  │
  ▼
┌──────────┐
│   LLM    │
└────┬─────┘
     │
     ├── 通常回答 ──────► END
     │
     └── Tool Call
             │
             ▼
       ┌──────────┐
       │ ToolNode │
       └────┬─────┘
            │
            ▼
          MCP
            │
            ▼
         Redmine
            │
            ▼
       ┌──────────┐
       │   LLM    │
       └────┬─────┘
            │
            ▼
           END

単純なチャットなら User → LLM → Answer で済みます。

一方、RedmineとSlackを順番に検索したり、結果を比較したりする場合は、LangGraphで処理を明示的に管理できます。

7. 目指す構成

最終的には、次のような処理を実現します。

ユーザー

「プロジェクトAの進捗どう?」

          ↓

      LangGraph
          ↓
        LLM
          ↓
   ┌──────┴──────┐
   ▼             ▼
Redmine         Slack
   │             │
   ▼             ▼
チケット        会話
   │             │
   └──────┬──────┘
          ▼
        LLM
          ↓
     進捗を分析
          ↓
        回答

回答例は次のようなものです。

プロジェクトAは現在78%のチケットが完了しています。
未完了チケットのうち3件は期限を超過しています。
SlackではAPI開発の遅延を示すやり取りが確認されており、Redmine上の期限とSlack上の認識にも差があります。

8. 計算はプログラム、解釈はLLM

進捗率のような計算は、LLMに任せずプログラムで処理します。

全チケット: 100
完了: 75

であれば、

progress = completed / total

で計算します。

LLMに任せるのは、次のような処理です。

  • Slackの文脈を理解する
  • チケットの状況を要約する
  • 遅延リスクを読み取る
  • 情報同士の矛盾を見つける
  • 人間向けの報告文にまとめる

役割分担は次のとおりです。

正確な処理
    ↓
プログラム

意味理解・要約・推論
    ↓
LLM

9. ローカルLLMを使う理由

今回扱うのは、RedmineやSlackなどの社内データです。

これらを外部のLLM APIへ送信する場合、セキュリティやデータ取り扱いを検討する必要があります。

一方、社内ネットワーク内で処理を完結できれば、社内データを外部に出さずに済みます。

Slack
  ↓
MCP
  ↓
LangGraph
  ↓
oMLX
  ↓
ローカルLLM

ただし、ローカルだから自動的に安全というわけではありません。

  • APIキーの管理
  • MCP Serverの認証
  • ネットワーク制御
  • ログ・監査
  • 最小権限
  • 読み取り専用

といった対策は必要です。

10. 構成要素の役割

コンポーネント 役割
oMLX ローカルLLMを動かす
LLM 推論・自然言語理解
LangGraph Agentの処理フローを制御
MCP Client MCP Serverと接続
MCP Server AIにツールを提供
Redmine プロジェクト情報
Slack コミュニケーション情報

全体の構成は次のとおりです。

                ┌──────────────┐
                │    User      │
                └──────┬───────┘
                       │
                       ▼
                ┌──────────────┐
                │  LangGraph   │
                │  Agent       │
                └──────┬───────┘
                       │
                       ▼
                ┌──────────────┐
                │     LLM      │
                │    oMLX      │
                └──────┬───────┘
                       │
                  Tool Calling
                       │
                       ▼
                ┌──────────────┐
                │  MCP Client  │
                └──────┬───────┘
                       │
                       ▼
                ┌──────────────┐
                │  MCP Server  │
                └──────┬───────┘
                       │
              ┌────────┴────────┐
              ▼                 ▼
          ┌────────┐        ┌────────┐
          │Redmine │        │ Slack  │
          └────────┘        └────────┘

おわりに

今回の構成では、次のように役割を分担します。

  • oMLX:ローカルLLMを動かす
  • MCP:RedmineやSlackをツールとして公開する
  • LangGraph:ツール呼び出しや処理フローを制御する

まずは読み取り専用でRedmineのチケット検索から始め、最終的にはRedmineとSlackを横断した進捗報告Agentを目指します。

次のステップでは、実装編に移りたいと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?