Build a JavaScript AI Agent With LangGraph.js and MongoDB
Jesse Hall15 min read • Published Sep 10, 2024 • Updated Sep 10, 2024
APLICATIVO COMPLETO
Avalie esse Tutorial
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:
- 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.
- 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.
- It plays well with humans: You can easily add human input to your AI workflows to monitor and alter the agent's approach.
- 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:
- Start new conversations and continue existing ones.
- Look up employee information using MongoDB Atlas Vector Search.
- 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!
Before we begin, make sure you have the following:
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.
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: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.
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.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.
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: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.
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:
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.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.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.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.
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.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.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:
- The conversation starts with the "agent" node.
- The agent processes the user's input and decides whether to use a tool or end the conversation.
- If a tool is needed, control is passed to the "tools" node, where the selected tool is executed.
- The result from the tool is sent back to the "agent" node.
- The agent interprets the tool's output and formulates a response or decides on the next action.
- 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.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.Finally, we'll run the agent:
This will run the agent and return the final response. Here's a breakdown of what's happening:
- We invoke the compiled workflow (
app.invoke()
) with the initial state containing the user's query. - The
recursionLimit
is set to 15 to prevent infinite loops. - We pass a
thread_id
in the configurable options, which allows for conversation persistence across multiple interactions. - The workflow runs through its nodes (agent and tools) until a final state is reached.
- We extract the last message from the final state, which contains the agent's final response.
- This final response is both logged to the console and returned from the function.
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.Now that we have our server set up, we can test our AI agent:
- 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:
- 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.
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.
Principais comentários nos fóruns
Ainda não há comentários sobre este artigo.