Building AI agents with LangChain LangChain agents built on LangGraph use a tool-calling loop until a final answer is returned. The high-level createAgent function accepts a model, tools defined with tool(), and an optional system prompt. A support triage agent demonstrates parallel tool calls and recursion limits. LangChain https://docs.langchain.com/oss/javascript/langchain/overview agents are built on LangGraph : the model calls tools in a loop until it returns a final answer. The high-level entry point is createAgent https://docs.langchain.com/oss/javascript/langchain/agents - pass a model, tools defined with tool , and an optional systemPrompt .This post builds the same support triage agent as the Vercel AI SDK agents https://sevic.dev/notes/ai-agents-vercel-ai-sdk/ and OpenAI Agents SDK https://sevic.dev/notes/ai-agents-openai-sdk/ posts so you can compare SDKs on one scenario. It follows the LangChain overview for Node.js https://sevic.dev/notes/langchain-overview-nodejs/ and fits as post 4 in the LangChain series after loaders/chunking and the RAG with pgvector https://sevic.dev/notes/rag-openai-embeddings-pgvector-langchain/ pipeline . langchain , @langchain/openai , @langchain/core , and zod installed: npm i langchain @langchain/openai @langchain/core zod OPENAI API KEY set in the environmentA turn is one model generation. In that turn the model either: Typical flow for the support triage agent: user question → model calls lookup tools get customer , get invoice , search knowledge base → model creates a ticket or escalates → final answer. A single turn can include multiple parallel tool calls . Set recursionLimit on invoke or stream to cap how many graph steps run each model generation and tool batch counts toward the limit . Use tool from langchain with a Zod schema , plus name and description so the model knows when to call each tool: js import { tool } from 'langchain'; import { z } from 'zod'; const getInvoice = tool async { invoiceId } = { const invoice = invoices.find item = item.id === invoiceId ; if invoice { return { found: false, invoiceId, error: 'Invoice not found' }; } return { found: true, invoice }; }, { name: 'get invoice', description: 'Look up an invoice by ID, including payment IDs and status', schema: z.object { invoiceId: z.string .describe 'Invoice ID, e.g. inv 8891' , } , }, ; LangChain uses schema not Vercel's inputSchema or OpenAI Agents' parameters . The handler receives validated input as the first argument. Wire the model, tools, and triage instructions: js import { createAgent } from 'langchain'; const agent = createAgent { model: 'gpt-5.5', tools: getInvoice , systemPrompt: You are a billing support triage agent. Look up records before recommending refunds or creating tickets. , } ; model can be a provider string 'gpt-5.5' , 'openai:gpt-5.5' or a chat model instance from @langchain/openai . Pass a messages array and read the final answer from result.messages : js const result = await agent.invoke { messages: { role: 'user', content: 'What is the status of invoice inv 8891? Reply in one sentence.', }, , } ; const lastAi = ...result.messages .reverse .find message = message.type === 'ai' ; console.log lastAi?.content ; The last AI message is the agent's final reply after any tool calls complete. Example prompt: Customer cus 1042 says they were charged twice for invoice inv 8891. What should we do? A realistic chain: get customer - plan tier, open ticket count get invoice - amount, status, payment IDs search knowledge base - duplicate-charge and refund policy create support ticket or escalate to human - write action or escalationThe demo uses in-memory fixtures customers, invoices, knowledge-base articles so scripts run without a database. Register all triage tools on one agent: js import { createAgent } from 'langchain'; import { getCustomer, getInvoice, searchKnowledgeBase, createSupportTicket, escalateToHuman, TRIAGE INSTRUCTIONS, } from './tools/index.js'; const agent = createAgent { model: 'gpt-5.5', tools: getCustomer, getInvoice, searchKnowledgeBase, createSupportTicket, escalateToHuman, , systemPrompt: TRIAGE INSTRUCTIONS, } ; const result = await agent.invoke { messages: { role: 'user', content: 'Customer cus 1042 says they were charged twice for invoice inv 8891. What should we do?', }, , recursionLimit: 15, } ; const answer = ...result.messages .reverse .find message = message.type === 'ai' ; console.log answer?.content ; Inspect result.messages for the full trace: human input, AI tool-call messages, tool results, and the final AI reply. agent.stream yields state updates as the graph runs. Use streamMode: 'values' to receive the full message list after each step: js const stream = await agent.stream { messages: { role: 'user', content: 'Customer cus 1042 says they were charged twice for invoice inv 8891. What should we do?', }, , }, { streamMode: 'values', recursionLimit: 15 }, ; let finalMessages = ; for await const state of stream { if state.messages { finalMessages = state.messages; } } const answer = ...finalMessages .reverse .find message = message.type === 'ai' ; console.log answer?.content ; For token-level streaming, use streamMode: 'messages' or streamEvents see LangGraph streaming https://docs.langchain.com/oss/javascript/langgraph/streaming . LangChain createAgent | Vercel AI SDK | OpenAI Agents SDK | | |---|---|---|---| Best for | RAG + LCEL + agents in one stack | TypeScript apps already on AI SDK | OpenAI-first agent primitives | Tool definition | tool + Zod schema | tool + inputSchema | tool + Zod parameters | Run API | agent.invoke / agent.stream | generateText + stopWhen | run + maxTurns | Handoffs / guardrails | Middleware advanced | Limited | Built-in | Memory | LangGraph checkpointers | Bring your own | Session helpers | Pick LangChain when document loaders, retrievers, and agents should share one ecosystem. Pick Vercel AI SDK or OpenAI Agents SDK when you want a focused agent layer without the broader LangChain surface. See the langchain-agents-nodejs-demo https://github.com/delimitertech/demos/tree/main/ai/langchain-agents-nodejs-demo folder for runnable scripts: single-tool lookup, full triage, and streaming.