Why LangChain still matters
LangChain is the closest thing the LLM ecosystem has to a standard library. It gives you primitives for prompts, models, tools, retrieval, and memory. For a prototype, you can wire up something useful in an afternoon. That alone is worth a lot.
What works well
- Document loaders. The library has a loader for almost every file format you care about. Skip writing your own.
- Text splitters. The recursive character splitter is a sane default that beats most homemade chunking.
- Output parsers. Structured-output helpers save real time when the model has to return JSON.
- Integrations. If a vector store or model exists, there is usually a LangChain wrapper for it.
What hurts in production
- Hidden abstractions. A short chain expands into a dozen internal calls. When something goes wrong, the stack trace is a maze.
- Breaking changes. APIs move fast. A pin you forgot to update will cost you an evening.
- Performance. Generic wrappers add latency. For a hot loop, write the call yourself.
- Memory primitives. The bundled "memory" classes rarely match what a real product needs. We almost always replace them.
Our default: Use LangChain for ingestion and retrieval helpers. Write the agent loop and orchestration yourself, or use LangGraph when the workflow is genuinely stateful.
A reasonable hybrid stack
| Job | What we use |
|---|---|
| Document loading | LangChain loaders |
| Chunking and embeddings | LangChain helpers plus a small custom layer |
| Vector store | pgvector or Qdrant (direct, not via the LangChain wrapper) |
| Orchestration | LangGraph for multi-step flows; plain code for simple ones |
| Observability | Langfuse, with traces around every model call |
Where to read next
For when you do need orchestration, see LangGraph for Stateful Agents. For the retrieval layer, see RAG in Production.


