Skip to main content

Command Palette

Search for a command to run...

Cómo Construir un Agente con LangGraph y AWS CDK - Pt. 1

Published
7 min read
Cómo Construir un Agente con LangGraph y AWS CDK - Pt. 1

La creación de agentes ha cobrado gran relevancia durante estos últimos años. En esta serie de artículos aprenderás a construir uno utilizando LangGraph y AWS CDK. Iremos desde lo mas básico hasta ver temas como la gestión de memoria e integración con MCP’s (Model Context Protocol).

LangGraph

LangGraph es una herramienta versátil que permite crear y gestionar flujos de trabajo de procesamiento de lenguaje natural (NLP) utilizando grafos. Proporciona una API sencilla para implementar diferentes modelos de lenguaje y conectarlos de manera eficaz, permitiendo así la creación de agentes conversacionales y sistemas de recomendación. Puedes aprender más sobre LangGraph aquí.

AWS CDK

AWS Cloud Development Kit (CDK) es un framework que permite a los desarrolladores definir su infraestructura en la nube utilizando lenguajes de programación familiares, como TypeScript, Python y Java. AWS CDK hace que la provisión de recursos en AWS sea más accesible y modular. Si quieres saber más sobre AWS CDK, puedes dirigirte a su documentación oficial.

¿Que vamos a construir?

Vamos a avanzar paso a paso en la construcción de un agente inteligente que tendrá la capacidad de recibir la URL de cualquier artículo en línea. Este agente no solo generará un resumen del contenido del artículo, sino que también nos enviará dicho resumen directamente a nuestro correo electrónico. Además, el agente será lo suficientemente sofisticado para recordar y almacenar nuestras preferencias personales en cuanto al tono y la estructura del resumen que deseamos recibir. Por ejemplo, si preferimos un resumen más formal o uno más casual, o si queremos que el resumen sea conciso o detallado, el agente ajustará su salida en consecuencia. Esta funcionalidad personalizada garantizará que los resúmenes sean útiles y alineados con nuestras expectativas.

Requisitos Previos

Antes de empezar, asegúrate de tener instalado lo siguiente en tu máquina:

  • Node JS (versión 22.x o superior)

  • AWS CLI configurado con tus credenciales de AWS.

  • AWS CDK instalado globalmente:

      npm install -g aws-cdk
    

Empezemos! 🚀

Estructura del Proyecto

  1. Primero, iniciemos creando un nuevo proyecto de CDK:

     mkdir article-summarizer-agent-cdk-langgraph && cd article-summarizer-agent-cdk-langgraph
     cdk init app --language=typescript
    
  2. Ahora, dentro de nuestro directorio del proyecto instalamos las dependencias que necesitaremos:

     npm install @langchain/core @langchain/langgraph @langchain/openai dotenv esbuild
    

    Instalamos algunos tipos para usarlos dentro de nuestras lambdas:

     npm install -D @types/aws-lambda
    
  3. La estructura del proyecto será la siguiente:

     article-summarizer-agent-cdk-langgraph/
     ├── bin
     │   └── article-summarizer-agent-cdk-langgraph.ts
     ├── lib
     │   ├── config
     │   └── article-summarizer-agent-cdk-langgraph-stack.ts
     ├── src
     │   ├── agent
     │   │   ├── agent.ts
     │   │   ├── instructions.ts 
     │   │   └── tools
     │   └── handlers
     ├── cdk.json
     ├── package.json
     └── tsconfig.json
    

Desarrollo del Agente

Implementar lógica básica del agente

Vamos a empezar creando la lógica de nuestro agente, es decir, como recibirá el input y como nos dará la respuesta. Para ello agregaremos el siguiente código en el archivo src/agent/agent.ts:

import { ChatOpenAI } from "@langchain/openai";
import { createReactAgent } from "@langchain/langgraph/prebuilt";

export class Agent {
  private agent: ReturnType<typeof createReactAgent>;

  constructor(model: ChatOpenAI) {
    this.agent = createReactAgent({
      llm: model,
      tools: [],
      prompt: "",
    });
  }

  async run(input: string): Promise<string> {
    const response = await this.agent.invoke({
      messages: [{ role: "user", content: input }],
    });

    return response.messages[response.messages.length - 1].content;
  }
}

Para nuestro agente vamos a usar un modelo de OpenAI, pero si gustas puedes cambiarlo por el modelo de tu preferencia (esta es una de las grandes ventajas de LangGraph 🔥). Por ejemplo, para utilizar Anthropic primero debemos instalar el paquete @langchain/anthropic y luego modificar la clase Agent para que se vea así:

import { ChatAnthropic } from "@langchain/anthropic";
...

export class Agent {
  private agent: ReturnType<typeof createReactAgent>;

  constructor(model: ChatAnthropic) {
    this.agent = createReactAgent({
      llm: model,
      tools: [],
      prompt: "",
    });
  }

  ...
}

Puedes revisar la lista de modelos disponibles aquí.

Crear función Lambda para interactuar con el agente

Una vez tengamos la lógica básica de nuestro agente, el siguiente paso es definir una función Lambda que se encargará de procesar las solicitudes y respuestas desde una API implementada en API Gateway. Abre el archivo lib/article-summarizer-agent-cdk-langgraph-stack.ts y añade lo siguiente:

import { StackProps, Stack, Duration } from "aws-cdk-lib";
import { HttpApi, HttpMethod } from "aws-cdk-lib/aws-apigatewayv2";
import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Construct } from "constructs";
import { getConfig } from "./config";

