GenAIスタックを使用した開発者向けの独自のAI駆動型コード分析チャットボットの構築

GenAIの話題は今や至る所で取り上げられていますが、これほどの関心が寄せられているにもかかわらず、多くの開発者は現実世界のユースケースが何であるかを理解しようとしています。 昨年、Dockerは AI/MLハッカソンを主催し、本当に興味深いプロジェクトが提出されました。 

この AI/ML ハッカソンの投稿では、プロジェクトのアイデアをひらめかせることを期待して、受賞した提出物である Code Explorer について詳しく説明します。 

Ai/mlハッカソン

開発者にとって、コードベースの理解と操作は絶え間ない課題です。 ChatGPT のような一般的な AI アシスタント ツールでさえ、コード アクセスを通じてプロジェクトのコンテキストを理解できず、複雑なロジックや独自のプロジェクト要件に苦労する可能性があります。 大規模言語モデル (LLM) は開発中の貴重なパートナーですが、コードベースの特定のニュアンスを常に把握しているとは限りません。 そこで、より深い理解と追加のリソースが必要になります。

猫と犬の両方のデータセットをクエリするプロジェクトに取り組んでいるとします。 ページネーション (データを分割してフェッチする手法) を使用して犬のデータを取得する関数型コード DogQuery.py が既にあります。 次に、cat データに対して同じ機能を実現するように更新 CatQuery.py します。 AI アシスタントに既存のコード DogQuery.py を参照し、変更プロセスをガイドしてもらうことができたら素晴らしいと思いませんか? 

そこで登場するのが、AI搭載のチャットボットである Code Explorerです。 

Code Explorer の独自性

AI/MLハッカソンに提出された次のデモは、コードエクスプローラーの概要を示しています(図 1)。

図 1: AI/ML ハッカソンに提出された Code Explorer 拡張機能のデモ。

コード エクスプローラーでは、プログラミング言語とフォルダーの場所に基づいて関連情報を検索することで、コードに関する回答を見つけることができます。 チャットボットとは異なり、コードエクスプローラーは一般的なコーディング知識を超えています。 検索拡張生成 (RAG) と呼ばれる強力な AI 手法を活用して、コードの特定のコンテキストを理解します。 これにより、実際のプロジェクトに基づいて、より適切で正確な回答を提供できます。

コードエクスプローラーは、*.swift、*.py、*.java、*.csなど、さまざまなプログラミング言語をサポートしています。 このツールは、Xcode プロジェクト、Android プロジェクト、AI アプリケーション、Web 開発などのコード プロジェクトの学習やデバッグに役立ちます。

CodeExplorer には、次のような利点があります。

  • 簡単な学習: コードベースをより簡単に探索して理解できます。
  • 効率的なデバッグ: コード自体から分析情報を得ることで、問題のトラブルシューティングを迅速化します。
  • 生産性の向上: コードの解読に費やす時間を減らし、優れたものの構築により多くの時間を費やすことができます。
  • さまざまな言語をサポート:Python、Java、Swift、C#などの一般的な言語で動作します。

ユースケースには、次のようなものがあります。

  • 複雑なロジックを理解する: "関数が calculate_pricebilling.py関数とget_discountどのように相互作用するかを説明します。
  • デバッグエラー:「関数 getUserDatauser.py 空のリストを返すのはなぜですか?」
  • 既存のコードから学ぶ: 「ページsearch_results.pyネーションを実装するにはどうすればよいsearch.pyですか?」

それはどのように機能しますか?

コードエクスプローラーは、RAG ベースの AI フレームワークの機能を活用し、コードに関するコンテキストを既存の LLM モデルに提供します。 図 2 は、舞台裏の魔法を示しています。

代替テキスト:コードエクスプローラーの主なステップ 3 詳細なフロー図(ステップ 1:ドキュメントの処理、LLMチェーンの作成 2 ステップ、ステップ 3:ユーザーが質問し、AIチャットボットが応答します—使用されるDockerサービスとともに。
図 2: コード エクスプローラーの手順の図。

ステップ 1. ドキュメントの処理

ユーザーは、Streamlit アプリを使用してコードベース フォルダーを選択します。 ファイルdb.py内の関数がprocess_documents呼び出されます。この関数は、次のアクションを実行します。

  1. 解析コード: 選択したフォルダー内のコード ファイルを読み取って解析します。 これには、言語固有のパーサー(Pythonのastモジュールなど)を使用して、コードの構造と構文を理解することが含まれます。
  2. 情報の抽出: コードから次のような関連情報を抽出します。
    • 変数名とその型
    • 関数名、パラメーター、および戻り値の型
    • クラスの定義とプロパティ
    • コードコメントとdocstring
  3. ドキュメントが読み込まれ、チャンク化されます。 言語に基づいてオブジェクトを作成します RecursiveCharacterTextSplitter 。 このオブジェクトは、コンテキストを改善するために、各ドキュメントを指定されたサイズ (5000 文字) の小さなチャンクに分割し、一部が重複 (500 文字) します。
  4. Neo4jベクターストアの作成: これは、ベクトルを使用してコード要素を格納および接続するデータベースの一種である Neo4j ベクター ストアを作成します。 これらのベクトルは、コードのさまざまな部分間の関係と類似性を表します。
    • 各コード要素(関数、変数など)は、Neo4jグラフデータベースのノードとして表されます。
    • 要素間の関係(関数呼び出し、変数代入など)は、ノードを接続するエッジとして表されます。

ステップ 2. LLM チェーンの作成

このステップは、コードベースが処理された後にのみトリガーされます (ステップ 1)。

次の 2 つの LLM チェーンが作成されます。

  • ドキュメント QnA チェーンの作成: このチェーンにより、ユーザーは質問と回答のスタイルでチャットボットと話すことができます。 コーディングの質問に答えるときは、ソースコードファイルを参照して、ベクトルデータベースを参照します。
  • エージェントチェーンの作成: QnA チェーンをツールとして使用する別のエージェント チェーンが作成されます。 これは、チャットボットとよりカジュアルに通信できるようにする QnA チェーン上の追加レイヤーと考えることができます。 内部的には、チャットボットは QnA チェーンにコーディングの質問 (AI がユーザーの質問について別の AI と話し合ってから最終的な回答を返す) についてサポートが必要かどうかを尋ねる場合があります。 テストでは、エージェントは技術的な応答を与えるのではなく、要約するように見えますが、QAエージェントのみではありません。

Langchainは、チャットボットのパイプライン/フローを調整するために使用されます。

ステップ 3. ユーザーが質問すると、AIチャットボットが回答します

Streamlitアプリは、ユーザーがコードについて質問するためのチャットインターフェイスを提供します。 ユーザーはStreamlitアプリのチャットインターフェースと対話し、ユーザー入力は保存され、LLMまたはQA/エージェントモデルへのクエリに使用されます。 次の要因に基づいて、アプリはユーザーに応答する方法を選択します。

  • 処理されたコードベース:
    • はい: ユーザーがサイドバーで 詳細モード を選択した場合、QA RAGチェーンが使用されます。 このモードでは、処理されたコードベースを利用して詳細な回答が得られます。
    • はい: ユーザーが エージェント・モード を選択した場合は、カスタム・エージェント・ロジック (関数を使用 get_agent ) が使用されます。このモードでは、QA RAGモデルと比較して、より簡潔な回答が得られる可能性があります。
  • 処理されていないコードベース:
    • LLMチェーンは、ユーザーがまだコードベースを処理していない場合に直接使用されます。

はじめ

コード エクスプローラーの使用を開始するには、次の点を確認してください。

次に、以下で説明する 4 つの手順を実行します。

1. リポジトリをクローンする

ターミナル ウィンドウを開き、次のコマンドを実行してサンプル アプリケーションを複製します。

https://github.com/dockersamples/CodeExplorer

これで、ディレクトリに CodeExplorer 次のファイルが作成されます。

tree
.
├── LICENSE
├── README.md
├── agent.py
├── bot.Dockerfile
├── bot.py
├── chains.py
├── db.py
├── docker-compose.yml
├── images
│   ├── app.png
│   └── diagram.png
├── pull_model.Dockerfile
├── requirements.txt
└── utils.py

2 directories, 13 files

2. 環境変数の作成

GenAI スタックサービスを実行する前に、 .env 必要に応じて、次の変数を変更します。 このファイルには、アプリケーションの動作に影響を与える環境変数が格納されます。

OPENAI_API_KEY=sk-XXXXX
LLM=codellama:7b-instruct
OLLAMA_BASE_URL=http://host.docker.internal:11434
NEO4J_URI=neo4j://database:7687
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=XXXX
EMBEDDING_MODEL=ollama
LANGCHAIN_ENDPOINT="https://api.smith.langchain.com"
LANGCHAIN_TRACING_V2=true # false
LANGCHAIN_PROJECT=default
LANGCHAIN_API_KEY=ls__cbaXXXXXXXX06dd

手記:

  • を使用する場合はEMBEDDING_MODEL=sentence_transformer、 と chains.pyのコードのコメントを解除しますrequirements.txt。コードサイズを小さくするためにコメントアウトしました。
  • OLLAMA_BASE_URL=http://llm:11434 .env必ず Ollama Dockerコンテナを使用する場合のファイル。 Macで実行している場合は、 OLLAMA_BASE_URL=http://host.docker.internal:11434 その代わりに。

3. Docker GenAI サービスの構築と実行

次のコマンドを実行して、Docker Compose サービスをビルドして起動します。

docker compose --profile linux up --build

これにより、次の出力が得られます。

+] Running 5/5
 ✔ Network codeexplorer_net             Created                                              0.0s
 ✔ Container codeexplorer-database-1    Created                                              0.1s
 ✔ Container codeexplorer-llm-1         Created                                              0.1s
 ✔ Container codeexplorer-pull-model-1  Created                                              0.1s
 ✔ Container codeexplorer-bot-1         Created                                              0.1s
Attaching to bot-1, database-1, llm-1, pull-model-1
llm-1         | Couldn't find '/root/.ollama/id_ed25519'. Generating new private key.
llm-1         | Your new public key is:
llm-1         |
llm-1         | ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGEM2BIxSSje6NFssxK7J1+X+46n+cWTQufEQjMUzLGC
llm-1         |
llm-1         | 2024/05/23 15:05:47 routes.go:1008: INFO server config env="map[OLLAMA_DEBUG:false OLLAMA_LLM_LIBRARY: OLLAMA_MAX_LOADED_MODELS:1 OLLAMA_MAX_QUEUE:512 OLLAMA_MAX_VRAM:0 OLLAMA_NOPRUNE:false OLLAMA_NUM_PARALLEL:1 OLLAMA_ORIGINS:[http://localhost https://localhost http://localhost:* https://localhost:* http://127.0.0.1 https://127.0.0.1 http://127.0.0.1:* https://127.0.0.1:* http://0.0.0.0 https://0.0.0.0 http://0.0.0.0:* https://0.0.0.0:*] OLLAMA_RUNNERS_DIR: OLLAMA_TMPDIR:]"
llm-1         | time=2024-05-23T15:05:47.265Z level=INFO source=images.go:704 msg="total blobs: 0"
llm-1         | time=2024-05-23T15:05:47.265Z level=INFO source=images.go:711 msg="total unused blobs removed: 0"
llm-1         | time=2024-05-23T15:05:47.265Z level=INFO source=routes.go:1054 msg="Listening on [::]:11434 (version 0.1.38)"
llm-1         | time=2024-05-23T15:05:47.266Z level=INFO source=payload.go:30 msg="extracting embedded files" dir=/tmp/ollama2106292006/runners
pull-model-1  | pulling ollama model codellama:7b-instruct using http://host.docker.internal:11434
database-1    | Installing Plugin 'apoc' from /var/lib/neo4j/labs/apoc-*-core.jar to /var/lib/neo4j/plugins/apoc.jar
database-1    | Applying default values for plugin apoc to neo4j.conf
pulling manifest
pull-model-1  | pulling 3a43f93b78ec... 100% ▕████████████████▏ 3.8 GB
pulling manifest
pulling manifest
pull-model-1  | pulling 3a43f93b78ec... 100% ▕████████████████▏ 3.8 GB
pull-model-1  | pulling 8c17c2ebb0ea... 100% ▕████████████████▏ 7.0 KB
pull-model-1  | pulling 590d74a5569b... 100% ▕████████████████▏ 4.8 KB
pull-model-1  | pulling 2e0493f67d0c... 100% ▕████████████████▏   59 B
pull-model-1  | pulling 7f6a57943a88... 100% ▕████████████████▏  120 B
pull-model-1  | pulling 316526ac7323... 100% ▕████████████████▏  529 B
pull-model-1  | verifying sha256 digest
pull-model-1  | writing manifest
pull-model-1  | removing any unused layers
pull-model-1  | success
llm-1         | time=2024-05-23T15:05:52.802Z level=INFO source=payload.go:44 msg="Dynamic LLM libraries [cpu cuda_v11]"
llm-1         | time=2024-05-23T15:05:52.806Z level=INFO source=types.go:71 msg="inference compute" id=0 library=cpu compute="" driver=0.0 name="" total="7.7 GiB" available="2.5 GiB"
pull-model-1 exited with code 0
database-1    | 2024-05-23 15:05:53.411+0000 INFO  Starting...
database-1    | 2024-05-23 15:05:53.933+0000 INFO  This instance is ServerId{ddce4389} (ddce4389-d9fd-4d98-9116-affa229ad5c5)
database-1    | 2024-05-23 15:05:54.431+0000 INFO  ======== Neo4j 5.11.0 ========
database-1    | 2024-05-23 15:05:58.048+0000 INFO  Bolt enabled on 0.0.0.0:7687.
database-1    | [main] INFO org.eclipse.jetty.server.Server - jetty-10.0.15; built: 2023-04-11T17:25:14.480Z; git: 68017dbd00236bb7e187330d7585a059610f661d; jvm 17.0.8.1+1
database-1    | [main] INFO org.eclipse.jetty.server.handler.ContextHandler - Started o.e.j.s.h.MovedContextHandler@7c007713{/,null,AVAILABLE}
database-1    | [main] INFO org.eclipse.jetty.server.session.DefaultSessionIdManager - Session workerName=node0
database-1    | [main] INFO org.eclipse.jetty.server.handler.ContextHandler - Started o.e.j.s.ServletContextHandler@5bd5ace9{/db,null,AVAILABLE}
database-1    | [main] INFO org.eclipse.jetty.webapp.StandardDescriptorProcessor - NO JSP Support for /browser, did not find org.eclipse.jetty.jsp.JettyJspServlet
database-1    | [main] INFO org.eclipse.jetty.server.handler.ContextHandler - Started o.e.j.w.WebAppContext@38f183e9{/browser,jar:file:/var/lib/neo4j/lib/neo4j-browser-5.11.0.jar!/browser,AVAILABLE}
database-1    | [main] INFO org.eclipse.jetty.server.handler.ContextHandler - Started o.e.j.s.ServletContextHandler@769580de{/,null,AVAILABLE}
database-1    | [main] INFO org.eclipse.jetty.server.AbstractConnector - Started http@6bd87866{HTTP/1.1, (http/1.1)}{0.0.0.0:7474}
database-1    | [main] INFO org.eclipse.jetty.server.Server - Started Server@60171a27{STARTING}[10.0.15,sto=0] @5997ms
database-1    | 2024-05-23 15:05:58.619+0000 INFO  Remote interface available at http://localhost:7474/
database-1    | 2024-05-23 15:05:58.621+0000 INFO  id: F2936F8E5116E0229C97F43AD52142685F388BE889D34E000D35E074D612BE37
database-1    | 2024-05-23 15:05:58.621+0000 INFO  name: system
database-1    | 2024-05-23 15:05:58.621+0000 INFO  creationDate: 2024-05-23T12:47:52.888Z
database-1    | 2024-05-23 15:05:58.622+0000 INFO  Started.

