🍎

対話型AIはどれがいい?

2024/07/25に公開

はじめに

以前の職場ではAIを使っていると、「AIは間違った回答が来るし、何より身にならない。公式ドキュメントだけ見るように。」と怒られていたのですが今ではわりと使っています。
その中で、chatGPTよりgeminiの方がいい!やclaudeが~などを聞くので結局どれがいいのかと思い調べてみました。

今回比較するAI

  • ChatGPT

https://chatgpt.com/

  • Gemini

https://gemini.google.com/

  • Claude

https://claude.ai/

比べてみた

今回は三つの質問をしてみました。

ユーザー登録をするapiで、idが重複している時に返すステータスコードは何にすればいい?

ChatGPTの回答

ユーザー登録をするAPIでIDが重複している場合に返すステータスコードとしては、一般的に 409 Conflict を使用します。このステータスコードは、リクエストが現在のリソースと競合することを示すために使用されます。

以下は、ID重複エラーの例を示すレスポンスの一例です:

{
  "status": 409,
  "error": "Conflict",
  "message": "The user ID already exists."
}

これにより、クライアントはリクエストが処理できなかった理由を理解し、適切な対処ができるようになります。

Geminiの回答

ユーザー登録APIでIDが重複した場合のステータスコード
ユーザー登録APIにおいて、IDが重複した場合に返す適切なステータスコードは、状況やAPI設計によって異なりますが、一般的には以下のいずれかが使用されます。

409 Conflict (コンフリクト)

  • 最も一般的な選択肢: リクエストが有効であっても、現在の状態では実行できないことを示します。
  • 理由: IDは一意であるべきという制約に違反しているため、リクエストは衝突している状態となります。
  • メリット:
    • 標準的なステータスコードであり、多くのクライアントが理解しやすい。
    • リクエストが不正であるという明確な信号を送ることができる。

422 Unprocessable Entity (処理不能なエンティティ)

  • 詳細なエラーメッセージが必要な場合: リクエストの構文は正しいが、セマンティックに正しくないことを示します。
  • 理由: 送信されたデータが、サーバー側のバリデーションルールに違反しているため、処理できません。
  • メリット:
    • クライアントに、具体的にどの部分が不正なのかを伝えることができる。
    • バリデーションエラーと重複エラーを区別したい場合に有効。

カスタムステータスコード

  • 独自のエラーコードを定義したい場合:
    • 4xx系のステータスコードで、より詳細なエラー情報を返すことができます。
    • 例えば、409.1 DuplicateUserId など。
  • メリット:
    • APIの独自性を高めることができる。
    • クライアント側でより詳細なエラー処理を行うことができる。

どのステータスコードを選ぶべきか?

  • APIの設計方針: API全体でどのレベルの詳細なエラー情報を返すか、によって選択が変わります。
  • クライアント側の処理: クライアント側でどのようなエラー処理を行うか、によって選択が変わります。
  • エラーメッセージ: どの程度の詳細なエラーメッセージを返すか、によって選択が変わります。
    一般的には、409 Conflict が最もシンプルかつ一般的な選択肢です。 しかし、クライアントに詳細なエラー情報を提供したい場合は、422 Unprocessable Entity やカスタムステータスコードも検討できます。

その他

  • エラーメッセージ: ステータスコードとともに、具体的なエラーメッセージを返すことで、クライアント側でのデバッグを容易にします。
  • エラーの詳細: 可能であれば、エラーの詳細な情報をJSON形式などで返すことで、クライアント側でより適切な処理を行うことができます。
  • APIドキュメント: APIドキュメントに、各ステータスコードの意味と、どのような状況で返されるのかを明確に記載しておくことが重要です。
    例 (JSON形式)
{
  "error": "duplicate_user_id",
  "message": "The specified user ID already exists."
}

コードは注意してご使用ください。

まとめ
ID重複エラーに対するステータスコードの選択は、API設計の全体的な方針や、クライアント側の要件に合わせて慎重に行う必要があります。適切なステータスコードを選択することで、APIの信頼性と使いやすさを向上させることができます。

ご不明な点があれば、お気軽にご質問ください。

より詳しい情報が必要な場合は、以下の点について教えていただけると、より適切な回答をすることができます。

