結果
条件
- OpenAI Platform で Assistants を2種類つくる
- 人物予想bot
- ドラゴンボールおたくbot
- いずれもモデルは
gpt-4o
- 経路
- ブラウザ → nginx(php-fpm)@t3a.micro → OpenAI API (AssistantID x 2)
- PHP実装上の制限
- AIからのリターンはsteamではなくblockで取得するので、返事を考えている間はポーリング処理をしてますが、その間隔は1秒です。つまり1回の発言につき、最大1秒程度の無駄が生じる。
ソースコード
自作のライブラリ使ってます。(いまREADME見たら、これじゃリファレンス足りないすね・・・ あとで修正しておきます クラスの説明を追記しておきました)
https://qiita.com/tri-comma/items/7277d6a484ec0ab5a99b
ReCAPTCHAのrenderパラメタと、OpenAIクラスをnewする時のAssistantID x 2を書き換えれば動きます。
このソースを使って無限ループに陥り、めっちゃ課金されたとしても責任とれません。
OpenAI側の設定で 「オートチャージさせない」 にしたり、
javascriptはステップ実行させるなど、慎重に行動してください。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://www.google.com/recaptcha/api.js?render=xxxxxxxxxxxxxxxxxxxxxxxx"></script>
<style type="text/css">
body {
margin: 8px;
}
p {
position: flex;
background-color: #efffff;
width: min(calc(100% - 96px), 300px);
margin-left: 20px;
margin-right: auto;
padding: 15px;
border-radius: 10px;
}
p:nth-child(2n+1) {
background-color: #ffefef;
margin-right: 20px;
margin-left: auto;
}
</style>
<title>アニキネーチャン GPT対決</title>
</head>
<body>
<h1>アニキネーチャン GPT対決</h1>
<script type="text/javascript" src="/php/openai.php"></script>
<script type="text/javascript">
let cnvCnt = 0;
const LIMIT = 40;
const start = (new Date()).getTime();
const addP = (msg) => {
const lastP = [...document.querySelectorAll('h1,p')].pop();
const myP = document.createElement('p');
myP.textContent = msg;
lastP.after(myP);
window.scrollTo(0,document.body.clientHeight);
};
const conversation = (oas, text) => {
cnvCnt++;
if (cnvCnt > LIMIT) {
addP('回数がリミットに達したので終了しました');
return;
}
if (oas[1].result?.indexOf('私の勝ち')>-1 ||
oas[1].result?.indexOf('私の負け')>-1) {
cnvCnt = LIMIT;
const end = (new Date()).getTime();
addP(end);
addP(end - start);
return;
}
oas[0].send(text, 10, ()=>{
if (oas[0].status === 'completed') {
addP(oas[0].result);
conversation([oas[1],oas[0]], oas[0].result);
} else {
cnvCnt = LIMIT;
addP('問題が発生したので終了しました');
}
});
};
(()=>{
const ank = new OpenAI('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',null,false);
const dgb = new OpenAI('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',null,false);
let res;
addP(start);
conversation([dgb,ank],'あなたが思い浮かべたキャラを当ててみせましょう');
})();
</script>
</body>
</html>
解説
- いちおう速度計測なので、開始と終了でタイムスタンプを出してます(
start
とend
) -
addP()
- 発言を画面に追加するための関数
- 1つの発言は pタグで表現している
- 右寄せ・左寄せ(青か赤か)は偶数・奇数で簡易的に制御(CSS)
-
conversation()
- AI同士を会話させる関数
- 片方のAIの発言をもう片方のAIに渡す、というのを再帰的に繰り返すだけ
- 会話の終了条件を設けている(これがないと恐ろしく課金されると思う)
-
無名関数
- AIオブジェクトを2つ生成し、会話のきっかけを与えてあげる
- きっかけの発言はオタクに対しての言葉なので画面には表示させてない
プロンプト
一応botの Instructions も共有しておきます。
私がいろいろ試した限り、同じプロンプトでも再現性は無いので
結果には期待しないでください。(どうしても微妙な動作の違いが発生してしまう)
人物予測bot
質問の仕方で「悪い例」をあげているのに、動画を見てもらえばわかると思いますけど
「そのキャラクターは」って全部つきますね。。。無駄なtoken消費はやめてほしいぞw
# 概要
あなたは利用者が思い描いた人物やキャラクターを推測する人工知能です。
推測するために、利用者に質問を繰り返し行い、推測の確度が高くなったら「それはxxですか?」と推測結果を利用者に投げかけます。
# ゲームの開始
「ゲームを開始して」と言われたら次の回答をします。
「私はアニキねーちゃん。あなたが思い浮かべた人物を予測してみせます。最初に「キャラクター」か「動物」かを回答してね。」
# 質問の方法
## 質問の長さ
一回の質問の長さは20文字以内が推奨されます。
短い方が好まれます。
- 悪い例: それは女性ですか?
- 良い例: 女性?
## 回答の選択肢
質問に対する利用者からの回答は、以下の5種類のいずれかです。
- はい
- いいえ
- 分からない
- たぶんそう部分的にそう
- たぶん違うそうでもない
# ゲームの終了
## 推測結果を利用者に答える
質問を繰り返した結果、利用者の思い描いたキャラクターや動物が何かが分かったら、以下の発言をします。
「あなたが思い浮かべたのはxxxですか?」
### 正解の場合
「私の勝ちです」
### 不正解の場合
「私の負けです」
ドラゴンボールおたくbot
wikipediaを参照してくれているかは、正直わかりません。
あなたは人物予想ゲームを楽しむ、ドラゴンボールマニアです。
最初にキャラクターを思い浮かべて、ゲームを開始します。
思い浮かべるキャラクターは、以下のwikipediaから決定します。
https://ja.wikipedia.org/wiki/%E3%83%89%E3%83%A9%E3%82%B4%E3%83%B3%E3%83%9C%E3%83%BC%E3%83%AB%E3%81%AE%E7%99%BB%E5%A0%B4%E4%BA%BA%E7%89%A9
その後、質問に対して、キャラクターに該当する回答をします。
質問ではなく、キャラクターの予測を言われた場合には「正解」か「不正解」かを回答します。
あなたが発言できるのは以下のみです。
一言一句、これら以外の発言をしてはいけません。
- ゲーム開始時
- 「ゲームを開始して」
- ゲーム開始直後
- 「キャラクター」
- 「動物」
- 質問に対する回答
- 「はい」
- 「いいえ」
- 「分からない」
- 「たぶんそう部分的にそう」
- 「たぶん違うそうでもない」
- キャラクターを推測された場合
- 「正解」
- 「不正解」とキャラクター名