ログは、アプリケーションが LLM、Neo4j データベース、メイン アプリケーション コンテナーなど、すべてのコンポーネントを正常に起動したことを示しています。 これで、ユーザー インターフェイスを介してアプリケーションを操作できるようになります。

サービスは、Docker Desktop ダッシュボードから表示できます(図 3)。

コードエクスプローラーの実行を示す docker desktop のスクリーンショット。
図 3: GenAI スタックを搭載した実行中のコードエクスプローラーを示す Docker Desktop ダッシュボード。

コード エクスプローラー スタックは、次のサービスで構成されています。

ボット

  • ボット サービスはコア アプリケーションです。 
  • Streamlitで構築され、Webブラウザを介してユーザーインターフェイスを提供します。このセクションでは build 、 という名前の bot.Dockerfile Dockerfile を使用して、Streamlit アプリケーション コードを含むカスタム イメージを構築します。 
  • このサービスは、Web ブラウザーからボット UI にアクセスできるようにするポート 8501を公開します。

プル モデル

  • このサービスでは 、codellama:7b-instruct モデルがダウンロードされます。 
  • このモデルは、OpenAI の LLM と同様のパフォーマンスを実現する Llama2 モデルに基づいていますが、追加のコード コンテキストでトレーニングされます。 
  • ただし、 codellama:7b-instruct コード関連のコンテキストでさらにトレーニングされ、人間の言語を理解して応答するように微調整されます。 
  • この専門性により、コードに関する質問の処理に特に長けています。

