Claude Code SDKで会話を継続する方法

Claude Code SDKで会話を継続する方法

2025.07.31

Introduction

最近はClaude Codeを毎日使い、毎日limitにひっかかっている私ですが、Claude Code SDKもよく使っています。

Claude Code SDKは、Anthropic社が提供するTypeScript/JavaScript向けのSDKです。(他にPython用もあり)
このSDKを使用することで、Claude Codeとの対話をプログラムから制御することができます。

ここの例のように、簡単に使うことができますが、
複数回にわたって対話を継続したいときもあります。

本記事では、複数回にわたって対話を継続させる方法について解説します。

Claude Code SDK?

Claude Code SDKは、Claudeとの対話をプログラマティックに制御するためのSDKです。

(実際のClaude Codeと同じく)セッション管理機能も持っており、
会話の文脈を保持しながら複数回のやり取りを行うことができます。
(resumeパラメータを使用すれば可能)

環境設定して動かしてみましょう。

Environment

  • Bun : 1.2.15〜
  • @anthropic-ai/code-sdk: 1.0.64

TypeScript実行環境があればNodeでもDenoでも問題ありません。

Setup

Claude Code SDKの実行環境をセットアップしましょう。

% mkdir path/your/examlpe && path/your/examlpe
% npm install @anthropic-ai/sdk
% touch run-simple-example.ts

Bunなら特に何も用意せずにtsは動作します。
Nodeとか使う場合は必要に応じてセットアップしてください。

APIキーの設定

Claude Code SDKを使うため、Claude APIキーを環境変数に設定します。

% export CLAUDE_API_KEY="your-api-key-here"

すでにclaude loginでログインしている場合、
その認証情報が、BunでSDKを実行する際も自動的に使用されるので、
その場合は環境変数なしでもOK。

Try

それでは、実際に継続会話を実装してみましょう。
SDKを使って複数回の対話をする場合、query関数を使うたびに
新しいセッションIDが生成されます。
このセッションIDを次の対話で指定することで、
いままでの文脈と履歴が引き継がれます。

実際の動作例

以下のような、シンプルな継続会話の実装を作成します。

2回目以降の対話ではresumeパラメータに前回の対話で
取得したsessionIdを指定します。

このsessionIdは対話するたびに新しいsessionIdを生成するので、
対話を続けるたびに最新に生成されたsessionIdを指定しなければいけません。

//run-simple-example.ts

import { query, SDKMessage, SDKAssistantMessage, SDKSystemMessage } from '@anthropic-ai/claude-code';

// デモ関数の実装
async function simpleDemo() {
  console.log('=== シンプルな継続会話デモ ===\n');
  const messages: SDKMessage[] = [];

  let sessionId: string | undefined = undefined;

  try {
    // 1. 最初の会話
    console.log('👤 ユーザー: プログラミングを始めたいのですが、何から勉強すればいいですか?');
    console.log('\n=== 1回目の対話 ===\n');

    for await (const message of query({
      prompt: 'プログラミングを始めたいのですが、何から勉強すればいいですか?',
      options: { maxTurns: 1 }
    })) {
      messages.push(message);

      // セッションIDを取得
      if (message.type === 'system' && 'session_id' in message) {
        sessionId = (message as SDKSystemMessage & { session_id: string }).session_id;
        console.log(`📝 セッションID: ${sessionId}`);
      }

      // アシスタントの応答を表示
      if (message.type === 'assistant') {
        const content = extractTextContent(message as SDKAssistantMessage);
        if (content) {
          console.log('\n🤖 Claude:');
          console.log(content.slice(0, 300) + (content.length > 300 ? '...' : ''));
          console.log('');
        }
      }
    }

    // 2. 会話を継続 - 最初のセッションIDを使用
    console.log('\n👤 ユーザー: どの言語がおすすめですか?');
    console.log('\n=== 2回目の対話(resumeオプション使用) ===\n');

    let sessionId2: string | undefined = undefined;

    for await (const message of query({
      prompt: 'どの言語がおすすめですか?',
      options: {
        maxTurns: 1,
        resume: sessionId  // 前のセッションIDを指定
      }
    })) {
      messages.push(message);

      // 新しいセッションIDを確認
      if (message.type === 'system' && 'session_id' in message) {
        sessionId2 = (message as SDKSystemMessage & { session_id: string }).session_id;
        console.log(`📝 新しいセッションID: ${sessionId2}`);
        console.log(`💡 セッションIDが変更されました: ${sessionId}${sessionId2}`);
      }

      // アシスタントの応答を表示
      if (message.type === 'assistant') {
        const content = extractTextContent(message as SDKAssistantMessage);
        if (content) {
          console.log('\n🤖 Claude:');
          console.log(content.slice(0, 300) + (content.length > 300 ? '...' : ''));
          console.log('');
        }
      }
    }

    // 3. 継続
    console.log('\n👤 ユーザー: その言語で、初心者向けの学習リソースを教えてください。');
    console.log('\n=== 3回目の対話(resumeオプション使用) ===\n');

    let sessionId3: string | undefined = undefined;

    for await (const message of query({
      prompt: 'その言語で、初心者向けの学習リソースを教えてください。',
      options: {
        maxTurns: 1,
        resume: sessionId2 || sessionId  // 最新のセッションIDを使用
      }
    })) {
      messages.push(message);

      // セッションIDを確認
      if (message.type === 'system' && 'session_id' in message) {
        sessionId3 = (message as SDKSystemMessage & { session_id: string }).session_id;
        console.log(`📝 最終セッションID: ${sessionId3}`);
      }

      // アシスタントの応答を表示
      if (message.type === 'assistant') {
        const content = extractTextContent(message as SDKAssistantMessage);
        if (content) {
          console.log('\n🤖 Claude:');
          console.log(content.slice(0, 300) + (content.length > 300 ? '...' : ''));
          console.log('');
        }
      }
    }

    // セッション情報のまとめ
    console.log('\n=== セッション継続の結果 ===');
    console.log(`総メッセージ数: ${messages.length}`);
    console.log('\nセッションIDの変化:');
    console.log(`1回目: ${sessionId}`);
    console.log(`2回目: ${sessionId2} ${sessionId !== sessionId2 ? '(新しいID生成)' : '(同じID)'}`);
    console.log(`3回目: ${sessionId3} ${sessionId2 !== sessionId3 ? '(新しいID生成)' : '(同じID)'}`);
  } catch (error) {
    console.error('\n❌ エラー:', error);
  }
}

