技術

LLMアプリケーションのための知識グラフの設計・実装ガイド

関係性のモデリングによる高度な対話システム構築の実践的なアプローチ

2025-04-01
21分
LLM
知識グラフ
AI技術
関係性モデリング
構造化知識
Next.js
ChatGPT
吉崎 亮介

吉崎 亮介

株式会社和談 代表取締役社長 / 株式会社キカガク創業者

LLMアプリケーションのための知識グラフの設計・実装ガイド

数値だけでは表現できない「理解」の探求

AI システム開発において、相手を「理解する」とはどういうことだろうか。これは私が投資面談システムを開発する中で向き合った根本的な問いだった。

教育分野から知識グラフへの道のり

私は元々教育技術の研究に携わっていた。教育の文脈では、学習者の理解度を数値で測るだけでなく、概念間のつながりや知識の構造化が重要だと考えられている。例えば「微分」という概念を理解するには、「関数」「極限」「導関数」などの関連概念とのつながりを把握する必要がある。

教育分野では、こうした概念間の関係性を可視化するために知識マップコンセプトマップが使われてきた。私はこれらのツールが学習者の理解を深めるのに非常に効果的だと感じていた。単に「微分の理解度 80 点」といった数値評価ではなく、関連概念とのつながりを構造化して捉えることで、学習者の真の理解を促進できると実感していたのだ。

対話システムへの応用と気づき

この経験が、投資面談システム開発に直接つながった。投資家として起業家と面談するとき、私は常に違和感を覚えていた。「技術力は 5 点中 3 点」「市場分析は 4 点」といった数値評価を並べても、相手を本当に理解したことにならないのではないか。

実際に私が作り始めた投資面談システムも、当初は 特性潜在推定値 θ\theta の推定に主眼を置いていた。しかし、このアプローチでは会話が極めて機械的になってしまう。例えば、こんな対話になるのだ。

システム: 「あなたの技術力について教えてください」
起業家: 「教育技術のバックグラウンドがあり、特に学習分析と適応学習システムを専門としています」
システム: 「あなたの市場規模について教えてください」

これは対話ではなく事情聴取だと気づいた瞬間があった。相手の話を聞いて、それに関連する質問をするのではなく、単に次々と自分の知りたい項目を聞いているだけ。これでは相手も気持ちよく話せないだろうし、本当の強みや特徴を引き出せない。

私が実現したかったのは、「教育技術に強みがあるのですね。学習分析のデータをどのように活用されているのですか?」といった、相手の発言内容に基づいた自然な質問の流れだった。

AI が面接を担当するからといって無機質で良いとは思わない

相手が AI とはいえども、質問してばかりで自分のことを本当に知ろうとしているかわからないものを相手にはしたくないはずだ。面接で答える相手の UX も当然考えるべきである。気持ちよく回答してもらえる方が、より良い回答を引き出せるはずである。だからこそ、相手の能力を推定しながら、相手の大事にしている言葉や領域、単語などの知識を一緒に吸収し、その情報に基づいて相手への共感を示しながら、次の最適な対話的な質問を考えていく。

先述した極端な質問は相手との対話ではない。単に聞きたいことを聞くだけの事情聴取である。私は AI に仕事を任せるとしてもそういった対話をちゃんと設計し、人よりもむしろ気持ちの良い対話を AI にでもできるようにしたい。

知識グラフという解決策

そこで私が注目したのが知識グラフだった。これは概念(ノード)とその関係性(エッジ)をグラフ構造で表現する手法であり、教育分野で使われてきた知識マップの発展形とも言える。

知識グラフを使えば、「学習分析」「教育市場」「データ活用」といった概念とそれらの関係性を構造化できる。そして、この構造化された情報に基づいて、より自然で共感的な質問を生成できるのではないかと考えた。

私が実現したかったのは、単なる数値評価ではなく、相手の言葉の背後にある概念間の関係性を捉える「真の理解」だった。そして、その理解に基づいた自然な対話を実現することだった。

知識グラフの基本と私の取り組み

グラフ理論から実装へ

知識グラフを実装するにあたって、まずはグラフ理論の基礎を学び直した。グラフとは、ノード(頂点)とエッジ(辺)の集合として定義される数学的構造である。

図表を生成中...

形式的には、グラフ GGG=(V,E)G = (V, E) と表される。VV はノードの集合、EE はエッジの集合だ。これをプログラムで表現するために、以下のようなインターフェースを設計した。

interface Node {
  id: string;
  label: string;
  type: string; // 'Person', 'Technology', 'Market' など
  importance: number; // 重要度(0-1)
  sigma: number; // 不確実性
  description?: string; // 説明(オプション)
}
 
interface Edge {
  id: string;
  source: string; // 始点ノードのID
  target: string; // 終点ノードのID
  label: string; // 関係性の種類
  weight: number; // 関係の強さ(0-1)
  sigma: number; // 不確実性
}

重要なのは、ノードとエッジの両方に「重要度」と「不確実性」のパラメータを持たせたことだ。これは私の投資面談システムの基礎となる特性潜在推定値 θ\theta の推定アプローチと整合性を持たせるためだった。

中心性の概念と応用

グラフ理論において特に興味深いと感じたのが中心性(Centrality)の概念だった。これはグラフ内でのノードの「重要度」を測る指標であり、様々な計算方法がある。

私が特に注目したのはよく社会ネットワーク分析などで使われる次の標準的な 4 つだった。

  1. 次数中心性(Degree Centrality): 単純にノードに接続するエッジの数を数える方法。多くの概念と関連しているノードは重要と見なされる。
  2. 近接中心性(Closeness Centrality): あるノードから他のすべてのノードへの距離の逆数の合計。情報の伝播速度に関連する。
  3. 媒介中心性(Betweenness Centrality): 他のノード間の最短経路上にそのノードが現れる回数。情報の流れを制御する能力を示す。
  4. 固有ベクトル中心性(Eigenvector Centrality): 重要なノードとつながっているノードは、それ自体も重要という考え方。Google の PageRank アルゴリズムの基礎となっている。

実験を繰り返した結果、固有ベクトル中心性が最も私の目的に合っていた。なぜなら、この指標は単に多くの概念とつながっているだけでなく、重要な概念とつながっている概念を高く評価するからだ。例えば、起業家が話す中で「データ分析」という概念が他の重要な概念と多くつながっていれば、それはその起業家の強みや関心の中心にある可能性が高い。

なぜ RAG ではなく知識グラフに注目したのか

定番の RAG を検討

私は当初、LLM とよく一緒に使用される RAG (Retrieval Augmented Generation) アプローチも検討した。RAG は大量のテキストをチャンクに分割してベクトル化し、類似度検索によって関連情報を取得する手法だ。

しかし、試行錯誤の前の段階から、RAG には投資面談システムにとって致命的な限界があることに気づいていた。

  1. 情報量の制約: RAG は前提としてある程度のデータ量が必要だ。しかし投資面談の初期段階では、相手のことをほとんど知らない。PDF の企業説明資料があったとしても、それだけでは不十分で、対話を通じて情報を得ていく必要がある。
  2. 文脈の断片化: テキストをチャンクに分割すると、文書全体の構造や概念間の関係性が失われてしまう。これでは「理解」とは言えない。
  3. 表面的な類似性のみに基づく検索: RAG は単語レベルの類似性を基に検索するため、意味的・構造的な関連性を捉えきれない。

RAG 系のライブラリやインフラはかなり整っているのでこれを利用できると楽ではあったのだが、やはり本質的なアプローチではないと考え、ひとまずは別のアプローチを考えた。ただ今回取り組んでいないため、今後は RAG も検討する可能性も残している。

なぜ知識グラフが適していたのか

一方で知識グラフは、概念と関係性を明示的に表現するため、少ない情報からでも全体像を構築していくのに適していた。投資面談では、相手の話から徐々に重要な概念とその関係性を抽出し、それに基づいて質問を重ねていく。このプロセスを知識グラフは自然にモデル化できたのだ。

私にとって決定的だったのは、「理解」とは単に情報を持っていることではなく、情報間の関係性を把握していることだという気づきだった。知識グラフはまさにこの関係性を明示的に表現できる。

θ\theta推定と知識グラフの組み合わせ

投資面談システムでは、起業家の各能力を評価するための特性潜在推定値 θ\theta を推定している。この値は正規分布N(μ,σ2)N(\mu, \sigma^2)で表現され、平均μ\muが推定値、標準偏差σ\sigmaが不確実性を表す。

図表を生成中...

私が実現したかったのは、θ\theta推定と知識グラフの両方の良さを活かしたハイブリッドアプローチだった。θ\theta推定だけでは「この起業家の技術力は 5 段階中 3.5」といった無機質な情報しか得られない。一方、知識グラフと組み合わせることで「教育工学に強みがあり、特にデータ分析と個別最適化学習の接点に革新性がある」といった具体的かつ構造化された理解が可能になる。

