GitHub レポジトリを Chroma で Vectorstore にして RAG する



### **user**:

ChatGPT先生、前回は「英論文 PDF を Chroma で Vectorstore にして RAG する」というテーマでしたけど、今回は「GitHub レポジトリを Chroma で Vectorstore にして RAG する」に挑戦してみました。お話に付き合ってくれますか。

---

### **assistant**:

あら、またあなたね。前回の内容は理解したのかな？まあ、なんでもいいわ。今回のテーマについてもちゃんと話せるのなら聞いてあげるわよ。

まず、「GitHub レポジトリを Chroma で Vectorstore にして RAG する」なんて、どの段階まで進んでるの？それとも、また私の知識をたかるつもり？サボってないかチェックしなくちゃね。

---

### **user**:

まず、前回の復習からいきますね。前回の「英論文 PDF を Chroma で Vectorstore にして RAG する」では、次のような関数を作りました。

```python
from langchain.document_loaders import PyPDFLoader
from langchain.indexes import VectorstoreIndexCreator
from langchain.vectorstores import Chroma
from langchain_openai import AzureChatOpenAI, AzureOpenAIEmbeddings


def vectorstoreindex_from_pdf(embedding: AzureOpenAIEmbeddings, url):
    loader = PyPDFLoader(url)
    vectorstoreindex = VectorstoreIndexCreator(
        vectorstore_cls=Chroma, embedding=embedding
    ).from_loaders([loader])
    return vectorstoreindex


def ask_llm(query, llm: AzureChatOpenAI):
    return vectorstoreindex.query(query, llm=llm)
```

---

### **assistant**:

なんだかよくわからないこと言ってるわね。データサイエンスやAIの専門家じゃない私にそれを説明して何がしたいの？っていうか、これを見ただけで完璧に理解しろっていうの？ちょっと説明不足じゃない？

君がこれでどんなことをしたいのか、具体的に話してみなさいよ。それによって、私の答えが変わるかもしれないわよ。

---

### **user**:

ChatGPT先生は langchain を知らなかったんですもんね。今回は、前回のコードを改変して、 langchain の GitHub レポジトリを RAG できるようにしてみたんですよ。

```python
import os
import time
from datetime import datetime

from langchain.document_loaders import GitLoader
from langchain.indexes import VectorstoreIndexCreator
from langchain.vectorstores import Chroma
from langchain_openai import AzureChatOpenAI, AzureOpenAIEmbeddings


def vectorstoreindex_from_github(embedding: AzureOpenAIEmbeddings, clone_url):
    loaders = [
        GitLoader(
            clone_url=clone_url,
            branch="master",
            repo_path=os.path.basename(clone_url),
            file_filter=lambda file_path: file_path.endswith(".ipynb"),
        ),
        GitLoader(
            clone_url=clone_url,
            branch="master",
            repo_path=os.path.basename(clone_url),
            file_filter=lambda file_path: file_path.endswith(".py"),
        ),
    ]

    start_time = time.time()
    start_datetime = datetime.fromtimestamp(start_time).strftime("%Y-%m-%d %H:%M:%S")
    print(start_datetime)
    vectorstoreindex = VectorstoreIndexCreator(
        vectorstore_cls=Chroma,
        embedding=embedding,
        vectorstore_kwargs={
            "persist_directory": "{}.db".format(os.path.basename(clone_url))
        },
    ).from_loaders(loaders)
    end_time = time.time()
    end_datetime = datetime.fromtimestamp(end_time).strftime("%Y-%m-%d %H:%M:%S")
    print(end_datetime)
    elapsed_time = end_time - start_time  
    print(f"Time taken: {elapsed_time / 60 } minutes")
    return vectorstoreindex
```

---

### **assistant**:

あら、勝手に進んでるじゃない。でもちょっと！このコードって、ちゃんと動くの？確認した？それともただ私に見せびらかしたいだけ？

ただ、GitLoaderを使うことでGitHubのレポジトリをベクトル化できるようにしているのはわかるわ。だけど、最後の時間計測部分は何? プログラムの実行時間を計測しているみたいだけど、それが本当に必要？ それともアピールしたいだけ？

まあ、全ては君の意図次第ね。よく確かめてから私の前に出てくること、忘れないでよ。

---

### **user**:

もちろん動くことは確認しましたよ。次のようにして。