function extractTextContent(message: SDKAssistantMessage): string | null {
  if (message.message?.content && Array.isArray(message.message.content)) {
    const textParts: string[] = [];
    for (const content of message.message.content) {
      if (content.type === 'text' && content.text) {
        textParts.push(content.text);
      }
    }
    return textParts.length > 0 ? textParts.join('\n') : null;
  }
  return null;
}

async function main() {
  try {
    await simpleDemo();
  } catch (error) {
    console.error('Failed to run demo:', error);
  }
}

main().catch(console.error);

動作確認

実装したコードを実行してみましょう。
以下のように、対話の文脈が維持されています。

% bun run run-simple-example.ts 

=== シンプルな継続会話デモ ===

👤 ユーザー: プログラミングを始めたいのですが、何から勉強すればいいですか?

=== 1回目の対話 ===

📝 セッションID: 58009e69-016d-4f67-b768-121ca2295950

🤖 Claude:
プログラミングを始めるなら、以下の順番がおすすめです:

1. **Python**から始める - 文法がシンプルで初心者に優しい
2. **基礎概念**を学ぶ - 変数、条件分岐、ループ、関数
3. **小さなプロジェクト**を作る - 電卓、ToDoリスト、簡単なゲーム
4. **Git/GitHub**を使えるようになる - コード管理の基本

👤 ユーザー: どの言語がおすすめですか?

=== 2回目の対話(resumeオプション使用) ===

📝 新しいセッションID: 9289416b-5c84-4a51-ae02-16e177fc824e
💡 セッションIDが変更されました: 58009e69-016d-4f67-b768-121ca2295950 → 9289416b-5c84-4a51-ae02-16e177fc824e

🤖 Claude:
目的によって異なりますが、初心者には**Python**が最もおすすめです。

**目的別のおすすめ言語:**
- **初心者/汎用** → Python(AI、データ分析、Web、自動化)
- **Web開発** → JavaScript(必須)+ HTML/CSS
- **スマホアプリ** → Swift(iOS)、Kotlin(Android)
- **ゲーム開発** → C#(Unity)、C++(高性能ゲーム)
- **システム開発** → Java、C#(企業向け)

**Pythonを最初に選ぶ理由:**
1. 文法が読みやすく直感的
2. エラーメッセージが分かりやすい
3. ...

👤 ユーザー: その言語で、初心者向けの学習リソースを教えてください。

=== 3回目の対話(resumeオプション使用) ===

📝 最終セッションID: 7456e532-8cff-468c-843a-14f0b3c6adcc

🤖 Claude:
**Python初心者向けの学習リソース:**

**無料リソース:**
1. **[Python公式チュートリアル](https://docs.python.org/ja/3/tutorial/)** - 公式の日本語解説
2. **[Progate Python講座](https://prog-8.com/courses/python)** - ブラウザで実行できる
3. **[paizaラーニング](https://paiza.jp/works)** - 動画で学べる、演習問題付き
4. **[Python-izm](https://www.python-izm.com/)** - 日本...

=== セッション継続の結果 ===
総メッセージ数: 9

セッションIDの変化:
1回目: 58009e69-016d-4f67-b768-121ca2295950
2回目: 9289416b-5c84-4a51-ae02-16e177fc824e (新しいID生成)
3回目: 7456e532-8cff-468c-843a-14f0b3c6adcc (新しいID生成)

Summary

Claude Code SDKで継続会話を実現する際は、SDKが毎回新しいセッションIDを生成することに留意し、適切に管理することが重要です。
実際のシステムでは、sessionIdを永続化する必要があるかと思います。

References

この記事をシェアする

facebookのロゴhatenaのロゴtwitterのロゴ

© Classmethod, Inc. All rights reserved.