ExcelでAI(ローカルAI)活用

ExcelでAI活用【VBA×ローカルLLMの実践ガイド】

ExcelとAIを組み合わせれば、データ処理がさらに効率化できます。

この記事では、VBAからローカルLLMを呼び出してExcel作業を自動化する方法を解説します。

1. Excel×AIでできること

活用シーン

用途 内容
データ分類 テキストを自動でカテゴリ分け
要約生成 長文コメントを要約
翻訳 多言語データの翻訳
データクレンジング 表記ゆれの統一
レポート生成 データから文章を生成

ローカルLLMのメリット

メリット
  • 機密データも安心(外部送信なし)
  • オフライン環境でも利用可能
  • API費用がかからない
  • 処理速度が安定

2. 環境構築

必要なもの

1. Ollama(ローカルLLM実行環境)
2. Excel(VBA対応版)
3. 適切なスペックのPC

Ollamaのインストール

1. ollama.com からダウンロード
2. インストーラーを実行
3. コマンドプロンプトで確認
   ollama --version

モデルのダウンロード

bash
# 日本語に強いQwenをダウンロード
ollama pull qwen2.5

# 軽量モデル(低スペックPC向け)
ollama pull phi3:mini

VBAの参照設定

VBAエディタ → ツール → 参照設定
→ Microsoft XML, v6.0 にチェック

3. VBAからOllamaを呼び出す

基本的なAPI呼び出し

VBA
Function CallOllama(prompt As String, Optional model As String = "qwen2.5") As String
    Dim http As Object
    Dim url As String
    Dim requestBody As String
    Dim response As String

    ' HTTPオブジェクトを作成
    Set http = CreateObject("MSXML2.XMLHTTP")

    ' OllamaのAPIエンドポイント
    url = "http://localhost:11434/api/generate"

    ' リクエストボディを作成
    requestBody = "{""model"":""" & model & """,""prompt"":""" & EscapeJson(prompt) & """,""stream"":false}"

    ' リクエストを送信
    http.Open "POST", url, False
    http.setRequestHeader "Content-Type", "application/json"
    http.send requestBody

    ' レスポンスを解析
    response = http.responseText
    CallOllama = ExtractResponse(response)

    Set http = Nothing
End Function

' JSON文字列をエスケープ
Function EscapeJson(text As String) As String
    Dim result As String
    result = Replace(text, "\", "\\")
    result = Replace(result, """", "\""")
    result = Replace(result, vbCrLf, "\n")
    result = Replace(result, vbCr, "\n")
    result = Replace(result, vbLf, "\n")
    result = Replace(result, vbTab, "\t")
    EscapeJson = result
End Function

' レスポンスからテキストを抽出
Function ExtractResponse(jsonResponse As String) As String
    Dim startPos As Long
    Dim endPos As Long

    startPos = InStr(jsonResponse, """response"":""") + 12
    endPos = InStr(startPos, jsonResponse, """,""done""")

    If startPos > 12 And endPos > startPos Then
        ExtractResponse = Mid(jsonResponse, startPos, endPos - startPos)
        ExtractResponse = Replace(ExtractResponse, "\n", vbCrLf)
        ExtractResponse = Replace(ExtractResponse, "\""", """")
    Else
        ExtractResponse = "エラー: レスポンスの解析に失敗"
    End If
End Function

ワークシート関数として使用

VBA
' カスタムワークシート関数
Function AI_PROCESS(text As String, instruction As String) As String
    Dim prompt As String
    prompt = instruction & vbCrLf & vbCrLf & text
    AI_PROCESS = CallOllama(prompt)
End Function

' 要約関数
Function AI_SUMMARIZE(text As String) As String
    Dim prompt As String
    prompt = "以下の文章を50文字以内で要約してください:" & vbCrLf & text
    AI_SUMMARIZE = CallOllama(prompt)
End Function

' 分類関数
Function AI_CLASSIFY(text As String, categories As String) As String
    Dim prompt As String
    prompt = "以下のテキストを分類してください。" & vbCrLf & _
             "カテゴリ:" & categories & vbCrLf & _
             "1つだけ回答してください。" & vbCrLf & vbCrLf & _
             "テキスト:" & text
    AI_CLASSIFY = CallOllama(prompt)
End Function

4. 実践的な活用例

一括分類処理

