EventGet 50% off your ticket to MongoDB.local London on October 2. Use code WEB50Learn more >>
MongoDB Developer
TypeScript
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Languageschevron-right
TypeScriptchevron-right

Build a JavaScript AI Agent With LangGraph.js and MongoDB

Jesse Hall15 min read • Published Sep 10, 2024 • Updated Sep 10, 2024
Node.jsAtlasSearchTypeScriptJavaScript
FULL APPLICATION
Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
As a web developer, building artificial intelligence into your web applications may seem daunting. As someone with zero background in AI/ML technologies, I totally understand. At first, it sounded so foreign to me. But I was quickly hooked when I saw how easy it is!
In this tutorial, we're going to dive into the exciting world of AI agents in JavaScript. Trust me, it's not as scary as it sounds! We're going to build something really cool using LangGraph.js and MongoDB.
So, what's the big deal with AI agents? And no, not Agent Smith. Imagine having a smart assistant that not only understands what you're saying but also remembers your previous conversations and can even utilize a number of "tools" to look up additional info, process data, and more. Pretty neat, right?
Enter LangGraph.js — your new best friend when it comes to building AI agents. Here's what makes it so awesome:
  1. It can handle complex stuff: Want your AI to make decisions or repeat tasks? LangGraph.js has got your back with its loops and branching features.
  2. It's got a great memory: No more "Oops, I forgot what we were talking about." LangGraph.js saves the state of your app after each step.
  3. It plays well with humans: You can easily add human input to your AI workflows to monitor and alter the agent's approach.
  4. It's super quick: With its streaming support, you get instant results. No more twiddling your thumbs waiting for responses.
These features make LangGraph.js an ideal choice for developing sophisticated AI agents that can maintain context and handle complex interactions. And, of course, LangGraph.js fits perfectly with LangChain.js, making it easy to integrate with other AI tools and libraries.
By integrating LangGraph.js with MongoDB, we can create AI agents that not only process and generate language but also store and retrieve information efficiently. This combination is particularly powerful for building applications that require context-aware conversations and data-driven decision-making.
This dynamic duo is perfect for building apps that need to have meaningful conversations and make smart decisions based on data. It's like creating your own J.A.R.V.I.S., minus the fancy holographic displays (for now, at least).
In this tutorial, we'll build an AI agent that can assist with HR-related queries using a database of employee information. Our agent will be able to:
  1. Start new conversations and continue existing ones.
  2. Look up employee information using MongoDB Atlas Vector Search.
  3. Persist conversation state (LangGraph checkpoints) in MongoDB.
Let's get started by setting up our project!
If you are a visual learner, give the video version of this tutorial a watch!

Setting up the project

Prerequisites

Before we begin, make sure you have the following:
  • Node.js and npm installed
While we are using OpenAI for embeddings and Anthropic for conversations, you can easily swap these out to use any LLM combo of your choice.

Project initialization

If you prefer to follow along with the code, you can clone the repository from GitHub.
Our base project structure will look like this:
Initialize a new Node.js project with TypeScript and install the required dependencies:
Create a .env file in the root of your project and add your OpenAI and Anthropic API keys as well as your MongoDB Atlas connection string:

Configuring MongoDB

Before we do anything, we need to create some synthetic data to work with. We'll use this data to seed our MongoDB database.
We'll use MongoDB Atlas as our database service. If you haven't already, create a cluster in MongoDB Atlas and obtain your connection string.

Connecting to the database

Create an index.ts file in the root of your project. We'll establish a connection to MongoDB using the MongoDB driver:
Start the server by running npx ts-node index.ts in your terminal. If you see the message "Pinged your deployment. You successfully connected to MongoDB!" you're good to go.

Seeding the database

