PowerShell × Ollama：日本語対応と会話履歴管理の実装

## はじめに

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/88e0cb93-3674-48d7-95cc-385a921b4868.png)

OllamaはローカルでLLMを実行できる素晴らしいツールですが、PowerShellから使う際に文字化けやセッション管理で困ったことはありませんか？

本記事では、PowerShellでOllamaを快適に使うための実用的なスクリプトを紹介します。日本語対応、会話履歴管理、複数セッション対応など、機能を盛り込みました。

## 主な機能

- 日本語文字化け完全対策
- 会話履歴の自動保存
- 複数セッション管理
- パイプライン対応
- 簡単な初期化とセットアップ

## 前提条件

筆者の動作確認の環境
- PowerShell 5.1以上
- Ollama がインストール済み
- お好みのモデル（例：gemma3, llama3など）

## スクリプトの構成

### 1. 初期化処理

まずはOllamaの設定を初期化します。文字化け対策も含まれています。

```powershell
function Initialize-Ollama {
    [CmdletBinding()]
    param(
        [string]$BaseUri = "http://localhost:11434",
        [string]$DefaultModel = "gemma3",
        [string]$DefaultSystemPrompt = "あなたは敬語で話すAIアシスタントです。日本語で質問された場合は、必ず日本語で回答してください。"
    )
    
    # PowerShellコンソールの文字化け対策
    try {
        # PowerShell 5.1以前とPowerShell Core/7の違いを考慮
        if ($PSVersionTable.PSVersion.Major -ge 6) {
            # PowerShell Core/7の場合
            $PSDefaultParameterValues['*:Encoding'] = 'utf8'
        } else {
            # PowerShell 5.1以前の場合、コンソールが利用可能かチェック
            if ([System.Console]::IsOutputRedirected -eq $false) {
                [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
            }
            if ([System.Console]::IsInputRedirected -eq $false) {
                [Console]::InputEncoding = [System.Text.Encoding]::UTF8
            }
            $PSDefaultParameterValues['*:Encoding'] = 'utf8'
        }
    }
    catch {
        Write-Warning "エンコーディング設定に問題がありました: $($_.Exception.Message)"
        Write-Host "継続して処理を実行します。" -ForegroundColor Yellow
    }
    
    # グローバル変数の初期化
    $Global:OllamaConfig = @{
        BaseUri = $BaseUri
        ChatEndpoint = "$BaseUri/api/chat"
        DefaultModel = $DefaultModel
        DefaultSystemPrompt = $DefaultSystemPrompt
    }
    
    # セッション管理用のハッシュテーブルも初期化
    $Global:OllamaSessions = @{}
    
    Write-Host "Ollama設定を初期化しました。" -ForegroundColor Green
    Write-Host "- BaseUri: $($Global:OllamaConfig.BaseUri)" -ForegroundColor Gray
    Write-Host "- DefaultModel: $($Global:OllamaConfig.DefaultModel)" -ForegroundColor Gray
    Write-Host "- セッション管理: 初期化完了" -ForegroundColor Gray
}
```

### 2. セッション管理

複数の会話セッションを管理できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/adee7461-05e9-49ca-bfbb-755e601febc6.png)

```powershell
function New-OllamaSession {
    [CmdletBinding()]
    param(
        [string]$SystemPrompt,
        [string]$Model,
        [string]$SessionName = "default"
    )
    
    if (-not $SystemPrompt) { $SystemPrompt = $Global:OllamaConfig.DefaultSystemPrompt }
    if (-not $Model) { $Model = $Global:OllamaConfig.DefaultModel }
    
    $session = @{
        Name = $SessionName
        Model = $Model
        Messages = @(@{ role = "system"; content = $SystemPrompt })
        CreatedAt = Get-Date
    }
    
    if (-not $Global:OllamaSessions) {
        $Global:OllamaSessions = @{}
    }
    $Global:OllamaSessions[$SessionName] = $session
    
    Write-Host "新しいセッション '$SessionName' を作成しました。" -ForegroundColor Green
    return $session
}
```

### 3. メッセージ送信

メインの処理です。文字化け対策を施したAPI呼び出しを行います。

```mermaid
flowchart TD
    A[👤 ユーザー入力<br/>Send-OllamaMessage<br/>-Message こんにちは<br/>-SessionName cooking] --> B{🔍 セッション確認<br/>SessionName exists?}
    
    B -->|No| C[🆕 新規セッション作成<br/>New-OllamaSession]
    B -->|Yes| D[📋 セッション取得<br/>履歴・モデル設定読み込み]
    C --> D
    
    D --> E[➕ メッセージ追加<br/>ユーザーメッセージを<br/>セッション履歴に追加<br/>role: user]
    
    E --> F[📦 JSON作成<br/>APIリクエスト用<br/>データ構築<br/>UTF-8エンコード]
    
    F --> G[🌐 Ollama API呼び出し<br/>POST /api/chat<br/>Content-Type: application/json; charset=utf-8]
    
    G -->|Success| H[📨 レスポンス受信<br/>AIの回答を取得]
    G -->|Error| I[⚠️ エラーハンドリング<br/>追加メッセージ削除<br/>エラー詳細表示]
    
    H --> J[💾 履歴更新<br/>AIレスポンスを<br/>セッション履歴に追加<br/>role: assistant]
    
    J --> K[📤 結果返却<br/>ユーザーに回答返却<br/>UTF-8で正常表示<br/>✅ 完了]
    
    I --> L[❌ エラー返却<br/>null を返却]
    
    %% スタイリング
    classDef inputBox fill:#e3f2fd,stroke:#1976d2,stroke-width:2px,color:#333
    classDef processBox fill:#fff3e0,stroke:#f57c00,stroke-width:2px,color:#333
    classDef apiBox fill:#e8f5e8,stroke:#4caf50,stroke-width:2px,color:#333
    classDef outputBox fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,color:#333
    classDef errorBox fill:#ffebee,stroke:#f44336,stroke-width:2px,color:#333
    classDef decisionBox fill:#f0f4c3,stroke:#827717,stroke-width:2px,color:#333
    
    class A inputBox
    class B decisionBox
    class C,D,E,F processBox
    class G,H apiBox
    class J,K outputBox
    class I,L errorBox
```

```powershell
function Send-OllamaMessage {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Message,
        [string]$SessionName = "default",
        [string]$Model,
        [switch]$NewSession
    )
    
    # セッション取得/作成
    if ($NewSession) {
        New-OllamaSession -SessionName $SessionName -Model $Model | Out-Null
    }
    
    $session = $Global:OllamaSessions[$SessionName]
    if (-not $session) {
        $session = New-OllamaSession -SessionName $SessionName -Model $Model
    }
    
    # ユーザーメッセージを追加
    $session.Messages += @{ role = "user"; content = $Message }
    
    try {
        # UTF-8エンコーディングでAPI呼び出し
        $body = @{
            model = $session.Model
            stream = $false
            messages = $session.Messages
        } | ConvertTo-Json -Depth 3
        
        $bodyBytes = [System.Text.Encoding]::UTF8.GetBytes($body)
        
        $response = Invoke-RestMethod `
            -Uri $Global:OllamaConfig.ChatEndpoint `
            -Method Post `
            -Body $bodyBytes `
            -ContentType "application/json; charset=utf-8" `
            -Headers @{ "Accept-Charset" = "utf-8" }
        
        $aiResponse = $response.message.content
        $session.Messages += @{ role = "assistant"; content = $aiResponse }
        $Global:OllamaSessions[$SessionName] = $session
        
        return $aiResponse
    }
    catch {
        Write-Error "Ollama APIの呼び出しに失敗しました: $($_.Exception.Message)"
        $session.Messages = $session.Messages[0..($session.Messages.Count - 2)]
        return $null
    }
}
```

### 4. パイプライン対応

PowerShellらしいパイプライン処理にも対応しています。

```powershell
function Invoke-OllamaChat {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline = $true, Position = 0)]
        [string]$Message,
        [string]$SessionName = "default"
    )
    
    process {
        return Send-OllamaMessage -Message $Message -SessionName $SessionName
    }
}
```

## 使用例
手持ちのミニPC(Windows）で試した例 モデルはgemma

### 基本的な使い方

```powershell
# 1. 初期化（セッション開始時に一度だけ）
Initialize-Ollama

