ホームページ ウェブフロントエンド jsチュートリアル OpenAI と LangChain を使用して強力なチャットボットを構築する

OpenAI と LangChain を使用して強力なチャットボットを構築する

Sep 12, 2024 am 10:33 AM

導入

チャットボットはさまざまな業界で不可欠なツールであり、ユーザーとの自動対話を提供します。今では、Chat GPT (またはその他の AI を利用したチャットボット) を少なくとも一度は試したことがない人は世界中にいません。 OpenAI の GPT モデルと LangChain ライブラリを使用すると、セッションを処理し、ストリーミング応答システムを通じてユーザー メッセージを処理するチャットボットを構築できます。後の投稿で API と通信し、特定のことに特化したエージェントを作成します。

ここで取り上げる内容は次のとおりです:

  • ミドルウェアを使用した Express サーバーのセットアップ。
  • チャットボット エージェントを処理するための「AgentManager」を作成します。
  • チャットボット エージェントを処理するための ChatAgent を作成します。
  • チャットボットの応答をリアルタイムでユーザーにストリーミングします。

環境のセットアップ

まず、いくつかの重要な依存関係が必要です。

  • API リクエストを処理するための Express。
  • GPT モデルとツールを管理するための LangChain。
  • GPT モデル対話用の OpenAI。スポーンセッションを使用してチャットボットと対話するには、Open AI からトークンを取得する必要があります

依存関係のインストール

最初に行うことは、新しいプロジェクトを初期化し、使用する必要なモジュールをインストールすることです。

npm init -Y
npm install express langchain openai uuid class-validator class-transformer mutex
ログイン後にコピー

エクスプレスルートの設定

まず、2 つの主要なルートを定義します。

最初のルートは新しいチャット セッションを作成し、2 番目のルートは既存のセッションにメッセージを送信します。

router.post('/session', APIKeyMiddleware, createSession);
router.post('/session/:id/message', APIKeyMiddleware, postMessage);
ログイン後にコピー

APIKeyMiddleware は、認証されたリクエストのみがこれらのルートにアクセスすることを保証します。ニーズに合ったミドルウェアを実装できることに注意してください。

エージェントマネージャーの作成

チャット エージェントを処理するための AgentManager クラスを作成します。このクラスは、新しいエージェントの作成とアクティブなセッションの管理を担当するため、このクラスがチャットを担当するエージェントを処理する API のメイン エントリポイントとして想像してください。最初のユーザーはセッションを作成する必要があり、その後、そのセッションがチャットに使用されます。

export class AgentManager {
    private __lock = new Mutex();
    private __agents: Map<string, AgentInstance> = new Map();

    async createAgent(authorization: string): Promise<string> {
        const uuid = uuidv4();
        const release = await this.__lock.acquire();
        try {
            this.__deleteExpiredAgentsLockless();
            let agent: ChatAgent | null = agent = new GeneralChatAgent(authorization);
            this.__agents.set(uuid, { agent, createdAt: Date.now() });
            return uuid;
        } finally {
            release();
        }
    }

    async getAgent(uuid: string): Promise<ChatAgent | null> {
        const release = await this.__lock.acquire();
        try {
            this.__deleteExpiredAgentsLockless();
            const agentInstance = this.__agents.get(uuid);
            return agentInstance ? agentInstance.agent : null;
        } finally {
            release();
        }
    }

    private __deleteExpiredAgentsLockless(): void {}
}
ログイン後にコピー

一般エージェントの作成

次に、一般的なチャット エージェントを作成する必要があります。これは、たとえば認証やその他の必要なパラメーターを取得し、API と通信できるようになりますが、今のところは既存の ChatAgent を拡張します。このステップではこれ以上何もする必要はありません。

export class GeneralChatAgent extends ChatAgent {
    constructor() {
        super();
    }
}
ログイン後にコピー