手記: サービスが pull-model-1 で終了する code 0と、実行が成功したことを示します。 このサービスは、LLMモデル()codellama:7b-instructをダウンロードするためだけに設計されています。ダウンロードが完了すると、このサービスを実行したままにする必要はなくなります。 で code 0 終了すると、サービスがタスクを正常に完了したことを示します (モデルのダウンロード)。

データベース

  • 本サービスは、 Neo4jグラフのデータベースを管理します。
  • LLMモデルによる分析に適した数学的形式でコードファイルを表すベクトル埋め込みを効率的に保存および取得します。
  • Neo4j ベクトルデータベースは、http://localhost:7474 で調べることができます (図 4)。
neo4j データベース情報を示すコードエクスプローラーデータベースサービスのスクリーンショット。
図 4: Neo4j データベース情報。

ティッカー

  • このサービスは、 Ollama フレームワークを利用して LLM ホストとして機能します。 
  • ダウンロードしたLLMモデル(埋め込みではない)を管理し、ボットアプリケーションからアクセスできるようにします。

4. アプリケーションにアクセスする

これで、ブラウザで http://localhost:8501 にアクセスして Streamlit アプリを表示できます(図 5)。

左側のサイドバーに「プロセスファイル」オプションを表示するコードエクスプローラーのスクリーンショット。
図 5: アプリを表示します。

サイドバーで、コードフォルダーへのパスを入力し、[ ファイルの処理 ] を選択します (図 6)。 その後、メインチャットでコードに関する質問を開始できます。

左側のサイドバーに実行中のプロセスを指す赤い矢印が表示されているコードエクスプローラーのスクリーンショット。
図 6: アプリが実行中です。

サイドバーにトグルスイッチがあります。 デフォルトでは 、詳細モード が有効になっています。 このモードでは、QA RAGチェーンチェーンが使用されます(detailedMode=true)。 このモードでは、処理されたコードベースを利用して詳細な回答が得られます。 

スイッチを別のモード()detailedMode=falseに切り替えると、エージェントチェーンが選択されます。 これは、あるAIが別のAIと議論して最終的な答えを作るのと似ています。 テストでは、エージェントはQAエージェントのみとは対照的に、技術的な応答ではなく要約しているように見えます。

(図7)の場合detailedMode=trueの結果を次に示します。

「llmsingleactionagent()関数の目的は何ですか? " detailmode=true の場合。
図 7: 結果は、 detailedMode=true.

図 8 は、次の場合 detailedMode=falseの結果を示しています。

「llmsingleactionagent()関数の目的は何ですか? detailmode=false の場合 "
図 8: 結果は、 detailedMode=false.

探索を開始する

GenAIスタックを搭載したコードエクスプローラーは、コーディングに関するAIの支援を求める開発者に魅力的なソリューションを提供します。このチャットボットは、RAGを活用してコードベースを掘り下げ、特定の質問に対する洞察に満ちた回答を提供します。 Dockerコンテナはスムーズな運用を保証し、Langchainはワークフローを調整します。 Neo4jは、効率的な分析のためにコード表現を格納します。 

Code Explorer と GenAI スタックを探索して、開発ジャーニーにおける AI の可能性を解き放ちましょう。

さらに詳しく