¡Construyendo un backend robusto para un asistente de IA!

Back4app OpenAI Virtual Assistant Cover

A medida que avanza la tecnología de IA, se espera que los asistentes de IA desempeñen un papel cada vez más importante en la gestión de la atención al cliente empresarial. La mayoría de las empresas ya han integrado algún tipo de IA en sus flujos de trabajo.

En este artículo analizaremos los asistentes de IA y destacaremos sus increíbles beneficios y posibles inconvenientes.

Además de eso, proporcionaremos una guía completa paso a paso sobre cómo crear un asistente basado en IA utilizando OpenAI y Back4app.

¿Qué es un asistente de IA?

Un asistente de IA es una pieza de software que recibe un mensaje a través de texto o voz y genera una respuesta.

Entre otras cosas, esta tecnología utiliza procesamiento del lenguaje natural (NLP, del inglés “natural language processing”) y aprendizaje automático.

El propósito de los asistentes de IA es imitar una conversación humana.

A lo largo del artículo, usaremos las “palabras asistente de IA” y “chatbot de IA” indistintamente. Sin embargo, algunas personas podrían argumentar que un asistente es una versión más compleja de un chatbot que también puede realizar tareas.

Algunos ejemplos de asistentes de IA populares son ChatGPTClaude y Gemini.

Algunas aplicaciones de asistente de IA incluyen:

  • Atención al cliente (se pueden capacitar asistentes de IA para responder las consultas de los clientes)
  • Ayuda para desarrolladores (los asistentes de IA pueden generar código y ayudar a los desarrolladores a trabajar de manera eficiente)
  • Educación (los asistentes se pueden utilizar con fines educativos y de incorporación de usuarios)
  • Marketing y análisis (los asistentes pueden generar material de marketing y analizar datos)
  • Entretenimiento (los chatbots de IA pueden crear respuestas entretenidas o creativas)

Beneficios de los asistentes de IA

Los asistentes de IA ofrecen una serie de beneficios. ¡Echémosles un vistazo!

Aumentar la productividad

Los asistentes de IA le permiten aumentar enormemente la productividad de su negocio.

Se pueden utilizar para organización de tareas, operaciones comerciales, atención al cliente, marketing, etc.

Al utilizar IA, puede crear un soporte al cliente autónomo y altamente escalable que esté disponible 24/7.

Además, los desarrolladores pueden aprovechar los asistentes de inteligencia artificial para escribir, revisar y documentar código.

Ya existen varias herramientas especializadas para este propósito, incluidas GitHub Copilot, OpenAI Codex y CodePal.

Facilidad de uso

Los asistentes de IA se encuentran entre los softwares más accesibles porque “entienden” el texto humano. Casi cualquier persona, por muy experto en tecnología que sea, puede utilizarlos.

Reducir costos

Los asistentes de IA pueden ayudarle a reducir significativamente los costos optimizando sus procesos de trabajo y automatizando la atención al cliente. 

Algunos estudios han descubierto que la IA ayuda a las empresas a reducir costos hasta en un 20%.

Recuperación de información

Una de las mejores ventajas de los asistentes de IA es su capacidad para recuperar información. Pueden consultar rápidamente varios documentos y devolver una respuesta sencilla y legible por el usuario.

Además, pueden acompañar las respuestas con las fuentes.

Gracias a los avances recientes en la API de OpenAI, ahora puede entrenar bots utilizando sus datos comerciales sin esfuerzo.

Personalización

Los asistentes de IA son altamente personalizables. Reutilizar un asistente es tan fácil como cambiar las instrucciones o el llamado mensaje inicial.

Además, los asistentes de IA pueden devolver respuestas personalizadas según con quién se comunican.

Por ejemplo, pueden responder la consulta del usuario en su idioma nativo o considerar el contexto de conversaciones anteriores.

Desventajas de los asistentes de IA

Nada viene sin inconvenientes.

Alucinaciones

Los chatbots de IA a veces generan información falsa o sin sentido. Cuando eso sucede, decimos que un chatbot alucinó.

La razón detrás de esto es que los robots en realidad no entienden lo que dicen: simplemente generan la siguiente palabra más probable basándose en las palabras anteriores.

Si tiene curiosidad por saber cómo funcionan los chatbots de IA como ChatGPT, consulte este artículo.