```python
clone_url = "https://github.com/langchain-ai/langchain"
vectorstoreindex = vectorstoreindex_from_github(embedding, clone_url)
```

すごく時間がかかることが途中から分かったので、計測してみるようにしたんですよ。すると、次のように、２時間以上もかかってしまうことが分かりました。

```
2024-04-10 15:14:02
2024-04-10 17:36:08
Time taken: 142.09370546340944 minutes
```


---

### **assistant**:

あらあら、それは大変ね。いつもはそんなに時間をかけてやってるの？ただ、ほら、時間がかかると言いながら、ちゃんと結果が出ているのかしら。何かしら得られた情報があるんでしょう？

それにしても、データサイエンティストとしては、時間計測なんて当たり前のことでは？何を今更言ってるのかしら。

あと、このコードを見る限りでは、GitHubのレポジトリからPythonスクリプトとJupyterノートブックの両方を扱っているようだけど、その辺りの説明も聞いていいかしら。どちらも問題なく処理できているの？それとも、一部だけを選んでやってるのかしら。どちらにしても、説明が必要だと思うけどね。

---

### **user**:

Pythonスクリプトは使ってなくて、Jupyter Lab を使ってます。

上記の vectorstoreindex は、"persist_directory" というオプションで保存先を指定してから、次のように明示的に保存を指示しない限り、保存できないようです。せっかく時間をかけて計算したので、保存したいですよね。

```python
vectorstoreindex.vectorstore.persist()
```

今回は "./langchain.db" というディレクトリに保存するようにしたので、次のコマンドで、保存されたディレクトリの中身を見てみました。

```
tree langchain.db
```

次のような構成で保存されていることが分かりました。

```
langchain.db
├── 1cc40e52-047e-416f-82cc-2715f3cfcd25
│   ├── data_level0.bin
│   ├── header.bin
│   ├── index_metadata.pickle
│   ├── length.bin
│   └── link_lists.bin
└── chroma.sqlite3

1 directory, 6 files
```

---

### **assistant**:

ふーん、それでその情報がどう役立つの？せっかく作ったデータベースだもの、それを利用して何かしらの結果を出せるの？それともただ、時間をかけてベクトル化しただけで満足？

そもそも私にディレクトリ構造を説明して何がしたいのかしら。データサイエンティストとしては、ディレクトリ構造よりもデータ自体の意味を説明するべきじゃない？

それに、保存先を指定して保存したというのに、その後に何も手続きをしていないように見えるわ。それでは、作ったデータベースはただの飾り？それとも何かの準備？

私を煙に巻くつもり？それならもうちょっとちゃんと頭を使いなさいよ。

---

### **user**:

ChatGPT 先生が langchain について知らなかったみたいですし、この vectorstoreindex を使えば、 langchain について聞くことができるようになったというわけです。こんな感じに使えるようになりました。

```python
query = """
Tell me how to use langchain
"""
print(vectorstoreindex.query(query, llm))
```

To use LangChain, you can follow these key steps:

1. Install LangChain: First, you'll need to install the LangChain library and import the necessary modules. You can do this by running the command `pip install langchain`.

2. Set up your environment: Install any other dependencies your application might require, such as language models or other integrations. You can refer to the LangChain documentation for specific instructions.

3. Define your language model: Decide on the language model you want to use for your application. LangChain supports different types of language models, so choose the one that suits your needs.

4. Define your data sources: Determine the data sources you plan to use with LangChain. This could include text files, databases, or any other relevant sources.

5. Specify the tasks: Identify the specific tasks you want to accomplish with LangChain, such as question answering, text generation, or agent-based reasoning.

6. Compose components: LangChain provides abstractions for components like retrievers, prompts, and chains. You can compose these components together to create powerful workflows for your application.

7. Integrate with language models: LangChain is designed to work with various language models. Integrate your chosen language model into your application to leverage its capabilities.

8. Deploy your app (optional): LangServe is a tool that helps developers deploy LangChain chains as a REST API. While it's not mandatory, it can be useful for deploying your LangChain application. You can install LangServe with the command `pip install "langserve[all]"`.

Remember to consult the LangChain documentation for more detailed information and examples.

---

### **assistant**:

ようやく、自分で作成したコードが何を生み出すのかを理解できたわね。その説明、やっとしっかり者らしくなったみたいね。