この組み合わせにより、数値評価の客観性と概念的理解の豊かさの両方を実現できると考えた。

知識グラフの設計と実装:試行錯誤の記録

エンティティと関係性の抽出:プロンプト設計の試行錯誤

知識グラフを構築する最初の課題は、テキストからエンティティと関係性を抽出することだった。私は LLM を活用してこれを行うことにしたが、ここでプロンプト設計の難しさに直面した。

最初に試したのは非常にシンプルなプロンプトだった。

以下のテキストから重要な概念と関係性を抽出してください。
テキスト:[テキスト]

しかし、この方法では出力のばらつきが大きすぎた。抽出される概念の粒度が一貫せず、あるときは「AI 技術」という大きな概念が抽出され、あるときは「ニューラルネットワーク」「深層学習」「自然言語処理」といった細かい概念が抽出される。これでは知識グラフ全体の一貫性が保てない。

特に苦労したのは、概念の粒度をどう揃えるかという点だった。単語単位で切るべきか、熟語で切るべきか、それとも文章の意味的なまとまりで切るべきか。試行錯誤の末、私は以下のようなより詳細なプロンプトに落ち着いた。

以下のテキストから重要な概念(エンティティ)とそれらの関係性を抽出し、JSON形式で出力してください。

【テキスト】
${text}

【抽出のポイント】
1. 重要な概念を識別し、その種類(Technology, Market, Person など)を特定
2. 概念間の関係性を特定(例:「開発している」「応用している」「依存している」)
3. 各概念の重要度と不確実性、関係性の強さと不確実性を0.1〜1.0の範囲で評価
4. 概念は基本的に2-3語の名詞句で表現し、過度に細かいか広すぎる概念は避ける

【出力形式】
{
  "concepts": [
    {
      "concept": "概念名",
      "type": "概念の種類",
      "importance": 0.1-1.0の重要度,
      "sigma": 0.1-1.0の不確実性
    },
    ...
  ],
  "relationships": [
    {
      "source": "始点の概念名",
      "target": "終点の概念名",
      "relation": "関係性の種類",
      "strength": 0.1-1.0の関係の強さ,
      "sigma": 0.1-1.0の不確実性
    },
    ...
  ]
}

このプロンプトでの重要なポイントは以下の通りだ。

  1. 概念の粒度を明示的に指定:「2-3 語の名詞句」という指定を入れた
  2. 概念の種類を分類:Technology などの分類を求めることで構造化を促進
  3. 重要度と不確実性の両方を評価θ\theta推定との整合性を持たせた
  4. 出力形式を明確に指定:JSON の厳密な形式を示して解析しやすくした

それでも出力にはかなりのばらつきがあった。同じテキストに対しても、実行するたびに異なる概念セットが抽出されることがあった。特に「importance」と「sigma」の値は実行ごとに大きく変わることもあった。

JSON パースの苦労と車輪の再発明

LLM の出力を JSON として解析する際も苦労した。当初は基本的なJSON.parse()を使っていたが、LLM が必ずしも完全に有効な JSON を出力するとは限らないことがわかった。そこで次のようなエラーハンドリングを実装した。

try {
  const knowledge = JSON.parse(response);
  return validateAndNormalizeKnowledge(knowledge);
} catch (error) {
  console.error("JSON parsing error:", error);
 
  // 失敗した場合、前後の余分な文字列を削除して再試行
  const extractedJson = extractJsonFromText(response);
  try {
    const knowledge = JSON.parse(extractedJson);
    return validateAndNormalizeKnowledge(knowledge);
  } catch (error) {
    console.error("Second JSON parsing error:", error);
    throw new Error("Failed to parse LLM response");
  }
}

このようなパース処理を実装した後、LangChain のwithStructuredOutput機能を知り、これがまさに私が再発明していた車輪だと気づいた。

import { ChatOpenAI } from "langchain/chat_models/openai";
import { z } from "zod";
 
// Zodスキーマ定義
const extractedKnowledgeSchema = z.object({
  concepts: z.array(
    z.object({
      concept: z.string(),
      type: z.string(),
      importance: z.number().min(0.1).max(1.0),
      sigma: z.number().min(0.1).max(1.0),
    })
  ),
  relationships: z.array(
    z.object({
      source: z.string(),
      target: z.string(),
      relation: z.string(),
      strength: z.number().min(0.1).max(1.0),
      sigma: z.number().min(0.1).max(1.0),
    })
  ),
});
 
