skip to content
logo
Table of Contents

Building a Web Search Agent with Langchain and Node.js

As AI capabilities continue to advance, developers need efficient ways to connect language models with external data sources. Langchain provides a powerful framework for building AI applications with web search capabilities. This guide demonstrates how to quickly set up a Langchain web search agent in Node.js.


Prerequisites

Before starting, ensure you have:

  • Node.js 18+ installed
  • OpenAI API key
  • Google Search API key and CSE ID

Project Setup

First, create a new Node.js project and install the required dependencies:

Terminal window
mkdir langchain-search-agent
cd langchain-search-agent
npm init -y
npm install langchain @langchain/openai @langchain/google-genai langchain-google-search dotenv

Create a .env file in your project root:

OPENAI_API_KEY=your_openai_api_key
GOOGLE_API_KEY=your_google_api_key
GOOGLE_CSE_ID=your_google_cse_id

Building the Web Search Agent

Create an index.js file with the following code to set up a basic web search agent:

import { config } from 'dotenv';
config();
import { ChatOpenAI } from '@langchain/openai';
import { GoogleSearchAPIRetriever } from 'langchain-google-search';
import { createRetrievalChain } from 'langchain/chains/retrieval';
import { createStuffDocumentsChain } from 'langchain/chains/combine_documents';
import { ChatPromptTemplate } from '@langchain/core/prompts';
import { StringOutputParser } from '@langchain/core/output_parsers';
async function main() {
// Initialize the language model
const model = new ChatOpenAI({
modelName: 'gpt-4-turbo',
temperature: 0,
});
// Set up Google search retriever
const retriever = new GoogleSearchAPIRetriever({
apiKey: process.env.GOOGLE_API_KEY,
engineId: process.env.GOOGLE_CSE_ID,
topK: 5,
});
// Create prompt template
const prompt = ChatPromptTemplate.fromTemplate(`
Answer the following question based on the provided context.
If you don't know the answer, just say that you don't know.
Context: {context}
Question: {question}
`);
// Create document chain
const documentChain = await createStuffDocumentsChain({
llm: model,
prompt,
outputParser: new StringOutputParser(),
});
// Create retrieval chain
const retrievalChain = await createRetrievalChain({
retriever,
combineDocsChain: documentChain,
});
// Run the chain with a query
const result = await retrievalChain.invoke({
question: 'What are the latest developments in nuclear fusion as of 2025?',
});
console.log('Question:', result.question);
console.log('Answer:', result.answer);
}
main().catch(console.error);

Adding Error Handling and Rate Limiting

For production applications, implement error handling and rate limiting:

import { RateLimiter } from 'limiter';
// Create a rate limiter - 5 requests per minute
const limiter = new RateLimiter({ tokensPerInterval: 5, interval: 'minute' });
async function searchWithRateLimit(question) {
const remainingRequests = await limiter.removeTokens(1);
console.log(`Remaining requests: ${remainingRequests}`);
try {
const result = await retrievalChain.invoke({ question });
return result;
} catch (error) {
console.error('Error during search:', error.message);
if (error.response) {
console.error(`Status: ${error.response.status}`);
console.error(`Data: ${JSON.stringify(error.response.data)}`);
}
throw new Error('Search failed. Please try again later.');
}
}

Creating a Simple API

To expose your search functionality as an API, use Express:

import express from 'express';
const app = express();
app.use(express.json());
app.post('/search', async (req, res) => {
try {
const { question } = req.body;
if (!question) {
return res.status(400).json({ error: 'Question is required' });
}
const result = await searchWithRateLimit(question);
res.json({ answer: result.answer });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});

Enhancing Results with Memory

Add conversation memory to maintain context across multiple queries:

import { BufferMemory } from 'langchain/memory';
// Create memory instance
const memory = new BufferMemory({
memoryKey: 'chat_history',
returnMessages: true,
});
// Modify your chain to include memory
const conversationalChain = await createConversationalRetrievalChain({
retriever,
combineDocsChain: documentChain,
memory,
});

Performance Optimization

Optimize your web search agent for production use:

  1. Caching: Add Redis for caching frequent searches
import { Redis } from '@upstash/redis';
const redis = new Redis({
url: process.env.REDIS_URL,
token: process.env.REDIS_TOKEN,
});
async function searchWithCache(question) {
const cacheKey = `search:${question}`;
const cachedResult = await redis.get(cacheKey);
if (cachedResult) {
console.log('Cache hit');
return JSON.parse(cachedResult);
}
console.log('Cache miss');
const result = await searchWithRateLimit(question);
await redis.set(cacheKey, JSON.stringify(result), { ex: 3600 }); // 1 hour expiry
return result;
}
  1. Parallel Processing: Handle concurrent search requests efficiently
async function batchProcess(questions) {
return Promise.all(
questions.map(async (question) => {
try {
return await searchWithCache(question);
} catch (error) {
return { question, error: error.message };
}
})
);
}

Conclusion

Building a Langchain web search agent in Node.js provides a powerful way to enhance AI applications with up-to-date information. This implementation can be further expanded with:

  • Different retrieval sources (e.g., Bing, DuckDuckGo)
  • Custom document processing
  • Advanced query formulation
  • Integration with vector databases

The combination of large language models and web search capabilities creates versatile applications that can answer complex queries with current, real-world information.


Troubleshooting Common Issues

  • API Rate Limits: Both OpenAI and Google Search APIs have rate limits. Implement proper error handling and backoff strategies.
  • Context Length: Be mindful of token limits when passing search results to the LLM.
  • Search Quality: Refine your search queries for better results by implementing query planning.
  • Cost Management: Monitor API usage to control costs, especially for production deployments.

By following this guide, you now have a functional Langchain web search agent that can be integrated into various Node.js applications and services.