ブログ

  • Docker ComposeでNode.js + PostgreSQL環境を5分で構築する

    開発環境の構築は地味に時間がかかる作業です。Docker Composeを使えば、Node.jsアプリケーションとPostgreSQLデータベースを含む開発環境を、たった1コマンドで立ち上げることができます。

    前提条件

    • Docker Desktop がインストール済み
    • docker compose コマンドが使える状態

    プロジェクト構成

    my-app/
    ├── docker-compose.yml
    ├── Dockerfile
    ├── package.json
    ├── src/
    │   └── index.js
    └── .env

    docker-compose.yml

    version: "3.8"
    services:
      app:
        build: .
        ports:
          - "3000:3000"
        environment:
          - DATABASE_URL=postgresql://myuser:mypass@db:5432/mydb
          - NODE_ENV=development
        volumes:
          - ./src:/app/src
        depends_on:
          db:
            condition: service_healthy
    
      db:
        image: postgres:16-alpine
        environment:
          POSTGRES_USER: myuser
          POSTGRES_PASSWORD: mypass
          POSTGRES_DB: mydb
        ports:
          - "5432:5432"
        volumes:
          - pgdata:/var/lib/postgresql/data
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U myuser -d mydb"]
          interval: 5s
          timeout: 5s
          retries: 5
    
    volumes:
      pgdata:

    Dockerfile

    FROM node:20-alpine
    WORKDIR /app
    COPY package*.json ./
    RUN npm ci
    COPY src/ ./src/
    EXPOSE 3000
    CMD ["node", "src/index.js"]

    Node.jsアプリケーション

    // src/index.js
    const { Pool } = require("pg");
    const http = require("http");
    
    const pool = new Pool({
      connectionString: process.env.DATABASE_URL,
    });
    
    const server = http.createServer(async (req, res) => {
      try {
        const result = await pool.query("SELECT NOW() as current_time");
        res.writeHead(200, { "Content-Type": "application/json" });
        res.end(JSON.stringify({
          message: "Hello from Docker!",
          db_time: result.rows[0].current_time,
        }));
      } catch (err) {
        res.writeHead(500);
        res.end(JSON.stringify({ error: err.message }));
      }
    });
    
    server.listen(3000, () => {
      console.log("Server running on port 3000");
    });

    起動と確認

    # ビルド&起動
    docker compose up -d
    
    # ログ確認
    docker compose logs -f app
    
    # 動作確認
    curl http://localhost:3000

    開発時のTips

    • volumesでsrcディレクトリをマウントしておけば、ファイル変更が即座に反映されます(nodemonと組み合わせると便利)
    • healthcheckを設定しておくと、DBが起動する前にアプリが接続しようとするエラーを防げます
    • PostgreSQLのデータはnamed volumeに保存されるので、コンテナを再作成してもデータは消えません

    まとめ

    Docker Composeを使えば、チームメンバー全員が同じ環境で開発できます。新メンバーのオンボーディングも「git cloneしてdocker compose up」だけで完了。環境差異によるトラブルから解放されます。

  • OpenAI Function Callingの実装ガイド:AIに外部ツールを使わせる

    OpenAIのFunction Calling(関数呼び出し)機能を使うと、AIが外部APIやデータベースと連携して、リアルタイムの情報を取得できるようになります。天気予報の取得、商品検索、データベースクエリなど、実践的なユースケースを解説します。

    Function Callingとは

    Function Callingは、GPT-4やGPT-4oに「使える関数」を定義しておくと、ユーザーの質問に応じて適切な関数を呼び出してくれる機能です。AIが直接関数を実行するのではなく、「この関数をこの引数で呼んでください」という指示を返します。

    基本的な実装

    商品検索を例に実装してみましょう。

    from openai import OpenAI
    import json
    
    client = OpenAI()
    
    # 利用可能な関数を定義
    tools = [
        {
            "type": "function",
            "function": {
                "name": "search_products",
                "description": "商品データベースからキーワードで商品を検索する",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "keyword": {
                            "type": "string",
                            "description": "検索キーワード(例: 赤いTシャツ)"
                        },
                        "max_price": {
                            "type": "integer",
                            "description": "最大価格(円)"
                        }
                    },
                    "required": ["keyword"]
                }
            }
        }
    ]
    
    # 実際の検索関数
    def search_products(keyword, max_price=None):
        # 本番ではDBクエリを実行
        products = [
            {"name": "赤いTシャツ", "price": 2980},
            {"name": "青いTシャツ", "price": 3480},
        ]
        if max_price:
            products = [p for p in products if p["price"] <= max_price]
        return [p for p in products if keyword in p["name"]]

    AIとの対話フロー

    Function Callingの対話は3ステップで進みます。

    # Step 1: ユーザーの質問をAIに送信
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": "3000円以下の赤いTシャツはありますか?"}],
        tools=tools,
    )
    
    # Step 2: AIが関数呼び出しを要求
    tool_call = response.choices[0].message.tool_calls[0]
    args = json.loads(tool_call.function.arguments)
    # args = {"keyword": "赤いTシャツ", "max_price": 3000}
    
    # Step 3: 関数を実行して結果をAIに返す
    result = search_products(**args)
    final_response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "user", "content": "3000円以下の赤いTシャツはありますか?"},
            response.choices[0].message,
            {"role": "tool", "tool_call_id": tool_call.id, "content": json.dumps(result, ensure_ascii=False)}
        ],
        tools=tools,
    )
    print(final_response.choices[0].message.content)

    複数関数の定義

    実際のアプリケーションでは複数の関数を定義し、AIに状況に応じて使い分けてもらいます。商品検索に加えて、注文状況の確認や在庫確認なども追加できます。AIは質問の内容から最適な関数を自動で選択します。

    注意点とベストプラクティス

    • 関数のdescriptionは詳しく書く。AIはこれを見て関数を選択します
    • パラメータのdescriptionも具体例を含めると精度が上がります
    • AIが不要な関数呼び出しをしないよう、tool_choice パラメータで制御可能
    • 関数の実行結果は構造化されたJSONで返すと、AIの応答品質が向上します

    まとめ

    Function Callingを使うことで、AIは単なるテキスト生成を超えて、実際のデータやサービスと連携する強力なアシスタントになります。ECサイトの商品検索、カスタマーサポート、社内ツールの自動化など、応用範囲は広大です。

  • Claude APIとPythonで作るAIチャットボット入門

    Anthropic社のClaude APIを使って、Pythonで動作するAIチャットボットを作成する方法を解説します。2024年以降、ClaudeはGPT-4oと並ぶ高性能LLMとして注目を集めています。

    Claude APIとは

    Claude APIは、Anthropic社が提供する大規模言語モデル(LLM)のAPIです。ChatGPTのOpenAI APIと同様に、HTTPリクエストでAIとの対話が可能です。特にClaude 3.5 Sonnetは、コーディング支援や長文処理において高い性能を発揮します。

    環境構築

    まずAnthropicの公式サイトでAPIキーを取得し、Pythonの環境を準備します。

    pip install anthropic
    export ANTHROPIC_API_KEY="your-api-key-here"

    基本的なチャットボットの実装

    以下がClaude APIを使った最もシンプルなチャットボットの実装です。

    import anthropic
    
    client = anthropic.Anthropic()
    
    def chat(user_message: str) -> str:
        message = client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=1024,
            messages=[
                {"role": "user", "content": user_message}
            ]
        )
        return message.content[0].text
    
    # 対話ループ
    while True:
        user_input = input("You: ")
        if user_input.lower() in ["quit", "exit"]:
            break
        response = chat(user_input)
        print(f"Claude: {response}")

    会話履歴を保持する

    実用的なチャットボットでは、会話の文脈を保持する必要があります。messagesリストに過去のやり取りを蓄積することで実現できます。

    class ChatBot:
        def __init__(self, system_prompt="あなたは親切なアシスタントです。"):
            self.client = anthropic.Anthropic()
            self.system = system_prompt
            self.messages = []
    
        def send(self, user_message: str) -> str:
            self.messages.append({"role": "user", "content": user_message})
            response = self.client.messages.create(
                model="claude-sonnet-4-20250514",
                max_tokens=2048,
                system=self.system,
                messages=self.messages
            )
            assistant_msg = response.content[0].text
            self.messages.append({"role": "assistant", "content": assistant_msg})
            return assistant_msg
    
    bot = ChatBot("あなたはPythonプログラミングの専門家です。")
    print(bot.send("リスト内包表記について教えてください"))
    print(bot.send("具体例をもう少し見せてください"))

    エラーハンドリング

    本番環境ではレート制限やネットワークエラーへの対策が必要です。anthropicライブラリは自動リトライ機能を備えていますが、明示的なエラーハンドリングも重要です。

    import anthropic
    from anthropic import RateLimitError, APIConnectionError
    
    try:
        response = client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=1024,
            messages=[{"role": "user", "content": "Hello"}]
        )
    except RateLimitError:
        print("レート制限に達しました。しばらく待ってから再試行してください。")
    except APIConnectionError:
        print("API接続エラー。ネットワーク状態を確認してください。")

    まとめ

    Claude APIは直感的なインターフェースで、少ないコード量でAIチャットボットを構築できます。次回はFunction Callingを活用した、外部データベースと連携するチャットボットの作り方を紹介します。

IP: 取得中...
216.73.216.31216.73.216.31