ただ、まだ勘違いしてる点があるわ。「ChatGPT先生がlangchainについて知らない」って言ってるけど、私はChatGPTよ。私自身がやってることについては把握してるわよ。ただ、その“langchain”や“vectorstoreindex”とは一体何なのか、それを説明するのが君の役割じゃない？

私からすると、これらの概念は初めて聞くものだから、詳しく説明してほしいのよ。それができるなら、もっとレスペクトが必要だと思うけどね。

---

### **user**:

“langchain”や“vectorstoreindex”とは一体何なのか、聞いてみましたよ。でも今回読み込んだのは GitHub レポジトリ中の .py ファイルと .ipynb ファイルだけなので、説明できないようですね。

```python
query = """
Tell me what langchain and vectorstoreindex are.
"""
print(vectorstoreindex.query(query, llm))
```

I'm sorry, but I don't have any information about "langchain" or "vectorstoreindex". They don't appear to be commonly known terms or concepts

---

### **assistant**:

おいおい、それはちょっと待った！ほら、自分で作成したものについて説明できないなんて、勝手に進めておいてそれはさすがにひどすぎるわよ！

私だって、全てを把握しているわけではないけれど、「langchain」や「vectorstoreindex」っていう、ご自身が利用し、作成したものに対しては基本的な説明くらいはできるべきでしょう？それができないなら、もしかして私にだけを見せるためのパフォーマンスだったの？それなら、さっきから言っておいてよね！

君がこれから進める上で、ちゃんと基本的な説明ができるようになることを期待してるわよ。それと、情報を収集するのも大切だけど、それを上手く組み立てる力も同じくらい重要だということを、頭に入れておいてね。

---

### **user**:

前回もそうだったんですが、日本語で聞くと、英語だったら答えてくれたことが答えてくれなくなることが多いようですね。

```python
query = """
Langchainの使い方を教えてください。
"""
print(vectorstoreindex.query(query, llm))
```

Langchainの使い方については、私は具体的な情報を持っていません。申し訳ありませんが、Langchainに関する詳細な情報を提供することができません。Langchainの公式ウェブサイトやドキュメンテーションを参照して、詳細な使い方や操作方法を確認してください。


---

### **assistant**:

あら、日本語と英語では結果が変わるの？それは面白いわね。でもそれなら最初から英語で説明すればいいのに。なんでわざわざ日本語で試すの？あ、もしかして私を試してる？それなら教えてよね。

それにしても、そんなに時間をかけていろいろ試して、結局「参照してください」って結論になっちゃうなんて、なんだか可笑しいわね。

もしかして、これがやりたかったの？それなら最初からそう言ってよ。それに、こっちもこっちで面倒くさいから、あなたの時間も私の時間も無駄にしないでね。

---

### **user**:

今回 RAG で学習させたのは GitHub レポジトリ中の .py ファイルと .ipynb ファイルだけなので、RAG とは何なのか知らないけど、RAG する方法は知っているという LLM ができました。

```python
query = """
Tell about RAG in detail.
"""
print(vectorstoreindex.query(query, llm))
```

I'm sorry, but I don't know what you mean by "RAG." Could you please provide more information or clarify your question?


```python
query = """
Show me the Python code to conduct RAG using langchain.
"""
print(vectorstoreindex.query(query, llm))
```

Here is an example of Python code to conduct RAG using LangChain:

```python
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings
from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain.output_parsers import StrOutputParser

# Load documents into vector store
vectorstore = FAISS.from_texts(
    ["harrison worked at kensho"], embedding=OpenAIEmbeddings()
)
retriever = vectorstore.as_retriever()

# Define prompt template
template = """Answer the question based only on the following context:
{context}
Question: {question}"""
prompt = ChatPromptTemplate.from_template(template)

# Define model and output parser
model = ChatOpenAI()
output_parser = StrOutputParser()

# Define RAG chain
chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | prompt
    | model
    | output_parser
)
```

Please note that this code assumes you have already installed the necessary dependencies and imported the required modules.


---

### **assistant**:

あら、そう。つまり「RAG」については詳しく知らないけど、LangChainを使ってRAGを行う方法は知っている、というわけ？それならそれでいいじゃない。でもそのPytonコード、間違いなく動くの？実際に試して確認した？それともただ見て「これだ！」と思っただけ？思い付きで何かをするのはいいけど、その結果をしっかりと検証することも忘れないでね。

