見出し画像

ChatGPT勉強日記(#6) Pineconeのベクターデータを文脈に使って講義資料に関して答えるAIを作成


前回、IDEOのHuman Centered Design (人間中心設計)の講義資料をOpenAIのEmbeddingsを使ってベクターデータにしたものをPineconeに保存した。

https://note.com/mizutory/n/naa6c3b0178d0

今回はそのPineconeのベクデータベースをつかって、講義資料に関して答えるプロンプトを作るところを勉強していきたい。


前回のプロジェクトにsearch.ipynbというファイルを新たに足し、ここにコーディングをしていく。

search.ipynb

まず先程のconstants.ipynbを先に実行し、必要なものをimportする。

%run constants.ipynb


from tqdm.autonotebook import tqdm 
from langchain.callbacks import get_openai_callback

(tqdmはJupyter Notebookの警告を回避するためだけにimportしています。本質的に必要なライブラリではありません)

次に前回と同じ用にpinecone、そして、LangChainのPineconeクラスとOpenAIEmbeddingsクラスをインポートする。

from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Pinecone
import pinecone

# Initialize OpenAi Embedding
embeddings = OpenAIEmbeddings(openai_api_key=os.environ['OPENAI_API_KEY'])

# Initialize Pinecone
pinecone.init(api_key=os.environ['PINECONE_API_KEY'], environment=os.environ['PINECONE_INDEX_REGION'])


次に、pinecone.Index()関数にインデックス名(この場合前回作ったhcd-embeddings)を渡してIndexオブジェクトを取得し、それをつかってLangChainのPineconeオブジェクトを作成する。

index = pinecone.Index(os.environ['PINECONE_INDEX_NAME'])
docsearch = Pinecone(
    index, embeddings.embed_query, "text"
)

次にLangChainのChatOpenAIクラスとConversationalRetrievalChainクラスをimport。

ChatOpenAIのインスタンスをmodel="gpt-3.5-turbo"、temperature=1を指定して作成。


# langchain
from langchain.chat_models import ChatOpenAI
from langchain.chains import ConversationalRetrievalChain


llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=1)

chat_history=[]

↑の最後にチャット履歴を保持するchat_history変数を空の配列で初期化した。

最後に、質問に返答する関数(ask_question)を作成する。
パラメーターは、query, vectordb, chat_historyの3つ。

def ask_question(query, vectordb, chat_history):    
    retriever = vectordb.as_retriever(search_kwargs={"k": 2})
    chat = ConversationalRetrievalChain.from_llm(llm, retriever=retriever, return_source_documents=True)
    result = chat({"question": query,"chat_history": chat_history})
    print("answer: ", result["answer"])    
    chat_history.insert(0, (query, result["answer"]))
    return chat_history

queryには質問の文字列を、vectordbには先程Indexを指定して作ったLangChainのPineconeオブジェクトを、そして、chat_historyには先程初期化した配列を渡して使うことになる。
vectordb (LangChainのPineconeオブジェクト)のas_retriever関数を呼び、retrieverオブジェクトを取得する。
ConversationalRetrievalChain.from_llm()にretrieverとllm(モデル)を渡し、chatという変数にオブジェクトを取得する。
これはcallableオブジェクト(呼び出し可能オブジェクト)なので、
それを関数のように次の行で呼ぶ。

result = chat({"question": query,"chat_history": chat_history})

このresultの中に、"answer"というkeyで、モデルからの解答が入っているので、これをprintする。

print("answer: ", result["answer"])  

また、chat_historyの配列に質問と解答のペアをタプルにして、insertする。

chat_history.insert(0, (query, result["answer"]))

今回、insertを使って新しいQ&Aが配列の前に来るようにしてみたが、
まだchat_history配列の作り方・使い方は詳しく調べてないのでもしかしたら、新しいものが後ろに来るようにhistoryを作るのが成果もしれない。このあたりはまた調べて見たいと思う。

出来上がった、ask_question関数に質問を投げてみた。

query1="What is the common technichs IDEO uses in their projects?"
chat_history = ask_question(query1, docsearch, chat_history)
print("history: ", chat_history)

良さそうな解答が返ってきた↓↓↓

より具体的な質問をし、IDEOの資料の一部が使われているか、確認してみた。

query2="What did Bezos Family Foundation launch in Washington State?"
chat_history = ask_question(query2, docsearch, chat_history)
print("history: ", chat_history)

資料中にある記述に即した回答が返ってきたので、pineconeのデータが使われていることが確認できた。

最後に前回と同じ質問をしてみた。

query3="What is the project IDEO did in Zambia?"
ask_question(query3, docsearch, chat_history)

「与えられた文脈」にはIDEOがZambiaで行ったプロジェクトについては述べられていません」という回答が返ってきた。

第4回では、Zambiaで行ったプロジェクト"Pump Away"について回答していたので、今回は挙動が変わったということになる。

第4回では、max=500トークンでオーバーラップなしに文章をぶつ切りにし、それをpandaライブラリのDataFrameに一時保存した。
今回は1000トークンで、200トークン分のオーバーラップを入れて文章をチャンクにし、pineconeに保存した。

トークンの切り方の違いが回答に影響しているのかもしれない。

もう一度時間をとって、トークンの区切り方と回答の違いについていろいろと実験をして見たいと思う。

続く。

このブログに関する質問や、OpenAI APIをつかったWebサービス、Android・iOSアプリの開発の相談はこちら↓↓↓からお願いします!

@mizutory
mizutori@goldrushcomputing.com


次回は↓↓↓




この記事が気に入ったらサポートをしてみませんか?