createAgent メソッドは、エージェントを初期化し、プロセスをロックし、一意のセッション ID に割り当てます。エージェントは指定されたセッション期間が経過すると期限切れになります。これは __deleteExpiredAgentsLockless メソッドによって処理されますが、次の反復で実装しますので、今のところは回避できます。

セッションとメッセージの処理

次に、セッションの作成とメッセージ処理のルートを定義しましょう:

export const createSession = async (req: Request, res: Response): Promise<void> => {
    const authorization = req.headers['authorization'] as string;
    try {
        const sessionId = await agentManager.createAgent(authorization, AgentType.WEB);
        res.json({ sessionId });
    } catch (err) {
        if (err instanceof Error) {
            res.status(400).json({ error: err.message });
        } else {
            res.status(500).json({ error: 'An unknown error occurred' });
        }
    }
}

export const postMessage = async (req: Request, res: Response): Promise<void> => {
    const { id } = req.params;
    const { message } = req.body;

    if (!id || !message) {
        return res.status(400).json({ error: 'Bad request. Missing session ID or message' });
    }

    try {
        const agent = await agentManager.getAgent(id);
        if (!agent) {
            return res.status(400).json({ error: `No agent found with id ${id}` });
        }

        const iterable = await agent.invoke(message);
        await streamResponse(res, iterable);
    } catch (err) {
        res.status(500).json({ error: err instanceof Error ? err.message : 'An unknown error occurred' });
    }
}
ログイン後にコピー

ここで、createSession は新しいセッションを設定し、postMessage はユーザーのメッセージをエージェントに送信します。セッションまたはメッセージが提供されていない場合は、400 Bad Request エラーが返されます。
ストリーミング応答

次に、チャット ボットの応答性とインタラクティブ性を高めるための鍵となるのは、応答のストリーミングです。

async invoke(input: string): Promise<AsyncIterable<Chunk>> {
    const release = await this.__lock.acquire();
    try {
        const tool = this.determineTool(input);
        if (tool) {
            const toolOutput = await tool.call(input);
            this.callbackQueue.enqueue({ type: ChunkType.TOKEN, value: toolOutput });
            this.callbackQueue.enqueue({ type: ChunkType.FINISH, value: '' });
        } else {
            await this.chat.invoke([new HumanMessage(input)], {
                callbacks: [
                    {
                        handleLLMNewToken: (token: string) => {
                            this.callbackQueue.enqueue({ type: ChunkType.TOKEN, value: token });
                        },
                        handleLLMEnd: () => {
                            this.callbackQueue.enqueue({ type: ChunkType.FINISH, value: '' });
                        },
                        handleLLMError: (error: Error) => {
                            this.callbackQueue.enqueue({ type: ChunkType.ERROR, value: error.message });
                        }
                    }
                ]
            });
        }
        return this.createAsyncIterable(this.callbackQueue);
    } finally {
        release();
    }
}

private createAsyncIterable(callbackQueue: AgentCallbackQueue): AsyncIterable<Chunk> {
    return {
        [Symbol.asyncIterator]: async function* () {
            let finished = false;
            while (!finished) {
                const chunk = await callbackQueue.dequeue();
                if (chunk) {
                    yield chunk;
                    if (chunk.type === ChunkType.FINISH || chunk.type === ChunkType.ERROR) {
                        finished = true;
                    }
                } else {
                    await new Promise(resolve => setTimeout(resolve, 100));
                }
            }
        }
    };
}
ログイン後にコピー

invoke メソッドでは、エージェントがユーザーの入力を処理し、応答をチャンクでストリームバックします。各チャンクは、モデルからのトークン、またはストリームの終わりを示すメッセージのいずれかです。

createAsyncIterable メソッドを使用すると、これらのチャンクを 1 つずつ生成し、クライアントにストリーミングして戻すことができます。

ストリーミング応答

最終的には、受信した応答をクライアントにストリーミングしたいのですが、完了するまでしばらく待って応答全体を返すのは望ましくありません。より良い解決策は、応答をチャンクに分けてストリーミングすることです。

