この記事では、2 つのテクノロジー ( LangChainとAnthropic ) を組み合わせて、検索機能を備えたパーソナル アシスタントを作成する方法を説明します。
ハッカソンの参加者によって、ますます多くの AI 製品が作成されています。開発者にとっての次の機会は、 Google Cloud Vertex AIとの共同ハッカソンであり、各参加者はGoogle Cloudの最新テクノロジーを使用して独自のAI アプリケーションを作成する機会があります。ここでは、ますます重要性を増している AI のアプリケーションの 1 つである検索エンジンについて説明します。
検索機能を備えたパーソナル アシスタントは、検索エンジン テクノロジーを使用して、情報の検索、予約、リマインダーの設定、メッセージの送信などのタスクを行うユーザーを支援するデジタル アシスタントです。これらのアシスタントは、検索アルゴリズムを使用してさまざまなソースからデータを収集および分析し、それを有用かつ簡潔な方法でユーザーに表示します。
検索機能を備えたパーソナル アシスタントの代表的な例としては、 Google アシスタント、 Siri 、 Alexa 、 Cortanaがあります。これらのアシスタントは、検索機能を効果的に使用して、正確で関連性の高い情報を提供し、タスクを完了し、ユーザーと対話する際の応答を改善します。
Anthropic は、高度な AI システムの開発に焦点を当てた研究組織です。彼らの最新作である Claude は、役に立つ、正直、そして無害になるように設計された次世代 AI アシスタントです。この最先端のモデルは、さまざまなタスクにおいて高度な信頼性と予測可能性を保証します。
クロードの主な特徴は次のとおりです。
多彩な会話機能とテキスト処理機能
ユーザーの安全とプライバシーを最優先に維持する
Claude の主な使用例は次のとおりです。
要約
検索
創造的で共同執筆
Q&A
コーディング支援
これらの機能により、Claude は幅広いアプリケーションにとって理想的な AI ツールとなり、さまざまなドメインにわたるユーザーに力を与えます。
LangChain は、エンドツーエンドの言語モデル アプリケーションを構築するための多用途ツールです。言語学習モデル (LLM) の作成、管理、展開のプロセスを簡素化する堅牢なフレームワークを提供します。 LLM は、さまざまな言語やタスクで人間のようなテキストを理解、生成、操作するように設計された高度な AI モデルです。
LLM のプロンプトの効率的な管理
複雑なワークフローのタスクのチェーンを作成する機能
AI に状態を追加して、以前のインタラクションからの情報を記憶できるようにする
これらの機能により、LangChain は、さまざまなアプリケーションで言語モデルの可能性を活用するための強力でユーザーフレンドリーなプラットフォームになります。
Flask をインストールする: まず、環境に Flask がインストールされていることを確認してください。 pip
使用してこれを行うことができます。
pip install Flask
新しいディレクトリを作成する: プロジェクト用に新しいディレクトリを作成し、そこに移動します。
mkdir claude-langchain cd claude-langchain
仮想環境をセットアップする (オプション) : Python プロジェクトを操作するときは、仮想環境を使用することをお勧めします。 venv
またはその他の任意のツールを使用して作成できます。
python -m venv venv source venv/bin/activate (Linux/Mac) venv\Scripts\activate (Windows)
main.py
ファイルを作成する: Flask アプリケーション コードを記述するためのmain.py
ファイルを作成します。
touch app.py # Linux/Mac echo.>app.py # Windows
Flask アプリケーション コードを作成します。お気に入りのコード エディターでmain.py
ファイルを開き、次のコードを追加します。
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, World!' if __name__ == '__main__': app.run()
Flask アプリケーションを実行します。 main.py
ファイルを保存し、ターミナル/コマンド プロンプトで次のコマンドを実行します。
python main.py
ブラウザを開く: 任意の Web ブラウザを開き、 http://127.0.0.1:5000/に移動します。 「Hello, World!」が表示されるはずです。ウェブページに表示されます。
以上です! Flask プロジェクトが正常に初期化され、簡単なアプリケーションが作成されました。
python-dotenv と langchain をインストールする: .env
ファイルで環境変数を簡単に管理するには、 python-dotenv
パッケージを使用します。同時にlangchain
インストールしましょう。 pip
を使用して両方のパッケージをインストールします。
pip install python-dotenv langchain
.env
ファイルを作成する: プロジェクトのルート ディレクトリに.env
ファイルを作成します。
touch .env # Linux/Mac echo.>.env # Windows
環境変数を追加する: お気に入りのコード エディターで.env
ファイルを開き、環境変数を追加します。各変数は、KEY=VALUE の形式で新しい行に置く必要があります。
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxxxxxx SERPAPI_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Anthropic の ClaudeモデルとSerpAPIの Web 検索サービスの両方の API キーが必要であることに注意してください。
環境変数をロードする: main.py
ファイルを変更して、 python-dotenv
を使用して.env
ファイルから環境変数をロードします。 main.py
を次のように更新します。
import os from flask import Flask from dotenv import load_dotenv load_dotenv() app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, World!' if __name__ == '__main__': app.run()
バージョン管理の.env
ファイルを無視する: バージョン管理では秘密キーなどの機密情報を共有しないことが重要です。 Git を使用している場合は、 .gitignore
ファイルに次の行を追加します (ファイルがない場合は作成します)。
.env
これで、 .env
ファイルの環境変数を使用するように Flask プロジェクトが設定されました。必要に応じてさらに変数を追加し、 os.environ.get('KEY')
を使用してアクセスできます。 .env
ファイルは非公開にし、バージョン管理には決してコミットしないようにしてください。
このチュートリアルは、Node.js、npm、React、Typescript の基本を理解している中級ユーザー向けに設計されています。これらのテクノロジーを含むスタックと、スタイル設定用の Tailwind CSS を使用します。このスタックは、その堅牢性、多用途性、およびこれらのテクノロジーに対するコミュニティの強力なサポートにより選択されました。さらに、Anthropic の Claude モデルと LangChain という 2 つの強力な AI テクノロジーを統合し、アプリが人間のような正確なテキスト応答を生成できるようにします。
公式サイトから OS 用の Node.js インストーラーをダウンロードします。
インストール プロンプトに従って、Node.js と npm をインストールします。ほとんどのユーザーには LTS (長期サポート) バージョンが推奨されます。
インストールしたら、ターミナルから Node.js と npm のバージョンを確認して、インストールを確認します。
ノード -v npm -v
Create React App (CRA) は、新しい React.js アプリケーションの作成を支援するコマンドライン ユーティリティです。 npm 経由でグローバルにインストールします。
npm install -g create-react-app
CRA と Typescript テンプレートを使用してai-assistant-claude
という名前の新しいプロジェクトを作成します。
npx create-react-app ai-assistant-claude --template typescript
このコマンドは、現在のディレクトリにai-assistant-claude
という新しいディレクトリを作成し、Typescript をサポートする新しい React アプリケーションを格納します。
このチュートリアルで従う手順は、 Tailwind CSS の公式ドキュメントに基づいています。最新の手順については、これらのドキュメントを参照してください。
まず、TailwindCSS をインストールし、プロジェクト内のライブラリを初期化します。
npm install -D tailwindcss npx tailwindcss init
次に、テンプレート パスをtailwind.config.js
ファイルに追加して構成します。 ++
は、追加する行を示します。
/** @type {import('tailwindcss').Config} */ module.exports = { -- content: [], ++ content: [ ++ "./src/**/*.{js,jsx,ts,tsx}", ++ ], theme: { extend: {}, }, plugins: [], }
最後に、Tailwind の各レイヤーの@tailwind
ディレクティブを./src/index.css
ファイルに追加します。
@tailwind base; @tailwind components; @tailwind utilities;
そして出来上がり! Tailwind CSS がプロジェクトに統合されました。
コーディングセクションに進む前に、 fontawesome
、 react-markdown
、 axios
、 react-hook-form
などの必要なライブラリをインストールして準備を完了しましょう。
npm i --save @fortawesome/fontawesome-svg-core npm install --save @fortawesome/free-solid-svg-icons npm install --save @fortawesome/react-fontawesome
npm install --save react-markdown
これらの手順が完了すると、プロジェクトには必要なツールとライブラリがすべてセットアップされます。次に、Anthropic の Claude API と LangChain を使用して正確で人間のようなテキスト応答を生成する AI アシスタント アプリの構築を開始します。
インストールまたはセットアップ中に問題が発生した場合の一般的な解決策をいくつか示します。
その他の問題については、それぞれのライブラリのドキュメントを参照するか、StackOverflow または関連する GitHub リポジトリに問題を投稿してください。
このセクションでは、前に初期化した Flask アプリに戻り、 /ask
や/search
などの新しいエンドポイントを追加します。これらは、シンプルなチャット機能と高度なチャット機能 (後者は Google 検索結果を利用します) のエンドポイントとして機能します。
必要なモジュールをインポートすることから始めましょう。
from flask import Flask, jsonify, request from dotenv import load_dotenv from langchain.chat_models import ChatAnthropic from langchain.chains import ConversationChain from langchain.agents import Tool from langchain.agents import AgentType from langchain.utilities import SerpAPIWrapper from langchain.agents import initialize_agent from langchain.memory import ConversationBufferMemory from langchain.prompts.chat import ( ChatPromptTemplate, MessagesPlaceholder, SystemMessagePromptTemplate, AIMessagePromptTemplate, HumanMessagePromptTemplate, ) load_dotenv() app = Flask(__name__)
上記のセクションでは、必要なパッケージをすべてインポートし、Flask アプリケーションを初期化します。
まず、基本的なエンドポイント ( /
) を作成して、サーバーが正しく実行されているかどうかをテストします。
@app.route('/') def hello_world(): return 'Hello, World!'
ルート URL にアクセスすると、「Hello, World!」という応答が返され、サーバーが期待どおりに実行されていることを示します。
/ask
エンドポイントの作成このエンドポイントは、アプリケーションの基本的なチャット機能のメッセージを処理します。リクエストから JSON データを読み取り、メッセージを処理し、Anthropic の Claude モデルと LangChain を使用してレスポンスを生成します。
@app.route('/ask', methods=['POST']) def ask_assistant(): # The code for /ask endpoint goes here
リクエストからのメッセージの抽出
まず、データが提供されているかどうかを確認し、そこからメッセージを抽出する必要があります。
data = request.get_json() if not data: return jsonify({"error": "No data provided"}), 400 messages = data.get("message")
応答の生成
次のコード セグメントは、LangChain のChatAnthropic()
モデルとChatPromptTemplate
を使用してチャット応答を生成し、会話を構造化します。会話履歴はConversationBufferMemory
を使用して保存されます。
llm = ChatAnthropic() input = "" message_list = [] for message in messages: if message['role'] == 'user': message_list.append( HumanMessagePromptTemplate.from_template(message['content']) ) input = message['content'] elif message['role'] == 'assistant': message_list.append( AIMessagePromptTemplate.from_template(message['content']) ) # Adding SystemMessagePromptTemplate at the beginning of the message_list message_list.insert(0, SystemMessagePromptTemplate.from_template( "The following is a friendly conversation between a human and an AI. The AI is talkative and " "provides lots of specific details from its context. The AI will respond with plain string, replace new lines with \\n which can be easily parsed and stored into JSON, and will try to keep the responses condensed, in as few lines as possible." )) message_list.insert(1, MessagesPlaceholder(variable_name="history")) message_list.insert(-1, HumanMessagePromptTemplate.from_template("{input}")) prompt = ChatPromptTemplate.from_messages(message_list) memory = ConversationBufferMemory(return_messages=True) conversation = ConversationChain(memory=memory, prompt=prompt, llm=llm) result = conversation.predict(input=input)
応答を生成した後、結果内の改行を置換し、JSON オブジェクトとして返します。
print(result) return jsonify({"status": "success", "message": result})
/search
エンドポイントの作成/search
エンドポイントは/ask
に似ていますが、より詳細な応答を提供する検索機能が含まれています。この機能を追加するにはSerpAPIWrapper
を使用します。
@app.route('/search', methods=['POST']) def search_with_assistant(): data = request.get_json() if not data: return jsonify({"error": "No data provided"}), 400 messages = data.get("message") llm = ChatAnthropic() # Get the last message with 'user' role user_messages = [msg for msg in messages if msg['role'] == 'user'] last_user_message = user_messages[-1] if user_messages else None # If there is no user message, return an error response if not last_user_message: return jsonify({"error": "No user message found"}), 400 input = last_user_message['content'] search = SerpAPIWrapper() tools = [ Tool( name = "Current Search", func=search.run, description="useful for when you need to answer questions about current events or the current state of the world" ), ] chat_history = MessagesPlaceholder(variable_name="chat_history") memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) agent_chain = initialize_agent( tools, llm, agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True, memory=memory, agent_kwargs = { "memory_prompts": [chat_history], "input_variables": ["input", "agent_scratchpad", "chat_history"] } ) result = agent_chain.run(input=input) print(result) return jsonify({"status": "success", "message": result})
最後に、 Flask アプリを実行するための標準ボイラープレートを追加します。
if __name__ == '__main__': app.run()
すべてがうまくいけば、これが最終的なバックエンド コードです。
from flask import Flask, jsonify, request from dotenv import load_dotenv from langchain.chat_models import ChatAnthropic from langchain.chains import ConversationChain from langchain.agents import Tool from langchain.agents import AgentType from langchain.utilities import SerpAPIWrapper from langchain.agents import initialize_agent from langchain.memory import ConversationBufferMemory from langchain.prompts.chat import ( ChatPromptTemplate, MessagesPlaceholder, SystemMessagePromptTemplate, AIMessagePromptTemplate, HumanMessagePromptTemplate, ) load_dotenv() app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, World!' @app.route('/ask', methods=['POST']) def ask_assistant(): data = request.get_json() if not data: return jsonify({"error": "No data provided"}), 400 messages = data.get("message") llm = ChatAnthropic() input = "" message_list = [] for message in messages: if message['role'] == 'user': message_list.append( HumanMessagePromptTemplate.from_template(message['content']) ) input = message['content'] elif message['role'] == 'assistant': message_list.append( AIMessagePromptTemplate.from_template(message['content']) ) # Adding SystemMessagePromptTemplate at the beginning of the message_list message_list.insert(0, SystemMessagePromptTemplate.from_template( "The following is a friendly conversation between a human and an AI. The AI is talkative and " "provides lots of specific details from its context. The AI will respond with plain string, replace new lines with \\n which can be easily parsed and stored into JSON, and will try to keep the responses condensed, in as few lines as possible." )) message_list.insert(1, MessagesPlaceholder(variable_name="history")) message_list.insert(-1, HumanMessagePromptTemplate.from_template("{input}")) prompt = ChatPromptTemplate.from_messages(message_list) memory = ConversationBufferMemory(return_messages=True) conversation = ConversationChain(memory=memory, prompt=prompt, llm=llm) result = conversation.predict(input=input) print(result) return jsonify({"status": "success", "message": result}) @app.route('/search', methods=['POST']) def search_with_assistant(): data = request.get_json() if not data: return jsonify({"error": "No data provided"}), 400 messages = data.get("message") llm = ChatAnthropic() # Get the last message with 'user' role user_messages = [msg for msg in messages if msg['role'] == 'user'] last_user_message = user_messages[-1] if user_messages else None # If there is no user message, return an error response if not last_user_message: return jsonify({"error": "No user message found"}), 400 input = last_user_message['content'] search = SerpAPIWrapper() tools = [ Tool( name = "Current Search", func=search.run, description="useful for when you need to answer questions about current events or the current state of the world" ), ] chat_history = MessagesPlaceholder(variable_name="chat_history") memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) agent_chain = initialize_agent( tools, llm, agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True, memory=memory, agent_kwargs = { "memory_prompts": [chat_history], "input_variables": ["input", "agent_scratchpad", "chat_history"] } ) result = agent_chain.run(input=input) print(result) return jsonify({"status": "success", "message": result}) if __name__ == '__main__': app.run()
それでは、アプリをテストしてみましょう。このコマンドを使用してバックエンド アプリを実行します。また、仮想環境がアクティブ化されていることを確認してください。
flask run
ターミナルがこの出力を返せば、すべてがうまくいくことがわかります。
早速、2 つのエンドポイント/ask
と/search
をテストしてみましょう。 2 つを区別するために、それぞれに同様のペイロードを送信してみましょう。 REST API テストおよびドキュメント ソフトウェアを開くか、単に cURL を使用します。ただし、このチュートリアルではInsomniaを使用します。
まず、次のペイロードを使用して/ask
エンドポイントを呼び出してみましょう。ビデオゲーム「 ゼルダの伝説 ブレス オブ ザ ワイルド」の続編について質問したとします。それは不正確に答えます。このモデルは 2021 年末の時点でトレーニングが終了しており、続編についてはまだ発表されていないため、これは予想されることです。
/search
エンドポイントはどうですか?先ほどのコードにお気づきかと思いますが、このエンドポイントは、エージェントを利用するより洗練されたチェーンで処理されます。
エージェントを使用することで、AI に独自のモデル (すでに示したように、独自の欠陥がある) だけでなく、より多くのツールを提供することで、AI の意思決定においてより大きな力を与えることができます。
/search
エンドポイントがどのように機能するかを示すために、前と同じペイロードを使用して呼び出してみましょう。
今回もうまくいきました!ボンネットの下ではどのように機能するのでしょうか?ターミナルの出力を見てみましょう。
興味深いことに、今回の AI モデルはすぐには答えませんでしたが、答えるために何をすべきかについて「熟考」したようでした。同社はウェブ検索結果から「ニュース検索によると、『ゼルダの伝説 涙の王国』という続編が発表されたようだ」との見解を示したことから回答を決定した。
したがって、その論理によれば、 /search
エンドポイントを使用するだけでよいのではないでしょうか?それはより正確であり、したがってより賢明だからでしょうか?完全ではありません。通常、チャットボットベースのアプリでは、ボットは以前の会話のコンテキストを保持することが期待されているため、会話のコンテキスト全体を「覚えている」かのように応答を提供できます。 /search
エンドポイントでそれができるかどうかを見てみましょう。
/search
エンドポイントが今尋ねた内容を思い出せるかどうかをテストしてみましょう。
これは、LangChain ライブラリには過去の会話、Web サーバー、およびその上に構築された REST API サービスを保持するために使用できるメモリ チェーン機能が本質的にステートレスであるために発生しました。つまり、Web サーバーは各リクエストを新しいリクエストとして扱います。
しかし、以前の会話をペイロードとして含めていませんか?それは良い質問です。現在、LangChain で使用されているエージェント チェーンは、ユーザーと AI の両方のリクエストと応答で構成される、合成プロンプトの処理をサポートしていないことがわかりました。これは主に、モデルに会話の例を提供するために使用され、望ましい応答に合わせてモデルをさらに調整します。
一方、エージェントは単一の指示を受け取ることによって動作し、それを中心に思考の連鎖を展開します。そのため、会話がどれだけ長くても、エージェントは最新のリクエストのみに応答します。
/ask
エンドポイントをテストして違いを確認してみましょう。
今回は、私たちの過去の会話を追加のコンテキストとして使用して答えてくれました。ここまでで、AI アシスタント アプリを構築するには両方のエンドポイントが必要であることがわかりました。しかし、時代遅れだが常に覚えている/ask
エンドポイントと、忘れっぽいが徹底的で最新の/search
エンドポイントの両方をどのように組み込むのでしょうか?もちろん、フロントエンドを構築することによってです。
ai-assistant-claude
プロジェクト ディレクトリに戻りましょう。このプロジェクトでは、エントリ ポイント ファイルApp.tsx
から始めて、React コンポーネントの変更を開始します。
import React from 'react'; import logo from './logo.svg'; import './App.css'; import { ChatClient } from './ChatClient'; function App() { return ( <div> <ChatClient/> </div> ); } export default App;
上記のコード スニペットでは、後の手順で作成されるChatClient
コンポーネントをインポートします。次に、 <ChatClient/>
コンポーネントを<div>
要素内に含めます。これにより、React コンポーネントを使用した AI アシスタント アプリの構造が設定されます。
import React, { useState } from 'react'; import { ChatInput } from './ChatInput'; import { ChatHistory } from './ChatHistory'; export interface Message { content: string; role: string; } export const ChatClient: React.FC = () => { const [messages, setMessages] = useState<Array<Message>>([]); const [isLoading, setIsLoading] = useState(false) const handleSimpleChat = (message: string) => { // Send the message and past chat history to the backend // Update messages state with the new message let newMessages = [...messages, { content: message, role: 'user' }] setMessages(newMessages); let postData = { message: newMessages } setIsLoading(true) fetch('/ask', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(postData), }) .then((response) => response.json()) .then((data) => { if (data.status === "success") { setMessages([...newMessages, { content: data.message, role: 'assistant' }]) } setIsLoading(false) console.log('Success:', data); }) .catch((error) => { console.error('Error:', error); setIsLoading(false) }); }; const handleAdvancedChat = (message: string) => { // Trigger AI agent with Google Search functionality // Update messages state with the new message and AI response let newMessages = [...messages, { content: message, role: 'user' }] setMessages(newMessages); let postData = { message: newMessages } setIsLoading(true) fetch('/search', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(postData), }) .then((response) => response.json()) .then((data) => { if (data.status === "success") { setMessages([...newMessages, { content: data.message, role: 'assistant' }]) } console.log('Success:', data); setIsLoading(false) }) .catch((error) => { console.error('Error:', error); setIsLoading(false) }); }; return ( <div className="h-screen bg-gray-100 dark:bg-gray-900 flex items-center justify-center"> <div className='flex flex-col items-center gap-2'> <h1 className='text-white text-xl'>AI Assistant with Claude and LangChain</h1> <div className="w-full max-w-md h-[80vh] bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden flex flex-col"> <ChatHistory messages={messages} isLoading={isLoading} /> <ChatInput onSimpleChat={handleSimpleChat} onAdvancedChat={handleAdvancedChat} /> </div> </div> </div> ); };
このコンポーネントは、AI アシスタントの主要なユーザー インターフェイスとして機能します。図に示すように、会話履歴を表示するChatHistory
コンポーネントとテキストを入力するChatInput
コンポーネントが組み込まれています。
このコンポーネントは、 ChatInput
コンポーネントからの入力を処理し、この入力を使用してバックエンドにリクエストを送信し、読み込みステータスを表示します。リクエストが正常に処理された場合、コンポーネントはバックエンドから受信した応答も表示します。
import React from 'react'; import { ReactMarkdown } from 'react-markdown/lib/react-markdown'; import { Message } from './ChatClient'; interface ChatHistoryProps { messages: Array<Message>; isLoading: boolean } export const ChatHistory: React.FC<ChatHistoryProps> = ({ messages, isLoading }) => { return ( <div className="p-4 h-full overflow-y-auto"> {messages.map((message, index) => ( <div key={index} className={`mb-3 ${ message.role === 'user' ? 'text-right' : 'text-left' }`} > <ReactMarkdown className={`inline-block px-3 py-2 rounded-md ${ index % 2 === 0 ? 'bg-gray-300 dark:bg-gray-700' : 'bg-blue-200 dark:bg-blue-900' }`} > {message.content} </ReactMarkdown> </div> ))} {isLoading && ( <div className="mb-3 text-left"> <ReactMarkdown className="inline-block px-3 py-2 rounded-md bg-blue-200 dark:bg-blue-900 animate-pulse" > {/* Put your desired loading content here */} Thinking... </ReactMarkdown> </div> )} </div> ); };
幸いなことに、TailwindCSS には、 animate-pulse
などの単純なアニメーション用の組み込みユーティリティ クラスが用意されています。このクラスは、リクエストが応答を待っていることをエレガントに示すのに役立ちます。このコンポーネントでは、「ユーザー」と「アシスタント」からのメッセージの位置付けも区別します。
import React, { useState } from 'react'; interface ChatInputProps { onSimpleChat: (message: string) => void; onAdvancedChat: (message: string) => void; } export const ChatInput: React.FC<ChatInputProps> = ({ onSimpleChat, onAdvancedChat }) => { const [input, setInput] = useState(''); const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => { setInput(event.target.value); }; const handleSubmit = (handler: (message: string) => void) => { handler(input); setInput(''); }; return ( <div className="flex p-4 border-t border-gray-200 dark:border-gray-700"> <input type="text" value={input} onChange={handleInputChange} placeholder="Type your message..." className="flex-grow px-3 py-2 rounded-md bg-gray-200 text-gray-900 dark:bg-gray-700 dark:text-gray-100 focus:outline-none" /> <button onClick={() => handleSubmit(onSimpleChat)} className="ml-2 px-4 py-2 font-semibold text-gray-600 bg-white dark:text-gray-400 dark:bg-gray-800 border border-gray-300 rounded-md hover:bg-gray-200 dark:hover:bg-gray-700 focus:outline-none" > Ask </button> <button onClick={() => handleSubmit(onAdvancedChat)} className="ml-2 px-4 py-2 font-semibold text-white bg-blue-500 border border-blue-600 rounded-md hover:bg-blue-400 focus:outline-none" > Ask and Search </button> </div> ); };
最後に、テキスト入力に 2 つのボタンを追加しました。最初のボタンは、入力を/ask
エンドポイントに送信するために使用され、追加の機能拡張を行わずに AI モデルを使用して入力を処理します。
このエンドポイントはコンテキスト認識型です。 2 番目のボタンは、「Ask and Search」という適切な名前が付けられており、入力を/search
エンドポイントに送信します。このボタンは、AI モデルによる入力の処理に加えて、状況に応じて AI 駆動の Web 検索もトリガーします。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="theme-color" content="#000000" /> <meta name="description" content="Web site created using create-react-app" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <!-- manifest.json provides metadata used when your web app is installed on a user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ --> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <!-- Notice the use of %PUBLIC_URL% in the tags above. It will be replaced with the URL of the `public` folder during the build. Only files inside the `public` folder can be referenced from the HTML. Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> -- <title>React App</title> ++ <title>Claude AI Assistant</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> <!-- This HTML file is a template. If you open it directly in the browser, you will see an empty page. You can add webfonts, meta tags, or analytics to this file. The build step will place the bundled scripts into the <body> tag. To begin the development, run `npm start` or `yarn start`. To create a production bundle, use `npm run build` or `yarn build`. --> </body> </html>
最後の仕上げとして、 index.html
ページ内のアプリのタイトルを「 React App 」から「 Claude AI Assistant 」に変更して更新します。
{ "name": "ai-assistant-claude", "version": "0.1.0", "private": true, ++ "proxy": "http://localhost:5000", "dependencies": {
最後に、プロキシ構成をpackage.json
ファイルに追加し、 http://localhost:5000
に設定します。これにより、別のポートの使用によって生じる CORS 制限を回避できます。
テストを開始するには、まずバックエンド アプリ (claude-langchain) がすでに実行されていることを確認します。
次に、ディレクトリをフロントエンド アプリ (ai-assistant-claude) に変更し、次のコマンドを使用してアプリを起動します。
npm start
アプリのビルドには少し時間がかかる場合があります。準備が完了すると、ブラウザでlocalhost:3000
に自動的に開きます。
コンテキスト認識と検索機能の両方をテストしてみましょう。まず、2021 年のリリースがまだ発表されていない別のビデオ ゲーム、つまりSEGAの最新龍が如くゲームの続編について聞いてみましょう。さらに、このゲームには過去のゲームで人気のキャラクターである桐生一馬が登場するかどうかも尋ねます。これを行うには、「質問する」ボタンをクリックします。
数秒考えてください...
驚いたことに、AIは不正解でした。 『龍が如く:龍が如く』は確かに最新の龍が如くゲームですが、主役は別の主人公、春日一番です。質問を言い換えて、今度は「質問して検索」ボタンを使用してみましょう。
現在、AI はウェブを検索する必要があるかどうかを判断するのに時間がかかりました。 Web 検索が必要であると判断し、満足のいく答えが見つかった後、情報をクライアント/フロントエンドに返します。
今回はタイトルを『龍が如く 外伝 名前を消した男』に戻り、まさに桐生一馬が主人公となっている。
魅力的ですね。大規模言語モデルを利用したエージェントは、利用可能なリソース (検索) を考慮してどのようなアクションが必要かを予測し、満足のいく答えを提供します。 LangChain を使用すると、モデル、プロンプト (モデルへの指示)、エージェントやツールなどのその他の機能の接続と「チェーン」が簡単になります。
このアプリの構築とこれらのテクノロジーについての学習を楽しんでいただければ幸いです。さらに詳しく知りたい場合は、フロントエンドとバックエンドの完成したプロジェクトにアクセスできます。
また、パートナーが実現した最新テクノロジーを使用して構築したい場合は、次の AI チャレンジに参加してください。
*please see lablab.ai for all terms and conditions