LoginSignup
5
8

More than 1 year has passed since last update.

LangChain+Chromaを使ってLangChainの専門家を作ってみる

Last updated at Posted at 2023-05-22

はじめに

csvに対する処理を自然言語で実装してみたい

そのためには、多様な命令に対して必要な処理をモデル自身に考えさせる必要がありそう?

モデル自身に考えさせる技術について調べるにはAuto-GPTのソースコードを読み解く必要がありそう?

LangChainのUseCasesにもある方法を使ってソースコードを読み込んでみよう

こんな感じの思いつきでとりあえずやってみました。

環境

Python 3.11.3
mac os 13.2.1(intel)

作成手順

基本的にはLangChainのUseCasesを元に処理をまとめただけです。

1.仮想環境構築

python3 -m venv .venv
. .venv/bin/activate

2.ライブラリインストール

pip install openai chromadb langchain tiktoken

3.ディレクトリ準備

mkdir source_code #ソースコードの保存先
mkdir vectors #ソースコードのベクトルデータの保存先

4.git clone

cd source_code
git clone https://github.com/hwchase17/langchain.git
cd ../

5.API_KEYの設定

touch .env
.env
OPENAI_API_KEY={YOUR_OPENAI_API_KEY}

6.embedding用クラスの作成

touch embedding.py
embedding.py
import os

from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.text_splitter import CharacterTextSplitter
from langchain.document_loaders import TextLoader


class Embedding:

    def __init__(self, root_dir, persist_directory) -> None:
        self.root_dir = root_dir
        self.docs = []
        self.texts = []
        self.persist_directory = persist_directory
        self.embedding = OpenAIEmbeddings()
        
    def load(self):
        for dirpath, dirnames, filenames in os.walk(self.root_dir):
            for file in filenames:
                try:
                    loader = TextLoader(os.path.join(dirpath, file), encoding='utf-8')
                    self.docs.extend(loader.load_and_split())
                except Exception as e:
                    pass
    
    def split(self):
        text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
        self.texts = text_splitter.split_documents(self.docs)

    def init_vector(self) -> Chroma:
        self.load()
        self.split()
        # ベクトルデータの初期化
        chroma_index = Chroma.from_documents(self.docs, embedding=self.embedding, persist_directory=self.persist_directory)
        # ベクトルデータをディレクトリに保存
        chroma_index.persist()
        return chroma_index

7.実行ファイルの作成

main.py
import os
import pdb
from dotenv import load_dotenv

import openai

from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chat_models import ChatOpenAI
from langchain.chains import ConversationalRetrievalChain

from embedding import Embedding

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
root_dir = f'{os.getcwd()}/source_code/langchain/langchain'
persist_directory = f"{os.getcwd()}/vectors/langchain"


def main():
    # 対象ソースコードのベクトルデータがあれば既存データをそのまま使う
    if not os.path.exists(persist_directory):
        embeddings = Embedding(root_dir=root_dir, persist_directory=persist_directory)
        vectordb = embeddings.init_vector()
    else:
        vectordb = Chroma(persist_directory=persist_directory, embedding_function=OpenAIEmbeddings())
    
    # retrieverの設定
    retriever = vectordb.as_retriever()
    retriever.search_kwargs["distance_metric"] = "cos"
    retriever.search_kwargs["fetch_k"] = 100
    retriever.search_kwargs["maximal_marginal_relevance"] = True
    retriever.search_kwargs["k"] = 7

    model = ChatOpenAI(model_name="gpt-3.5-turbo")
    qa = ConversationalRetrievalChain.from_llm(model, retriever=retriever)

    chat_history = []
    print("Chat Start!!")
    while True:
        query = input()
        if query == "exit":
            print("Exit!!")
            break
        
        result = qa({"question": query, "chat_history": chat_history})
        chat_history.append((query, result['answer']))
        print(f"**Answer**: {result['answer']} \n")

if __name__ == "__main__":
    main()

8.実行

入力

$python main.py

出力

Using embedded DuckDB with persistence: data will be stored in: {YOUR_ENVIRONMENT}/oss_reading_project/vectors/langchain
Chat Start!!
# 文章をここに入力

改善案

まとめ

自分で作ってみて初めてわかったのだが、トークン管理が思ったよりシビアだった。

参考

5
8
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
5
8