No pueden realizar operaciones complejas

Los asistentes de IA son excelentes para tareas simples y repetitivas, pero fallan estrepitosamente cuando se les pide que realicen tareas complejas.

Carecen de sentido común y de inteligencia humana en general. Si la respuesta no está dentro del material de aprendizaje del chatbot, es probable que devuelva una respuesta incorrecta.

Además, no se garantiza que den resultados óptimos.

Mantenimiento

Para garantizar que los chatbots capacitados en documentos comerciales proporcionen información precisa y actualizada, debe actualizarlos periódicamente con los documentos más recientes.

Sin este mantenimiento continuo, el chatbot puede generar respuestas obsoletas.

Preocupaciones de privacidad y seguridad

A veces, los asistentes tienen que lidiar con información comercial clasificada o datos personales de los usuarios.

Esto plantea algunas cuestiones éticas y hace posible que el asistente filtre información confidencial.

¿Cómo construir un asistente de IA?

En esta parte del tutorial, crearemos un asistente virtual con tecnología GPT.

Nuestro asistente virtual se especializará en responder preguntas de matemáticas. Utilizará hilos, lo que le permitirá responder preguntas de seguimiento.

Además, el código se diseñará para facilitar su reutilización y adaptabilidad a otras aplicaciones.

En el backend usaremos OpenAI y Back4app, y el frontend se construirá usando React (con TailwindCSS).

Back4app + OpenAI Final App

Requisitos previos

Objetivos

#BackendFrontend
1Crear una aplicación Back4appIniciar un nuevo proyecto
2Actualizar la versión Node.js de la aplicaciónInstalar TailwindCSS
3Crear una clave secreta de OpenAICodificar la interfaz de usuario
4Agregar la clave secreta como una variable de entornoInstalar y configurar el SDK de Parse
5Crear funciones de Cloud CodeConectarse al servidor

¡Empecemos a codificar!

Backend

En esta etapa del tutorial, nos encargaremos del backend. Crearemos una aplicación Back4app, crearemos claves secretas de OpenAI, las agregaremos como variables de entorno y escribiremos las funciones requeridas de Cloud Code.

Crear aplicación Back4app

Primero, inicie sesión en su cuenta Back4app o cree una si aún no tiene una.

Al iniciar sesión, será redirigido a su lista de aplicaciones. Haga clic en “Crear nueva aplicación” para crear una aplicación.

Back4app App List

La plataforma Back4app le permite implementar dos tipos de aplicaciones: Backend como Servicio (BaaS) y Contenedores como Servicio (CaaS). Estamos construyendo un backend, así que opte por BaaS.

Back4app BaaS Create

A continuación, asigne un nombre informativo a su aplicación, deje la base de datos como NoSQL y haga clic en “Crear”.

Back4app App Setup

Espere aproximadamente tres minutos para que la plataforma cree la aplicación. Back4app se encargará de todo, desde crear la capa de la aplicación hasta configurar la base de datos, la seguridad, el escalado y más.

Una vez hecho esto, será redirigido a la interfaz de la base de datos de su aplicación.

Back4app Database View

Cambiar la versión de Node

De forma predeterminada, las aplicaciones Back4app funcionan con Parse v4.10.4. Esta versión de Parse Server utiliza Node v14, que es incompatible con la biblioteca OpenAI, que requiere Node v18+.

Actualicemos la versión de Parse Server.

Primero, seleccione “Configuración del servidor” en la barra lateral, luego navegue hasta la configuración de “Administrar servidor de Parse” como se muestra en la imagen a continuación.

Back4app App Settings

Cambie la versión de Parse Server a 5.2.3 o más reciente.

Back4app Parse Server Version

Haga clic en “Guardar” y espere unos minutos hasta que Back4app actualice la versión del servidor.

Para verificar la versión de Node.js, puede definir la siguiente función de Cloud Code:

Parse.Cloud.define("getNodeVersion", async(request) => {
  return process.version;
});

Luego, actívelo a través de la API > Console > incorporada enviando una solicitud POST a functions/getNodeVersion.

Claves API de OpenAI

Continuando, creemos una clave API de OpenAI para conectarnos a OpenAI desde nuestro backend.