使用しているプログラミング言語: (例: Python, Ruby, Javaなど)

  • Webフレームワーク: (例: Django, Rails, Springなど)
  • データベース: (例: MySQL, PostgreSQLなど)
  • APIの設計方針: (例: RESTful API, GraphQLなど)
  • クライアント側の技術: (例: JavaScript, Reactなど)
    どのような状況でIDが重複する可能性があるのか、具体的なユースケースを教えていただけると、より具体的なアドバイスができます。
Claudeの回答

ユーザー登録APIでIDが重複している場合、一般的には以下のステータスコードを返すことが適切です:

409 Conflict

409 Conflictは、リクエストが現在のサーバーの状態と競合する場合に使用されます。ユーザーIDの重複は、まさにこのケースに該当します。
このステータスコードを使用する理由:

1.リソース(この場合はユーザーID)が既に存在することを明確に示します。
2.クライアントに対して、リクエストが処理できなかった具体的な理由を伝えます。
3.RESTful APIの設計原則に沿っています。

レスポンスボディには、エラーの詳細な説明を含めることをお勧めします。例えば:

{
  "error": "User ID already exists",
  "message": "The provided user ID is already in use. Please choose a different ID."
}

他の選択肢として考えられるステータスコード:

  • 400 Bad Request: リクエストが不正である場合に使用しますが、409ほど具体的ではありません。
  • 422 Unprocessable Entity: リクエストの構文は正しいが、セマンティックエラーがある場合に使用します。IDの重複もこれに該当する可能性がありますが、409の方がより適切です。

このAPIの実装や他のエラーケースの処理について、さらに詳しい情報が必要ですか?

reactで入力された文字をコメント投稿のAPIに送信するコードを書いて

ChatGPTの回答

Reactで入力された文字をコメント投稿のAPIに送信するコードの例を以下に示します。この例では、Reactの状態管理を使ってフォーム入力を管理し、フォームが送信されたときにAPIにコメントを送信します。

必要なパッケージをインストール
最初に、axiosを使用してAPIリクエストを行うために、パッケージをインストールします。

npm install axios

React コンポーネントの作成
以下は、コメント投稿フォームを持つReactコンポーネントの例です。

import React, { useState } from 'react';
import axios from 'axios';

const CommentForm = () => {
  const [comment, setComment] = useState('');
  const [status, setStatus] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();
    setStatus('Sending...');

    try {
      const response = await axios.post('https://api.example.com/comments', { comment });
      setStatus('Comment submitted successfully!');
      setComment(''); // Clear the input field
    } catch (error) {
      setStatus('Failed to submit comment.');
      console.error('There was an error submitting the comment:', error);
    }
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <label htmlFor="comment">Comment:</label>
        <textarea
          id="comment"
          value={comment}
          onChange={(e) => setComment(e.target.value)}
          required
        />
        <button type="submit">Submit</button>
      </form>
      {status && <p>{status}</p>}
    </div>
  );
};

export default CommentForm;

説明

  1. 状態の管理:
  • useStateフックを使って、コメント入力(comment)と送信ステータス(status)を管理します。
  1. フォームの送信処理:
  • フォームが送信されると、handleSubmit関数が呼び出されます。
  • e.preventDefault()を呼び出して、デフォルトのフォーム送信動作(ページのリロード)を防ぎます。
  • コメントをAPIに送信するために、axios.postを使います。送信が成功した場合、ステータスを更新し、コメント入力をクリアします。失敗した場合、エラーメッセージを表示します。
  1. フォームのレンダリング:
  • コメント入力フィールドとしてtextareaを使用し、送信ボタンを追加します。
  • ステータスメッセージを表示するために、status状態を表示します。

この例では、コメントを送信するAPIエンドポイントとしてhttps://api.example.com/commentsを使用しています。実際のプロジェクトでは、適切なAPIエンドポイントに置き換えてください。

Geminiの回答

Reactで入力された文字をコメント投稿のAPIに送信するコード
概要
Reactで入力された文字を、コメント投稿のAPIに送信するコードの例を以下に示します。この例では、以下の機能を実装しています。

  • 入力フォーム: ユーザーがコメントを入力するためのテキストエリア
  • 送信ボタン: 入力されたコメントをAPIに送信するボタン
  • APIリクエスト: Fetch APIを用いて、入力されたコメントをAPIのエンドポイントにPOSTリクエストで送信
  • エラー処理: APIリクエストが失敗した場合のエラー表示

コード例

import React, { useState } from 'react';

