Upgrade to Pro — share decks privately, control downloads, hide ads and more …

マルチテナント+マルチプロダクト SaaS への AI Agent の組み込み方

マルチテナント+マルチプロダクト SaaS への AI Agent の組み込み方

川中 真耶(株式会社ナレッジワーク / CTO)
東京大学大学院情報理工学系研究科コンピュータ科学専攻修士課程修了。日本IBM東京基礎研究所研究員やGoogleソフトウェアエンジニアなどを経て株式会社ナレッジワークを共同創業。CTO of the year 2022 ファイナリスト。「王様達のヴァイキング」(週刊ビッグコミックスピリッツ)技術監修。

<概要>
AI Agent を組み込んだプロダクトを開発することは一般的になってきましたが、マルチテナント SaaS への組み込み手法がまだ広く議論されているとはいえません。本講演では、マルチテナントSaaS環境において、AIエージェントを効果的に導入・運用するための実践的手法を解説します。最適なアーキテクチャ設計、テナント毎のデータ分離・セキュリティ確保、スケーラビリティ、テナント毎のカスタマイズ運用のポイントを具体例を交えて紹介します。

※AI Engineering Summit(2025/6/18開催)での登壇資料です
https://ai-engineering-summit.findy-tools.io/

More Decks by KNOWLEDGE WORK / 株式会社ナレッジワーク

Other Decks in Technology