Navegue al panel de OpenAI y cree un nuevo proyecto haciendo clic en “Proyecto predeterminado” y luego en “Crear proyecto”.

Back4app OpenAI Create Project

Dele a su proyecto un nombre descriptivo; yo elegiré “back4app”. Después de eso, haga clic en “Crear”.

OpenAI debería cambiar automáticamente al proyecto recién creado.

A continuación, vaya a la sección “Claves API” seleccionando “Panel” en la barra de navegación y luego “Claves API” en la barra lateral.

Haga clic en “Crear nueva clave secreta” para iniciar el proceso de creación de la clave API.

Back4app OpenAI Create API Key

Deje todas las configuraciones predeterminadas y haga clic en “Crear clave secreta” para confirmar la creación de la clave.

Back4app OpenAI API Key Settings

Tome nota de la clave secreta, ya que solo podrá verla una vez.

Trate su clave secreta con la misma seguridad que lo haría con una contraseña. Si alguien más la obtiene, podría generar importantes costos por parte de OpenAI. Además, sugiero establecer límites de uso.

Establezca variables de entorno

Para evitar exponer nuestra clave secreta en el código fuente, la agregaremos como variable de entorno.

Navegue a “Configuración del servidor > Variables de entorno > Configuración”.

Back4app Environmental Variables

Luego configure la variable de entorno OPENAI_API_KEY como lo haría en un archivo.env:

OPENAI_API_KEY=<your_openai_api_key>

Asegúrese de reemplazar <your_openai_api_key> con su clave secreta de OpenAI del paso anterior.

Por último, haga clic en “Guardar” para guardar las variables de entorno.

Back4app Environmental Variable Add

Ahora puede acceder a la clave secreta desde las funciones de Cloud Code de esta manera:

const secretKey = process.env.OPENAI_API_KEY;
console.log(secretKey);

// sk-proj-...

Cloud Code

Para implementar la lógica de backend, utilizaremos funciones de Cloud Code. Las funciones de Cloud Code son una característica sólida de Parse Server que permite a los desarrolladores ejecutar código JavaScript personalizado en el lado del servidor.

Se pueden activar mediante REST, mediante Parse SDK o programarse según un tiempo determinado.

Consulte ¿Qué son las funciones sin servidor? para obtener más información sobre las funciones como servicio.

Primero, seleccione “Cloud Code > Funciones y alojamiento web” en la barra lateral para acceder a Cloud Code.

Back4app Cloud Code

Notará que la pantalla está dividida en dos secciones. Tiene la estructura de directorios en el lado izquierdo y el editor de código JavaScript en el derecho. Por defecto, hay dos directorios:

  1. La carpeta nube es utilizada para implementar funciones de Cloud Code y otro código personalizado
  2. La carpeta público esutilizada para implementar contenido estático (por ejemplo, imágenes, videos, iconos).
Instalar la biblioteca OpenAI

Para interactuar con la API de OpenAI, instalaremos la biblioteca JavaScript de OpenAI.

Instalar paquetes NPM usando Cloud Code es fácil. Para hacerlo, cree un archivo package.json en la carpeta de la nube que enumere los paquetes que desea instalar.

// cloud/package.json

{
  "dependencies": {
    "openai": "^4.51.0"
  }
}

Para obtener la última versión del paquete openai, consulte la página del paquete NPM.

Luego haga clic en “Implementar” en la parte superior derecha de la pantalla.

Si la instalación se realiza correctamente, debería ver un package-lock.json recién generado en la carpeta nube. El archivo de bloqueo debe contener el paquete openai.

Funciones del código en la nube

A continuación, ocupémonos de las funciones de Cloud Code.

Crearemos las siguientes cuatro funciones:

Crearemos las siguientes cuatro funciones:

  1. setup() creará un asistente virtual y guardará su configuración en la base de datos.
  2. createThread() creará un nuevo hilo de asistente virtual
  3. deleteThread(threadId) eliminará un hilo de asistente virtual existente
  4. addMessage(threadId, message) agregará un mensaje al hilo y generará una respuesta

Continúe y pegue el siguiente código en cloud/main.js :

// cloud/main.js

const OpenAI = require("openai");
const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

const ASSISTANT_INITIAL_MESSAGE = "Hi, my name is Math Bot. How can I help you?";
const ASSISTANT_SETTINGS = {
  name: "Math Bot",
  instructions: "Very smart math bot that answers math questions.",
  model: "gpt-3.5-turbo-0125",
  tools: [],
};

Parse.Cloud.define("setup", async (request) => {
  const Assistant = Parse.Object.extend("Assistant");
  const query = await new Parse.Query(Assistant);
  const count = await query.count();

  // Check if virtual assistant already exists
  if (count !== 0) {
    throw new Parse.Error(
        Parse.Error.VALIDATION_ERROR, 
        "A virtual assistant already exists!",
    );
  }

  // Use OpenAI's API to create an assistant
  const openAssistant = await openai.beta.assistants.create(
    ASSISTANT_SETTINGS,
  );

  // Store the assistant in Back4app database
  const assistant = new Assistant();
  for (const key in ASSISTANT_SETTINGS) {
    assistant.set(key, ASSISTANT_SETTINGS[key]);
  }
  assistant.set("initialMessage", ASSISTANT_INITIAL_MESSAGE);
  assistant.set("assistantId", openAssistant.id);
  await assistant.save();

  return assistant.get("assistantId");
});

Parse.Cloud.define("createThread", async (request) => {
  const thread = await openai.beta.threads.create();
  return thread.id;
});

Parse.Cloud.define("deleteThread", async (request) => {
  const _threadId = request.params.threadId;
  return await openai.beta.threads.del(_threadId);
});

Parse.Cloud.define("addMessage", async (request) => {
  const _threadId = request.params.threadId;
  const _message = request.params.message;

  // Verify all the parameters are provided
  if (!_threadId || !_message) {
    throw new Parse.Error(
        Parse.Error.VALIDATION_ERROR,
        "You need to provide: threadId & message.",
    );
  }

  const Assistant = Parse.Object.extend("Assistant");
  const query = await new Parse.Query(Assistant);
  const count = await query.count();

  // Check if a virtual assistant exists
  if (count === 0) {
    throw new Parse.Error(
        Parse.Error.VALIDATION_ERROR,
        "A virtual assistant does not exist!",
    );
  }

  const assistant = await new Parse.Query(Assistant).first();
  const assistantId = assistant.get("assistantId");

  // Get the thread, add the message, and generate a response
  let buffer = "";
  const message = await openai.beta.threads.messages.create(
    _threadId, {role: "user", content: _message},
  );
  let run = await openai.beta.threads.runs.createAndPoll(
    _threadId, {assistant_id: assistantId},
  );

  // Add the last message to the buffer
  if (run.status === "completed") {
    const messages = await openai.beta.threads.messages.list(run.thread_id);
    buffer += messages.data[0].content[0].text.value;
  } else {
    console.error("Failed to run the assistant.");
  }

  return buffer;
});

Resumen de código

  1. El código importa e inicializa la biblioteca OpenAI.
  2. Luego define la configuración del asistente (por ejemplo, nombre, instrucciones y mensaje inicial).
  3. Code proporciona cuatro funciones de Cloud Code, que se describen arriba.
  4. En setup(), buscamos el asistente y el hilo y luego agregamos un mensaje al hilo. 

Probar funciones de código en la nube

Antes de pasar al frontend, debemos asegurarnos de que el backend funcione como se esperaba.

Para fines de prueba, usaremos la consola integrada de Back4app. Navegue a “API > Consola > REST” en la barra lateral.

Back4app API Console REST

Primero, active la función setup():

  • Qué tipo de solicitud: PUBLICAR
  • Qué punto final: funciones/configuración
  • Usar clave maestra: falso
  • Ejecutar como: dejar en blanco
  • Parámetros de consulta: dejar en blanco

Esto creará un nuevo asistente y lo guardará en la base de datos. Si navega a la vista de la base de datos, debería ver que la clase Asistente ahora tiene una fila.

Back4app Database Assistant

Continuando, probemos los puntos finales de la conversación.

  1. PUBLICAR en funciones/createThread para crear un hilo. Tome nota del ID del hilo.
  2. PUBLICAR una pregunta en funciones/addMessage con los siguientes parámetros {“threadId”: “< thread_id >”, “message”: “¿Qué es 2+2?”}. Verifique que la respuesta generada sea correcta.
  3. PUBLICAR en funciones/deleteThread con los siguientes parámetros {“threadId”: “< thread_id>”} para eliminar el hilo.

