見出し画像

AIML - チャットボットのマークアップ言語の元祖

チャットボットのマークアップ言語の元祖である「AIML」についてまとめました。

1. AIML

AIML」(Artificial Intelligence Markup Language)は、ルールベースのチャットボットを構築するためのXMLベースのマークアップ言語です。「A.L.I.C.E.」 (Artificial Linguistic Internet Computer Entity)というボットの定義を記述した言語としても知られています。

2. AIMLのタグ

「AIML 1.X」のタグのリファレンスは、次のとおりです。

重要なタグは、次のとおりです。

・<aiml> : AIMLドキュメントの開始と終了の定義。
・<category> : ナレッジベースのナレッジの定義。
・<pattern> : ユーザー入力のパターンの定義。
・<template> : ユーザー入力に対する応答の定義。
・<learn> : AIMLファイルの学習。

その他のタグは、次のとおりです。

・<star> : ワイルドカード文字の取得。
・<srai> : 他のカテゴリの再帰呼び出し。
・<random> : 複数の応答をランダムに返す。
・<li> : 個別の応答の定義。
・<set> : AIML変数に値を設定。
・<get> : AIML変数の値を取得。
・<think> : <set>で設定したAIML変数の非表示。
・<that> : 特定のテンプレート後のみ応答するカテゴリの定義。
・<topic> : topic変数が特定値の時のみ応答するカテゴリの定義。
・<condition> : AIML変数が特定値の時のみ利用するテンプレートの定義。

3. 開発環境の準備

「Python」で「AIML 1.1」を試す環境を準備します。

(1) 「Anaconda」で「Python 3.6」の仮想環境を作成。

$ conda create -n aiml python=3.6
$ conda activate aiml

(2) 「python-aiml」のインストール。

$ pip install python-aiml

4. はじめてのAIMLの実行

◎ std-startup.xml
はじめに、スタートアップを作成します。ユーザー入力「LOAD AIML B」に応じて、AIMLファイルを学習します。<template>内に必用な全てのAIMLファイルを定義します。

<aiml version="1.0.1" encoding="UTF-8">

  <category>
    <pattern>LOAD AIML B</pattern>
    <template>
      <learn>basic_chat.aiml</learn>
      <!--<learn>more_aiml.aiml</learn>-->
    </template>
  </category>
    
</aiml>

◎ basic_chat.aiml
ユーザー入力「こんにちは」「あなたの名前は?」に応じるカテゴリを作成します。

<aiml version="1.0.1" encoding="UTF-8">

  <category>
    <pattern>こんにちは</pattern>
    <template>こんにちは!</template>
  </category>

  <category>
    <pattern>あなたの名前は?</pattern>
    <template>ロボ太郎です</template>
  </category>

</aiml>

◎ start_aiml.py
「AIML」を実行するPythonスクリプトを作成します。

import aiml

# カーネルの生成とAIMLの実行
kernel = aiml.Kernel()
kernel.learn("std-startup.xml")
kernel.respond("load aiml b")

# 入力ループ (Ctrl-Cで終了)
while True: 
    print(kernel.respond(input("> ")))

カーネル関係のAPIは、次のとおりです。

・kernel.learn(learnFiles) : AIMLファイルの学習。
・kernel.respond(input_, sessionID) : ユーザー入力を元に応答を取得。

◎ 実行結果
実行結果は、次のとおりです。

> こんにちは
こんにちは!
> あなたの名前は?
ロボ太郎です

5. ワイルドカード

<pattern>でワイルドカード(「*」または「_」)を使うことで、任意テキストをマッチングできます。

  <category>
    <pattern>こんにちは * です</pattern>
    <template>
      こんにちは!
    </template>
  </category>
> こんにちは 田中 です
こんにちは!
【注意】AIMLは、単語間にスペースがある言語を前提としています。日本語で利用する場合は、MeCabなどで分かち書きしておく必用があります。

6. ワイルドカード文字の取得

<star>を使うことで、<pattern>のワイルドカード文字を取得できます。

  <category>
    <pattern>こんにちは * です</pattern>
    <template>
        こんにちは!<star index="1"/>さん
    </template>
  </category>
> こんにちは 田中 です
こんにちは!田中さん

7. 他のカテゴリの再帰呼び出し

<srai>を使うことで、他のカテゴリの再帰呼び出しができます。複数のユーザー入力に対して同じ応答を行う場合、<srai>を使うことで、応答を1ヶ所にまとめて記述することができます。

