4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Qiita×Findy記事投稿キャンペーン 「今の開発組織でトライしたこと・トライしていること・トライしようとしていること」

Neo4j5.18 + NeoDash2.4 と Langchain で、自前閉鎖的 Graph ダッシュボードを見せびらかす!

Last updated at Posted at 2024-04-12

はじめに(背景)

なぜだ?!なぜ、Neo4J+NeoDashのQiita記事がないんだ?ないんだったら、作るか。しかも今作れば、第一人者になれるわ(2024年4月現在)。そういうわけで、作ってみましょう。

読者の中には、Qiita記事を書く時間がないけど、Neo4J現役バリバリで使っている人もいるだろう。使っているひとを尊敬する。筆者はNeo4Jの存在は以前から知ってはいたが、そのデータ投入がめんどくさくて使う気になれなかったひとりだ。

しかし、neo4jのグラフデータめんどくさがりに強い味方が現れた。大規模言語モデルだ!

まずは、こちらの記事を見てほしい。

(「要約」の抜粋翻訳)

  • オープンソースのLLMを微調整することで、OpenAIへの依存から脱却することができます。
  • このブログ記事を書いている間、GPUメモリの問題により、20Bモデルを除いて複数のモデルをテストしました。モデルを微調整して、運用環境に十分な Cypher ステートメントを生成できると自信を持って言えます。

これだ!これを我々ものぐさ民は待っていたのだ!

そして、同志たちよ、これも読んでくれたまえ。ちょっと複雑な文脈を扱おうとしているようだが、codellama-13bでやろうとしている例だ。codellama-13b単体では心もとなく、プロンプトに工夫が必要だったそうだ。

だが、2024年春となったいま、langchainがプロンプトも引き受けてCypherしてくれる!

これで、我々は超長文を理解しようとするとき、Neo4Jデータベースを作る仕事はLLMに任せたうえでNeo4Jのグラフインターフェースをいじって文章を理解することができると思わないか?! 思うよね!

