Azure OpenAI x Pinecone x TeamsでFAQ検索ボットを作成する~pineconeにqueryを投げる+LLMで回答を作成する編
この記事について
この記事ではApp Serviceを利用してpinecone.queryがアップロードしたpinecone.Indexに対してqueryするところまでを解説しています。ところどころソースは載せていますが、常に最新とはいかないので、参考までにしてください。なお、使用しているframeworkはflaskです。
手順
1.queryを受け付けるapp.pyを記述する
# app.py
import openai
import pinecone
from flask import Flask, request
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
# pineconeに検索を投げるため、質問もvector化する
def search(pindex,keyword):
embeddings = embedded.embedding(keyword)
embeds = [record['embedding'] for record in embeddings['data']]
response = pindex.query(
top_k=3,
vector=embeds
)
return(response)
# ChatCompetionで回答を生成する
def llm(question,assitant):
openai.api_type = 'azure'
openai.api_base = '自分のurl'
openai.api_version = '2023-03-15-preview'
openai.api_key = '自分のAPIキー'
response = openai.ChatCompletion.create(
engine='gpt-35-turbo',
messages = [
{"role":"system","content":"assistantからの情報のみで答えること"},
{"role":"assistant","content": assitant},
{"role":"user","content": question},
],
temperature=0.7,
max_tokens=800,
top_p=0.95,
frequency_penalty=0,
presence_penalty=0,
stop=None
)
return(response.choices[0]['message']['content'].strip())
@app.route('/chat', methods=['POST'])
def post_chat():
try:
chat = request.json["chat"]
except:
return('{"Status":"Nothing"}')
pinecone.init(
api_key= '自分のAPIキー',
environment='自分の環境'
)
# 既存のindexへの接続を行う
# search関数に渡したいので、意味がないかもしれないが、pcnindexに入れてみる
pcnindex = pinecone.Index(index_name='index_of_faq')
# pineconeからはtop_k=3分の3件が返ってくる
results = search(pcnindex,chat)
reschat = ""
urls = []
titles = []
num = 0
# json形式で戻ってきているmatchesをループする
for res in results["matches"]:
id = res['id']
# postgresqlにidを投げてオリジナルのテキストデータを取得する
count = db.session.query(faqdata).filter_by(id=id).count()
if(count != 0):
result = db.session.query(faqdata).filter_by(id=id).first()
urls.append(result.url)
titles.append(result.title)
#metadataの取り出しサンプル
print(res["metadata"]["text"],res["metadata"]["url"])
#最初の一件だけ処理をする
if num == 0:
reschat = llm(chat,result.textdata)
num += 1
# Teamsにそのまま投げられるようにhtmlをある程度作成してresponseすることにする
answer = ""
answer += reschat
answer += "\n\n<br><br>他にも候補があります。<br>\n"
row = 0
for url,title in zip(urls,titles):
answer += f'\n<br><a href="{url}">"{title}"</a><br>\n'
row += 1
return(answer)
embedded.pyは再掲します。
#embedded.py
import openai
openai.api_type = 'azure'
openai.api_key = '自分のキー'
openai.api_base = '自分のエンドポイント'
openai.api_version = "2023-05-15"
def embedding(textdata):
response = openai.Embedding.create(
input=textdata,
engine = 'text-embedding-ada-002',
)
return(response)
このままコピペされても動かないと思います。申し訳ございません。
処理の流れとしては、jsonで受け付けたキーワードをembeddingでvector化して、それをpineconeのqueryに渡します。結果が返ってくるのですが、pineconeのidがオンプレのDBのFAQのユニークキーになっているため、postgresqlに検索をかけて、FAQのurlとタイトルを持ってこれるというわけです。pineconeのidが何でもいいみたいなので、そういう使い方にしました。そして、そのオリジナルの回答をプロンプトのassistantデータにして、Chat-GPTに投げて回答を生成させています。
Teamsにはhtmlで直接投稿ができるので、App Service側で加工をしてresponseしています。
(2023/06/20追記)
pineconeのmetadataが取り出せることが判明したのでソースにサンプルを追加しました。
相互リンク
概要編
Pineconeアップロード編
postgresqlアップロード編
Logic App作成編