**TL;DR:** Current LangChain composes runnables with the pipe operator (LCEL). LLMChain and the other legacy chains moved to langchain-classic in v1. Chains are for straight pipelines; the moment the model needs to decide, that is an agent.

## The fix

1. For new code, use LCEL (`prompt | model | parser`). Do not reach for LLMChain in new code; it lives in langchain-classic now and only exists for old codebases.

2. LCEL runnables get `.invoke`, `.batch`, `.stream`, `.astream_events`, `.with_retry`, and `.with_fallbacks` for free. If you are hand-rolling retry loops around a chain, you are reimplementing built-ins.

3. Prefer create_agent over chains for anything with tools. Chains are for straight pipelines; the moment the model needs to decide, that is an agent.

## When to use this

- This covers exactly what the title says: LCEL vs legacy chains.
- You are setting this up for the first time, or auditing an existing setup.
- You want the key gotchas in one place before you start.

## When not to use this

- You are doing a different workflow with LCEL; these steps are specific to the title above.
- You need the full reference docs; this is the short path, not the manual.

## Compatibility

- Mentions 5.4 in the original; behavior may differ on much older or newer releases.