Module 6 of 10, lesson 1 of 5
Choosing a framework
Choose by type of system rather than popularity, and know when to skip a framework.
A framework provides the loop, tool integration, memory, coordination and sometimes supervision. It also gets in the way: prompts and calls become less visible, and debugging suffers.
Start from the type of system
| Need | Example tools |
|---|---|
| Linear steps, data | LangChain, LlamaIndex |
| Loops, state, resuming, human in the loop | LangGraph, Microsoft Agent Framework |
| Teams with defined roles | CrewAI |
| Java ecosystem | LangChain4j |
| Visual prototype | LangFlow, Flowise |
November 2026 update. Older tutorials may show outdated APIs and advice.
- Microsoft presents Agent Framework as the direct successor to AutoGen and Semantic Kernel, built by the same teams. For a new project in that ecosystem, start there.
- LangChain 1.0 runs its agents on LangGraph. So don’t treat “LangChain for simple, LangGraph for complex” as an either-or choice.
Five criteria
- Real complexity: one agent or several, and where does the human step in?
- Security: secrets management, access, sensitive data.
- Team skills and the low-level control you need.
- Integration with your data and infrastructure.
- Behavior under load: latency and concurrent requests.
Start without a framework
An agent loop fits in a few dozen lines: call the model, run the requested tool, send back the result, repeat. Writing it once shows you what frameworks automate, and you’ll be able to read their traces when they fail.
Compare two candidates on the same case, with the same evaluation set.
Worked example: What a checkpoint really does
Before paying for a framework feature, write it once by hand. A checkpoint is the state saved after each step, so a run can continue instead of restarting.
function run(steps, store, runId) {
const saved = store.get(runId) ?? { next: 0, done: [] };
for (let i = saved.next; i < steps.length; i += 1) {
saved.done.push(steps[i]);
saved.next = i + 1;
store.set(runId, saved);
}
return saved.done;
}
const store = new Map([['run-1', { next: 2, done: ['read', 'check'] }]]);
run(['read', 'check', 'refund'], store, 'run-1');
['read', 'check', 'refund']
The run resumes at the refund and does not read the order again. If your steps have side effects, this is what stops a customer being refunded twice, and a framework gives you the same thing plus storage and tooling.
Try it in the editor
const END = '__end__';async function runGraph({ nodes, edges, start, state, reducers = {}, maxSteps = 25 }) { // TODO return state;}module.exports = { runGraph, END };