Transcript

  1. © Knowledge Work Inc. 講演者プロフィール 2 株式会社ナレッジワーク CTO 
 川中

    真耶
 主な経歴
 2006 東京大学大学院情報理工学系研究科コンピュータ科学専攻
 修士課程修了
 2006 日本IBM 東京基礎研究所リサーチャー
 2011 Google Japan ソフトウェアエンジニア
 2020 株式会社ナレッジワーク共同創業
 
 王様達のヴァイキング(週刊ビックコミックスピリッツ)技術監修

  2. © Knowledge Work Inc. Profile 会社概要 3 ナレッジワーク 会社概要 創業日  2020年4月1日

    代表者  麻野 耕司 資本金  61.3億円(資本準備金等含む) 事業内容  ナレッジワークの開発・提供 主な株主  グロービス・キャピタル・パートナーズ、DNX Ventures、WiL  Salesforce Ventures、One Capital、ANRI、XTech、  ユーザベース、フォースタートアップス、Sansan
  3. © Knowledge Work Inc. ナレッジワーク プロダクト紹介 4 みんなが売れる営業になる セールスイネーブルメント AIなら

    ナレッジワーク 営業担当の支援をするプロダクト 「ナレッジワーク」を提供しています
  4. © Knowledge Work Inc. 様々な AI Agent 開発フレームワークが生まれている 7 ちょっと

    AI Agent を動かすだけなら非常に簡単にできる時代になった 初見のフレームワークを動かすのに環境整備から始めても1時間かからない Agent Development Kit
  5. © Knowledge Work Inc. 実際に AI Agent をプロダクトに組み込もうとすると 認証、権限、開発プロセスやデプロイ戦略との整合等の解決すべき課題が発生する 8

    AI Agent の組み込みに関する課題 データ 読取権限 デプロイ戦略 AI Agent サーバー ブラウザ MCP サー バー サー バー サー バー 他社 AI 認証 認証 テナント別プ ロンプト ライセンス
  6. © Knowledge Work Inc. マルチテナント +マルチプロダクト SaaS への AI Agent

    組み込みの一例を示す 同じ道を歩む人の考え方の ヒントになってほしい 9 今日のメイントピック
  7. © Knowledge Work Inc. システムアーキテクチャの前提 10 一定の複雑さを持ったシステム、および顧客ユースケースを想定する • マルチテナントアーキテクチャ ◦

    1つのシステムに多数のテナントが相乗りしている状態 • マルチプロダクト ◦ 1つのシステムに複数のプロダクトを抱えており、それぞれのプロダクトで AI Agent を動かしたいと考えている ◦ 一定のサービスごとに(プロダクト単位で、あるいはマイクロサービス単位で)サーバーが分かれている ▪ ナレッジワークではプロダクト単位でサーバーを分け、プロダクト間通信を認めないというアーキテクチャに なっている • テナント単位で挙動を少し(あるいは大幅に)変えたい ◦ 会社によって業務フローが異なり、意味のある結果を出そうと思うと現状会社ごとにプロンプトをカスタマイズして最 適化していくことが必要になっている 実際のナレッジワークのアーキテクチャをベースに話します
  8. © Knowledge Work Inc. 11 ナレッジワーク社の実際のアーキテクチャ frontend scim cloud scheduler

    scim client (Azure AD, ...) cloud tasks knowledgework web frontend admin frontend externalshare external share viewer product backend knowledge work learning ... ex-api oauth client server authenticated by token auth client job invoker admin frontend admin gateway admin gateway gateway client layer gateway layer backend layer DB not accessible Authentication layer authenticated by admin token central backend central middleware / product directory middleware directory content middleware content admin backend admin notification middleware notification * cloud tasks and cloud scheduler have service account, so it's OK to skip gateway subsystems content processing cpv4 data processing dbt email email-sender search elasticsearch subsystem can access backend layer middleware layer 最終形 updated at 2024-08-01
  9. © Knowledge Work Inc. 12 ナレッジワーク社の実際のアーキテクチャ frontend scim cloud scheduler

    scim client (Azure AD, ...) cloud tasks knowledgework web frontend admin frontend externalshare external share viewer product backend knowledge work learning ... ex-api oauth client server authenticated by token auth client job invoker admin frontend admin gateway admin gateway gateway client layer gateway layer backend layer DB not accessible Authentication layer authenticated by admin token central backend central middleware / product directory middleware directory content middleware content admin backend admin notification middleware notification * cloud tasks and cloud scheduler have service account, so it's OK to skip gateway subsystems content processing cpv4 data processing dbt email email-sender search elasticsearch subsystem can access backend layer middleware layer 最終形 updated at 2024-08-01 共通基盤 認証 プロダクト 複数の サブシステム フロントエンド クライアント 今日の話には関係ないので 忘れてください プロダクト 横断機能
  10. © Knowledge Work Inc. 13 今日の話向けにもう少しシンプルに 共通基盤 認証 プロダクト クライアン

    ト 横断 プロダクト 左から右にはアクセス可能、同じレイヤー内では相互アクセスは基本禁止 このシステムに AI Agent を組み込みたい
  11. © Knowledge Work Inc. 14 まだ AI Agent framework なんてものも整備されていなかった時代

    • 各プロダクトサーバーにて、自分で Open AI や Vertex AI (Gemini) と通信している ◦ 一発で求める水準の答が出るほど LLM も賢くない(今も怪しいが)ので、ある程度 step by step で LLM を利用 し、結果をプログラムでさらに変換して次の LLM を呼び出すみたいなことをしている • 手で書かれた温かみのあるプロンプトがバイナリに埋め込まれている ◦ テナント単位でのカスタマイズは不可能 初期の頃は動けばそれで一定の価値が出せるので、それでよかった → AI が当たり前になり、各プロダクトに AI Agent が組み込まれ、また様々な顧客が AI を使うようになってくると困ることも増えて きた ナレッジワークでの初期の AI 組み込み
  12. © Knowledge Work Inc. 15 テナントによって使って良いモデルが異なる • エンタープライズのセキュリティ意識の高いお客様から、データを国内に閉じること、データが保存されないこと、などという 要望がそこそこある ◦

    金融・保険・医療業界は厳しいことが多い 今日完全に国内に閉じようとすると主要クラウドベンダーだと以下のモデルのみ*(世知辛い)で、大手の最新モデルがとにかく日 本リージョンで動いていない(この辺で日本への対応が遅れているのをすごく感じる) • Google Cloud は Gemini 1.5 flash の 32k token モデルのみ (1.5 pro すらない) ◦ 先週 1M token まで使えていたのが突然 32k に制限された……(ナンデ!?) • Azure Open AI は o4 のみ • AWS Bedrock は Claude Haiku 3.0 or Sonnet 3.5 日本から使える ≠ データが日本に閉じている • 使えると思って使うと海外にデータが送られることになり、インシデント扱いになりかねない • 「グローバルリージョン」は危険 • 海外モデルを許してもらえば Gemini 2.5, o3, Sonnet 3.7, 4.0 etc. が使えるのに Azure Open AI は abuse monitoring があり、これが log に残るので使えないことがある マルチテナントに伴うさまざまな課題(1) * embedding 関連のモデルはわりと日本でも使えます
  13. © Knowledge Work Inc. 16 テナントごとにプロンプトをカスタマイズしたい • 最適な顧客体験を提供するために、カスタマーサクセスやコンサルがお客様ごとにプロンプトをカスタマイズしたいという要 望がある ◦

    ナレッジワークは業務に根付いた SaaS なので、深く業務に入り込んで価値を出していく必要があり、一定やむを 得ないものであると考えている • 全部が全部カスタマイズしたいわけではないがテナントによってカスタマイズしたい場所が異なり、一定のカスタマイズ機能 を提供する必要がある お客様だけで十分カスタマイズしきれないことが多くカスタマーサクセスやコンサルが併走する必要があるが、併走はできるので 彼らが設定できれば十分ではある マルチテナントに伴うさまざまな課題(2)
  14. © Knowledge Work Inc. 17 ライセンスや権限に対する課題 • ユーザーによって保持しているプロダクトライセンスが異なる ◦ そのユーザーが使えるプロダクトの中で機能を実装していく必要がある

    アーキテクチャ上の課題 • 一部の AI が機能上どうしてもプロダクト連携を必要とする ◦ ナレッジワークではプロダクト間通信は禁止しており、プロダクト連携が必要な機能は「クロスプロダクト」に置く必要 がある。プロダクト内で AI Agent を動かすと早晩詰む構成をシステム上強制*している マルチプロダクトにともなう様々な課題(1) * システムの依存を DAG にすることでデプロイの依存関係がシンプルになるように強制している
  15. © Knowledge Work Inc. 18 開発プロセスに対する課題 • 各プロダクトが AI を勝手に使うことによる

    AI インタフェースの非統一や車輪の再発明 ◦ 各プロダクトが独自に AI インタフェースを拡張していく ◦ メモリ機能やセッション管理があったりなかったり、定義方法が違ったりしてしまう • MCP server や A2A など、外界との AI 通信に関連する機能のオーナーシップ不在 ◦ MCP server を外部に公開したり、A2A (Agent to Agent) Protocol などにより AI を呼びだす機能を作ったりするこ とが求められる ◦ 外からみたら1つの「ナレッジワーク」というプロダクトなので、プロダクト単位で別々に公開するわけにもいかず、イ ンタフェースの統一が期待される ▪ 開発チームは一定プロダクトで割っていたりするので、クロスプロダクトチームの組成が不可欠 • プロダクトのデプロイサイクルと AI Agent フレームワークのデプロイサイクルの不一致 ◦ プロダクトのリリースとともに新しいエージェント定義を動かしたい ◦ AI Agent フレームワーク上にエージェントを実装していくと、リリース可能なエージェントと開発途中のエージェント が混ざってしまう マルチプロダクトにともなう様々な課題(2)
  16. © Knowledge Work Inc. 19 マルチテナントに対する解決 • テナントによってどの言語モデルが使えるかを一律定義し、勝手に言語モデルが使えないようにする • 同じエージェントでもテナントによってプロンプトの定義を変更できるように、同じ名前のデフォルトエージェントとカスタマイ

    ズエージェントを定義する マルチプロダクトに対する解決 • エージェント定義はプロダクト単位でできるような構成に ◦ プロンプト定義、ツール定義をすべてプロダクト側から設定できるようにする ◦ ナレッジワークは protobuf でいろんなものを定義しているので、protobuf で tool を構成する • エージェント実行は抽象化しておく ◦ 定義を渡して実行するインターフェースにしておき、プロダクト開発者は詳細をみなくてもよいようにする 解決案(サマリー)
  17. © Knowledge Work Inc. アーキテクチャ詳細 ナレッジワークでどういうアーキテクチャで AI Agent を開発しているかを話します •

    アーキテクチャ外観 • エージェントの定義と実行 • ツール定義とツールの実行 • 外部 MCP 注: 我々も試行錯誤の途中なので、今後これがずっと続くわけではありません 現時点である程度よいと思った構成になるようにしています 21
  18. © Knowledge Work Inc. 22 AI Agent のアーキテクチャ 共通基盤 認証

    プロダクト クライアン ト 横断 プロダクト エージェント実行部や MCP をプロダクト横断サーバーへ 各プロダクトや共通基盤でツールを定義 エージェントそのものの定義を共通基盤へ エージェント実行部 ツール定義 ツール定義 ツール定義 エージェント 定義 内部向け MCP proxy 外部向け MCP エージェント セッション 定義
  19. © Knowledge Work Inc. • エージェント定義はすべてのプロダクトから やりたい • エージェント実行部はすべてのプロダクトを ツールとして呼び出したい

    ◦ いろんなプロダクトからデータを取得 したい 結果、必然的にこのように分けざるをえない • エージェント実行をすべてのプロダクトから 行いたい、も実はある ◦ フロントエンドから実行する分には横 断が呼べるので問題ない ◦ プロダクトから複雑なエージェント実 行をしようとする場合のみ、エージェ ント実行部を呼ぶのは目をつむるも のの、推奨はしない(実行途中に ユーザーからの入力が難しい) 23 なぜこんなアーキテクチャに? 共通基盤 プロダクト 横断 プロダクト エージェント実行部 ツール定義 ツール定義 ツール定義 エージェント 定義 内部向け MCP proxy エージェント セッション 定義
  20. © Knowledge Work Inc. 25 エージェントを実行するための AI Agent framework は様々あって、まだどれに乗っていくのがいいか判断しづらい(正直読めてま

    せん) • AI Agent framework の価値の多くがワークフロー定義やエージェント評価機能などにあるものの、プロダクトがすでにある とワークフローをフレームワークに組み込みにくい(ドメイン知識が分散する) ◦ なるべくプロダクトの知識はプロダクトサーバーだけに載せておきたい ナレッジワークでは、単体のエージェントや、チームエージェントが定義できて動かせれば現状十分で、おそらくしばらく十分 • ワークフローは結局「プログラム」なので、単体のエージェントやチームエージェント呼び出しを組み合わせれば同じものは 作れる • AI Agent framework にこの辺も乗せられば早くモノが作れるものの、持続的なプロダクトの発展を考えたときには pros よ り cons が大きくなると考えて採用しなかった エージェント定義と実行に関する課題
  21. © Knowledge Work Inc. 26 ナレッジワークでは基本的にサーバー間のデータ交換は protobuf 定義をすることになっているので、エージェントも汎用 的に protobuf

    定義する • プロダクト内で定義したり保存したりしたいので、なんら かデータ交換可能なフォーマットになっている必要があ る 実行時には、protobuf 定義から AI Agent framework の形式 に変換して利用する 現状ほぼどんな AI Agent framework も似たような形式で Agent が定義できるので、今後さらに新しい AI Agent framework が現れて採用することがあってもなんとかなるだろ う、という目論見 エージェント定義 // 単体エージェントの定義 message SingleAgentSpec { string name = 1; AgentModel model = 2; optional string description = 3; optional string instruction = 4; // 利用するツール定義 optional ToolSpec tool = 5; // Output フォーマット定義 (例: json?) optional SingleOutputSpec output = 6; // メモリ定義 optional SingleMemorySpec memory = 7; }
  22. © Knowledge Work Inc. 27 UI 上でエージェントを動かしたいときは目的をもってエージェン トを実行しようとしているから、どのエージェントを呼び出したい のかは決まっている →

    テナントによらないデフォルトのエージェントと、テナントでカ スタマイズしたエージェントを同じ名前で定義しておき (protobuf で定義しているので RDB にシリアライズして保存するのが容 易)、名前で呼び出して利用する • テナントによって使えるモデルが違うのとモデルによって プロンプトの癖が違うので、どうしてもモデルとプロンプト はペアで保持しておく必要がある • ちょっと定義を汎用的にしすぎたきらいはある テナントによるエージェントのカスタマイズ // エージェントの定義 message Agent { string id = 1; string system_name = 2; // AgentSpec に前ページで定義した SingleAgentSpec や、Team 向けの AgentSpec を保持する AgentSpec agent_spec = 3; AgentOption agent_option = 4; }
  23. © Knowledge Work Inc. 28 エージェントを実際に動かすにはセッションを作成する必要があ る • エージェントは一般にセッション単位で会話を覚える •

    ナレッジワークのエージェントは、UI に溶け込んだエー ジェントが多く、どういう文脈でエージェントを動かそうとし ているか(例えば、どの文書に対するエージェントを動かそ うとしているか)が自然とエージェント定義に溶け込んでい る必要がある ◦ cline 等は @ で文書を指定して文脈を読み込ませ たりできるが、そこまで利用者のリテラシーは高く ないため、利用者が指定しなくても自然と文脈が定 義されてほしい → session_context (JSON) のような定義をセッション中に定義 して表現する エージェントセッションの定義 // エージェントセッションの定義 message AgentSession { string agent_session_id = 1; Agent agent = 2; google.protobuf.Struct session_context = 3; }
  24. © Knowledge Work Inc. 29 エージェントの実行フロー(フロントから) プロダクト ツール定義 ① セッション定義リクエス

    ト 共通基盤 エージェント 定義 エージェント セッション 定義 ② セッション定義 ③ セッション id 返却 クライアン ト どういう context でエージェントを動かそうとし ているか? その context でエージェントを動 かす権限はあるか? などをプロダクトサー バーが確認できる必要があり、プロダクトから セッションを定義する仕組みになっている 横断 ④ クエリ ⑤ エージェント定義読込&検証 (一度読めば横断内で一定キャッシュ可 ) ⑥ エージェント定義送信 と実行 tool の定義や実行は後で話します ・Agent framework として agno を採用してい る (なんでもよかったが python 慣れしている 人が多いため agno にした) ・クライアントは直接 agno を触れず横断から 呼び出して使う ⑦ フレームワークからの レスポンスを変形して返却 ・横断と agno を同じサーバー内で動かして local 通信し ている (side car 利用) ・agent 定義を http で agno に送ってその場で agent を 組み立てて実行する (LangChain だとパフォーマンスに 問題があるが agno はその辺が速い) ・agno 部は極力コードを小さくしてある(1〜2ファイルに 収まる程度)
  25. © Knowledge Work Inc. 30 • ぱっと見、わりとややこしいことをしている • フローだけみるともっとシンプルにできるが…… ◦

    権限チェック、エージェント定義、セッションコンテキスト定義などを自然な場所でやろうとするとフローを少し回りくど くする必要があった ◦ フローの方を簡単にすると、権限チェックやコンテキスト定義が自然な場所でなくなる • どっちをとるか? が問題だが、プロダクト側が簡単になる方が今後プロダクトが増えていくことを考えるとメリットが大きい と判断した エージェントの実行
  26. © Knowledge Work Inc. 31 エージェントの実行フロー(プロダクトから) プロダクト ツール定義 共通基盤 エージェント

    定義 エージェント セッション 定義 ① セッション定義 ② セッション id 返却 基本はフロントからと同じだが、プロダクト から呼び出してよい ここだけアーキテクチャの DAG が崩れる 苦渋の決断をしている プロダクトが「横断」のアップデートで壊れな いように API 定義などを最小限として極力 変更がない形としている 横断 ④ クエリ ⑤ エージェント定義読込&検証 (一度読めば横断内で一定キャッシュ可 ) ⑥ エージェント定義送信 と実行 ⑦ フレームワークからの レスポンスを変形して返却
  27. © Knowledge Work Inc. 33 LLM は外部機能をツールとして呼び出すことができる ツール実装時には、単にツールを定義する以外にもやらなければならないめんどくさいチェックが多数ある • 認証

    • 認可 ◦ ライセンス ◦ 権限 さらに、プロダクトサーバーをデプロイすることによって、エージェント実行部に手を入れなくてもツールやエージェントを更新したい ツール定義の要件
  28. © Knowledge Work Inc. 34 ツールを実装するときの課題 • ツールは基本 MCP で実装する流れができつつあるので、基本的にそれに乗っておく

    • 「横断」サーバーにツールを実装するとツール更新時に横断サーバーのデプロイが必要となるため避けたい • ツール呼び出しには権限やライセンスチェックなどが必要 ◦ ナレッジワークでは protobuf + connect rpc で様々なものが定義され、権限チェックやライセンスチェックも protobuf に書いておくと自動でチェックコードが生成されるようになっており、これにのりたい ◦ 一方で MCP は JSON-RPC なのでなんらかの返還が必要 解決案 • ツール自体をプロダクトサーバーに実装する • ツールの基本形を protobuf + connect rpc として実装し、JSON-RPC のアダプタを自動生成する ツール定義の課題と解決策
  29. © Knowledge Work Inc. 35 ツールを protobuf で定義 (RPC 定義編)

    service McpToolService { // 定義した tool をすべて返す RPC を1つ用意してお く rpc List(ListRequest) returns (ListResponse) {} // tool を RPC として定義する ... (次ページで) } message ListRequest {} message ListResponse { // 定義されたツールを返す repeated mcp.Tool tools = 1; } 各プロダクトサーバー(+共通基盤)に、MCP ツールを定 義するための connect rpc サービスをはやす 右のような形式で McpToolService を定義する
  30. © Knowledge Work Inc. 36 ツールを protobuf で定義 (RPC 定義編)

    rpc McpToolSearchKnowledgeChunks( McpToolSearchKnowledgeChunksRequest ) returns ( McpToolSearchKnowledgeChunksResponse ) { option (mcp.tool) = { name: "search_knowledge_chunk" description: "search_knowledge_chunk は、ナレッジチャンクを検索 します。\n" "検索結果には検索スコアが高い順に複数のナレッジチャンク が含まれます。\n" "各ナレッジチャンクは以下の内容をもっています。 \n" " - knowledge_id: ナレッジのID\n" " - knowledge_title: ナレッジのタイトル \n" " - knowledge_summary: ナレッジの内容の要約 \n" " - chunk_content: ナレッジチャンクの内容 \n" }; // ほかいろいろ tool options を足せるようになっている } } message McpToolSearchKnowledgeChunksRequest { // tenant 情報やエージェントの実行時コンテキストが // ここに必ず入る mcp.ToolCallContext context = 1; // proto の annotation を書いておくと tool の情報になる string query = 2 [(mcp.field) = { description: "ユーザーが入力した質問文。 " }]; repeated string keywords = 3 [(mcp.field) = { description: "質問文に関連するキーワード。複数指定可。 " "キーワードが多数含まれているナレッジチャンクほど " "優先的に返される。 " }]; } message McpToolSearchKnowledgeChunksResponse { message Chunk { string knowledge_id = 1; string knowledge_title = 2; string knowledge_summary = 3; string chunk_content = 4; } repeated Chunk chunks = 1; } 一つツールを定義した例
  31. © Knowledge Work Inc. 37 ツールを protobuf で定義 (RPC 定義編)

    rpc McpToolSearchKnowledgeChunks( McpToolSearchKnowledgeChunksRequest ) returns ( McpToolSearchKnowledgeChunksResponse ) { option (mcp.tool) = { name: "search_knowledge_chunk" description: "search_knowledge_chunk は、ナレッジチャンクを検索 します。\n" "検索結果には検索スコアが高い順に複数のナレッジチャンク が含まれます。\n" "各ナレッジチャンクは以下の内容をもっています。 \n" " - knowledge_id: ナレッジのID\n" " - knowledge_title: ナレッジのタイトル \n" " - knowledge_summary: ナレッジの内容の要約 \n" " - chunk_content: ナレッジチャンクの内容 \n" }; // ほかいろいろ tool options を足せるようになっている } } message McpToolSearchKnowledgeChunksRequest { // tenant 情報やエージェントの実行時コンテキストが // ここに必ず入る mcp.ToolCallContext context = 1; // proto の annotation を書いておくと tool の情報になる string query = 2 [(mcp.field) = { description: "ユーザーが入力した質問文。 " }]; repeated string keywords = 3 [(mcp.field) = { description: "質問文に関連するキーワード。複数指定可。 " "キーワードが多数含まれているナレッジチャンクほど " "優先的に返される。 " }]; } message McpToolSearchKnowledgeChunksResponse { message Chunk { string knowledge_id = 1; string knowledge_title = 2; string knowledge_summary = 3; string chunk_content = 4; } repeated Chunk chunks = 1; } 一つツールを定義した例 protobuf に tool name や tool のデスクリプションを書 いておくと、MCP 上の tool の定義となるようにアダプ タを作れる
  32. © Knowledge Work Inc. 38 ツールを protobuf で定義 (RPC 定義編)

    rpc McpToolSearchKnowledgeChunks( McpToolSearchKnowledgeChunksRequest ) returns ( McpToolSearchKnowledgeChunksResponse ) { option (mcp.tool) = { name: "search_knowledge_chunk" description: "search_knowledge_chunk は、ナレッジチャンクを検索 します。\n" "検索結果には検索スコアが高い順に複数のナレッジチャンク が含まれます。\n" "各ナレッジチャンクは以下の内容をもっています。 \n" " - knowledge_id: ナレッジのID\n" " - knowledge_title: ナレッジのタイトル \n" " - knowledge_summary: ナレッジの内容の要約 \n" " - chunk_content: ナレッジチャンクの内容 \n" }; // ほかいろいろ tool options を足せるようになっている } } message McpToolSearchKnowledgeChunksRequest { // tenant 情報やエージェントの実行時コンテキストが // ここに必ず入る mcp.ToolCallContext context = 1; // proto の annotation を書いておくと tool の情報になる string query = 2 [(mcp.field) = { description: "ユーザーが入力した質問文。 " }]; repeated string keywords = 3 [(mcp.field) = { description: "質問文に関連するキーワード。複数指定可。 " "キーワードが多数含まれているナレッジチャンクほど " "優先的に返される。 " }]; } message McpToolSearchKnowledgeChunksResponse { message Chunk { string knowledge_id = 1; string knowledge_title = 2; string knowledge_summary = 3; string chunk_content = 4; } repeated Chunk chunks = 1; } 一つツールを定義した例 引数の説明も同様に可能
  33. © Knowledge Work Inc. 39 普通の RPC としてツールを定義させることで • 当然普通の

    RPC には備わっているはずの内部のユーザー認証、ライセンス認可、権限認可がこれまでと同じ仕組みで実 装される ◦ この辺もナレッジワークでは protobuf の定義を書けば自動で生成されるようになっている • サービスがデプロイされればその RPC が呼べる これでツール定義の本質ではない部分をすべて既存の仕組みに乗せることができる ナレッジワークでは protobuf エコシステムの上に様々な自動実装を組んでいるので、この仕組みに乗れるとライセンスや権限な どの必要なチェックがすべて自動でついてくるため、ツール内部の実装だけに集中できる ツール定義
  34. © Knowledge Work Inc. 40 MCP tool は JSON-RPC で呼び出さなければならないので、connect

    rpc で API を定義してもそれを MCP tool として直接呼べ るわけではない → MCP server を別に作成し、JSON-RPC と connect rpc の変換ができるようにしておく必要がある MCP Tool の呼び出し方
  35. © Knowledge Work Inc. 41 ツールの実行 エージェント実行部 内部向け MCP proxy

    プロダクト ツール定義 実行受付部 ④ ツール情報取得 ⑤ ツール呼出 JSON-RPC ① セッション実行リクエスト ② セッション情報伝達 ③ エージェント実行 ・セッション情報 (session_id) ・テナント情報 (tenant_id) ・ユーザー情報 (user_id) ・エージェント定義 ⑥ ツール RPC 呼出 connect rpc エージェント実行部は自分たちのサーバーではないので、自分たちを同じように テナント情報やユーザー情報を扱うことができない そこで、実行受付部で内部向け MCP proxy にセッション情報を渡し、エージェント実行 部からもセッション id を MCP proxy に渡す id からどのツールをどの tenant の誰が利用しているか判別できる session_id を渡す 内部向け proxy は JSON-RPC で受け、該当 connect RPC を 呼び出す
  36. © Knowledge Work Inc. • エージェント実行部 (agno) からのみリクエストを受け付ける port を用意

    ◦ streamable http で MCP server をエージェント実行部に公開 ◦ エージェント実行部からのみ呼び出せること、side car での実装につき、ここに認証は不要 ▪ MCP の認証はしばらく決まっておらずまだ実装も進んでない部分があり、認証なしで呼べるようにした • エージェント実行部がツールを取得 ◦ ここで、「エージェント定義」中にかかれたツールのみを返却することで、多数のツール定義だけで token が埋まっ てツール呼び出しの精度が落ちることを防止できる ◦ ツールの endpoint を MCP proxy にしておく • エージェント実行部は http header に session_id を含めてツールを JSON-RPC で呼び出す ◦ MCP Proxy はこれを connect rpc に変換して RPC を呼び出す。 ◦ http header に session_id が含まれているので、MCP server はどの session のものかを理解できる、すなわち tenant_id や user_id を理解できる ◦ tenant_id や user_id を設定して RPC を呼び出し、権限・ライセンスはこの段階で処理できる 42 内部向け MCP Proxy の実装
  37. © Knowledge Work Inc. connect rpc は通常 protobuf 定義して、クライアントを生成して呼び出す 必要があるため、普通にやるとツールを定義したときにプロダクト側だけ

    でなく MCP proxy も再デプロイする必要がある → connect rpc は endpoint さえわかっていれば Content-Type: application/json で呼び出せるので、Request と Response をどちらも Struct と呼ばれる JSON 型だと思って呼び出せば、型がわからなくても 呼べる どうせもらった reponse を JSON にして tool からの返却値と言い張って agent に返すだけなので、ここは型がついてなくても大きな問題がない tool 一覧はプロダクトから取得できるようにしてあるので、tool さえ定期 的に再取得すれば、プロダクトサーバーをデプロイすれば tool 一覧も アップデートされる 43 ツール呼び出しの HACK 内部向け MCP proxy プロダクト ツール定義 ⑥ ツール RPC 呼出 connect rpc
  38. © Knowledge Work Inc. 44 外部向け MCP と内部向け MPC は使える

    tool がどうしても違 う MCP server は JSON-RPC を受けないといけないので、 gateway レイヤーで JSON-RPC を受け、横断 backend へ 内部向け MCP と同じ記法で外部向けツールを定義できる 外部向け MCP 横断 backend 外部向 MCP rpc McpToolSearchKnowledgeChunks( McpToolSearchKnowledgeChunksRequest ) returns ( McpToolSearchKnowledgeChunksResponse ) { option (mcp.tool) = { name: "search_knowledge_chunk" description: "search_knowledge_chunk は、ナレッジチャンクを検索 します。\n" "検索結果には検索スコアが高い順に複数のナレッジチャンク が含まれます。\n" "各ナレッジチャンクは以下の内容をもっています。 \n" " - knowledge_id: ナレッジのID\n" " - knowledge_title: ナレッジのタイトル \n" " - knowledge_summary: ナレッジの内容の要約 \n" " - chunk_content: ナレッジチャンクの内容 \n" }; // ほかいろいろ tool options を足せるようになっている } } 横断 gateway JSON-RPC connect rpc
  39. © Knowledge Work Inc. 45 • マルチテナント、マルチプロダクト SaaS における AI

    エージェントの組み込みについての困難なところとその解決のための 仕組みを話した ◦ プロダクトサーバーでの Agent 定義 ◦ デフォルトエージェント、カスタマイズエージェント • ツール定義について、デプロイ戦略との整合性をとるための様々な仕組みについて話した • ツール定義について、テナント隔離、ユーザー認証、権限チェック、ライセンスチェックなど既存の仕組みにのるための様々 な HACK について話した まとめ