Langchainを使用したKnowledge Graphの構築と質問応答

# はじめに
「Knowledge Graph（知識グラフ）」は、情報を関連付けて構造化するグラフベースのデータモデルです。エンティティ（例：人、物、場所、概念など）間の関係をノードとエッジで表現することができます。以前紹介したRetrieval（本記事の下に該当記事へのリンクがあります）を用いた方法と似ているのですが、Retrievalが基本的には1:Xでデータベースから回答に関連した情報を探しにいくのに対し、知識グラフでは、逆引きを含むX:Xのような情報が複雑に関連している場合や、複雑なクエリの解決に役立ちます。一方で、情報の正確性確保やスケーラビリティの問題などの課題も存在します。

今回は、Langchainを使用して、テキストから知識グラフを構築し、その知識グラフを基に質問応答を行う方法について解説します。知識グラフを使うことで、ChatGPTだけでは回答の難しい、現在の出来事や専門知識に関する質問にも対応することが可能になります。

# 1. 知識グラフの構築
まず、テキストから知識グラフを構築する方法について見ていきます。

```python
from langchain.chat_models import ChatOpenAI
from langchain.indexes import GraphIndexCreator

# ChatOpenAIモデルの設定
LLM = ChatOpenAI(
    model_name='gpt-3.5-turbo-16k',
    temperature=0
)
# GraphIndexCreatorの設定
index_creator = GraphIndexCreator(llm=LLM)
```
OpenAIのモデルを設定し、その後に`GraphIndexCreator`を初期化しています。この`GraphIndexCreator`は、テキストから知識グラフを構築するためのクラスです。`GraphIndexCreator`はLLMを引数にとります。

```python
with open('./input/XXXXXXXXX.txt', 'r', encoding='utf-8') as f:
    all_text = f.read()

text = "\n".join(all_text.split("\n\n"))
graph = index_creator.from_text(text)
graph.write_to_gml("graph/graph_xxxxx.gml")
```

ここでは、テキストファイルを読み込み、その内容を`GraphIndexCreator`をつかって知識グラフに変換しています。そしてその結果をGML形式で保存しています。`GraphIndexCreator`インスタンスはテキストを引数としてとっていますが、基本的には長いテキストではなく１文程度の短い文を想定しているようです。それでは`GraphIndexCreator`のソースコードを実際に見てみます。

https://api.python.langchain.com/en/latest/_modules/langchain/indexes/graph.html#GraphIndexCreator

```python
def from_text(
        self, text: str, prompt: BasePromptTemplate = KNOWLEDGE_TRIPLE_EXTRACTION_PROMPT
    ) -> NetworkxEntityGraph:
        """Create graph index from text."""
        if self.llm is None:
            raise ValueError("llm should not be None")
        graph = self.graph_type()
        chain = LLMChain(llm=self.llm, prompt=prompt)
        output = chain.predict(text=text)
        knowledge = parse_triples(output)
        for triple in knowledge:
            graph.add_triple(triple)
        return graph
```
グラフの初期化後、LLMに加え、独自のプロンプト`KNOWLEDGE_TRIPLE_EXTRACTION_PROMPT`をLLMChainに渡し、トリプレットに分解後、複数のトリプレットがある場合はそれを独立なインプットとして順にグラフに加えていることがわかります。次に、`KNOWLEDGE_TRIPLE_EXTRACTION_PROMPT`の中身をみてみます。

```text
template="You are a networked intelligence helping a human track knowledge triples about all relevant people, things, concepts, etc. and integrating them with your knowledge stored within your weights as well as that stored in a knowledge graph. Extract all of the knowledge triples from the text. A knowledge triple is a clause that contains a subject, a predicate, and an object. The subject is the entity being described, the predicate is the property of the subject that is being described, and the object is the value of the property.

EXAMPLE
It's a state in the US. It's also the number 1 producer of gold in the US.
Output: (Nevada, is a, state)<|>(Nevada, is in, US)<|>(Nevada, is the number 1 producer of, gold)
END OF EXAMPLE

EXAMPLE
I'm going to the store.
Output: NONE
END OF EXAMPLE

EXAMPLE
Oh huh. I know Descartes likes to drive antique scooters and play the mandolin.\n
Output: (Descartes, likes to drive, antique scooters)<|>(Descartes, plays, mandolin)\n
END OF EXAMPLE

EXAMPLE
{text}
Output:"
```
具体例を挙げながらトリプレットの作り方を説明しています。


# 2. 知識グラフを基にした質問応答
次に、構築した知識グラフをもとに質問応答を行う方法について見ていきます。

```python
from langchain.indexes.graph import NetworkxEntityGraph
from langchain.chains import GraphQAChain

# Knowledge Graphのロード
loaded_graph = NetworkxEntityGraph.from_gml("graph/graph_xxxxx.gml")
chain = GraphQAChain.from_llm(LLM, graph=loaded_graph, verbose=True)

# 質問応答
result = chain.run('○○についてくわしく教えてください')
print(result)
```

上記のコードでは、前段で保存した知識グラフをロードし、GraphQAChainを使用して、質問応答の準備をしています。


# まとめ
Langchainを使用することで、テキストから知識グラフを構築し、その知識グラフを基に質問応答を行うことができます。このライブラリを活用することで、独自の知識ベースを持つ質問応答システムを簡単に構築することができるでしょう。

最後まで読んでいただきありがとうございます。最近X(Twitter)もはじめたのでこちらもよろしくお願いします！

https://x.com/keisuke_yoshiha

# 関連記事

https://qiita.com/mashmoeiar11/items/5aa2c1f3381e5184c919

https://qiita.com/mashmoeiar11/items/214984400e3452615ea5

＊本記事はcode snippetをもとにChatGPTに作らせています。