Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

Knowledge Work の AI Backend

Knowledge Work の AI Backend

mayah / 株式会社ナレッジワーク CTO
※2025/12/23開催「Encraft #22 AIプロダクトを支えるアーキテクチャ設計 ー理論と実践」での登壇資料です。
https://knowledgework.connpass.com/event/372086/

セッション概要:
Knowledge Work は初期は AI を利用しない SaaS プロダクトでした。しかし、AI の利用が盛んになるにつれ、AI を動かすための基盤、AI がデータを取得するための基盤などを整えてきました。本日はその基盤の概略と行ってきた基盤整備についてお話しします。

登壇者プロフィール:
2006年、東京大学大学院情報理工学系研究科コンピュータ科学専攻修士課程修了。日本IBM東京基礎研究所では研究者として入社。2011年、Googleにソフトウェアエンジニアとして入社。Chrome browserの開発に関わった。2020年4月、株式会社ナレッジワークを共同創業。「王様達のヴァイキング」(週刊ビッグコミックスピリッツ)技術監修。X: @mayahjp

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

Other Decks in Technology

Transcript

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

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

  2. © Knowledge Work Inc. 今回の AI Backend 定義とお話のスコープ 7 今回は

    LLM による AI アプリケーションをメインに考えて エージェント実行部 + データ・ツール提供部 の課題と解決策について話します データ・ツール提供にも内部向けと外部向けの両方があります クライアント サーバー エージェント実行部 MCP 等による外部 エージェントへのデー タ・ツール提供 LLM の実行 内部向けデータ・ ツールの提供
  3. © Knowledge Work Inc. AI 営業記録や AI 営業ロープレの AI Backend

    については今日は割愛します • 「AI 営業記録」は M&A したプロダクトであってまだナレッジワークの AI Backend とは統合されておらず、異なる条件で動 いている ◦ 将来的には統合することを考えている • 「AI 営業ロープレ」はリアルタイム音声処理などが含まれており、求められる要件がほかプロダクトで動かしたい AI と非常 に異なるので、この AI 基盤とは異なる条件で動いている ◦ 将来的にも統合することは考えていない 今日話さないこと 8
  4. © Knowledge Work Inc. 前提: ナレッジワークはエンタープライズ向けのマルチプロダクト SaaS であり; • 各プロダクトのバックエンドは独自アプリケーションとして他プロダクトと独立して動く

    • 各プロダクトはテナント・ユーザーなどの共通データを共通基盤を介して利用できる • エンタープライズのお客様がそれぞれ固有に望まれる AI 利用規約が存在することがある • LLM 費用をプロダクト単位やテナント単位で集計したい(していきたい) エージェントの実行に関する課題 • 各プロダクトが自由に LLM を呼び出していいのか? どこかに寄せた方がよいのか? • LLM の単なる呼び出し以外に、LLM や API を複数回呼び出すような複雑なワークフロー呼出を実装していきたい データ・ツールの提供に関する課題 • どのようにすれば LLM にデータを安全に渡すことができるのか? • ツールの作り方を標準化することはできるのか? ナレッジワークにおける AI Backend を作成するときの課題 9
  5. © Knowledge Work Inc. ナレッジワークのアーキテクチャ外観 (管理部分や AI 部分除く) 10 frontend

    scim scim client (Azure AD, ...) cloud tasks / scheduler knowledgework web frontend externalshare external share viewer ex-api oauth client authenticated by token auth job invoker gateway client layer gateway layer backend layer DB not accessible Authentication layer cross backend central middleware / product directory middleware directory * cloud tasks and cloud scheduler have service account, so it's OK to skip gateway product middleware content crmsfa skill product backend portal process learning recording coaching external share creation knowhow content processing cpv4 search elasticsearch subsystem layer activityevent / audit activityevent notification email-sender queue tftq platform subsystem content subsystem system middleware notification
  6. © Knowledge Work Inc. ナレッジワークのアーキテクチャ外観 (管理部分や AI 部分除く) 11 frontend

    scim scim client (Azure AD, ...) cloud tasks / scheduler knowledgework web frontend externalshare external share viewer ex-api oauth client authenticated by token auth job invoker gateway client layer gateway layer backend layer DB not accessible Authentication layer cross backend central middleware / product directory middleware directory * cloud tasks and cloud scheduler have service account, so it's OK to skip gateway product middleware content crmsfa skill product backend portal process learning recording coaching external share creation knowhow content processing cpv4 search elasticsearch subsystem layer activityevent / audit activityevent notification email-sender queue tftq platform subsystem content subsystem system middleware notification フロントエンド クライアント 認証 共通基盤 プロダクト 固有データ プロダクト単位 サーバー群 プロダクト 横断処理 プロダクトと 独立した 隔離環境 共通データ 外部向け 認証 赤枠 本日のスコープ
  7. © Knowledge Work Inc. エージェント実行部に対する要件 • 各プロダクトからエージェントを呼び出すことができ、別プロダクトのデータを要求することができる • 利用できる LLM

    は Gemini, GPT, Claude などから選ぶことができる ◦ 基本的に国内リージョンで実行するモデルを選択する ◦ お客様が許せばグローバルリージョンで動くモデルを選択することもできる • エージェント定義のバージョン管理をしたい • LLM の実行だけでなく、可能ならワークフローも定義して実行したい ◦ ワークフロー: LLM の実行やツール呼び出しを規定の手順で動かすプログラム • 他社エージェント、他社ワークフローもナレッジワークから同じインタフェースでつないで呼び出せる ◦ salesforce 上で動くエージェントである agentforce や、各社が自社で保持しているワークフロー (dify や MS copilot 等) を、ナレッジワーク上から同じインタフェースで呼び出して提供したい 13
  8. © Knowledge Work Inc. ナレッジワークのアーキテクチャ外観 (管理部分や AI 部分除く) 14 frontend

    scim scim client (Azure AD, ...) cloud tasks / scheduler knowledgework web frontend externalshare external share viewer ex-api oauth client authenticated by token auth job invoker gateway client layer gateway layer backend layer DB not accessible Authentication layer cross backend central middleware / product directory middleware directory * cloud tasks and cloud scheduler have service account, so it's OK to skip gateway product middleware content crmsfa skill product backend portal process learning recording coaching external share creation knowhow content processing cpv4 search elasticsearch subsystem layer activityevent / audit activityevent notification email-sender queue tftq platform subsystem content subsystem system middleware notification フロントエンド クライアント 認証 共通基盤 プロダクト 固有データ プロダクト単位 サーバー群 プロダクト 横断処理 プロダクトと 独立した 隔離環境 共通データ すべてのデータにアクセスできなければならないという制約を満たすためには プロダクト単位サーバー群でエージェントを動かすことが難しい(プロダクトが独立しているから) → 隔離環境上にエージェント実行部を構築
  9. © Knowledge Work Inc. 15 ナレッジワークではすべてのデータ定義は protobuf で定義す ることになっているので、エージェントも汎用的に protobuf

    定義 する いくつかのタイプが同一の方法で定義できるようになっている • 単体の LLM + Tool 呼出だけで完結する簡単なエー ジェント • agentforce, dify などナレッジワーク外部に定義された エージェント ◦ ナレッジワークとしては必要データを付与してプ ロキシして呼び出す形 • ワークフローも1つのエージェントとみなす エージェント定義 message AgentSpec { oneof spec { SingleAgentSpec single = 1; // 単体 ProxyAgentSpec proxy = 2; // 外部 WorkflowAgentSpec workflow = 3; } } // 単体エージェントの定義 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; }
  10. © Knowledge Work Inc. エージェントの実行は過去手探りをしてきた • 様々な AI Agent Framework

    (agno, mastra 等) によるエージェント実行 ◦ Backend は Go だがそこにほかの言語の実装が入り、インフラがやや複雑になる悩みを抱えていた • 自前で Gemini, GPT, Claude の SDK を呼び出す ◦ Single Agent (LLM + Tool 呼出) だけであれば、作ってみたら数日で十分動くものができた ◦ → インフラを複雑にするよりもメリットが大きいため SDK 呼出をメインへ • ワークフロー実装はまあまあめんどうだと思っていたが、Go でかけるフレームワークとして adk-go が浮上 ◦ backend が go なのでインフラが複雑にならず、これで討ち取れるならうれしい ◦ 技術調査の名目で数日遊んでいたら proto 定義したワークフローがきれいに動くものがかけたので、これでいいん じゃないかということで、本番実装中 → インフラが複雑にならないように、フレームワークをプロダクトに組み込める形で書けると美しく統合できる エージェントの実行 16
  11. © Knowledge Work Inc. 17 エージェントの実行フロー(フロントから) プロダクト ツール定義 ② セッション定義

    エージェント 基盤 エージェント定義 エージェント セッション定義 ② セッション定義 ③ セッション id 返却 クライアン ト ④ クエリ ④ クエリ ⑥ エージェント基盤から のレスポンスを変形して返 却 ① エージェントを動かす 前にあらかじめ定義 ⑤ ツール呼出(必要であれば)
  12. © Knowledge Work Inc. • データ提供はすべてツール呼出 として整理する ◦ データの取得をツール呼出は分けず、すべてツール呼出として実装すればよい ◦

    LLM 実行部はサブシステムとしてプロダクトから隔離されている状態なので、関数呼出 (RPC) の形でデータを取 得できるようにしなければならない • 実行ユーザーの認証・認可 が簡単に実装できる ◦ ユーザーの権限や保持するライセンスによって取得できる情報が異なる • プロダクトやプロダクトデータのサーバーを更新するだけでツールが使える ◦ プロダクト開発者が責任を持っているのは自分のプロダクトに関連するサーバーだけであり、LLM 実行部に責任を 持っていないため、LLM 実行部に全く手を入れなくても利用できることが望ましい ◦ → ツール一覧を動的に更新したいため、ツールの一覧取得と呼出をそれぞれ実装する必要がある • 外部向けのツール提供には MCP server を提供する ◦ MCP server であればツール一覧取得とツール呼出をそれぞれ実装できるため手間が少ない ◦ 最近は Agent skills のようなものが作られているが、ツール提供者としては MCP server を提供しておけば責任は 果たせるはず(そこから利用者がさらに調理することは可能) プロダクトからのデータ・ツールの提供に対する要件 20
  13. © Knowledge Work Inc. 基本的にナレッジワーク内ではすべての RPC を protobuf 定義している •

    ナレッジワークでは frontend, backend の共通知識となる事柄は protobuf に記述するという思想である • ユーザーの認証・認可条件は共通知識であるため protobuf に記述している • ほかの様々な呼出側が知っておくべき制約も protobuf に記述している → ツールも protobuf 定義すれば、ユーザーの認証・認可やその他制約チェックが無料でついてくる仕組 • さらに、protobuf 定義していればツール一覧を自動的に生成することも容易 → protobuf でツールを定義し、LLM 実行部は各プロダクトサーバーからツール一覧を適宜ダウンロードして呼出可能なツール一 覧を構築するという実装とした ナレッジワーク内から呼び出すツールの実装 21
  14. © Knowledge Work Inc. 22 ツールの protobuf の例 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 { mcp.ToolCallContext context = 1; // proto の annotation を書いておくと tool の情報になる string query = 2 [(mcp.field) = { llm_description: { "locale": "ja-JP" "text": "ユーザーが入力した質問文。" } }]; repeated string keywords = 3 [(mcp.field) = { llm_description: { "locale": "ja-JP" "text": "質問文に関連するキーワード。複数指定可。" "キーワードが多数含まれているナレッジチャンクほど" "優先的に返される。" } }]; } message McpToolSearchKnowledgeChunksResponse { message Chunk { string knowledge_id = 1; string knowledge_title = 2; string knowledge_summary = 3; string chunk_content = 4; } repeated Chunk chunks = 1; } ナレッジ検索ツールの定義例
  15. © Knowledge Work Inc. 23 ツールの protobuf の例 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 { mcp.ToolCallContext context = 1; // proto の annotation を書いておくと tool の情報になる string query = 2 [(mcp.field) = { llm_description: { "locale": "ja-JP" "text": "ユーザーが入力した質問文。" } }]; repeated string keywords = 3 [(mcp.field) = { llm_description: { "locale": "ja-JP" "text": "質問文に関連するキーワード。複数指定可。" "キーワードが多数含まれているナレッジチャンクほど" "優先的に返される。" } }]; } 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 の定義となるようにアダプ タを作る
  16. © Knowledge Work Inc. 24 ツールの protobuf の例 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 { mcp.ToolCallContext context = 1; // proto の annotation を書いておくと tool の情報になる string query = 2 [(mcp.field) = { llm_description: { "locale": "ja-JP" "text": "ユーザーが入力した質問文。" } }]; repeated string keywords = 3 [(mcp.field) = { llm_description: { "locale": "ja-JP" "text": "質問文に関連するキーワード。複数指定可。" "キーワードが多数含まれているナレッジチャンクほど" "優先的に返される。" } }]; } message McpToolSearchKnowledgeChunksResponse { message Chunk { string knowledge_id = 1; string knowledge_title = 2; string knowledge_summary = 3; string chunk_content = 4; } repeated Chunk chunks = 1; } ナレッジ検索ツールの定義例 引数の説明も mcp.field というアノテーションをつける ことで同様に可能
  17. © Knowledge Work Inc. MCP server を構築し(まだ試験的)、MCP server はそこから次の処理を行う •

    各サーバーのツール一覧を自動的に取得し、MCP server から配布するツール一覧を更新する • MCP server に対する RPC 呼出形式は JSON-RPC なので、内部で利用する connect-rpc 形式に変換して呼び出す ◦ 注意点として MCP server が動的にツール一覧を作っているため、protobuf が生成する自動生成された go コード などを利用できない (それを組み込むには再コンパイルが必要だから) ◦ → connect-rpc は json 形式でデータを送ることができるので json を(ツール一覧を取得したときに含まれている 入力・出力スキーマを検証しながら) 構築してあげれば、動的 RPC も呼び出せる (HACK) 外部向けツールは内部向けツールと仕組みはほぼ同じだが、追加のアノテーションを必要としている • 一度外部公開すると仕様変更が非常に難しくなるため、ツールが GA 版、β版、α版なのかを設定する ◦ β版、α版のツールは開発・検証環境でのみしか利用できない • 外部は認証認可が OAuth2 ベースになるので、OAuth2 で検証するための呼び出しスコープを追加する • (実際にプロダクトサーバーに RPC 呼出を行うときに、OAuth2 のスコープに加えてユーザーのライセンスチェック、権限 チェックなどが自動的に行われる ナレッジワーク外から呼び出すツールに対する実装 25