Maison > interface Web > js tutoriel > le corps du texte

Créer un chatbot puissant avec OpenAI et LangChain

王林
Libérer: 2024-09-12 10:33:02
original
1192 Les gens l'ont consulté

Introduction

Les chatbots sont des outils essentiels dans divers secteurs, offrant une interaction automatisée avec les utilisateurs. De nos jours, personne au monde n’a essayé au moins une fois Chat GPT (ou tout autre chatbot alimenté par l’IA). En utilisant les modèles GPT d'OpenAI et la bibliothèque LangChain, nous pouvons créer un chatbot qui gère les sessions et traite les messages des utilisateurs via un système de réponse en streaming, car dans un article ultérieur, nous communiquerons avec nos API et créerons des agents qui seront spécialisés pour certaines choses.

Voici ce que nous allons aborder :

  • Mise en place d'un serveur Express avec middleware.
  • Création d'un `AgentManager` pour gérer les agents chatbot.
  • Création d'un ChatAgent pour gérer les agents chatbot.
  • Diffusion des réponses du chatbot aux utilisateurs en temps réel.

Configuration de l'environnement

Tout d'abord, nous avons besoin de quelques dépendances clés :

  • Express pour gérer les requêtes API.
  • LangChain pour gérer les modèles et outils GPT.
  • OpenAI pour l'interaction du modèle GPT. Nous devons obtenir un jeton d'Open AI afin d'utiliser les sessions d'apparition et d'interagir avec le chatbot

Installer les dépendances

La première chose que nous faisons est d'initialiser le nouveau projet et d'installer les modules nécessaires que nous utiliserons.

npm init -Y
npm install express langchain openai uuid class-validator class-transformer mutex
Copier après la connexion

Configuration d'itinéraires express

Pour commencer, nous définirons deux itinéraires principaux :

Le premier itinéraire créera une nouvelle session de discussion, tandis que le second enverra des messages à une session existante.

router.post('/session', APIKeyMiddleware, createSession);
router.post('/session/:id/message', APIKeyMiddleware, postMessage);
Copier après la connexion

L'APIKeyMiddleware garantit que seules les requêtes authentifiées accèdent à ces routes. Notez que vous pouvez implémenter un middleware adapté à vos besoins.

Création du gestionnaire d'agents

Nous allons créer une classe AgentManager pour gérer les agents de chat. Cette classe est responsable de la création de nouveaux agents et de la gestion des sessions actives, alors imaginez cette classe comme le point d'entrée principal de nos API car elle aura des agents qui seront responsables du chat. Le premier utilisateur devra créer une session et plus tard, cette session sera utilisée pour discuter.

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 {}
}
Copier après la connexion

Création d'un agent général

Maintenant, nous devons créer un agent de chat général, qui obtiendra des paramètres avec, par exemple, l'authentification ou tout autre dont vous avez besoin et pourra communiquer avec l'API, mais pour l'instant, nous allons étendre le ChatAgent existant. et rien de plus pour cette étape.

export class GeneralChatAgent extends ChatAgent {
    constructor() {
        super();
    }
}
Copier après la connexion

La méthode createAgent initialise un agent, verrouille le processus et lui attribue un ID de session unique. Les agents expirent après une durée de session spécifiée, qui est gérée par la méthode __deleteExpiredAgentsLockless mais nous l'implémenterons lors de la prochaine itération, vous pouvez l'éviter pour l'instant.

Gestion des sessions et des messages

Ensuite, définissons nos itinéraires de création de session et de gestion des messages :

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' });
    }
}
Copier après la connexion

Ici, createSession configure une nouvelle session et postMessage envoie le message d'un utilisateur à l'agent. Si aucune session ou aucun message n'est fourni, il renvoie une erreur 400 Bad Request.
Réponses en continu

Maintenant, la clé pour que notre chatbot se sente réactif et interactif : diffuser la réponse.

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));
                }
            }
        }
    };
}
Copier après la connexion

Dans la méthode d'invocation, l'agent traite les entrées de l'utilisateur et renvoie la réponse par morceaux. Chaque morceau est soit un jeton du modèle, soit un message indiquant la fin du flux.

La méthode createAsyncIterable nous permet de générer ces morceaux un par un et de les renvoyer au client.

Réponse en streaming

En fin de compte, nous voulons diffuser la réponse au client au fur et à mesure que nous la recevons, nous ne voulons pas attendre un certain temps jusqu'à ce qu'elle soit terminée et renvoyer l'intégralité de la réponse, la meilleure solution consiste à diffuser la réponse en morceaux.

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();
    }
}

Copier après la connexion

Conclusion

Félicitations ! Vous disposez désormais d'un chatbot de base qui gère les sessions de chat et transmet les réponses au client. Cette architecture peut être facilement étendue avec des outils supplémentaires, une logique plus sophistiquée ou différents modèles GPT, mais pour l'instant nous disposons du squelette d'un chatbot plus complexe.

En utilisant les puissants modèles de langage d'OpenAI et la gestion des outils de LangChain, vous pouvez créer des chatbots plus avancés et interactifs pour divers domaines. Vous pouvez étendre les capacités des chatbots et les créer de la manière que vous souhaitez, mais d'un autre côté, vous n'avez pas besoin de le faire. utilisez Langchain, vous pouvez utiliser OpenAI et créer un chatbot encore plus simple si vous préférez cette façon.

Restez à l'écoute pour en savoir plus, dans le prochain article, nous parlerons de la création d'outils pour l'agent de chat que nous avons créés
Bon codage !

N'hésitez pas à consulter le message original

Building a Powerful Chatbot with OpenAI and LangChain

Créer un chatbot puissant avec OpenAI et LangChain

Dans cet article, nous expliquerons comment créer un chatbot basique mais puissant à l'aide d'OpenAI et LangChain.

bojanjagetic.com

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal