LLMをいまだにわかってないので簡易例で試した

## はじめに

LLM（大規模言語モデル）という言葉をよく聞くけれど、実際どう動くのかよくわからない。
そこで、まずは社内ドキュメントを活用した簡易的なQAシステムを、**ダミーLLMで**動かす例を使って理解を深めました。


## 全体の構成概要

```
[ユーザー質問] → ベクトル化 → [FAISSインデックス] → 類似文書を検索 → contextとして連結 → LLMに渡す
```

| ステップ     | 処理内容                                          |
| -------- | --------------------------------------------- |
| ベクトルDB読込 | `db = FAISS.load_local(...)` で保存済みインデックスを読み込む |
| 質問から検索   | `similarity_search(question)` で類似文書を取得        |
| 文書連結     | `"\n".join(...)` で文書を一括テキスト化                  |
| 回答生成     | `chain.run(...)` でLLMから回答を得る（今回はダミー）          |



## 1. ファイルを自然言語で解釈できるようにする（ベクトル化）

### ベクトルストアの読み込みと類似検索

以下のコードは、ユーザーの質問をもとに社内文書の中から類似文を取り出し、それをひとつの文章として連結します。

```python
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
db = FAISS.load_local("rag_app/faiss_index", embeddings, allow_dangerous_deserialization=True)

docs = db.similarity_search(question)
context = "\n".join([doc.page_content for doc in docs])
```

ここで得られる `context` が、質問への回答の土台となる情報になります。



## 2. 取得した情報をLLMで処理（今回はダミー応答）

`DummyLLM` を使用し、どんな質問に対しても固定文を返すようにしています。

```python
class DummyLLM(LLM):
    def _call(self, prompt, stop=None):
        return "（ダミー応答）これは社内資料の内容に基づく自動回答です。"
```

この `llm` を以下のように `LLMChain` に渡しています：

```python
llm = DummyLLM()
chain = LLMChain(llm=llm, prompt=prompt)
```

そして、実際の `get_answer()` の中では以下のように呼ばれます：

```python
def get_answer(question):
    docs = db.similarity_search(question)
    context = "\n".join([doc.page_content for doc in docs])
    answer = chain.run({"context": context, "question": question})
    return answer
```


## 3. Pythonにおけるクラスとインスタンス生成

```python
llm = DummyLLM()
```

この形式は Python における**標準的なインスタンス生成**方法です。Javaなどと違い、`new` キーワードは使いません。



## 4. 今回省いているステップ

今回は事前にベクトル化されたデータを `rag_app/faiss_index` から読み込んでいます。
つまり、**ファイルを読み込み→分割→ベクトル化→保存**のステップは省略されています。

---

## 5. 今後の発展（実運用への置き換え）

### OpenAI API を使う場合：

```python
from langchain.llms import OpenAI
llm = OpenAI(model_name="gpt-3.5-turbo", temperature=0)
```

`.env` ファイルに `OPENAI_API_KEY` を設定する必要があります。

### ローカルLLMを使う場合：

たとえば `llama.cpp` や `GPT4All`, `LocalGPT` などを導入すれば、
社内データを外部に出さずに回答生成が可能です。


## おわりに

この検証で、LLMとベクトル検索の基本的な構成（RAG: Retrieval-Augmented Generation）の流れを把握できました。
今後は、**実際の社内文書で検証する／ダミーから実稼働モデルに切り替える**といったステップで改善していく予定です。

## 今回のソース箇所
質問の回答で以下の画面からの回答箇所です。

画面は下記で対応しています。
https://qiita.com/kenji123/items/051a3e6282bab7e62e3a

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176603/a59002fd-29f7-4490-a5b3-9ddf46e448c1.png)

以下の回答で動く部分です。

```rag_core.py
from langchain.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.llms.base import LLM
from dotenv import load_dotenv

load_dotenv()

# ローカル埋め込みモデル（無料）
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
db = FAISS.load_local("rag_app/faiss_index", embeddings, allow_dangerous_deserialization=True)

# ローカルLLM（ダミー応答用）
class DummyLLM(LLM):
    def _call(self, prompt, stop=None):
        return "（ダミー応答）これは社内資料の内容に基づく自動回答です。"

    @property
    def _llm_type(self):
        return "dummy"

llm = DummyLLM()

prompt = PromptTemplate.from_template("以下の文章を参考に質問に答えてください。\n\n{context}\n\n質問: {question}\n\n回答:")

chain = LLMChain(llm=llm, prompt=prompt)

def get_answer(question):
    docs = db.similarity_search(question)
    context = "\n".join([doc.page_content for doc in docs])
    answer = chain.run({"context": context, "question": question})
    return answer
```