Building Langchain Web Search with Node.js
/ 4 min read
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:
mkdir langchain-search-agentcd langchain-search-agentnpm init -ynpm 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_keyGOOGLE_API_KEY=your_google_api_keyGOOGLE_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 minuteconst 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 instanceconst memory = new BufferMemory({ memoryKey: 'chat_history', returnMessages: true,});
// Modify your chain to include memoryconst conversationalChain = await createConversationalRetrievalChain({ retriever, combineDocsChain: documentChain, memory,});
Performance Optimization
Optimize your web search agent for production use:
- 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;}
- 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.