To populate your database with synthetic employee data, let's create a seed-database.ts script. This script generates realistic employee records using OpenAI's GPT model and stores them in MongoDB along with their vector embeddings.
First, we import the necessary dependencies. We're using LangChain for AI-related functionality, MongoDB for database operations, and Zod for schema validation.
Next, let's set up our MongoDB client and ChatOpenAI instance:
Here, we create a MongoDB client using the connection string from our environment variables. We also initialize a ChatOpenAI instance with a specific model and temperature setting.
Now, let's define our employee schema using Zod:
Maybe this schema is too detailed, but it shows the power of what we can do with LLMs. As far as the LLM is concerned, this is a walk in the park.
This schema defines the structure of our employee data. We use Zod to ensure type safety and create a parser that will help us generate structured data from the AI's output.
This really is a game changer. We can now use this schema to generate data that is both realistic and consistent.
Next, let's implement the function to generate synthetic data:
This function uses the ChatOpenAI instance along with some prompt engineering to generate synthetic employee data based on our schema.
Now, let's create a function to generate a summary for each employee:
This function takes an employee object and creates a concise summary of their information using the various metadata created by the LLM. We'll use this summary to create embeddings for each employee.
Finally, let's implement the main function to seed the database:
This function connects to the MongoDB database, generates synthetic data, creates summaries for each employee, and then stores the data in the database using MongoDB Atlas Vector Search. It also handles error logging and ensures the database connection is closed when the operation is complete.
To seed the database, run the following command:
This script creates a collection of employee records in the hr_database.
Go to your MongoDB Atlas dashboard and check out the data that has been generated. It's really amazing! You'll find the same structure as the schema we defined earlier along with the summary and vector embeddings for the summary.
Next, we need to set up a vector index for similarity search, which we'll use later in our AI agent.

Setting up the MongoDB Atlas Vector Search index

To set up the vector index, follow the steps outlined in our How to Index Fields for Vector Search documentation.
Be sure to name your index “vector_index” and select the employees collection. This is the JSON definition for the index:

Building the AI agent with LangGraph.js

Now that we have our database set up, let's create our AI agent using LangGraph.js. We'll define the agent structure, implement tools for employee lookup, and set up the conversation flow.

Agent structure

Let's create a new file to define the agent called agent.ts. Here are the key components:
This is the full list of imports for the agent. It's a mix of LangChain, LangGraph, Zod, and MongoDB libraries.
To use this code within our application, we will set up a function that will be exported from this file. We'll also start by defining the MongoDB connection and collection:

Defining the agent state

Next, we'll use LangGraph's StateGraph and Annotation to define our agent's state. This will help us manage the conversation state and keep track of the conversation history.
The GraphState keeps track of the conversation messages.

Implementing tools

We'll implement an employee lookup tool that uses MongoDB Atlas Vector Search:
This tool uses MongoDB Atlas Vector Search to find relevant employee information based on the query. It returns a list of employees with their details.
The tool leverages vector embeddings to perform semantic search. This approach enables the agent to understand the intent behind the query and retrieve relevant information accordingly.
The n parameter allows you to customize the number of results returned, with a default of 10. This flexibility enables users to retrieve more or fewer results based on their specific needs.

Creating the tools node

Now, we'll define our tools and create a toolNode to manage the tools and their execution. In this example, we are only using a single tool, but you can add more tools as needed.

Defining our chat model

We'll use the ChatAnthropic model from LangChain.js for our chat model and bind it with our tools.
Again, you can change this out to any other LLM model you’d like to use.

Defining the function that calls the model

Some prompt engineering will go into this function which is our main entry point for the agent.
The callModel function is responsible for formatting the prompt, invoking the model, and returning the result. It takes the current state of the conversation and uses it to format the prompt. It then invokes the model and returns the result. The result is an array of messages, which is what the GraphState expects. The GraphState will then update the state with the new messages. This is a simple example, but it can be extended to handle more complex conversations.

Helping the agent to decide when to quit

Next, we'll define a function that decides whether the agent should call a tool or stop and reply to the user.
The shouldContinue function grabs the last message from the state and checks if it has a tool call. If it does, it returns "tools," which will be handled by the tools node. If it doesn't, it returns "end," which will be handled by the end node.