VBA
Sub ClassifyAllData()
    Dim ws As Worksheet
    Dim lastRow As Long
    Dim i As Long
    Dim text As String
    Dim category As String

    Set ws = ThisWorkbook.Sheets("データ")
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

    Application.ScreenUpdating = False

    For i = 2 To lastRow
        text = ws.Cells(i, 1).Value  ' A列:テキスト

        If Len(text) > 0 And Len(ws.Cells(i, 2).Value) = 0 Then
            category = AI_CLASSIFY(text, "問い合わせ,クレーム,要望,その他")
            ws.Cells(i, 2).Value = category  ' B列:カテゴリ

            ' 進捗表示
            Application.StatusBar = "処理中... " & i & "/" & lastRow
            DoEvents
        End If
    Next i

    Application.StatusBar = False
    Application.ScreenUpdating = True

    MsgBox "分類が完了しました"
End Sub

コメントの要約

VBA
Sub SummarizeComments()
    Dim ws As Worksheet
    Dim lastRow As Long
    Dim i As Long
    Dim comment As String
    Dim summary As String

    Set ws = ThisWorkbook.Sheets("コメント一覧")
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

    For i = 2 To lastRow
        comment = ws.Cells(i, 1).Value

        If Len(comment) > 100 Then  ' 100文字以上のコメントのみ
            summary = AI_SUMMARIZE(comment)
            ws.Cells(i, 2).Value = summary
        End If
    Next i
End Sub

表記ゆれの統一

VBA
Sub NormalizeText()
    Dim ws As Worksheet
    Dim lastRow As Long
    Dim i As Long
    Dim original As String
    Dim normalized As String
    Dim prompt As String

    Set ws = ThisWorkbook.Sheets("住所データ")
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

    For i = 2 To lastRow
        original = ws.Cells(i, 1).Value

        prompt = "以下の住所を正規化してください。" & vbCrLf & _
                 "・全角数字は半角に" & vbCrLf & _
                 "・都道府県から記載" & vbCrLf & _
                 "・ハイフンは「-」に統一" & vbCrLf & vbCrLf & _
                 original

        normalized = CallOllama(prompt)
        ws.Cells(i, 2).Value = normalized
    Next i
End Sub

感情分析

VBA
Function AI_SENTIMENT(text As String) As String
    Dim prompt As String
    prompt = "以下のテキストの感情を分析してください。" & vbCrLf & _
             "ポジティブ、ネガティブ、ニュートラルの3つから1つだけ回答:" & vbCrLf & vbCrLf & _
             text
    AI_SENTIMENT = CallOllama(prompt)
End Function

Sub AnalyzeSentiment()
    Dim ws As Worksheet
    Dim lastRow As Long
    Dim i As Long

    Set ws = ThisWorkbook.Sheets("レビュー")
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

    For i = 2 To lastRow
        ws.Cells(i, 2).Value = AI_SENTIMENT(ws.Cells(i, 1).Value)
    Next i
End Sub

5. データ分析への活用

データの傾向分析

VBA
Sub AnalyzeDataTrend()
    Dim ws As Worksheet
    Dim dataRange As Range
    Dim dataText As String
    Dim analysis As String
    Dim prompt As String

    Set ws = ThisWorkbook.Sheets("売上データ")
    Set dataRange = ws.Range("A1:D10")

    ' データをテキスト化
    dataText = RangeToText(dataRange)

    prompt = "以下のデータを分析し、傾向と改善点を3点挙げてください:" & vbCrLf & vbCrLf & dataText

    analysis = CallOllama(prompt)

    ' 結果を別シートに出力
    ThisWorkbook.Sheets("分析結果").Range("A1").Value = analysis
End Sub

Function RangeToText(rng As Range) As String
    Dim cell As Range
    Dim result As String
    Dim row As Range

    For Each row In rng.Rows
        For Each cell In row.Cells
            result = result & cell.Value & vbTab
        Next cell
        result = result & vbCrLf
    Next row

    RangeToText = result
End Function

レポート文章の生成

VBA
Sub GenerateReport()
    Dim ws As Worksheet
    Dim reportWs As Worksheet
    Dim dataText As String
    Dim report As String
    Dim prompt As String

    Set ws = ThisWorkbook.Sheets("月次データ")
    Set reportWs = ThisWorkbook.Sheets("レポート")

    dataText = RangeToText(ws.Range("A1:E20"))

    prompt = "以下のデータから月次報告書を作成してください。" & vbCrLf & _
             "形式:" & vbCrLf & _
             "1. サマリー(3行)" & vbCrLf & _
             "2. 主要指標" & vbCrLf & _
             "3. 考察" & vbCrLf & vbCrLf & _
             dataText

    report = CallOllama(prompt)
    reportWs.Range("A1").Value = report
End Sub

6. パフォーマンス最適化

バッチ処理