<srai>パターン</srai>

<srai>を使わない書き方は、次のとおりです。

  <category>
    <pattern>こんにちは</pattern>
    <template>今日は良い天気ですね</template>
  </category>
  <category>
    <pattern>* こんにちは</pattern>
    <template>今日は良い天気ですね</template>
  </category>
  <category>
    <pattern>こんにちは *</pattern>
    <template>今日は良い天気ですね</template>
  </category>
  <category>
    <pattern>* こんにちは *</pattern>
    <template>今日は良い天気ですね</template>
  </category>

<srai>を使う書き方は、次のとおりです。

  <category>
    <pattern>こんにちは</pattern>
    <template>今日は良い天気ですね</template>
  </category>
  <category>
    <pattern>* こんにちは</pattern>
    <template>
      <srai>こんにちは</srai>
    </template>
  </category>
  <category>
    <pattern>こんにちは *</pattern>
    <template>
      <srai>こんにちは</srai>
    </template>
  </category>
  <category>
    <pattern>* こんにちは *</pattern>
    <template>
      <srai>こんにちは</srai>
    </template>
  </category>

8. 複数の応答をランダムに返す

<random><li>を使うことで、複数の応答をランダムに返すことができます。

<random>
    <li> 〜 </li>
    <li> 〜 </li>
        :
</random>
  <category>
    <pattern>こんにちは</pattern>
    <template>
      <random>
        <li>こんにちは!</li>
        <li>今日も良い天気ですね</li>
        <li>また会いましたね</li>
      </random>
    </template>
  </category>
> こんにちは
こんにちは!
> こんにちは
今日も良い天気ですね

9. AIML変数の設定と取得

<set>でAIML変数の設定、<get>でAIML変数の取得を行うことができます。

<set name="AIML変数の名前">AIML変数の値</set>
<get name="AIML変数の名前" />

  <category>
    <pattern>私の名前は * です</pattern>
    <template>
      <set name="user_name"><star/></set> さんですね。覚えました
    </template>
  </category>

  <category>
    <pattern>こんにちは</pattern>
    <template>
      こんにちは <get name="user_name"/> さん
    </template>
  </category>
> 私の名前は 田中 です
田中 さんですね。覚えました
> こんにちは
こんにちは 田中 さん

<think>を使うことで、<set>で設定したAIML変数を非表示にすることができます。

  <category>
    <pattern>私の名前は * です</pattern>
    <template>
      <think><set name="user_name"><star/></set></think>覚えました
    </template>
  </category>
> 私の名前は 田中 です
覚えました

10. 特定のテンプレート後のみ応答するカテゴリの定義

<that>を使うことで、特定のテンプレート後のみ応答するカテゴリを定義できます。

<that>テンプレート</that>
  <category>
    <pattern>映画を見に行きましょう</pattern>
    <template>コメディ映画は好きですか?</template>
  </category>

  <category>
    <pattern>はい</pattern>
    <that>コメディ映画は好きですか?</that>
    <template>いいですね</template>
  </category>

  <category>
    <pattern>いいえ</pattern>
    <that>コメディ映画は好きですか?</that>
    <template>では、アクション映画を見に行きましょう</template>
  </category>
> 映画を見に行きましょう
コメディ映画は好きですか?
> はい
いいですね

11. topic変数が特定値の時のみ応答するカテゴリの定義

<topic>を使うことで、topic変数が特定値の時のみ応答するカテゴリを定義できます。

<topic name="topic変数の値">
    <category> 〜 </category>
    <category> 〜 </category>
        :
</topic>
  <category>
    <pattern>ラーメン</pattern>
    <template>
      ラーメン好き?
      <think>
        <set name="topic">RAMEN</set>
      </think>
    </template>
  </category>

  <category>
    <pattern>カレー</pattern>
    <template>
      カレー好き?
      <think>
        <set name="topic">CURRY</set>
      </think>
    </template>
  </category>

  <topic name="RAMEN">
    <category>
      <pattern>好き</pattern>
      <template>ラーメン美味しいよね</template>
    </category>
  </topic>

  <topic name="CURRY">
    <category>
      <pattern>好き</pattern>
      <template>カレー美味しいよね</template>
    </category>
  </topic>
> ラーメン
ラーメン好き?
> 好き
ラーメン美味しいよね
> カレー
カレー好き?
> 好き
カレー美味しいよね

12. AIML変数が特定値の時のみ利用するテンプレートの定義