export class ArticleSummarizerAgentCdkLanggraphStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const config = getConfig();

    // Definimos la API para interactuar con el agente
    const httpApi = new HttpApi(this, "ArticleSummarizerAgentApi", {
      apiName: "article-summarizer-agent-api",
      description: "API for Article Summarizer Agent",
    });

    // Definimos la función Lambda que ejecutará el agente
    const agentExecutorLambdaFunction = new NodejsFunction(
      this,
      "AgentExecutorLambdaFunction",
      {
        functionName: "agent-executor-handler",
        entry: "src/handlers/agent-executor/handler.ts",
        handler: "handler",
        memorySize: 1024,
        timeout: Duration.seconds(30),
        environment: {
          OPENAI_API_KEY: config.OPENAI_API_KEY,
        },
      }
    );

    // Agregamos un endpoint POST /message a la API que invoca la función Lambda
    httpApi.addRoutes({
      path: "/message",
      methods: [HttpMethod.POST],
      integration: new HttpLambdaIntegration(
        "AgentExecutorIntegration",
        agentExecutorLambdaFunction
      ),
    });
  }
}

Llamar al agente desde nuestra lambda

Ahora, necesitamos llamar a nuestro agente desde la lambda que acabamos de agregar. Para ello creamos un nuevo directorio llamado agent-executor dentro de la carpeta handlers y agregamos un archivo llamado handler.ts con el siguiente código:

import { APIGatewayProxyEventV2, APIGatewayProxyResultV2 } from "aws-lambda";
import { Agent } from "../../agent/agent";
import { ChatOpenAI } from "@langchain/openai";

// Creamos una instancia del modelo de lenguaje
const openAiModel = new ChatOpenAI({
  model: "gpt-4o-mini",
});

export const main = async (
  event: APIGatewayProxyEventV2
): Promise<APIGatewayProxyResultV2> => {
  // Extraemos el mensaje del cuerpo de la solicitud
  // Si no hay cuerpo, usamos un objeto vacío
  // El mensaje se encuentra en la propiedad "message"
  const body = JSON.parse(event.body || "{}") as { message?: string };

  // Creamos una instancia del agente
  const agent = new Agent(openAiModel);

  // Ejecutamos el agente con el mensaje recibido
  const responseFromAgent = await agent.run(body.message || "");

  // Devolvemos la respuesta del agente en el cuerpo de la respuesta HTTP
  return {
    statusCode: 200,
    body: JSON.stringify({
      message: responseFromAgent,
    }),
  };
};

export const handler = main;

Agregar variables de entorno

Antes de desplegar nuestro proyecto debemos configurar algunas variables de entorno para poder usar nuestro modelo de OpenAI. Para ello agregamos un nuevo directorio llamado config dentro de la carpeta lib y agregamos un archivo index.ts con el siguiente contenido:

import * as dotenv from "dotenv";

dotenv.config();

export type Config = {
  OPENAI_API_KEY: string;
};

export const getConfig = (): Config => {
  return {
    OPENAI_API_KEY: process.env.OPENAI_API_KEY!,
  };
};

Creamos un archivo .env dentro del directorio raiz y agregamos la variable OPENAI_API_KEY

OPENAI_API_KEY=<your_open_ai_key>
💡
Consejo de conejo: Mantén las configuraciones sensibles (como API Keys) fuera del código y usa AWS Secrets Manager o SSM Parameter Store para ambientes de producción

Desplegar el proyecto y probar

Una vez que tengamos todos estos componentes ya estamos listos para desplegar nuestro proyecto y probarlo para ver como funciona. Para ello nos vamos a nuestra terminal y ejecutamos el siguiente comando

cdk deploy --profile <your_aws_profile>
💡
Si es la primera vez que ejecutaras este comando, primero tendrás que ejecutar el comando cdk bootstrap —profile <your_aws_profile> donde your_aws_profile debe ser reemplazado por el perfil que hayas configurado para utilizar aws cli

Si nos aparece un mensaje similar a este: Do you wish to deploy these changes (y/n)? simplemente escribimos la letra “y” y presionamos Enter.

Cuando veamos algo similar a esto en nuestra terminal, significa que nuestro proyecto a sido desplegado con éxito 🔥🚀.

Para probar nuestro agente debemos dirigirnos a la consola de AWS y buscar el servicio de API Gateway, ahi encontraremos nuestra API llamada article-summarizer-agent-api, le damos clic y en los detalles encontraremos la url que debemos llamar dentro de la opcion Invoke URL (URL de invocación).

Con esto ya podremos ir a Postman o hacer una petición desde nuestra terminal hacia el endpoint /message y ver que nos responde nuestro agente.

curl -X POST https://<invoke_url>/message \
  -H "Content-Type: application/json" \
  -d '{"message": "Hola como estas?"}'

🎯 En el próximo artículo veremos cómo ampliar nuestro agente añadiendo instrucciones personalizadas sobre su funcionamiento. Le daremos nuevas herramientas (tools) y una memoria para almacenar las preferencias de los usuarios sobre cómo quieren sus resúmenes.

📰 Si no quieres perderte la continuación, puedes suscribirte a la newsletter aquí.

Como construir un agente con LangGraph y AWS CDK

Part 1 of 1

En esta serie vamos a aprender a como construir un agente sin servidor utilizando LangGraph y AWS CDK. Vamos a ver desde los conceptos básicos de un agente hasta conceptos avanzados como la gestión de la memoria e integración con MCP's.