langchain
langchain is the JavaScript/TypeScript framework for building LLM applications and agents. Version 1.x centers on createAgent: a tool-calling loop that takes a model (as a 'provider:model' string or an instance), a set of tools, and optional middleware, and runs the model against those tools until the task completes. It adds structured output, streaming, and thread-level memory, with LangGraph underneath for state and persistence, and one interface across OpenAI, Anthropic, Google, Ollama, and many other providers.
v1 finally gives LangChain.js a focused core: createAgent is a capable agent loop with real provider breadth. If your app is a few direct model calls, a provider SDK and fifty lines of your own code remain the simpler, more debuggable choice.
Use it if
- You swap or compare model providers and want one calling convention instead of rewriting against each vendor SDK
- You need an agent loop with tools, conversation memory, and structured output and do not want to hand-build the loop, retries, and message plumbing
- You expect to grow into LangGraph orchestration or LangSmith tracing, which plug into the same stack
- Your app is a couple of direct calls to one provider: the official SDK plus a little of your own code is fewer layers and much easier to debug
- You have a 0.x LangChain codebase: 1.0 was a breaking rewrite around createAgent, old chain-style patterns are gone or moved, and migration is a project rather than a version bump
- You ship size-sensitive frontend bundles: the package depends on zod, langsmith, and @langchain/langgraph before you add any provider package
- You have low tolerance for churn: the core abstractions have been rethought more than once, and online examples for 0.x will actively mislead you
Setup reality
You install langchain plus @langchain/core (a peer dependency) plus one provider package like @langchain/openai, and the docs quickstart assumes Node 22+. The classic install trap is peer-dependency version mismatch between @langchain/core and provider packages after a partial upgrade; align them or you get confusing type and runtime errors. Provider API keys come from environment variables. Expect to spend time orienting in docs that span LangChain, LangGraph, and LangSmith, and to distrust any tutorial written before the 1.0 rewrite.
Patterns
Create and invoke a basic agentcreate-agent
import { createAgent } from 'langchain';
const agent = createAgent({
model: 'openai:gpt-5.5',
tools: [],
});
const result = await agent.invoke({
messages: [{ role: 'user', content: 'What is 6 times 7?' }],
});The 'provider:model' string needs the matching provider package installed and its API key set as an env var.
Define a tool with a zod schemadefine-tool
import { createAgent, tool } from 'langchain';
import * as z from 'zod';
const search = tool(({ query }) => `Results for: ${query}`, {
name: 'search',
description: 'Search for information',
schema: z.object({ query: z.string() }),
});
const agent = createAgent({ model: 'openai:gpt-5.5', tools: [search] });The description is what the model reads to decide when to call the tool; vague descriptions produce bad tool choice.
Set a system prompt on the agentsystem-prompt
import { createAgent } from 'langchain';
const agent = createAgent({
model: 'anthropic:claude-sonnet-4-6',
tools,
systemPrompt: 'You are a helpful assistant. Be concise and accurate.',
});systemPrompt is a plain string; for dynamic prompts based on state you reach for middleware instead.
Get validated structured outputstructured-output
import { createAgent } from 'langchain';
import * as z from 'zod';
const Answer = z.object({ summary: z.string(), confidence: z.number() });
const agent = createAgent({
model: 'openai:gpt-5.5',
tools,
responseFormat: Answer,
});
const result = await agent.invoke({
messages: [{ role: 'user', content: 'Summarize AI trends' }],
});
result.structuredResponse; // { summary, confidence }The parsed object lives on result.structuredResponse, not in the message list.
Stream tokens as they generatestream-tokens
for await (const [token, metadata] of await agent.stream(
{ messages: [{ role: 'user', content: 'what is the weather in sf' }] },
{ streamMode: 'messages' },
)) {
console.log(metadata.langgraph_node, token.contentBlocks);
}streamMode 'messages' yields token chunks; 'values' yields the full state after each step, which is much chattier.
Keep conversation history across turnsconversation-memory
import { createAgent } from 'langchain';
import { MemorySaver } from '@langchain/langgraph';
const agent = createAgent({
model: 'openai:gpt-5.5',
tools: [],
checkpointer: new MemorySaver(),
});
const config = { configurable: { thread_id: crypto.randomUUID() } };
await agent.invoke({ messages: [{ role: 'user', content: 'Weather in SF?' }] }, config);
// same thread_id = the agent remembers the previous turn
await agent.invoke({ messages: [{ role: 'user', content: 'And tomorrow?' }] }, config);MemorySaver is in-process only; use a persistent checkpointer in production or history dies with the process.
Read the final text reply from a resultread-agent-reply
const result = await agent.invoke({
messages: [{ role: 'user', content: 'Hello' }],
});
const last = result.messages.at(-1);
console.log(last?.content);result.messages contains the whole run including tool calls and tool results, not just the final answer.
Call a chat model without an agentdirect-model-call
import { ChatOpenAI } from '@langchain/openai';
const model = new ChatOpenAI({ model: 'gpt-5.5' });
const res = await model.invoke([
{ role: 'system', content: 'You translate English to French.' },
{ role: 'user', content: 'Good morning' },
]);
console.log(res.content);For a single completion with no tools, calling the model directly skips the whole agent loop and its overhead.
Build a reusable prompt template chainprompt-template
import { ChatPromptTemplate } from '@langchain/core/prompts';
import { ChatOpenAI } from '@langchain/openai';
const prompt = ChatPromptTemplate.fromMessages([
['system', 'You translate English to {language}.'],
['user', '{text}'],
]);
const chain = prompt.pipe(new ChatOpenAI({ model: 'gpt-5.5' }));
const out = await chain.invoke({ language: 'French', text: 'Hello' });Templates live in @langchain/core; single curly braces are template variables, so escape literal braces by doubling them.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| ai | npm | You want a leaner TypeScript SDK with first-class streaming UI hooks, especially in Next.js |
| @langchain/langgraph | npm | You need custom multi-step orchestration beyond what the createAgent loop offers |
| llamaindex | npm | Your app is primarily retrieval over your own documents rather than a general agent |