<condition>を使うことで、AIML変数が特定値の時のみ利用するテンプレート文言を定義できます。

<condition name="AIML変数の名前" value="AIMLの値">テンプレート文言</condition>
<condition name="AIML変数の名前">
    <li value="AIML変数の値">テンプレート文言</li>
    <li value="AIML変数の値">テンプレート文言</li>
        :
</condition>
  <category>
    <pattern>じゃんけん</pattern>
    <template>
      <condition name="eindex">
        <li value="choki">
          チョキ
          <think>
            <set name="eindex">pa</set>
          </think>
        </li>
        <li value="pa">
          パー
          <think>
            <set name="eindex">gu</set>
          </think>
        </li>
        <li>
          グー
          <think>
            <set name="eindex">choki</set>
          </think>
        </li>
      </condition>
    </template>
  </category>
> じゃんけん
グー
> じゃんけん
チョキ
> じゃんけん
パー

13. ボット起動時のAIMLファイルの学習の高速化

AIMLファイルの数が増えると、起動時の学習に時間がかかります。AIMLファイルの学習後にBrainファイルを保存することで、次回からボット起動が大幅に短縮されます。

import aiml
import os

# カーネルの生成とAIMLの実行
kernel = aiml.Kernel()
if os.path.isfile("bot_brain.brn"):
    kernel.bootstrap(brainFile = "bot_brain.brn")
else:
    kernel.bootstrap(learnFiles = "std-startup.xml", commands = "load aiml b")
    kernel.saveBrain("bot_brain.brn")

# 入力ループ (Ctrl-Cで終了)
while True:
    print(kernel.respond(input("> ")))

Brainファイル関係のAPIは、次のとおりです。

・kernel.bootstrap(brainFile, learnFiles, commands,chdir) : ブートストラップ
・kernel.saveBrain(filename) : Brainファイルの保存。

14. ボット実行中のAIMLファイルのリロード

ボット実行中にロードメッセージを送信することで、AIMLファイルのリロードが可能です。Brainファイルの利用時は、Brainファイルの削除も必用になります。

load aiml b

15. Pythonコマンドの追加

Pythonコマンドを追加するには、ユーザー入力を処理してから、kernel.respond()に送信する必要があります。

while True:
    message = input("> ")
    if message == "quit":
        exit()
    elif message == "save":
        kernel.saveBrain("bot_brain.brn")
    else:
        bot_response = kernel.respond(message)
        # bot_responseで何らかを処理

16. セッション

セッションを指定することで、AIMLは会話を人に合わせて調整できます。たとえば、ある人がボットに自分の名前をアリスと言い、別の人がボットに自分の名前をボブと言った場合、ボットは人を区別することができます。respond()の2番目のパラメータでセッションを指定します。

sessionId = 12345
kernel.respond(input("> "), sessionId)

これは、各クライアントとパーソナライズされた会話をするのに適しています。独自のセッションIDを何らかの方法で生成し、追跡する必要があります。Brainファイルを保存しても、全てのセッション値が保存されるわけではないことに注意してください。

sessionId = 12345

# セッション情報を辞書として取得。 
# 入力履歴と出力履歴、および既知の述語が含まれる
sessionData = kernel.getSessionData(sessionId)

# 各セッションIDは一意の値である必要がある
# 述語名は、ボットとのセッションでボットが知っている何か/誰かの名前
# ボットはあなたを"Billy"、"dog"は"Brandy"という名前と認識
kernel.setPredicate("dog", "Brandy", sessionId)
clients_dogs_name = kernel.getPredicate("dog", sessionId)

kernel.setBotPredicate("hometown", "127.0.0.1")
bot_hometown = kernel.getBotPredicate("hometown")

AIMLのテンプレートでも述語を利用することができます。

<aiml version="1.0.1" encoding="UTF-8">

  <category>
    <pattern>MY DOGS NAME IS *</pattern>
    <template>
      That is interesting that you have a dog named <set name="dog"><star/></set>
    </template>  
  </category>  

  <category>
    <pattern>WHAT IS MY DOGS NAME</pattern>
    <template>
      Your dog's name is <get name="dog"/>.
    </template>  
  </category>  

</aiml>

上記のAIMLを使用した、ボットとの会話例は、次のとおりです。

人間 : My dogs name is Max
ボット : That is interesting that you have a dog named Max
人間 : What is my dogs name?
ボット : Your dog's name is Max.

17. 参考


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