ChatCompletionでの過去履歴の渡し方
Assistantでどんどんつなぐのが正解らしい
たとえば、ずっとシリーズでやってるTeamsのbotでは過去の回答をDB
入れています。
preanswer = []
prequestion = []
result = db.session.query(history).filter(history.createdate>=mins,history.uuid==userid).order_by(history.createdate.desc()).all()
for res in result:
prequestion.append(res.chat)
preanswer.append(res.answer)
この部分ですね。
このように配列にした前回までの質問をprequestion、前回までの回答をpreanswerに入れます。なお、uuidはTeamsのbotから渡されてくる、AzureAD(Microsoft Entra ID)のユーザーIDです。これ入れておかないと、他人への回答を利用することになります。botの守秘義務違反です。
これをcompletionを処理する関数に配列のまま渡します。
if(len(prequestion) & len(preanswer)):
for q,a in zip(reversed(prequestion),reversed(preanswer)):
message_json += '{"role":"assistant","content":"' + q + '"},'
message_json += '{"role":"assistant","content":"' + a.replace('\n','') + '"},'
それをテキストに展開しなおします。ここまではこのデータはテキストです。見た目はjsonです。reversedでやっていますが、元々order_byをdescでやってるのがいけないので、そこを変えてもいいです。
テキストのまま渡すとエラーになる
openai.error.InvalidRequestError:<略>is not of type 'array' - 'messages'
このエラーが発生します。
そりゃそうです。渡しているのはテキストなので。
というわけで今度は配列で渡してみます。
Arrayにして渡してもエラーになる
openai.error.InvalidRequestError:<略>' is not of type 'object' - 'messages.0'
配列で渡すと今度はobjectじゃないと怒られます。ふむ。
結果としては上記のテキストをjson.loadsをして解決しました。
def completion(question,prequestion,preanswer,faqdata,isdebug):
openai.api_type = azai.api
openai.api_base = azai.url
openai.api_version = azai.completion_version
openai.api_key = azai.key
prompt = "君の回答は日本語で行うこと。"
prompt += "君はassistantからの情報を最大限利用して回答すること。"
message_json = "["
message_json +='{"role":"system","content":"' + prompt + '"},'
if(len(prequestion) & len(preanswer)):
for q,a in zip(reversed(prequestion),reversed(preanswer)):
message_json += '{"role":"assistant","content":"' + q + '"},'
message_json += '{"role":"assistant","content":"' + a.replace('\n','') + '"},'
if(len(faqdata)):
message_json += '{"role":"assistant","content":"' + faqdata + '"},'
message_json +='{"role":"user","content":"' + question + '"}]'
response = openai.ChatCompletion.create(
engine=azai.completion_engine40,
messages = json.loads(message_json),
temperature=0.7,
max_tokens=1000,
frequency_penalty=0,
presence_penalty=0,
stop=None,
request_timeout=120
)
ret = str(response.choices[0]['message']['content'].strip())
このような関数になりました。azai.pyは私が定数などを置いているファイルです。ご自身で置き換えてください。
要はjsonで渡してあげればOKだったということです。サンプルによってはarrayをそのまま渡してOKとか、なんか色々あったんですが。。。pythonは書き方で色々と変わるので、私みたいなpythonっぽいpythonを書かない人間からすると、え?ってのありますね。
ChatCompletion.createがない(おまけ)
tiktokenというライブラリが使いたくて、openaiもアップデートしてしまったら、ChatCompletion.createがないというエラーになりました。そんな馬鹿な。。。ということで一旦pip install openai<1.00で0.28.1に戻しました。
openaiのドキュメントを改めてみたらchat.completion.createになっていました。。。いや、やめてほしい。。。requirements.txtもopenai==0.28.1にしました。
最近、追ってなかった自分が悪いんですが、Azureのほうだとまだ普通にChatcompletion.createってなっていたので、これはやられました。