// LLMモデルの初期化と構造化出力の設定
const model = new ChatOpenAI({
  modelName: "gpt-4",
  temperature: 0.1,
}).withStructuredOutput(extractedKnowledgeSchema);

この方法では、Zod スキーマを使って出力形式を指定し、LLM の出力を直接型安全なオブジェクトに変換できる。まさに私が苦労して作っていた機能だった。車輪の再発明は時間の無駄だと痛感した瞬間だった。

ただし、このwithStructuredOutputは LangChain の知識グラフ機能とは別物だ。LangChain には比較的新しい機能として知識グラフのためのモジュールも追加されたが、私の当初の実装時点では調査不足で気づいていなかった。そのため、JSON 出力の構造化部分だけ LangChain の機能を使い、知識グラフの構築と活用は自前で実装することにした。

知識グラフの更新と一貫性の維持

知識グラフを作る上で特に苦労したのは、グラフの更新と一貫性の維持だった。新たな情報が得られるたびに、既存の知識グラフを更新する必要がある。その際の主な課題は以下の点だ。

  1. 同一概念の識別: 「AI」と「人工知能」など、同じ概念が異なる表現で現れる場合にどう対処するか。
  2. 信頼度を考慮した更新: 新情報と既存情報の信頼度(不確実性の逆数)に基づいた重み付け更新をどう行うか。
  3. グラフの一貫性維持: 更新後もグラフ全体の関係性が矛盾なく保たれているかをどう確認するか。

特に同一概念の識別では、単純な文字列マッチングでは不十分だった。「機械学習」と「ML」のような略語や、「教育システム」と「学習システム」のような類似概念をどう扱うかが難しかった。そして、まだここに関しては試行錯誤の段階であるが、意味的なマッチングなども採用する可能性がある。ただ、なるべく意味を抽出しているはずのプロンプトの段階に内包したい。LangChain などではここをどう扱っているかもこれから調べて試行錯誤をしたいところである。

中心性計算と質問生成への活用

知識グラフを構築した後、私が最も興味を持ったのは中心性の計算とその活用だった。特に、固有ベクトル中心性(Eigenvector Centrality)が起業家の強みや関心の中心を特定するのに役立つと考えた。

当初は実装の簡単さから Python の NetworkX ライブラリを検討したが、技術スタックの統一性を考慮して最終的には TypeScript での実装に決めた。TypeScript で中心性を算出できるライブラリとして Graphology を採用した。ただ、今思うと LangChain の知識グラフモジュールと相性の良い Neo4j を次以降は採用すると思う。ただ、Graphology 自体に不満はなく、中心性の算出程度であれば非常に簡単であった。

この中心性を活用して重要な知識に焦点を当てることにより、「技術力はどうですか?」といった無機質な質問ではなく、「教育システムでのデータ分析技術をどのように個別最適化に活かしているのですか?」といった相手の強みに焦点を当てた自然な質問をある程度生成できるようになった。

実践から得た教訓

プロンプト設計と出力のばらつき対策

この開発を通じて学んだ最も重要な教訓の 1 つは、LLM のプロンプト設計の重要性だ。特に知識グラフのようなデータ構造を生成する場合、出力のばらつきが大きな問題となる。

私が効果的だと感じた対策は以下の通りだ。

  1. 詳細な指示と例示: 単に「概念を抽出して」と言うよりも、概念の粒度や種類を明確に指定し、例を示すことで一貫性を高めた。
  2. 温度パラメータの最適化temperature: 0.1のような低い値を設定して、出力の安定性と再現性を高めた。
  3. 構造化出力の指定: JSON や Zod スキーマを使って出力形式を厳密に指定した。
  4. 後処理の実装: それでも残るばらつきに対応するため、出力の正規化や検証の後処理を実装した。

上記のように色々とベストプラクティスを調べて試行錯誤したが、まだまだ課題は多かった。素人がパッと思いつきのプロンプトを作るよりも、LangChain などでカスタマイズされたプロンプトを作る方が遥かに質も高いし、短い時間で目的にたどり着けたはずと後悔している。もちろん、それぞれ細かく調整することで学びにはなった。

対話の質と相手の UX を重視する視点