Defining the conversation flow

We'll use LangGraph to define our conversation flow:
This sets up a simple back-and-forth between the agent and its tools. Let's break down the workflow:
  1. The conversation starts with the "agent" node.
  2. The agent processes the user's input and decides whether to use a tool or end the conversation.
  3. If a tool is needed, control is passed to the "tools" node, where the selected tool is executed.
  4. The result from the tool is sent back to the "agent" node.
  5. The agent interprets the tool's output and formulates a response or decides on the next action.
  6. This cycle continues until the agent determines that no further action is needed (shouldContinue returns "end").
This workflow allows for flexible and dynamic conversations, where the agent can use multiple tools in sequence, if necessary, to fulfill the user's request. The StateGraph structure ensures that the conversation maintains context and can handle complex, multi-step interactions efficiently.

Adding memory to the agent

We'll use the MongoDBSaver checkpoint saver from LangGraph to add memory to our agent.
This will save the state of the conversation to a MongoDB database. We'll also compile the graph and include the MongoDB checkpointer to create an application that can be run.

Running the agent

Finally, we'll run the agent:
This will run the agent and return the final response. Here's a breakdown of what's happening:
  1. We invoke the compiled workflow (app.invoke()) with the initial state containing the user's query.
  2. The recursionLimit is set to 15 to prevent infinite loops.
  3. We pass a thread_id in the configurable options, which allows for conversation persistence across multiple interactions.
  4. The workflow runs through its nodes (agent and tools) until a final state is reached.
  5. We extract the last message from the final state, which contains the agent's final response.
  6. This final response is both logged to the console and returned from the function.

Creating the Express.js server

Now, let's set up an Express.js server to expose our AI agent via API endpoints. We'll do this in the index.ts file:
This sets up two main endpoints:
  • /chat for starting a new conversation
  • /chat/:threadId for continuing an existing conversation
The /chat endpoint handles the initial message and starts a new conversation. It generates a unique thread ID for each conversation and passes it to the callAgent function.
The /chat/:threadId endpoint handles subsequent messages in an existing conversation. It passes the thread ID to the callAgent function to continue the conversation.

Testing the AI agent

Now that we have our server set up, we can test our AI agent:
  1. Start the server.
2. Use a tool like cURL or Postman to send requests to the /chat endpoint with the initial message.
This will start a new conversation and return the agent's response. Here's an example response:
  1. The server should respond with the agent's message. You can continue the conversation by sending additional messages to the /chat/:threadId endpoint.
Congratulations! You've successfully built an AI agent using LangGraph.js and MongoDB.

Conclusion

There you have it; we've created a sophisticated AI agent with the help of LangGraph.js and MongoDB! This agent can hold a conversation, remember what is being talked about, look up information about employees, and give a smart response to HR-related questions.
The combination of LangGraph.js for conversational flow control and MongoDB to store and retrieve memory offers a great way forward for you to build some amazing AI applications. This example can be layered with additional tools, more sophisticated conversation flows, or connectors to other data sources such as images, audio, and video.
LangGraph is a powerful tool that can enhance your AI agent development. If you're already familiar with Node.js and MongoDB, you have a solid foundation to create sophisticated AI agents capable of handling diverse tasks during interactions. By leveraging these technologies together, you can build intelligent systems that provide valuable recommendations and insights.
If you have any questions or need assistance, please check out the MongoDB community forums.
Top Comments in Forums
There are no comments on this article yet.
Start the Conversation

Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Related
Code Example

myLeG


Jul 07, 2022 | 1 min read
Article

What to Expect from Realm JavaScript v12


Apr 02, 2024 | 5 min read
Tutorial

Type Safety With Prisma & MongoDB


Aug 09, 2024 | 4 min read
Code Example

Trends Analyser


Sep 11, 2024 | 1 min read
Table of Contents