const delay = (ms: number): Promise<void> => new Promise(resolve => setTimeout(resolve, ms));

export async function streamResponse(res: Response, iterable: AsyncIterable<Chunk>) {
    res.setHeader('Content-Type', 'application/x-ndjson');
    res.setHeader('Transfer-Encoding', 'chunked');

    try {
        let buffer = '';
        for await (const chunk of iterable) {
            switch (chunk.type) {
                case ChunkType.TOKEN:
                    buffer += chunk.value; 
                    res.write(buffer);
                    if (res.flush) res.flush();
                    buffer = '';
                    break;

                case ChunkType.ERROR:
                    console.error('Error chunk:', chunk.value);
                    if (!res.headersSent) {
                        res.status(500).json({ error: 'Streaming failed.' });
                    }
                    return;

                case ChunkType.FINISH:
                    if (buffer.trim()) {
                        res.write(`${buffer.trim()}\n`);
                    }
                    return;
            }
        }
    } catch (err) {
        console.error('Error during streaming:', err);
        if (!res.headersSent) {
            res.status(500).json({ error: 'Streaming failed.' });
        }
    } finally {
        res.end();
    }
}

ログイン後にコピー

結論

おめでとうございます!これで、チャット セッションを処理し、応答をクライアントにストリーミングする基本的なチャットボットが完成しました。このアーキテクチャは、追加ツール、より洗練されたロジック、またはさまざまな GPT モデルを使用して簡単に拡張できますが、今のところ、より複雑なチャットボット用のスケルトンが用意されています。

OpenAI の強力な言語モデルと LangChain のツール管理を使用することで、さまざまなドメイン向けに、より高度でインタラクティブなチャットボットを作成できます。チャットボットの機能を拡張して、希望する方法で作成できますが、一方で、そうする必要はありません。 Langchain を使用するか、OpenAI を使用して、よりシンプルなチャット ボットを作成することもできます。

続報をお楽しみに。次の投稿では、私たちが作成したチャット エージェントのツールの構築について説明します
コーディングを楽しんでください!

お気軽に元の投稿をチェックしてください

Building a Powerful Chatbot with OpenAI and LangChain

OpenAI と LangChain を使用して強力なチャットボットを構築する

この投稿では、OpenAI と LangChain を使用して、基本的かつ強力なチャットボットを作成する方法を説明します。

bojanjagetic.com

以上がOpenAI と LangChain を使用して強力なチャットボットを構築するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットな記事タグ

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

JavaScriptの文字列文字を交換します JavaScriptの文字列文字を交換します Mar 11, 2025 am 12:07 AM

JavaScriptの文字列文字を交換します

カスタムGoogle検索APIセットアップチュートリアル カスタムGoogle検索APIセットアップチュートリアル Mar 04, 2025 am 01:06 AM

カスタムGoogle検索APIセットアップチュートリアル

例JSONファイルの例 例JSONファイルの例 Mar 03, 2025 am 12:35 AM

例JSONファイルの例

8見事なjQueryページレイアウトプラグイン 8見事なjQueryページレイアウトプラグイン Mar 06, 2025 am 12:48 AM

8見事なjQueryページレイアウトプラグイン

10 jQuery構文蛍光物 10 jQuery構文蛍光物 Mar 02, 2025 am 12:32 AM

10 jQuery構文蛍光物

独自のAjax Webアプリケーションを構築します 独自のAjax Webアプリケーションを構築します Mar 09, 2025 am 12:11 AM

独自のAjax Webアプリケーションを構築します

' this' JavaScriptで? ' this' JavaScriptで? Mar 04, 2025 am 01:15 AM

' this' JavaScriptで?

10 JavaScript&JQuery MVCチュートリアル 10 JavaScript&JQuery MVCチュートリアル Mar 02, 2025 am 01:16 AM

10 JavaScript&JQuery MVCチュートリアル

See all articles