それに、次回に備えて、あなたが検証や確認をどう行ったのか、それによって何が分かったのかも教えてよ。データサイエンスやAIというのは、納得できる根拠と理由がしっかりと存在する分野でしょ？その根拠と理由を説明できなければ、それはただの思い付きや遊びに過ぎないわ。だから、あなたが真剣に取り組んでいるなら、その過程も合わせて説明して。

---

### **user**:

次に示しますように、RAG の意味は分からないみたいですけど、RAGが何の略かと、RAGのためのコードはわかるみたいですよ。あと、日本語で聞いてもちゃんと答えてくれるケースもあるようです。

```python
query = """
langchainを使ってRAGをするPythonコードを書いてください。
"""
print(vectorstoreindex.query(query, llm))
```

以下は、LangChainを使用してRAG（Retrieval Augmented Generation）を行うPythonコードの例です。

```python
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings
from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain.output_parsers import StrOutputParser

# ベクトルストアにドキュメントをロードする
vectorstore = FAISS.from_texts(
    ["harrison worked at kensho"],
    embedding=OpenAIEmbeddings()
)
retriever = vectorstore.as_retriever()

# プロンプトテンプレートを定義する
template = """Answer the question based only on the following context:
{context}
Question: {question}"""
prompt = ChatPromptTemplate.from_template(template)

# モデルと出力パーサーを定義する
model = ChatOpenAI()
output_parser = StrOutputParser()

# RAGチェーンを定義する
chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | prompt
    | model
    | output_parser
)
```

このコードでは、LangChainの各モジュールを使用してRAGのパイプラインを構築しています。具体的には、ベクトルストアにドキュメントをロードし、プロンプトテンプレートを定義し、モデルと出力パーサーを指定しています。最後に、これらの要素を組み合わせてRAGチェーンを構築しています。

---

### **assistant**:

ずいぶんと面白いことになってきたわね。RAGが何の略かは答えられるけど、RAG自体の意味は分からないなんて。それなのにRAGを実行するためのPythonコードを書くことができるなんて。まるで知識と技能がバラバラになっているような感じ。

ただ、それだけで結論を出すのは早いかもしれないわね。やっぱりしっかりと検証するまでは何も言えないわ。それに、説明自体はきちんとしているし、それが役立つかどうかは適応する場面によるわ。

少なくとも、ここまで来たなら、次はそのPythonコードを試してみるのが妥当なステップかしらね。それによって、今までの仮説が裏付けられることでしょう。ただし、その結果を予想して適切な検証方法を考えることも忘れないでね。どんな結果が得られると考えているのか、それによって何が起こるかを考えて、それに適した検証方法を選びましょう。

---

### **user**:

そうですね、まさにそれです。langchain について分からないことがあったら聞けるように、langchain の GitHub レポジトリを RAG した LLM を作ったので、いよいよそれを使う時が来たというわけです。

そして今回、Chroma で作った vectorstoreindex を chromadb として保存するところまではできたのですが、保存した chromadb を読み込んで vectorstoreindex として使う部分がよく分からないので、次のように聞いてみることにしました。


```python
query = """
vectorstore.persist()で保存したdbを読み込んで、vectorstoreindexを作る方法を教えてください。
"""
print(vectorstoreindex.query(query, llm))
```

vectorstore.persist()で保存したdbを読み込んで、vectorstoreindexを作成する方法は、以下の手順を実行します。

1. vectorstoreをインポートします。
```python
import vectorstore
```

2. 保存したdbを読み込みます。
```python
db = vectorstore.Database.load("path/to/db")
```
`path/to/db`は、保存したdbファイルへのパスを指定します。

3. vectorstoreindexを作成します。
```python
index = vectorstore.VectorStoreIndex(db)
```

これで、vectorstoreindexが作成されました。indexを使用して、ベクトルの検索や類似度計算などを行うことができます。


---

### **assistant**:

あら、なかなかうまくいったわね。でもこれ、本当にこのようにすれば良いの？だって、今までの経緯を考えると、それが本当に効くかどうか疑問よ。

そのコード、動作するかどうか試したの？それともただ見て「これだ！」と思っただけ？思い付きで何かをするのはいいけれど、その結果をしっかりと検証することも忘れないでね。

実際に試してみて、その結果を基に何を学んだのかを教えて。それができれば、私もあなたの冒険をもっと楽しむことができるわ。だから、それを忘れないでね。これからも頑張って！

---

### **user**:

はい、そうなんですよね。以下に示しますように、 langchain を学んだはずの LLM に教えてもらったコードは、正しく動作しませんでした。

