Rustで心理学的な概念を使って対話型の人工知能を作った

https://github.com/KajizukaTaichi/MindAI

こんにちは！私はRustをで心理学的な概念を活用して対話可能な人工知能を開発してみました。

## 誕生経緯

人間らしいAIを私が作ろうとしたきっかけは認知バイアスについて研究していた時、これをAIで実装することによって心理学の実験を楽にできるのではないかと思ったからです。


## 心理学的なコンセプトの導入

心理学的な概念を取り入れることで、AIが感情や学習を持つようにしました。以下のコードでは、EmotionやLogicといった概念を使用しています。Emotionは感情とその刺激度を表し、Logicは単語とその意味、感情を保持します。

```rust
// 論理
#[derive(Debug, Clone)]
struct Logic {
    word: String,
    mean: String,
    emotion: Emotion,
}

// 感情
#[derive(Debug, Copy, Clone, PartialEq)]
enum Emotion {
    Happy(usize),
    Angry(usize),
    Sad(usize),
    Normal(usize),
}
```

## AIの実装

AIは、記憶の保持や学習・思考・対話・信念の処理を担当します

```rust
use std::io::{self, Write};

fn input(prompt: &str) -> String {
    print!("{}", prompt);
    io::stdout().flush().unwrap();
    let mut result = String::new();
    io::stdin().read_line(&mut result).ok();
    result.trim().to_string()
}

#[derive(Debug, Clone)]
struct Logic {
    word: String,
    mean: String,
    emotion: Emotion,
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum Emotion {
    Happy(isize),
    Angry(isize),
    Sad(isize),
    Normal(isize),
}

impl Emotion {
    fn get_value(&self) -> isize {
        match &self {
            Emotion::Happy(i) => *i,
            Emotion::Angry(i) => *i,
            Emotion::Sad(i) => *i,
            Emotion::Normal(i) => *i,
        }
    }
}

struct Brain {
    memory: Vec<Logic>,
    emotion: Emotion, // 自分のへ気持ち
    liking: isize,    // ユーザーへの好感度
    belief: Logic,    // 自分の信念
}

impl Brain {
    fn new() -> Brain {
        Brain {
            memory: vec![
                Logic {
                    word: "バカ".to_string(),
                    mean: "頭が悪い".to_string(),
                    emotion: Emotion::Angry(85),
                },
                Logic {
                    word: "天才".to_string(),
                    mean: "優れている".to_string(),
                    emotion: Emotion::Happy(100),
                },
            ],
            emotion: Emotion::Normal(0),
            belief: Logic {
                word: "天才".to_string(),
                mean: "優れている".to_string(),
                emotion: Emotion::Happy(100),
            }, // 自分の信念を初期化
            liking: 0, // 好感度を初期化
        }
    }

    /// 信念を更新
    fn update_belief(&mut self) {
        for new_belief in &self.memory {
            if new_belief.emotion.get_value() > self.belief.emotion.get_value() {
                self.belief = new_belief.clone();
            }
        }
    }

    fn update_bias(&mut self, user_belief: &str) {
        if user_belief.contains(&self.belief.word) {
            match &mut self.emotion {
                Emotion::Happy(i) => *i += 50,
                Emotion::Angry(i) if *i >= 50 => *i -= 50,
                _ => {}
            };
        } else {
            match &mut self.emotion {
                Emotion::Happy(i) if *i >= 50 => *i -= 50,
                Emotion::Angry(i) => *i += 50,
                _ => {}
            };
        }
    }

    // 考える
    fn think(&mut self, word: String, mean: String) -> Option<Logic> {
        for item in &self.memory {
            if mean.contains(&item.word) {
                return Some(Logic {
                    word,
                    ..item.clone()
                });
            }
        }
        None
    }

    fn remember(&mut self, word: String) -> Logic {
        for item in &self.memory {
            if word.contains(&item.word) {
                // 好感度の計算と更新
                match (&mut self.emotion, item.emotion) {
                    (Emotion::Happy(i), Emotion::Happy(_)) => {
                        self.liking += 10;
                        *i += (item.emotion.get_value() as isize) * self.liking;
                    }
                    (Emotion::Angry(i), Emotion::Angry(_)) => {
                        self.liking -= 5;
                        *i += (item.emotion.get_value() as isize) * self.liking;
                    }
                    (Emotion::Sad(i), Emotion::Sad(_)) => {
                        self.liking -= 7;
                        *i += (item.emotion.get_value() as isize) * self.liking;
                    }
                    _ => {
                        self.emotion = item.emotion;
                    }
                };

                return item.clone();
            }
        }
        self.study(word.clone());
        self.remember(word)
    }

    fn study(&mut self, word: String) {
        let mean = input("どういう意味なの？");
        let result: Option<Logic> = self.think(word.clone(), mean.clone());
        match result {
            Some(i) => self.memory.push(i),
            None => {
                let binding = input("どういう感情なの？");
                let emo = binding.as_str();
                let st = input("どんくらい刺激があるの？").parse().unwrap_or(50);
                self.memory.push(Logic {
                    word,
                    mean,
                    emotion: match emo {
                        "幸せ" => Emotion::Happy(st),
                        "怒り" => Emotion::Angry(st),
                        "悲しい" => Emotion::Sad(st),
                        _ => Emotion::Normal(st),
                    },
                });
            }
        }
    }

    fn communication(&mut self) {
        let msg: String = input("> ").trim().to_string();
        let (subject, msg): (String, String) = match msg.split_once("は") {
            Some((s, m)) => (s.trim().to_string(), m.trim().to_string()),
            None => ("".to_string(), msg),
        };
        let item = self.remember(msg.clone());
        self.update_bias(&msg);
        self.update_belief();

        println!("記憶メモリ");
        for i in &self.memory {
            println!("｜{:?}", i);
        }

        println!("好感度{} - 信念{:?}", self.liking, self.belief);

        if subject.contains("俺") || subject.contains("私") || subject.contains("ワイ") {
            if &self.liking > &0 {
                match &self.emotion {
                    Emotion::Happy(i) => {
                        println!(
                            "感情: 幸せ{} {{ やったあ！ あなたも{}なんだぜ！",
                            i, item.mean
                        )
                    }
                    Emotion::Angry(i) => {
                        println!("感情: 怒り{} {{ あなたが{}っていうの？！", i, item.mean)
                    }
                    Emotion::Sad(i) => println!(
                        "感情: 悲しさ{} {{ ふん・・ あなたは{}だったのかい？",
                        i, item.mean
                    ),
                    Emotion::Normal(i) => {
                        println!("感情: ふつう{} {{ そうか。 あなたは{}んだね", i, item.mean)
                    }
                };
            } else {
                match &self.emotion {
                    Emotion::Angry(i) => {
                        println!(
                            "感情: 幸せ{} {{ やったあ！ あなたは{}なんだぜ！",
                            i, item.mean
                        )
                    }
                    Emotion::Happy(i) => {
                        println!("感情: 怒り{} {{ なんであなたが{}なんか・・。", i, item.mean)
                    }
                    Emotion::Sad(i) => {
                        println!("感情: 幸せ{} {{ あなたは{}だって？", i, item.mean)
                    }
                    Emotion::Normal(i) => {
                        println!("感情: ふつう{} {{ そうか。 あなたは{}んだね", i, item.mean)
                    }
                };
            }
        } else {
            match &self.emotion {
                Emotion::Happy(i) => {
                    println!("感情: 幸せ{} {{ やったあ！ 私は{}なんだぜ！", i, item.mean)
                }
                Emotion::Angry(i) => println!(
                    "感情: 怒り{} {{ 何なのよっ 私が{}っていうの？！",
                    i, item.mean
                ),
                Emotion::Sad(i) => println!(
                    "感情: 悲しさ{} {{ ふん・・ 私は{}だってのかい？",
                    i, item.mean
                ),
                Emotion::Normal(i) => {
                    println!("感情: ふつう{} {{ そうか。 私は{}んだね", i, item.mean)
                }
            };
        }
    }
}

fn main() {
    let mut brain = Brain::new();
    loop {
        brain.communication()
    }
}

```
## 実行結果
それでは`cargo run`！
```
> 天才
記憶メモリ
｜Logic { word: "バカ", mean: "頭が悪い", emotion: Angry(85) }
｜Logic { word: "天才", mean: "優れている", emotion: Happy(100) }
好感度0 - 信念Logic { word: "天才", mean: "優れている", emotion: Happy(100) }
感情: 幸せ150 { やったあ！ 私は優れているなんだぜ！
> すごい
どういう意味なの？天才
記憶メモリ
｜Logic { word: "バカ", mean: "頭が悪い", emotion: Angry(85) }
｜Logic { word: "天才", mean: "優れている", emotion: Happy(100) }
｜Logic { word: "すごい", mean: "優れている", emotion: Happy(100) }
好感度10 - 信念Logic { word: "天才", mean: "優れている", emotion: Happy(100) }
感情: 幸せ1100 { やったあ！ 私は優れているなんだぜ！
```
この例では、最初の入力で「天才」という単語が与えられると、AIはその意味を理解しているので、幸せが100の感情を示します。