筆者はたまたま、LocalAI (https://localai.io/)で構築したOpenAI互換API利用環境を持っている。これを使えば、自前でしかも、Neo4jのインターフェースを閲覧専用公開してほかの人にも見せてみようと思わないか?! 思うよね!

概要

以上の背景を持つこの投稿は、つぎのような作業の記録となります。
(1)Neo4JのDBを立ち上げる
(2)Neo4JにLangchainを使ってデータを投入する
(3)NeoDashを立ち上げる
(4)NeoDashの公開設定を行う

なお、本件取り扱いは、個人的もしくは小規模人数での情報共有目的のNeoDash環境構築を目的としたものであるので、Neo4Jのフリーライセンス利用範囲であります。

また、LocalAI利用環境の構築方法については、今回は書きません。すでに環境ができているものとして記述しています。

もうひとつ、Neo4jのセキュリティ設定については今回は書きません。

目的

個人的もしくは小規模人数での情報共有目的のNeoDash環境構築を目的とします。

手順

実行環境を docker compose する

実行環境を、わざわざjupyterhubで作るという変態的初手を踏む。jupyterhub については、公式のgithubから真似して作る。

neo4j, neodash についても公式のdocker構築術をまねる。

そこで、次のようなフォルダ構成とし、 docker-compose.yml を配置するのはどうだろう。

-(project root)
    |--- docker-compose.yml
    |--- README.md
    |
    (jupyterhub)
    |    |--- config_token.py
    |    |--- Dockerfile.jupyterhub
    |    |--- jupyterhub_config.py
    |
    (neo4j)
services:
  neo4j:
    image:  neo4j:latest
    environment:
      - NEO4J_AUTH=none
      - NEO4J_PLUGINS=["genai", "graphql", "graph-algorithms", "graph-data-science","apoc", "apoc-extended", "n10s"]
    ports:
      - 7474:7474
      - 7687:7687
    networks:
      - jupyterhub-network
      - neo4j-network
    volumes: 
      - ./neo4j/data:/data
      - ./neo4j/logs:/logs
      - ./neo4j/conf:/conf
  neodash:
    depends_on:
      - neo4j
    image: neo4jlabs/neodash:latest
    ports:
      - 5005:5005
    networks:
      - neo4j-network
  hub:
    build:
      context: ./jupyterhub
      dockerfile: Dockerfile.jupyterhub
      args:
        JUPYTERHUB_VERSION: latest
    restart: always
    image: jupyterhub
    container_name: jupyterhub
    networks:
      - jupyterhub-network
    volumes:
      # The JupyterHub configuration file
      - "./jupyterhub/jupyterhub_config.py:/srv/jupyterhub/jupyterhub_config.py:ro"
      # Bind Docker socket on the host so we can connect to the daemon from
      # within the container
      - "/var/run/docker.sock:/var/run/docker.sock:rw"
      # Bind Docker volume on host for JupyterHub database and cookie secrets
      - "jupyterhub-data:/data"
      - "./example/requirements.txt:/home/jovyan/requirements.txt"
      - "./example/prototype.ipynb:/home/jovyan/prototype.ipynb"
    ports:
      - "8000:8000"
    environment:
      # This username will be a JupyterHub admin
      JUPYTERHUB_ADMIN: admin
      # All containers will join this network
      DOCKER_NETWORK_NAME: jupyterhub-network
      # JupyterHub will spawn this Notebook image for users
      DOCKER_NOTEBOOK_IMAGE: quay.io/jupyter/base-notebook:latest
      # Notebook directory inside user image
      DOCKER_NOTEBOOK_DIR: /home/jovyan/work

volumes:
  jupyterhub-data:

networks:
  jupyterhub-network:
    name: jupyterhub-network
  neo4j-network:
    name: neo4j-network

neo4j にモリモリでプラグインをぶっこんだが、ライセンスがあわないものは動かない。

jupyterhub について公式のとおりだが、docker.sockがちゃんとアクセスできているのかわからない。今回はそこは突っ込まないで進める。

docker compose up

dockerが、neo4j と neodash と jupterhub を起動する。

jupyter hub にログイン

頃合いをみて、 ブラウザで localhost:8000 にアクセスして、jupyterhub のサインアップを行おう。

image.png

jupyterhub 公式にも説明のあったとおり、あらかじめ登録されているユーザーはない。だが、"admin"というユーザーを作るとそれはadminユーザーになるとのこと。

画面左下の sign up のリンクを押して、サインアップ画面でユーザー名「admin」、パスワードは好みで設定する。

sign up ができたら、続けて、jovyanユーザーを作っておくとよいかもしれない。jovyanユーザーは、公式が設定例ユーザーに用意しているユーザーで、コンテナの中のOS上に存在しているユーザーでもある。

image.png

ユーザーを作ったらlogin リンクを押してログインに戻ろう。

作った「admin」ユーザーでログインしてみて、さっそくfileメニューを選んでみる。hub control panel でユーザー管理できたりする。
image.png

admin ユーザーではログアウトして、jovyanユーザーでログインしなおして以下、操作してみた。

langchain をインストール

jovyanユーザーでログインした筆者は、早速、requirements.txtファイルと、neo4j_examleディレクトリを作成した。今回作成したdocker-compose では、作成したファイルを、永続ボリュームに保存する。作成したファイル類はdockerを再起動しても残るようになっている。

Launchar の Other メニューから TextFileを選んで作成開始。

image.png

requirements.txt
langchain
langchain-community
langchain-openai
langchain-experimental
neo4j
wikipedia
tiktoken
yfiles_jupyter_graphs
numpy
pandas

ファイルを作成、保存できたら、 Launcher で Terminal を起動。次のコマンドを実行。

mkdir neo4j_example
pip install -U -r requirements.txt

インストールの成功を見届けたら、Terminalを閉じる。

neo4j にデータを投入する

neo4j_exampleディレクトリに、ノートブックを一つ作り、そこにneo4j にデータを投入するスクリプトを書いてみよう。ノートブック名は、テキトーに pototype.ipynb とした。

記述内容は、こちらの先達のものを参考に。


from langchain_core.runnables import (
    RunnableBranch,
    RunnableLambda,
    RunnableParallel,
    RunnablePassthrough,
)
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.prompts.prompt import PromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field
from typing import Tuple, List, Optional
from langchain_core.messages import AIMessage, HumanMessage
from langchain_core.output_parsers import StrOutputParser
import os
from langchain_community.graphs import Neo4jGraph
from langchain.document_loaders import WikipediaLoader
from langchain.text_splitter import TokenTextSplitter
from langchain_openai import ChatOpenAI
from langchain_experimental.graph_transformers import LLMGraphTransformer
from neo4j import GraphDatabase
from yfiles_jupyter_graphs import GraphWidget
from langchain_community.vectorstores import Neo4jVector
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores.neo4j_vector import remove_lucene_chars
from langchain_core.runnables import ConfigurableField, RunnableParallel, RunnablePassthrough

try:
  import google.colab
  from google.colab import output
  output.enable_custom_widget_manager()
except:
  pass

langchain 関連のモジュールの読み込みがうまくできたら、次は、「投入データのもとになる長文」のデータ化だ。
langchain の WikipediaLoaderで、エリザベス一世の検索結果(https://en.wikipedia.org/wiki/Elizabeth_I)を取得する。英語版 Wikipedia を参照しているはずだ。

# Read the wikipedia article
raw_documents = WikipediaLoader(query="Elizabeth I").load()
# Define chunking strategy
text_splitter = TokenTextSplitter(chunk_size=512, chunk_overlap=24)
documents = text_splitter.split_documents(raw_documents[:3])

ここ、1分強時間かかるけど、Wikipediaのあの長文を自動でデータ化してくれるんだから、考えたらコスパヨシ。

次は、LLMのセットアップ。

ここは人によると思う。筆者はLocalAIがあるのでllm_server_urlにそのURLを指定するし、自前のLLMモデル名を指定する。LocalAIでなく、OpenAI API を使う人は、OpenAI環境情報をあてはめたらよい。

llm_server_url = "http://localhost:8080"
model_name="gpt-3.5-turbo"

llm=ChatOpenAI(temperature=0.01, model_name=model_name, openai_api_base=llm_server_url, openai_api_key="sk-xkkkkkkkkkkkkkkkkkkkkkkkkkk") 

次に、先のWikipedia長文データをグラフデータに!これだ!これだよ!

llm_transformer = LLMGraphTransformer(llm=llm)
graph_documents = llm_transformer.convert_to_graph_documents(documents)

これは、2分ほどかかる。エラーなく終了するのが待ち遠しい!

環境変数設定して、「Neo4jGraph」クラスインスタンスを生成。

docker で起動してある Neo4j のユーザー名は neo4j だが、パスワードは設定していない。だが、この環境変数設定場面で何らかの文字列を持たせていないと、インスタンスの生成がエラーになる。適当な文字列を書いておく。

os.environ["NEO4J_URI"] = "bolt://neo4j:7687"
os.environ["NEO4J_USERNAME"] = "neo4j"
os.environ["NEO4J_PASSWORD"] = "everything"

graph = Neo4jGraph()

ここまでエラーなく動作した時点で、ワクワクする! わくわくしながら、次の項目へ。
Neo4J サーバーへデータ投入だ!

graph.add_graph_documents(
    graph_documents,
    baseEntityLabel=True,
    include_source=True
)

これもエラーなく終わったら、NeoDashでみよう!ひゃっほー!

NeoDash にアクセスする。

ブラウザで http://localhost:5005 にアクセスする。

image.png

New Dashboard をクリックして、Create New Dashboad を Yes だ!

image.png

なにも設定してないので、そのまま「 Connect 」

image.png

image.png

真ん中の記号みたいのを押す・・・

image.png

右上の3点を押す・・・

image.png

Typeを選んで、キャレットの点滅している欄に、Cypherでクエリを書くと、それがビジュアライズされる!すげぇ!

サンプルとして、エリザベス一世の人間関係を調べてみたいな、と、いうわけで、TypeにGraphを選び、次のクエリを書いて、右上の丸に右向き三角なアイコンを押す!

MATCH (n:Person) RETURN n LIMIT 25

なんか、つぶつぶ出た! 小っちゃくて見えねぇ・・・
image.png

真ん中付近で、マウススクロールさせると拡大縮小されるので、なんとかElizabethIを見つけて右クリック。
image.png

Expandで、なんかいっちゃん大きい数字の __Entity_Person を押すと・・・
image.png

キャー!もう、ナニコレ、かわいい(爆)
しかし小っちゃくてみにくいわー(笑)

とりあえず、ダッシュボード名とレポート名を書く
image.png

保存するまえに一工夫。次に開くときEditモードじゃなくて読み取りモードにしておきましょう。右上のギヤマークアイコンを押して、表示されるモーダルのメニューで Editable をオフ。

image.png

画面左、サイドメニューを開き、(Draft)になっている現在のダッシュボード名に名前をつけて、その横の3点リーダをクリック。Saveメニューを選んで、保存しませう。

image.png

書き込み権限があるかー?とか聞かれるけど、今回はある。

image.png

書き込み成功時モーダル
image.png

左サイドメニューが (Draft)でなくなり色も変わって、3点リーダのメニュー項目も変わっている。

image.png

Neo4j Dashboard を publish !

さて、このメニュー項目から「Share」を選ぶと、ダイアログが表示される。
今回作成したダッシュボードは、自前のDocker上にあるので、「Self-hosted」を選ぶ。ほかの人にはエディットされない状態でShareしたいので、「Hide Editor UI」を選ぶ。

そうすると、下にリンクが表示されるので、これをシェアすればよい!
image.png

・・・と、言っても、シェアリンクとしてはDockerで作った localhost アドレスになっているから、このままじゃほかのPCからは見えない。

ちなみにこのリンクを開くとNeoDashからNeo4j dashboardを開くよ~、みたいなメッセージが表示される。

image.png

その次には、Neo4j へのログイン情報確認ダイアログが表示される。実際に使うときは、ちゃんとユーザー名とか設定して、セキュリティも確保しないとな。

image.png

シェアできた・・・けど

今回は、セキュリティ関連の設定を一切おこなわず、Docker で NeoDash の共有機能を表示した。信頼できる顔見知りには見せてもいいけど、一般公開ってわけにはいかないですな。そのあたりは、また別のきかいに・・・

Langchainは、Graphデータを用いた探索型QA(RetrievalQA)システム構築もできるらしい。

Neo4jとLangchainで、だまだアレコレいじってみるのも面白そう。

終わりに(結論)

すごいや、Graphデータベース Neo4j と そのダッシュボード作成ツール NeoDash。
そして Neo4j へのデータ投入を容易にしてくれた Langchain もすげえ。

すげぇって感想で終わるって・・・結局自己満足だったってことやな。
みせびらかすってそんなもんや。(爆)

4
1
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
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?