見出し画像

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ってなっていたので、これはやられました。

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