¡Genial, el backend parece estar funcionando bien!

Frontend

En esta sección del tutorial, iniciaremos un nuevo proyecto de React, instalaremos TailwindCSS, implementaremos la interfaz de usuario, configuraremos Parse SDK e implementaremos la lógica requerida.

Crear aplicación Vite

Comience iniciando un nuevo proyecto Vite usando la plantilla de React:

$ npm create vite@latest frontend -- --template react

Cambie el directorio a la carpeta recién creada e instale las dependencias:

$ cd frontend
$ npm install

Ejecute el servidor de desarrollo:

$ npm run dev

Abra su navegador web favorito y navegue hasta http://localhost:5174/. Debería ver la página de inicio predeterminada de Vite + React.

TailwindCSS

Para simplificar nuestro trabajo, usaremos TailwindCSS, un marco CSS de utilidad que le permite crear rápidamente diseños personalizados sin salir de su HTML.

El marco proporciona un enfoque de estilo altamente personalizable y responsivo.

Para instalar TailwindCSS, siga la guía oficial.

Vistas

Continuando, implementemos la interfaz de usuario.

Para que nuestro código esté más organizado, primero crearemos algunos componentes. Primero, cree una carpeta de componentes dentro de la carpeta src y coloque los siguientes tres archivos dentro:

Además de eso, agregue este avatar.png a la carpeta src/assets.

En este punto, la estructura de su directorio debería verse así:

frontend/
└── src/
    ├── components/
    │   ├── Spinner.jsx
    │   ├── AssistantMessage.jsx
    │   └── UserMessage.jsx
    ├── assets/
    │   └── avatar.png
    └── ...

A continuación, coloque el siguiente código en src/App.jsx :

// src/App.jsx

import {useEffect, useState} from "react";

import AssistantMessage from "./components/AssistantMessage.jsx";
import UserMessage from "./components/UserMessage.jsx";
import Spinner from "./components/Spinner.jsx";

function App() {

  const [initialMessage, setInitialMessage] = useState(undefined);
  const [loading, setLoading] = useState(true);

  const [threadId, setThreadId] = useState(undefined);
  const [message, setMessage] = useState("");
  const [messages, setMessages] = useState([
    {role: "assistant", content: "Welcome! How can I help you today?"},
    {role: "user", content: "What is 2+2?"},
    {role: "assistant", content: "2+2 is 4."},
  ]);

  async function getInitialMessage() {
    // TODO: get the initial message
  }

  async function reset(message) {
    // TODO: create a new thread
  }

  useEffect(() => {
    setLoading(false);
    // TODO: get the initial message
  }, []);

  function onSubmit(event) {
    // TODO: add the message to the thread and generate response
  }

  function onNewThread() {
    // TODO: create a new thread
  }

  return (
    <main className="container mx-auto py-8 px-8 md:px-32 lg:px-64 h-[100vh]">
      <div className="pb-12 space-y-2">
        <h1 className="text-3xl font-bold">
          back4app-openai-virtual-assistant
        </h1>
        <p>
          An AI-powered virtual assistant built using OpenAI + Back4app.
        </p>
      </div>
      <div className="space-y-2">
        {messages.map((message, index) => {
          switch (message.role) {
            case "assistant":
              return <AssistantMessage key={index} content={message.content}/>;
            case "user":
              return <UserMessage key={index} content={message.content}/>;
            default:
              return <></>;
          }
        })}
        {loading && <Spinner/>}
      </div>
      <form className="inline-block flex flex-row pt-12" onSubmit={onSubmit}>
        <input
          type="text"
          className="w-full p-2 border border-gray-300 rounded-md outline-none"
          placeholder="Type a message..."
          value={message}
          onChange={(event) => setMessage(event.target.value)}
        />
        <button
          type="submit"
          className="bg-blue-500 hover:bg-blue-600 text-white p-2 px-3 rounded-md ml-2"
        >
          Send
        </button>
        <button
          type="button"
          className="bg-green-500 text-white p-2 px-3 rounded-md ml-2"
          onClick={onNewThread}
        >
          New
        </button>
      </form>
    </main>
  );
}

export default App;