function CommentForm() {
  const [comment, setComment] = useState('');
  const [error, setError] = useState(null);

  const handleSubmit = async (event) => {
    event.preventDefault();

    // APIのエンドポイント
    const apiUrl = 'https://your-api-endpoint/comments';

    try {
      const response = await fetch(apiUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ comment }),
      });

      if (!response.ok) {
        throw new Error('コメントの投稿に失敗しました');
      }

      // 成功時の処理 (例: フォームのリセット)
      setComment('');
      console.log('コメントが投稿されました');
    } catch (error) {
      setError(error.message);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <textarea value={comment} onChange={(e) => setComment(e.target.value)} />
      <button type="submit">投稿</button>
      {error && <p>{error}</p>}
    </form>
  );
}

export default CommentForm;

コードは注意してご使用ください。

コード解説

  1. useState: コメントの入力状態とエラーメッセージの状態を管理するために、useStateフックを使用しています。

  2. handleSubmit: フォーム送信時のイベントハンドラーです。

  • fetch APIを使用して、APIエンドポイントにPOSTリクエストを送信します。
  • headersでContent-Typeを指定し、bodyにJSON形式でコメントデータを含めます。
  • レスポンスが成功した場合、コメントをリセットし、成功メッセージを表示します。
  • レスポンスが失敗した場合、エラーメッセージを表示します。
  1. JSX: 入力フォーム、送信ボタン、エラーメッセージを表示するためのJSXを返します。
    注意点
  • APIエンドポイント: apiUrlの部分には、実際のコメント投稿APIのエンドポイントを置き換えてください。
  • エラー処理: エラーが発生した場合の処理は、この例では単純なエラーメッセージ表示ですが、実際のアプリケーションでは、より詳細なエラー処理が必要になる場合があります。
  • セキュリティ: ユーザーが入力したデータをそのままAPIに送信する場合は、XSSなどのセキュリティリスクに注意する必要があります。適切なサニタイジング処理を行うか、バックエンド側で入力値のバリデーションを行うようにしましょう。
  • 状態管理: より複雑なアプリケーションでは、ReduxやContext APIなどの状態管理ライブラリを使用することで、状態管理をより効率的に行うことができます。

その他

  • バリデーション: コメントの長さや内容に対してバリデーションを行うことができます。
  • 非同期処理: async/awaitを使用することで、非同期処理をより簡潔に記述できます。
  • フォームライブラリ: FormikやReact Hook Formなどのフォームライブラリを使用することで、フォームの管理をより楽に行うことができます。

実装のポイント

  • ユーザーエクスペリエンス: エラーメッセージを表示したり、送信中の状態を可視化したりすることで、ユーザーエクスペリエンスを向上させることができます。
  • テスト: ユニットテストや統合テストを行うことで、コードの品質を確保することができます。
    このコードをベースに、あなたのアプリケーションに合わせたカスタマイズを行ってください。

何か他に質問はありますか?

  • APIの認証方法について知りたい
  • フォームのバリデーションについて詳しく知りたい
  • エラーハンドリングをもっと詳しく知りたい

...
上記以外にも、ReactやAPIに関する質問があればお気軽にご質問ください。

Claudeの回答

Reactで入力された文字をコメント投稿のAPIに送信するコードを書きます。以下は基本的な実装例です:

import React, { useState } from 'react';
import axios from 'axios';

function CommentForm() {
  const [comment, setComment] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      const response = await axios.post('https://api.example.com/comments', { comment });
      console.log('Comment posted successfully:', response.data);
      setComment(''); // 投稿後、入力欄をクリア
    } catch (error) {
      console.error('Error posting comment:', error);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <textarea
        value={comment}
        onChange={(e) => setComment(e.target.value)}
        placeholder="コメントを入力してください"
      />
      <button type="submit">投稿</button>
    </form>
  );
}

export default CommentForm;

このコードについて説明や詳細な解説が必要ですか?

以下のコードとエラー文が出たから修正してほしい

const [text, setText] = useState("test");
setText(100);
型 'number' の引数を型 'SetStateAction<string>' のパラメーターに割り当てることはできません。

ChatGPTの回答

このエラーは、useStateで初期化した状態の型がstringであるため、setTextにnumber型の引数を渡すことができないことに起因しています。状態の型を正しく保つためには、setTextにはstring型の引数を渡す必要があります。

修正方法としては、setTextに渡す引数をstring型にするか、初期化時にuseStateの型を指定して状態がstring | number型を受け付けるようにする方法があります。

方法 1: setTextに文字列を渡す

const [text, setText] = useState("test");
setText("100");  // 文字列を渡す

方法 2: 状態をstring | number型にする

const [text, setText] = useState<string | number>("test");
setText(100);  // 数値を渡すことができる

使用例に応じて適切な方法を選んでください。もし状態が常に文字列であるべきなら、方法 1 を、状態が文字列と数値の両方を受け付ける必要があるなら、方法 2 を選択してください。

Geminiの回答

エラーの原因と修正方法

エラー内容の解説
「型 'number' の引数を型 'SetStateAction<string>' のパラメーターに割り当てることはできません。」というエラーは、ReactのuseStateフックで管理している状態変数textがstring型であるにも関わらず、数値の100を代入しようとしているために発生しています。

修正方法
useStateフックで設定した状態変数は、一度設定した型を変更することはできません。textがstring型であるため、setText関数には文字列を渡す必要があります。

const [text, setText] = useState("test");

// 数値を文字列に変換して代入
setText("100");

コードは注意してご使用ください。

より詳細な解説

  • useStateフック: Reactで状態を管理するためのフックです。useStateで初期値を設定すると、その型の変数と、その変数を更新するための関数が返されます。
  • SetStateAction: setTextのような状態更新関数に渡すことができる引数の型です。この場合、textがstring型なので、SetStateAction<string>となり、文字列か、新しい状態を返す関数を受け取ることができます。

その他の修正方法

  • 数値を文字列に変換する別の方法:
setText(String(100));

コードは注意してご使用ください。

setText(`${100}`); // テンプレートリテラル

コードは注意してご使用ください。

  • 状態変数の型を変更する: もし、textに数値も格納したい場合は、初期値をnumber型またはany型にして、状態変数の型をstring | numberのように変更できますが、型安全性が損なわれる可能性があるため、慎重に行う必要があります。

まとめ
このエラーは、状態変数の型と代入する値の型が一致していないことが原因です。useStateフックで設定した状態変数の型を守り、適切な値を代入するようにしましょう。

補足:

  • TypeScript: TypeScriptを使用している場合は、型チェックがより厳しくなり、このようなエラーを早期に発見することができます。
  • 状態管理: より複雑な状態管理が必要な場合は、ReduxやContext APIなどのライブラリを検討することもできます。
    ご不明な点があれば、お気軽にご質問ください。

もし、具体的なコードの断片や、どのような処理を行いたいのかを教えていただければ、より詳細なアドバイスをできます。

Claudeの回答

エラーの原因は、setText 関数に文字列型(string)ではなく数値型(number)の値を渡そうとしているためです。useState で初期値として文字列 "test" を設定しているので、setText は文字列型の値を期待しています。
このエラーを修正するには、以下のいずれかの方法を選択できます:

  1. 数値を文字列に変換する:
const [text, setText] = useState("test");
setText(100.toString()); // または setText(String(100));
  1. 状態の型を string から string | number に変更する:
const [text, setText] = useState<string | number>("test");
setText(100); // これで問題なく動作します
  1. もし本当に数値型の状態が必要な場合は、初期値も数値にする:
const [text, setText] = useState(0); // または useState<number>(0)
setText(100);

どの方法を選択するかは、アプリケーションの要件によります。文字列と数値の両方を扱う必要がある場合は2番目の方法が適しているかもしれません。純粋に数値だけを扱う場合は3番目の方法が適切です。文字列として扱いたい場合は1番目の方法を使用してください。
これらの修正のいずれかを適用することで、型エラーが解決されるはずです。特定の方法について詳しく知りたい場合や、他に質問があればお知らせください。

比べてみた結果

一言で言うと、ChatGPT、Claudeの簡潔さとGeminiの文章量の多さが目立っているなという感想です。
どれも学習元は同じだからか、ニュアンスとして言っていることは大きく変わらず正確性のような観点ではそこまで違いが見受けられませんでした。
その点をGeminiは文章量でカバーしている印象です。
あとは生成の速度がGeminiやClaudeの方が少し早かった気がします。

↓体感なのであくまで参考程度でお願いします。
速度
Gemini>Claude>>ChatGPT
簡潔さ
ChatGPT>Claude>>>Gemini

使い分けをするなら

答えが明確に決まりそうなプロンプトの場合にChatGPTかClaudeを、
複数の選択肢を検討したい見たいならGeminiを使うのが良いと思います。

NCDCエンジニアブログ

Discussion