はじめに
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!!
# 文章をここに入力
改善案
-
トークン上限への対策
現時点だと質問文を工夫しないと、トークン上限エラーが頻発する
参考になりそうな動画 -
ソースコード取得方法を修正
git cloneの関数化に使えそう
ドキュメントの要約
まとめ
自分で作ってみて初めてわかったのだが、トークン管理が思ったよりシビアだった。