VBA
Sub BatchProcess()
    Dim ws As Worksheet
    Dim lastRow As Long
    Dim i As Long
    Dim batchSize As Long
    Dim startTime As Double

    batchSize = 10  ' 10件ずつ処理
    Set ws = ThisWorkbook.Sheets("データ")
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

    startTime = Timer
    Application.ScreenUpdating = False

    For i = 2 To lastRow Step batchSize
        ' バッチ処理
        ProcessBatch ws, i, WorksheetFunction.Min(i + batchSize - 1, lastRow)

        ' 進捗表示
        Application.StatusBar = "処理中... " & i & "/" & lastRow & _
                               " (" & Format((i / lastRow) * 100, "0") & "%)"
        DoEvents
    Next i

    Application.ScreenUpdating = True
    Application.StatusBar = False

    MsgBox "完了しました。処理時間: " & Format(Timer - startTime, "0.0") & "秒"
End Sub

Sub ProcessBatch(ws As Worksheet, startRow As Long, endRow As Long)
    Dim i As Long

    For i = startRow To endRow
        If Len(ws.Cells(i, 1).Value) > 0 And Len(ws.Cells(i, 2).Value) = 0 Then
            ws.Cells(i, 2).Value = AI_SUMMARIZE(ws.Cells(i, 1).Value)
        End If
    Next i
End Sub

キャッシュの活用

VBA
' 結果をキャッシュするDictionary
Dim CacheDict As Object

Sub InitCache()
    Set CacheDict = CreateObject("Scripting.Dictionary")
End Sub

Function CallOllamaWithCache(prompt As String) As String
    Dim cacheKey As String

    If CacheDict Is Nothing Then InitCache

    ' プロンプトをキーとしてキャッシュ
    cacheKey = Left(prompt, 100)  ' 先頭100文字をキーに

    If CacheDict.Exists(cacheKey) Then
        CallOllamaWithCache = CacheDict(cacheKey)
    Else
        Dim result As String
        result = CallOllama(prompt)
        CacheDict.Add cacheKey, result
        CallOllamaWithCache = result
    End If
End Function

7. エラーハンドリング

堅牢なAPI呼び出し

VBA
Function CallOllamaSafe(prompt As String) As String
    On Error GoTo ErrorHandler

    Dim http As Object
    Dim url As String
    Dim requestBody As String
    Dim response As String
    Dim retryCount As Integer

    retryCount = 0

RetryPoint:
    Set http = CreateObject("MSXML2.XMLHTTP")
    url = "http://localhost:11434/api/generate"
    requestBody = "{""model"":""qwen2.5"",""prompt"":""" & EscapeJson(prompt) & """,""stream"":false}"

    http.Open "POST", url, False
    http.setRequestHeader "Content-Type", "application/json"
    http.send requestBody

    If http.Status = 200 Then
        response = http.responseText
        CallOllamaSafe = ExtractResponse(response)
    Else
        Err.Raise vbObjectError + 1, , "HTTP Error: " & http.Status
    End If

    Set http = Nothing
    Exit Function

ErrorHandler:
    retryCount = retryCount + 1

    If retryCount <= 3 Then
        Application.Wait Now + TimeSerial(0, 0, 2)  ' 2秒待機
        Resume RetryPoint
    Else
        CallOllamaSafe = "エラー: " & Err.Description
        Set http = Nothing
    End If
End Function

接続チェック

VBA
Function IsOllamaRunning() As Boolean
    On Error GoTo NotRunning

    Dim http As Object
    Set http = CreateObject("MSXML2.XMLHTTP")

    http.Open "GET", "http://localhost:11434/api/tags", False
    http.send

    IsOllamaRunning = (http.Status = 200)
    Set http = Nothing
    Exit Function

NotRunning:
    IsOllamaRunning = False
End Function

Sub CheckAndProcess()
    If Not IsOllamaRunning() Then
        MsgBox "Ollamaが起動していません。" & vbCrLf & _
               "コマンドプロンプトで 'ollama serve' を実行してください。", _
               vbExclamation
        Exit Sub
    End If

    ' 処理を実行
    ClassifyAllData
End Sub

8. まとめ

Excel×AIの活用パターン

活用パターン
  • テキスト分類
  • 要約生成
  • 表記ゆれ統一
  • 感情分析
  • レポート生成

実装のポイント

1. Ollamaをインストール
2. VBAからHTTPリクエスト
3. エラーハンドリング
4. バッチ処理で効率化

注意点

注意点
  • 大量データは分割処理
  • キャッシュを活用
  • エラーハンドリング必須
  • 結果は必ず確認

関連記事

お問い合わせ

Excel×AI活用についてのご相談は、お気軽にお問い合わせください。

お問い合わせはこちら

最終更新: 2025年1月