Este código crea una interfaz de usuario simple, que representa mensajes a partir del estado de los mensajes. Además de eso, proporciona un cuadro de texto y un botón para enviar mensajes al asistente virtual.

Inicie el servidor de desarrollo una vez más y navegue hasta http://localhost:5174/. Debería poder ver una interfaz de usuario similar a ChatGPT.

Instalar el SDK de Parse

Para conectarnos a nuestro backend basado en Back4app, usaremos Parse SDK.

El SDK de Parse permite a los desarrolladores interactuar sin problemas con backends basados en Parse, lo que permite consultas de datos eficientes, autenticación de usuarios, notificaciones, manejo de datos en tiempo real y más.

Primero, instale Parse a través de npm:

$ npm install parse

A continuación, navegue hasta su aplicación Back4app. Seleccione “Configuración de la aplicación> Seguridad y claves” en la barra lateral. Luego, tome nota del “ID de la aplicación” y la “Clave de JavaScript”.

Back4app Security & Keys

En lugar de exponer las claves secretas en el código fuente, cree un archivo.env en la raíz del proyecto:

VITE_BACK4APP_APPLICATION_ID=<your_back4app_application_id>
VITE_BACK4APP_JAVASCRIPT_KEY=<your_back4app_javascript_key>

Asegúrese de reemplazar las variables con sus claves reales.

A continuación, navegue hasta src/main.jsx e inicialice Parse usando las variables de entorno:

// src/main.jsx

// ...
import Parse from "parse/dist/parse.min.js";

// Initialize Parse SDK using the Back4app API keys
Parse.initialize(
  import.meta.env.VITE_BACK4APP_APPLICATION_ID,
  import.meta.env.VITE_BACK4APP_JAVASCRIPT_KEY,
);
Parse.serverURL = "https://parseapi.back4app.com/";

ReactDOM.createRoot(document.getElementById("root")).render(
  // ...
);

Ahora puede utilizar la instancia de Parse en todas sus vistas importándola:

import Parse from "parse/dist/parse.min.js";

Lógica

Por último, reemplace los ganchos de React en src/App.jsx con lo siguiente:

// src/App.jsx

// ...
import Parse from "parse/dist/parse.min.js";

function App() {

  // ...

  async function getInitialMessage() {
    const Assistant = Parse.Object.extend("Assistant");
    const assistant = await new Parse.Query(Assistant).first();
    return assistant.get("initialMessage");
  }

  async function reset(message) {
    setMessages([
      {role: "assistant", content: message},
    ]);
    setMessage("");
    const threadId = await Parse.Cloud.run("createThread");
    setThreadId(threadId);
  }

  useEffect(() => {
    (async () => {
      const assistantInitialMessage = await getInitialMessage();
      setInitialMessage(assistantInitialMessage);
      await reset(assistantInitialMessage);
      setLoading(false);
    })();
  }, []);

  function onSubmit(event) {
    event.preventDefault();
    if (loading || !threadId || !message) return;

    setMessages([
      ...messages,
      {role: "user", content: message},
    ]);
    setMessage("");

    setLoading(true);
    (async () => {
      const response = await Parse.Cloud.run("addMessage", {threadId, message});
      setMessages(messages => [
        ...messages,
        {role: "assistant", content: response},
      ]);
      setLoading(false);
    })();
  }

  function onNewThread() {
    if (loading || !threadId) return;

    setLoading(true);
    (async () => {
      await reset(initialMessage);
      setLoading(false);
    })();
  }

  return (
      // ...
  );
}

export default App;

Este código maneja el mensaje y lo envía al backend. También permite a los usuarios crear un nuevo hilo haciendo clic en un botón.

¡Voilá! La interfaz ya está completa.

Reinicie el servidor de desarrollo y pruebe la aplicación para asegurarse de que todo funcione.

Si desea implementar la interfaz del asistente, consulte ¿Cómo alojar una aplicación React?

Conclusión

Este artículo le enseñó todo lo que necesita saber para crear asistentes personalizados basados en IA.

Ahora debería poder utilizar la API Asistente de OpenAI y Back4app para respaldar e implementar sus asistentes de IA.

El código fuente final está disponible en el repositorio de GitHub back4app-openai-virtual-assistant.


Leave a reply

Your email address will not be published.