GraphAIによるRAGの実装例

GraphAIを使用したRAG（Retrieval Augmented Generation）の実装例と出力結果を解説します。以下のコードが全体像です：

```yaml
version: 0.5
nodes:
  # 1. コンテンツの準備
  source:
    value: |
      GraphAIは非同期データフロー実行エンジンです。
      開発者がYAMLやJSONでエージェントワークフローを宣言的に記述することで、
      エージェントアプリケーションを構築できます。
      
      GraphAIには2種類のノードがあります。
      計算ノードはエージェントに関連付けられ、特定の計算を実行します。
      静的ノードは、コンピュータ言語の変数のように値のプレースホルダーです。
      
      GraphAIは設計上、データフローグラフを非巡回にする必要がありますが、
      ループ、ネスト、if/unless、マッピングなどの制御フローメカニズムが追加されています。

  query:
    value: GraphAIのノードの種類について教えてください。

  # 2. テキストのチャンキング
  chunks:
    agent: stringSplitterAgent
    inputs:
      text: :source
    params:
      separator: "\n\n"  # 段落で分割

  # 3. 各チャンクのembedding取得
  chunkEmbeddings:
    agent: stringEmbeddingsAgent
    inputs:
      array: :chunks.contents

  # 4. クエリのembedding取得
  queryEmbedding:
    agent: stringEmbeddingsAgent
    inputs:
      item: :query

  # 5. 類似度計算
  similarities:
    agent: dotProductAgent
    inputs:
      matrix: :chunkEmbeddings
      vector: :queryEmbedding.$0

  # 6. 類似度でチャンクをソート
  sortedChunks:
    agent: sortByValuesAgent
    inputs:
      array: :chunks.contents
      values: :similarities

  # 7. コンテキストの準備
  referenceText:
    agent: tokenBoundStringsAgent
    inputs:
      chunks: :sortedChunks
    params:
      limit: 2000  # トークン数の制限

  # 8. プロンプトの構築
  prompt:
    agent: stringTemplateAgent
    inputs:
      query: :query
      context: :referenceText.content
    params:
      template: |-
        以下の文書を参考に質問に答えてください：
        ${context}

        質問：${query}

  # 9. LLMでの回答生成
  llmResponse:
    agent: openAIAgent
    inputs:
      prompt: :prompt
    params:
      model: gpt-4o
    console:
      after: true

  # 10. 結果の出力
  output:
    agent: copyAgent
    inputs:
      text: :llmResponse.text
    console:
      after: true
    isResult: true
```

## RAGの実装ステップ

### 1. 入力データの準備と分割

最初に、分析したい長文とユーザークエリを準備し、テキストを分割します：

```yaml
  source:
    value: |
      GraphAIは非同期データフロー実行エンジンです。
      # ...（ソーステキスト）

  query:
    value: GraphAIのノードの種類について教えてください。

  chunks:
    agent: stringSplitterAgent
    inputs:
      text: :source
    params:
      separator: "\n\n"  # 段落単位での分割
```

### 2. Embedding生成とベクトル検索

分割したテキストとクエリのembeddingを生成し、類似度を計算します：

```yaml
  chunkEmbeddings:
    agent: stringEmbeddingsAgent
    inputs:
      array: :chunks.contents

  queryEmbedding:
    agent: stringEmbeddingsAgent
    inputs:
      item: :query

  similarities:
    agent: dotProductAgent
    inputs:
      matrix: :chunkEmbeddings
      vector: :queryEmbedding.$0

  sortedChunks:
    agent: sortByValuesAgent
    inputs:
      array: :chunks.contents
      values: :similarities
```

チャンクしたテキストとユーザーの入力をベクトル化して類似解析をし、並び替えをします。

### 3. コンテキストの最適化とプロンプト生成

関連性の高いチャンクを選択し、プロンプトを構築します：

```yaml
  referenceText:
    agent: tokenBoundStringsAgent
    inputs:
      chunks: :sortedChunks
    params:
      limit: 2000  # トークン制限

  prompt:
    agent: stringTemplateAgent
    inputs:
      query: :query
      context: :referenceText.content
    params:
      template: |-
        以下の文書を参考に質問に答えてください：
        ${context}

        質問：${query}
```

### 4. LLM処理と出力

最後に、GPT-4で回答を生成し、結果を出力します：

```yaml
  llmResponse:
    agent: openAIAgent
    inputs:
      prompt: :prompt
    params:
      model: gpt-4o
    console:
      after: true

  output:
    agent: copyAgent
    inputs:
      text: :llmResponse.text
    console:
      after: true
    isResult: true
```

## 実行結果

```json
{
  "id": "chatcmpl-Ae6Xsqv3WXPeYwd4OQKE2Telx925S",
  "object": "chat.completion",
  "created": 1734121644,
  "model": "gpt-4o-2024-08-06",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "GraphAIには2種類のノードがあります。1つ目は「計算ノード」で、エージェントに関連付けられ特定の計算を実行します。2つ目は「静的ノード」で、コンピュータ言語の変数のように値のプレースホルダーとして機能します。",
        "refusal": null
      }
    }
  ],
  "usage": {
    "prompt_tokens": 206,
    "completion_tokens": 76,
    "total_tokens": 282
  }
}
```

## 実装の詳細分析

1. **チャンキングの特徴**
```yaml
  chunks:
    agent: stringSplitterAgent
    inputs:
      text: :source
    params:
      separator: "\n\n"
```
- 段落単位での分割により文脈を維持
- separatorパラメータによる柔軟な分割制御

2. **ベクトル検索の最適化**
```yaml
  similarities:
    agent: dotProductAgent
    inputs:
      matrix: :chunkEmbeddings
      vector: :queryEmbedding.$0
```
- ドット積による効率的な類似度計算
- 行列演算による高速な処理

3. **コンテキスト管理**
```yaml
  referenceText:
    agent: tokenBoundStringsAgent
    inputs:
      chunks: :sortedChunks
    params:
      limit: 2000
```
- トークン制限による最適なコンテキストサイズの管理
- 関連性の高いチャンクの優先的な選択

## まとめ

このGraphAIによるRAG実装の主な特徴は以下の点です：

- 段落単位でのチャンキングによる文脈の維持
- トークン制限による効率的なコンテキスト最適化
- 独立したノードによる明確な処理の分離
- 宣言的な記述による高い可読性と保守性

この実装は、大規模なドキュメント検索や質問応答システムなど、様々な実用的なアプリケーションに応用できます。また、各処理ステップが独立したノードとして定義されているため、システムの拡張や改善が容易です。