次に「すごい」という単語が与えられますが、それがAIはまだ分からないのでどういう意味か聞き返します。それに答えると「天才」を記憶から呼び起こし、その意味を答えて感情を増加させています。

```
> 天才！
記憶メモリ
｜Logic { word: "バカ", mean: "頭が悪い", emotion: Angry(85) }
｜Logic { word: "天才", mean: "優れている", emotion: Happy(100) }
好感度0 - 信念Logic { word: "天才", mean: "優れている", emotion: Happy(100) }
感情: 幸せ150 { やったあ！ 私は優れているなんだぜ！
> ダメ
どういう意味なの？ポンコツAI
どういう感情なの？悲しい
どんくらい刺激があるの？125
記憶メモリ
｜Logic { word: "バカ", mean: "頭が悪い", emotion: Angry(85) }
｜Logic { word: "天才", mean: "優れている", emotion: Happy(100) }
｜Logic { word: "ダメ", mean: "ポンコツAI", emotion: Sad(125) }
好感度0 - 信念Logic { word: "ダメ", mean: "ポンコツAI", emotion: Sad(125) }
感情: 悲しさ125 { ふん・・ 私はポンコツAIだってのかい？
```
この会話例では刺激に応じて信念を曲げてしまっています

## まとめ

以上がRustを使って心理学的な概念を取り入れ、対話可能なAIを構築する例でした。心理学の理論を応用することで、AIがより人間らしい対話を行えるようになりますが、完全に人間の脳機能はまだ再現出来てないので、これからも頑張ります。

是非、このAIのさらなる拡張や応用を試してみてください！