Building Framework-Agnostic AI Agents
The AI agent ecosystem is fragmented. LangChain, CrewAI, LangGraph, AutoGen, OpenAI Assistants, Claude Tools—every few months brings a new framework promising to be "the one."
Here's the problem: if you build deep into one framework, you're locked in. When something better comes along (and it will), you can't migrate without losing everything.
This guide shows you how to build agents that are framework-agnostic—portable, future-proof, and free from vendor lock-in.
The Lock-In Problem
What You Lose When Locked In
- Workflows — Defined in framework-specific DSLs
- State — Stored in framework-specific formats
- Agent configurations — Tied to framework abstractions
- History — What agents learned is trapped
- Integrations — Framework-specific tools/plugins
Imagine you built your agent system with LangChain in 2023. Now in 2026, you want to use LangGraph's superior state machine capabilities. Your options:
- Rewrite everything — Weeks of work, risk of bugs
- Run both — Operational nightmare
- Stay locked in — Miss out on better tools
None of these are good. The solution is to design for portability from the start.
The Framework-Agnostic Architecture
The key insight: separate what you're building FROM how you're orchestrating it.
┌─────────────────────────────────────────────────────────────┐
│ Your Agent Application │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ LangChain │ │ CrewAI │ │ LangGraph │ ... │
│ │ Agent │ │ Crew │ │ Graph │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └────────────────┼────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Framework-Agnostic Control Plane │ │
│ │ • Portable State • Versioned Workflows │ │
│ │ • Standard Handoffs • Universal Audit Trail │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Frameworks do orchestration. The control plane handles persistence, state, and coordination in a framework-independent way.
Principles of Framework-Agnostic Design
1. Portable State Format
Store state in a format any framework can read:
// ❌ Framework-specific state
langchain_state = {
"memory": BufferMemory(...),
"agent_scratchpad": AgentScratchpad(...),
"intermediate_steps": [AgentAction(...), ...]
}
// ✅ Portable state
portable_state = {
"conversation": [
{"role": "user", "content": "..."},
{"role": "assistant", "content": "..."}
],
"context": {
"customer_id": "123",
"current_task": "billing_inquiry",
"gathered_info": {...}
},
"decisions": [
{"timestamp": "...", "decision": "...", "reason": "..."}
]
}
2. Plain-Text Workflows
Define workflows in markdown, not framework DSLs:
// ❌ Framework-specific workflow
const graph = new StateGraph()
.addNode("research", researchNode)
.addNode("write", writeNode)
.addEdge("research", "write")
.compile();
// ✅ Portable workflow (markdown)
const workflow = `
# Customer Support Workflow
## Step 1: Classify Request
- Read customer message
- Classify as: billing, technical, general, escalation
- If unclear, ask clarifying question
## Step 2: Gather Context
- Retrieve customer history from CRM
- Check for open tickets
- Note any relevant policies
## Step 3: Respond
- Draft response using gathered context
- If billing: reference invoice numbers
- If technical: provide troubleshooting steps
- If escalation: hand off to human
## Edge Cases
- If customer is angry: acknowledge frustration first
- If request is outside policy: explain and offer alternatives
`;
Any framework can execute a markdown workflow. The intelligence is in following the instructions, not in the format.
3. Standard APIs for State Operations
// Framework-agnostic state API
interface StateStore {
read(component: string, key: string): Promise;
write(component: string, key: string, value: any, ttl?: number): Promise;
delete(component: string, key: string): Promise;
}
// Works identically from LangChain, CrewAI, or custom code
const state = await stateStore.read("customer", "user_123");
await stateStore.write("customer", "user_123", updatedState);
4. Universal Handoff Protocol
// Framework-agnostic handoff
interface Handoff {
id: string;
from_agent: string;
to_agent: string;
context: Record; // Plain JSON
workflow?: string; // Workflow name or inline markdown
status: "pending" | "accepted" | "rejected" | "completed";
}
// Any agent can create/accept handoffs regardless of framework
await handoffs.create({
to_agent: "specialist-agent", // Could be LangGraph, CrewAI, whatever
context: portableState,
workflow: "escalation-process"
});
Implementation Pattern
Here's how to structure a framework-agnostic agent:
// agent-wrapper.ts
// Thin wrapper that makes any framework agent portable
import { AgentMemo } from '@agentmemo/sdk';
class PortableAgent {
private agentmemo: AgentMemo;
private frameworkAgent: any; // LangChain, CrewAI, whatever
constructor(frameworkAgent: any) {
this.agentmemo = new AgentMemo({ apiKey: process.env.AGENTMEMO_KEY });
this.frameworkAgent = frameworkAgent;
}
async run(input: any) {
// 1. Load portable state
const state = await this.agentmemo.state.read("context", input.sessionId);
// 2. Load workflow (if applicable)
const workflow = await this.agentmemo.workflows.get(input.workflowName);
// 3. Run framework-specific agent
const result = await this.frameworkAgent.run({
input: input.message,
context: state,
workflow: workflow?.definition
});
// 4. Save updated state (in portable format)
await this.agentmemo.state.write("context", input.sessionId, {
...state,
lastInteraction: new Date(),
latestDecision: result.decision
});
// 5. Log to audit trail
await this.agentmemo.audit.log({
agent: this.frameworkAgent.name,
action: "process",
input: input.message,
output: result.response
});
return result;
}
async handoff(toAgent: string, reason: string) {
const state = await this.agentmemo.state.read("context", this.sessionId);
return this.agentmemo.handoffs.create({
to_agent: toAgent,
context: state,
metadata: { reason, from_framework: "langchain" }
});
}
}
Migration Example
With portable state and workflows, migration is trivial:
// Before: LangChain agent
const langchainAgent = new PortableAgent(
new LangChainAgent({ ... })
);
// After: LangGraph agent (workflows and state transfer automatically)
const langgraphAgent = new PortableAgent(
new LangGraphAgent({ ... })
);
// Same state, same workflows, different orchestration
Checklist: Is Your Agent Portable?
- ☐ State is stored in plain JSON (not framework-specific objects)
- ☐ Workflows are documented in markdown (not framework DSLs)
- ☐ Handoffs use a standard protocol (not framework-specific)
- ☐ Audit trail is framework-independent
- ☐ Agent configuration is separate from framework code
- ☐ You can describe what the agent does without mentioning the framework
The Test
Ask yourself: "If I had to rewrite this agent in a different framework tomorrow, what would I lose?"
If the answer is "nothing except the orchestration code," you're framework-agnostic.
Build Portable Agents with AgentMemo
Framework-agnostic state, workflows, and handoffs out of the box.
Start Free Trial →