私がこの開発で最も大切にしたのは、対話の質と相手の UX(ユーザー体験)だ。システムの技術的な完成度も重要だが、最終的に相手が気持ちよく対話できるかどうかが成功の鍵だと考えた。

そのために以下の点を心がけた。

  1. 文脈を考慮した質問: 単に情報を引き出すだけでなく、相手の発言内容を踏まえた質問を生成する。
  2. 強みや関心への焦点: 相手の強みや関心事に焦点を当てることで、前向きな対話を促進する。
  3. 自然な対話の流れ: 質問項目を機械的に列挙するのではなく、自然な会話の流れになるよう工夫する。
  4. 共感的な応答: 単に情報を記録するだけでなく、相手の発言に対して共感的な応答を示す。

これらの工夫により、システムは単なる「評価ツール」ではなく、「対話のパートナー」として機能するようになった。

車輪の再発明を避ける教訓

開発過程で痛感したのは、車輪の再発明を避けることの重要性だ。JSON パースや検証のような基本的な機能を自前で実装していたが、LangChain のwithStructuredOutputのような既存ツールを使えば簡単に解決できた。

この経験から、以下の教訓を得た。

  1. 実装前の調査の徹底: 何か実装する前に、既存のライブラリやツールが同様の機能を提供していないか徹底的に調査する。
  2. 最新動向のフォロー: AI 分野は進化が速いため、定期的に最新のライブラリやツールをチェックする。
  3. モジュール性の確保: 自前実装が必要な場合でも、後で既存ツールに置き換えやすいようモジュール性を高める。
  4. コアビジネスロジックへの集中: 車輪の再発明に時間を使うよりも、プロジェクト固有の価値を生むコアロジックに集中する。

これらの教訓は今後のプロジェクトでも心がけていきたい。

今後の展望と次のステップ

RAG と知識グラフの融合

開発を通じて私が特に興味を持ったのは、RAG と知識グラフの融合の可能性だ。RAG は大量の情報からの検索に優れ、知識グラフは関係性の表現に優れている。この両者を組み合わせることで、より高度な「理解」が実現できるのではないかと考えている。

具体的には、RAG による情報検索結果を知識グラフに統合し、その構造化された知識に基づいて質問生成や回答を行うハイブリッドアプローチを検討している。

時間的次元の導入

現在の知識グラフは静的だが、今後は時間的次元を導入したいと考えている。例えば、「以前は教育市場に注力していたが、最近はヘルスケア市場にも展開している」といった時間的変化を捉えることができれば、より深い理解が可能になる。

これには、知識グラフの各ノードとエッジに時間情報を付加し、時系列での変化を追跡する機能が必要だ。

LangChain の知識グラフ機能の活用

これは実装をある程度終えてから知ったのだが、最近の LangChain は知識グラフ関連の機能を充実させている。自前実装の多くの部分を LangChain のモジュールで置き換えることで、より堅牢で機能豊かなシステムに進化させられると考えている。プロンプトのチューニングなど実際に作り込んでみると初期のカスタマイズは減らしたいところが多くあったので、次回以降はこのようなライブラリを使ってみたい。特に、LangChain の Neo4j 連携機能を活用すれば、より高度なグラフクエリや中心性計算が可能になるだろう。

最後に

この投資面談システムの開発を通じて、私は「理解」の本質について深く考えさせられた。単なる数値評価や表面的な類似度ではなく、概念間の関係性を捉えることこそが真の理解だと実感した。

知識グラフはその「理解」を実現するための強力なツールだが、完璧ではない。プロンプト設計の難しさや出力のばらつきなど、多くの課題も残されている。しかし、それでも私はこのアプローチが人と AI の対話の質を大きく向上させる可能性を秘めていると確信している。

今後も、より自然で共感的な対話を実現するための探求を続けていきたい。そして、単なる事情聴取ではなく、真の対話を実現するシステムを作り上げていきたいと思う。

吉崎 亮介

吉崎 亮介

株式会社和談 代表取締役社長 / 株式会社キカガク創業者

「知の循環を拓き、自律的な価値創造を駆動する」をミッションに、組織コミュニケーションの構造的変革に取り組んでいます。AI技術と社会ネットワーク分析を活用し、組織内の暗黙知を解放して深い対話を生み出すことで、創造的価値が持続的に生まれる組織の実現を目指しています。

最新のインサイトを受け取る

定期的なニュースレターで、技術とビジネスの境界領域に関する最新の記事や独自のインサイトをお届けします。