cd /news/ai-agents/building-ai-agents-with-langchain Ā· home › topics › ai-agents › article
[ARTICLE Ā· art-30140] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=Ā· neutral

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.

read4 min views1 publishedJun 16, 2026

LangChain 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 - 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 and OpenAI Agents SDK posts so you can compare SDKs on one scenario. It follows the LangChain overview for Node.js and fits as post #4 in the LangChain series (after s/chunking and the RAG with pgvector 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:

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:

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

:

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 countget_invoice

  • amount, status, payment IDssearch_knowledge_base

  • duplicate-charge and refund policycreate_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:

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:

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).

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 s, 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 folder for runnable scripts: single-tool lookup, full triage, and streaming.

── more in #ai-agents 4 stories Ā· sorted by recency
── more on @langchain 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host āœ“
Get free account → Pricing
from €0/mo Ā· no card required
LIVE [news/building-ai-agents-w…] indexed:0 read:4min 2026-06-16 Ā· —