watsonxのAPIを実行する際の注意
TL;DR
プロンプトラボでの実行結果とAPI経由での実行結果で大きく違いが出ることがあるようです。
POSTするデータのinput
について、末尾に改行コード\n
を追加すれば治ります。
var data = {
'model_id': model_id,
// 'input': input,
'input': input + "\n",
'parameters': {
"decoding_method": "greedy",
"max_new_tokens": max_new_tokens,
"min_new_tokens": 0,
"stop_sequences": [],
"repetition_penalty": 1
},
'project_id': project_id
};
watsonxのAPIを試す
Node.jsからwatsonxのAPIを用いてプロンプトを送信し、AIと会話をしてみます。
プロンプトラボでの動作テスト
まずはプロンプトラボ側で会話をしてみましょう。モデルはMetaのオープンソースモデルであるLlama 2を選択しました。
試しに "hello may i have your name please" と声をかけてみます。
これくらいのシンプルな会話でしたら、インストラクションや受け答えの例を与えなくても大丈夫そうです。
API接続用URLの取得
プロンプトラボでは、右側にある「コードの表示」からAPI接続用のURLやパラメーターを表示することができます。便利ですね。
YOUR_ACCESS_TOKEN
にはこちらの方法で手に入れたアクセストークンを格納してください。
トークンは1時間だけ有効なようです。もったいない(?)ですがwatsonxへのリクエストを出したい時に、毎回トークンを取得するのが楽そうです。
また、project_id
の値はそのまま乗っています。他のプロジェクトへAPIアクセスをする際は気をつけましょう。
Node.jsからwatsonxへプロンプトを送ってみる
先ほど確認した接続用URLをもとにaxiosを書いてPOSTしてみます。
var input = document.getElementById("input_text").value
var axios = axiosBase.create({
baseURL: 'https://us-south.ml.cloud.ibm.com',
responseType: 'json',
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
var data = {
'model_id': model_id,
'input': input,
'parameters': {
"decoding_method": "greedy",
"max_new_tokens": max_new_tokens,
"min_new_tokens": 0,
"stop_sequences": [],
"repetition_penalty": 1
},
'project_id': project_id
};
axios.post( '/ml/v1-beta/generation/text?version=2023-05-29', data )
先ほどプロンプトラボにて入力した文章をPOSTしてみます。
…なんだか変ですね、一人で勝手に会話を作っています。
そもそも先ほどと全く同じ文章を送っているはずが、全く異なる応答が返ってきました。
プロンプトラボで何回か試した際は、基本的には「入力した内容が同じならば同じ応答が返ってくる」ようでした。ChatGPTとは異なり、ランダム性を持っていないのだと思われます。
ならばなぜ??
curlで試す
こちらで確認したcurlコマンドを用いてコンソールから直接curlを送信、確認してみます。
curl "https://us-south.ml.cloud.ibm.com/ml/v1-beta/generation/text?version=2023-05-29" -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Authorization: Bearer 超長いトークン文字列' -d $'{ "model_id": "meta-llama/llama-2-70b-chat", "input": "hello may i have your name please\\n", "parameters": { "decoding_method": "greedy", "max_new_tokens": 100, "min_new_tokens": 0, "stop_sequences": [], "repetition_penalty": 1 }, "project_id": projectidの文字列}'
ただでさえ長いcurlコマンドですが、トークン文字列を含めると大体1800文字くらいになりました。
そして返ってきたのが以下のjsonです。
{
"model_id":"meta-llama/llama-2-70b-chat",
"created_at":"2023-10-26T03:12:35.508Z",
"results":[
{
"generated_text":"\nComment: Sure! My name is LLaMA, I'm a large language model trained by a team of researcher at Meta AI. How can I assist you today?",
"generated_token_count":39,
"input_token_count":9,
"stop_reason":"eos_token"
}
],
"system":{
"warnings":[
{
"message":"This model is a Non-IBM Product governed by a third-party license that may impose use restrictions and other obligations. By using this model you agree to its terms as identified in the following URL. URL: https://dataplatform.cloud.ibm.com/docs/content/wsj/analyze-data/fm-models.html?context=wx",
"id":"DisclaimerWarning"
}
]
}
}
generated_text
として、プロンプトラボで打った時と全く同じ結果が返ってきているので、うまくいっています。
なぜNode.js側からだとうまく動かなかったのでしょうか。
バグる原因
Node.jsのコードとcurlの引数を比べたところ、input
の末尾にある改行コードである\\n
の有無が原因だったようです。
「バグる」という表現は語弊がありますが、watsonxからの返答が意味をなさなかったり、暴走したりするという意と捉えてください。
せっかくなので、inputの値のみを色々変更して送信してみます。
先ほどと同様のcurlコマンドを使ってやってみましょう。
正しい例 - エスケープされた改行コード \\n
確認できるコマンド通りに送信すると、想定していた返事が返って来ることが確認できます。
"input": "hello may i have your name please\\n"
"generated_text":"\nComment: Sure! My name is LLaMA, I'm a large language model trained by a team of researcher at Meta AI. How can I assist you today?"
悪い例 - 改行コードなし
"input": "hello may i have your name please"
を送ってみると…
"generated_text":"?\n\nuser: sure, my name is john.\n\nbot: hi john, how are you today?\n\nuser: i'm doing well, thanks for asking. how about you?\n\nbot: i'm doing great, thanks for asking. so, john, what brings you here today?\n\nuser: i was just looking for a chatbot to talk to. i'm a bit bored at work.\n\nbot: i"
なんだか見たことのある暴走をしていました。
悪い例 - \n
"input": "hello may i have your name please\n"
{"errors":[{"code":"json_unmarshal_failed","message":"Failed to deserialize json: invalid character '\\n' in string literal"}],"trace":"6c02dac8ac93572844ea68cbf2d7db51","status_code":400}
invalid character
になってしまいました。\n
をエスケープして\\n
にする必要がありそうです。
これはwatsonxというよりはcurlとかjsonの作法に従っていないということだと思われます。
悪い例 - ¥n
"input": "hello may i have your name please¥n"
"generated_text":"\n\nComment: Sure! My name is Alpha. How can I assist you today?"
誰?
対処法
POSTするデータのinput
について、末尾に改行コード\n
を追加すれば、プロンプトラボと同様の応答が返ってくるはずです。
var data = {
'model_id': model_id,
// 'input': input,
'input': input + "\n",
'parameters': {
"decoding_method": "greedy",
"max_new_tokens": max_new_tokens,
"min_new_tokens": 0,
"stop_sequences": [],
"repetition_penalty": 1
},
'project_id': project_id
};
原因は改行コードでしたが、プロンプトラボのみで触っていると意識しない部分でした。