GraphAIでチャットボットを作ってみた

## 1. 基本構成と概要

GraphAIを使用したチャットボットの実装例を詳しく解説します。このチャットボットは、ユーザーとの対話を継続的に行い、"/bye"というコマンドで終了する基本的な対話システムです。

### 1.1 実装コード
```yaml
version: 0.5
loop:
  while: :continue
nodes:
  continue:
    value: true
    update: :checkInput
  
  messages:
    value:
      - role: system
        content: You are a friendly and helpful assistant.
    update: :llm.messages
    isResult: true
  
  userInput:
    agent: textInputAgent
    params:
      message: "You: "
      required: true
  
  checkInput:
    agent: compareAgent
    inputs:
      array:
        - :userInput.text
        - "!="
        - /bye
  
  llm:
    agent: openAIAgent
    params:
      model: gpt-4o
    inputs:
      messages: :messages
      prompt: :userInput.text
  
  output:
    agent: stringTemplateAgent
    console:
      after: true
    inputs:
      text: "Assistant: ${:llm.text}"
```

## 2. コアコンポーネントの解説

### 2.1 ループ制御システム
```yaml
version: 0.5
loop:
  while: :continue

nodes:
  continue:
    value: true
    update: :checkInput
```
- `loop`構造が対話の継続を制御
- `continue`ノードが状態管理を担当
- `checkInput`の結果に基づいて更新される

checkInputがtrueである限り、チャットは継続されます。checkInputの条件はarrayで定義されています。
- ユーザーの入力(:userInput.text)
- 入力との比較（!=）
- ユーザーの入力と比較する値

つまり/byeをユーザーが入力するとチャットが終了します。

### 2.2 メッセージ管理システム
```yaml
messages:
    value:
      - role: system
        content: You are a friendly and helpful assistant.
    update: :llm.messages
    isResult: true
```
- 会話履歴の保持と更新を担当
- システムプロンプトを初期値として設定
- `update: :llm.messages`の役割:
  1. `llm`ノードから返される`messages`プロパティで更新
  2. これには現在の会話履歴に新しい対話（ユーザーの入力とアシスタントの応答）が追加されたものが含まれる
  3. 次のループでこの更新された履歴が使用される
- `isResult: true`でそのノードが最終的な結果を出力するノードであることを示す

### 2.3 メッセージ更新の流れ
1. 初期状態: システムプロンプトのみ含む
2. ユーザー入力後:
   ```yaml
   messages:
     - role: system
       content: You are a friendly and helpful assistant.
     - role: user
       content: [ユーザーの入力]
   ```
3. LLM応答後:
   ```yaml
   messages:
     - role: system
       content: You are a friendly and helpful assistant.
     - role: user
       content: [ユーザーの入力]
     - role: assistant
       content: [AIの応答]
   ```
4. この更新された配列が次のループで使用され、文脈を維持

## 3. エージェントシステムの詳細

### 3.1 ユーザー入力エージェント
```yaml
userInput:
  agent: textInputAgent
  params:
    message: "You: "
    required: true
```
- `textInputAgent`: コンソールからの入力を処理
- 必須入力パラメータを設定
- プロンプトとして "You: "を表示

### 3.2 入力チェックエージェント
```yaml
checkInput:
  agent: compareAgent
  inputs:
    array:
      - :userInput.text
      - "!="
      - /bye
```
- 終了コマンド("/bye")の検出を担当
- 比較結果に基づいてループ継続を判断

### 3.3 言語モデルエージェント
```yaml
llm:
  agent: openAIAgent
  params:
    model: gpt-4o
  inputs:
    messages: :messages
    prompt: :userInput.text
```
- GPT-4を使用して応答を生成
- 会話履歴と現在の入力を考慮

### 3.4 出力フォーマットエージェント
```yaml
output:
  agent: stringTemplateAgent
  console:
    after: true
  inputs:
    text: "Assistant: ${:llm.text}"
```
- 応答テキストの整形を担当
- コンソール出力のタイミング制御
- 今回は応答のフォーマットを定義

## 4. 実行フローの説明

### 4.1 初期化フェーズ
1. `continue`ノードが`true`に初期化
2. `messages`ノードがシステムプロンプトで初期化
3. チャットループの開始準備完了

### 4.2 対話ループフェーズ
1. ユーザー入力の受付
   - `textInputAgent`がプロンプトを表示
   - ユーザーからの入力を待機

2. 入力の処理
   - `checkInput`ノードで終了コマンドをチェック
   - 入力が"/bye"でない場合、処理を継続

3. LLM処理
   - `openAIAgent`が会話履歴と現在の入力を処理
   - 適切な応答を生成

4. 出力処理
   - `stringTemplateAgent`が応答をフォーマット
   - コンソールに整形された応答を表示

5. 状態更新
   - `messages`ノードの履歴を更新
   - 次のループの準備

### 4.3 終了フェーズ
1. ユーザーが"/bye"を入力
2. `checkInput`が`false`を返す
3. `continue`ノードが更新され`false`に
4. ループが終了

## 関連記事
https://qiita.com/yukiaprogramming/items/cc48465ee35e23d5214e

https://github.com/receptron/graphai-demo-web/