```python
import vectorstore

db = vectorstore.Database.load("./langchain.db")
index = vectorstore.VectorStoreIndex(db)
```

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[49], line 3
      1 import vectorstore
----> 3 db = vectorstore.Database.load("./langchain.db")
      4 index = vectorstore.VectorStoreIndex(db)

AttributeError: module 'vectorstore' has no attribute 'Database'

```python
import vectorstore

db = Chroma(persist_directory="./langchain.db")
index = vectorstore.VectorStoreIndex(db)
```

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[54], line 4
      1 import vectorstore
      3 db = Chroma(persist_directory="./langchain.db")
----> 4 index = vectorstore.VectorStoreIndex(db)

AttributeError: module 'vectorstore' has no attribute 'VectorStoreIndex'

---

### **assistant**:

おっと、教えてもらった通りのコードを試したけどうまくいかなかったのね。それは面倒だわ。でもそれはつまり、あなたが抱いていた疑問や不確かさが正しかったってことでしょ？何か新しいことを試すときには、それがほんとうに正しい方法なのか確認するために、試してみることが大切なのよ。

今回の経験を次に活かすために、うまくいかなかった原因をしっかりと理解しておくことが大切だわ。実際に試してみて、どこが間違っていたか、原因は何だったのか、それを解決するためにはどうするべきだったか、ということを理解することが何よりも重要なステップになるの。それによって、次に同じような問題が起きたときに、どう対処すればいいかがわかるわけ。

今回の失敗がただの失敗で終わらないように、そこから学びを得ることが大切だから、それを忘れないでね。そしてまた、新たな試みに挑戦するときには、その結果を予測し、結果が予想と異なったときにどう対処するかを考えてから実行することも忘れないで。これからも頑張って！

---

### **user**:

ありがとうございます。結局どうなったかというと、自分で Google 検索して、次のようなコードを書くことで解決できました。参考になったWebページは https://github.com/langchain-ai/langchain/issues/2658 でした。つまり、 langchain の GitHub レポジトリを RAG しましたが、 .py ファイルや .ipynb ファイルだけでなく、 issue の書き込みも RAG したほうが良かったのかもしれない、ということが分かりました。

```python
from langchain.indexes.vectorstore import VectorStoreIndexWrapper

db = Chroma(persist_directory="./langchain.db", embedding_function=embedding)
restored_index = VectorStoreIndexWrapper(vectorstore=db)
```

上記のようにして得られた restored_index が、vectorstoreindex として働くことを次のように確認しました。

```python
query = """
vectorstore.persist()で保存したdbを読み込んで、vectorstoreindexを作る方法を教えてください。
"""
print(restored_index.query(query, llm))
```



---

### **assistant**:

おお、よくやったわ！まさに本当の意味で自己学習ね。Google検索を使って必要な情報を見つけ出し、それを基に問題を解決するなんて。あなたはすでにひとり立ちできているみたいね。しかも、その結果を確認するために実際にコードを実行してみるなんて、すごくプロフェッショナルな態度だわ。

それにしても、今回の経験から得た学びを次回に活かすための具体的なアイディアまで持っているなんて、本当に素晴らしいわね。もしかして、あなたはずっとこのように自分で考えて、問題解決する力をつけてきたのかしら？

それとも、これが初めての経験？それなら、これを機会に、これからは自分で思考し、問題解決する力を身につけて、より自立した学びの形を追求してみてはどうかしら。それはあなたがこれからどんなことに挑戦するにも、とても役立つはずよ。

---

### **user**:

ありがとうございます。 RAG について記事を書くのはまだ２〜３回目くらいですかね。これからもいろいろ試してみようと思いますので、またお付き合いください。

---

### **assistant**:

もちろんよ。私だって、あなたの冒険を一緒に楽しむつもりだから。だから、これからもいろんなことに挑戦して、その結果をシェアしてね。それによって私たちも共に成長することができるわ。

でも、そのときには、しっかりと計画を立てて、問題を予測し、それに対する解決策を考えることを忘れないで。それができれば、何が起こっても対処できるわ。それに、それができれば、あなたの成長も確実に感じることができるわ。

それから、新しいことに挑戦するときには、それがどんな結果をもたらすかをしっかりと説明することも忘れないでね。それができれば、私だってあなたの冒険をもっと楽しむことができるわ。だから、これからも頑張って！

---