# 2. 基本的な質問
$response = Send-OllamaMessage -Message "こんにちは、今日の天気はどうですか？"
Write-Host "AI: $response"

# 3. パイプライン使用
"PowerShellの配列操作について教えて" | Invoke-OllamaChat
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/877a0113-7e7d-4774-97bf-1425ee39e295.png)

### 複数セッションの活用

```powershell
# 料理専用セッション
New-OllamaSession -SessionName "cooking" -SystemPrompt "あなたは料理に詳しいAIです。レシピや調理法について丁寧に説明してください。"

# プログラミング専用セッション  
New-OllamaSession -SessionName "coding" -SystemPrompt "あなたはプログラミングの専門家です。"

# それぞれのセッションで会話
"今日の夕食におすすめの料理は？" | Invoke-OllamaChat -SessionName "cooking"
"PowerShellの効率的な書き方を教えて" | Invoke-OllamaChat -SessionName "coding"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/4f36de7b-977e-43cb-800e-10ce76373e09.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/6c78ced4-d235-4822-907d-8457995fa39d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/b39c5032-a5af-42b7-ac2e-edf6bd45c9f6.png)

### 会話履歴の管理

```powershell
# セッション一覧を表示
Get-OllamaSession

# 特定のセッションの履歴を表示
Show-OllamaHistory -SessionName "cooking" -Last 4

# セッションをクリア
Clear-OllamaSession -SessionName "cooking"
```

### 連続会話の例

```powershell
"こんにちは" | Invoke-OllamaChat
"簡単に作れる和食を教えて" | Invoke-OllamaChat  
"材料と手順を詳しく教えて" | Invoke-OllamaChat
```

### システムプロンプトの例

```powershell
# 技術文書作成専用
$techWriterPrompt = "あなたは技術文書作成の専門家です。明確で分かりやすい説明を心がけ、コード例も含めて回答してください。"

# 翻訳専用
$translatorPrompt = "あなたは英日翻訳の専門家です。自然で読みやすい日本語に翻訳してください。"

New-OllamaSession -SessionName "tech-writer" -SystemPrompt $techWriterPrompt
New-OllamaSession -SessionName "translator" -SystemPrompt $translatorPrompt
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/b4bc705a-c567-4be3-a97b-12949def238e.png)

## まとめ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/2fbadd33-faca-4214-90d3-b38b7d5dee42.png)

このスクリプトを使うことで、PowerShellからOllamaを快適に使用できるようになります。特に：

- 日本語での会話が文字化けしない
- 複数の用途に応じたセッション管理
- PowerShellらしいパイプライン処理
- 会話履歴の自動保存

などの機能により、開発効率が大幅に向上します。

## 注意事項

会話履歴の制限について
このスクリプトは会話履歴を自動保存しますが、各LLMモデルには処理可能な最大トークン数（コンテキスト長）の制限があります。この制限を超えるとモデルが適切に応答できなくなったり、エラーが発生する可能性があります。長時間の会話では期待通りに動作しなくなる場合があるため、適度なタイミングで新しいセッションを作成するか、履歴をクリアすることをお勧めします。

## 参考リンク

- [Ollama公式サイト](https://ollama.ai/)
- [Ollama API Documentation](https://github.com/ollama/ollama/blob/main/docs/api.md)
- [PowerShell Documentation](https://docs.microsoft.com/en-us/powershell/)