·12 min

DeerFlow 2.0: Building Sovereign AI Agent Systems with Local-First Architecture

Learn how DeerFlow 2.0 bridges the execution gap in AI with its SuperAgent harness, AIO sandbox, and persistent memory. Complete guide to building sovereign, local-first AI agent systems.

DK

Daniel Kliewer

Author, Sovereign AI

deerflowai-agentslocal-firstsovereign-aiollamalangchainlanggraphsuperagentopen-source
Sovereign AI book cover

From the Book

This is from Sovereign AI: Building Local-First Intelligent Systems.

Get the Book — $88
DeerFlow 2.0: Building Sovereign AI Agent Systems with Local-First Architecture

DeerFlow 2.0 On Github

In the current AI landscape, we are witnessing a widening "execution gap." While Large Language Models (LLMs) have become remarkably eloquent, they often falter when tasked with complex, multi-hour workflows. Most agents can "talk" a good game, but they lose their way, blow up their context windows, or simply lack the environment to execute the code they generate. They are observers, not operators.

ByteDance has addressed this head-on with DeerFlow 2.0, an open-source "SuperAgent harness" that recently claimed the #1 spot on GitHub Trending. This guide explores DeerFlow's architecture and shows you how to build your own sovereign AI agent system with local-first control.

Table of Contents

  1. The Execution Gap in AI
  2. What Makes DeerFlow Different
  3. Core Architecture Components
  4. Installation and Setup
  5. Building Your Knowledge Bank
  6. Querying Your Knowledge Base
  7. Building a REST API
  8. Advanced Graph-Based Retrieval
  9. Integration Patterns
  10. Best Practices

The Execution Gap in AI

Most AI agents today suffer from fundamental limitations:

  • Context Window Blowups: Long-running tasks exceed token limits
  • Session Amnesia: No memory between conversations
  • Sandbox Limitations: No real execution environment
  • Linear Processing: Cannot parallelize complex workflows

DeerFlow 2.0 solves these problems with a ground-up rewrite that moves beyond simple text generation into the realm of sustained, autonomous productivity.

What Makes DeerFlow Different

It's Not a Framework—It's a Harness

The transition from DeerFlow 1.x to 2.0 is a pivot from a specialized Deep Research framework to a general-purpose Agent Runtime. While 1.x was focused on exploration, 2.0 is a comprehensive harness built on the robust foundations of LangGraph and LangChain.

The distinction is critical for architects: a framework is a library you call; a harness is the "batteries-included" infrastructure that manages the lifecycle of the agent. DeerFlow 2.0 provides the message gateway, the state management, and the execution protocols required for an agent to perform real work over long horizons.

"This is the difference between a chatbot with tool access and an agent with an actual execution environment."

Why Sovereign AI Matters

  • Local-First: Run everything on your machine with Ollama and local models
  • Graph-Based Memory: Not just vector search—relationships matter
  • Perfect Recall: Ingest years of documents and query them with precision
  • Sovereign Intelligence: Your data, your models, your control
  • Hybrid Search: Combine semantic, graph, and metadata-based retrieval

Core Architecture Components

The All-in-One (AIO) Sandbox

The core of DeerFlow's "doing" capability is its AIO Sandbox. Rather than simply emitting code for a human to copy-paste, DeerFlow operates within a dedicated, Docker-based environment. This is not just a shell; it is a full developer workstation.

The AIO Sandbox combines five critical components:

| Component | Purpose | |-----------|---------| | Browser | Real-time web navigation and visual verification | | Shell | Execute bash commands and manage system processes | | File System | Persistent, mountable space for reading and writing data | | MCP | Integrate external tools and data sources | | VSCode Server | Professional-grade code editing and debugging |

This persistence is the key to "long-horizon" tasks. Because the environment is stable and auditable, the agent can write code, run it, hit an error, and use the VSCode server or shell to debug—performing minutes or hours of work autonomously without human intervention.

Context Engineering

Managing a context window during an hour-long research or coding session is an architectural nightmare. DeerFlow employs a sophisticated "Context Engineering" strategy:

  1. Isolated Sub-Agent Context: Each sub-task is processed in its own containerized context. This ensures the agent remains hyper-focused on its specific objective, shielded from the "noise" of unrelated intermediate data.

  2. Aggressive Summarization & Compression: DeerFlow doesn't just store history; it actively manages it. It summarizes completed sub-tasks and offloads intermediate results to the filesystem, compressing what is no longer immediately relevant.

Progressive Skill Loading

For developers running local LLMs, context is the most expensive resource. DeerFlow addresses this with a modular Skill System. Instead of cramming every possible instruction into the system prompt, skills are loaded progressively—only what's needed, when it's needed.

These "Agent Skills" are Markdown-based structured capability modules stored in the /mnt/skills/ directory. They define workflows, best practices, and resource references in a format that LLMs digest easily.

Sub-Agent Swarms

DeerFlow 2.0 moves away from linear processing in favor of a Lead Agent and Sub-Agent architecture:

  1. Decomposition: The Lead Agent breaks a complex goal into parallelizable sub-tasks
  2. Parallel Execution: Specialized sub-agents are spawned simultaneously
  3. Synthesis: The Lead Agent gathers structured results and integrates them into the final deliverable

A single research task can "fan out into a dozen sub-agents," exploring disparate angles of a topic before converging back into a single, comprehensive report.

Persistent Long-Term Memory

Standard agents suffer from "session amnesia." DeerFlow solves this by building a persistent, locally stored memory that stays under the user's control.

This isn't just a log of past chats; it is a refined profile. The system learns your writing style, your technical stack preferences, and your recurring workflows. To prevent this from becoming a source of bloat, DeerFlow's memory update logic is designed to skip duplicate facts during the "apply" phase.

Installation and Setup

Prerequisites

bash
1# Install Python 3.9+
2python3 --version
3
4# Install Ollama for local LLMs
5# macOS
6brew install ollama
7
8# Linux
9curl -fsSL https://ollama.ai/install.sh | sh
10
11# Pull a model
12ollama pull llama3

Install Dependencies

bash
1# Create virtual environment
2python -m venv .venv
3source .venv/bin/activate # Linux/macOS
4
5# Install core dependencies
6pip install langchain langchain-community langgraph
7pip install chromadb sentence-transformers
8pip install flask flask-cors
9pip install networkx # for graph operations
10pip install tiktoken # for token counting

Initialize Your Bank

bash
1# Create the bank folder structure
2mkdir -p bank/{documents,graph,index,metadata,reddit,scripts,vectors,openai}
3
4# Initialize ChromaDB for vectors
5python -c "import chromadb; chromadb.PersistentClient(path='bank/vectors')"

Building Your Knowledge Bank

Bank Folder Structure

text
1bank/
2├── documents/ # Raw text documents
3│ ├── reddit/ # Reddit conversations
4│ └── openai/ # OpenAI chat exports
5├── vectors/ # ChromaDB persistent storage
6├── graph/ # NetworkX graph pickles
7│ ├── nodes.pkl # Node definitions
8│ └── edges.pkl # Relationship edges
9├── metadata/ # JSON metadata index
10│ └── index.json # Document metadata catalog
11├── index/ # Fast lookup structures
12├── scripts/ # Utility scripts
13│ ├── ingest.py # Document ingestion
14│ ├── search_bank.py # Search logic
15│ └── build_graph.py # Graph construction
16└── README.md # Documentation

Document Ingestion Script

python
1# bank/scripts/ingest.py
2import chromadb
3from langchain.text_splitter import RecursiveCharacterTextSplitter
4from langchain_community.embeddings import HuggingFaceEmbeddings
5from pathlib import Path
6
7class DeerFlowIngestor:
8 def __init__(self, bank_path: str):
9 self.bank_path = Path(bank_path)
10 self.collection = chromadb.PersistentClient(
11 path=str(self.bank_path / "vectors")
12 ).get_or_create_collection("documents")
13
14 # Initialize embeddings (local-first!)
15 self.embeddings = HuggingFaceEmbeddings(
16 model_name="sentence-transformers/all-MiniLM-L6-v2"
17 )
18
19 def ingest_document(self, file_path: str, source: str = "unknown"):
20 """Ingest a single document into the bank."""
21
22 with open(file_path, 'r') as f:
23 text = f.read()
24
25 splitter = RecursiveCharacterTextSplitter(
26 chunk_size=1000,
27 chunk_overlap=200,
28 separators=["\n\n", "\n", ". ", " ", ""]
29 )
30 chunks = splitter.split_text(text)
31
32 for i, chunk in enumerate(chunks):
33 doc_id = f"{Path(file_path).stem}_{i}"
34
35 self.collection.add(
36 ids=[doc_id],
37 embeddings=[self.embeddings.embed_query(chunk)],
38 documents=[chunk],
39 metadatas=[{
40 "source_file": str(file_path),
41 "source_type": source,
42 "chunk_index": i,
43 "total_chunks": len(chunks)
44 }]
45 )
46
47 print(f"Ingested {len(chunks)} chunks from {file_path}")
48 return len(chunks)

Building the Knowledge Graph

python
1# bank/scripts/build_graph.py
2import networkx as nx
3from pathlib import Path
4from collections import Counter
5import re
6
7class KnowledgeGraphBuilder:
8 def __init__(self, bank_path: str):
9 self.bank_path = Path(bank_path)
10 self.graph_path = self.bank_path / "graph"
11 self.graph_path.mkdir(exist_ok=True)
12 self.G = nx.Graph()
13
14 def extract_entities(self, text: str):
15 """Extract key entities and concepts from text."""
16 words = re.findall(r'\b[a-zA-Z][a-zA-Z0-9_]+\b', text.lower())
17 stopwords = {'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been'}
18
19 word_counts = Counter(
20 word for word in words
21 if word not in stopwords and len(word) > 3
22 )
23
24 return [entity for entity, _ in word_counts.most_common(20)]
25
26 def build_from_documents(self):
27 """Build graph from all ingested documents."""
28
29 documents_path = self.bank_path / "documents"
30
31 for doc_file in documents_path.rglob("*"):
32 if doc_file.is_file() and doc_file.suffix in ['.txt', '.md']:
33 with open(doc_file, 'r') as f:
34 text = f.read()
35
36 entities = self.extract_entities(text)
37
38 doc_id = doc_file.stem
39 self.G.add_node(doc_id, type="document", path=str(doc_file))
40
41 for entity in entities:
42 self.G.add_node(entity, type="entity")
43 self.G.add_edge(doc_id, entity, weight=1)
44
45 for i, entity1 in enumerate(entities):
46 for entity2 in entities[i+1:]:
47 self.G.add_edge(entity1, entity2, weight=0.5)
48
49 nx.write_gpickle(self.G, self.graph_path / "knowledge_graph.pkl")
50 print(f"Graph built: {self.G.number_of_nodes()} nodes, {self.G.number_of_edges()} edges")

Querying Your Knowledge Base

Hybrid Search Implementation

python
1# bank/scripts/search_bank.py
2import chromadb
3import networkx as nx
4from pathlib import Path
5from langchain_community.embeddings import HuggingFaceEmbeddings
6
7class DeerFlowSearch:
8 def __init__(self, bank_path: str):
9 self.bank_path = Path(bank_path)
10 self.embeddings = HuggingFaceEmbeddings(
11 model_name="sentence-transformers/all-MiniLM-L6-v2"
12 )
13
14 self.collection = chromadb.PersistentClient(
15 path=str(self.bank_path / "vectors")
16 ).get_collection("documents")
17
18 graph_file = self.bank_path / "graph" / "knowledge_graph.pkl"
19 self.G = nx.read_gpickle(graph_file) if graph_file.exists() else nx.Graph()
20
21 def vector_search(self, query: str, top_k: int = 5):
22 """Semantic similarity search."""
23 query_embedding = self.embeddings.embed_query(query)
24
25 return self.collection.query(
26 query_embeddings=[query_embedding],
27 n_results=top_k,
28 include=["documents", "metadatas", "distances"]
29 )
30
31 def graph_search(self, entity: str, max_depth: int = 2):
32 """Graph-based relationship search."""
33 if entity not in self.G:
34 return {"error": f"Entity '{entity}' not found"}
35
36 related = nx.single_source_shortest_path_length(
37 self.G, entity, cutoff=max_depth
38 )
39 related.pop(entity, None)
40
41 return {
42 "entity": entity,
43 "related_nodes": sorted(related.items(), key=lambda x: x[1])
44 }
45
46 def hybrid_search(self, query: str, top_k: int = 10, alpha: float = 0.7):
47 """
48 Combine vector and graph search.
49
50 alpha: Weight for vector search (0.7 = 70% vector, 30% graph)
51 """
52 vector_results = self.vector_search(query, top_k=top_k)
53 query_entities = query.split()
54
55 graph_scores = {}
56 for entity in query_entities:
57 graph_result = self.graph_search(entity, max_depth=2)
58 if "related_nodes" in graph_result:
59 for node, distance in graph_result["related_nodes"][:5]:
60 graph_scores[node] = graph_scores.get(node, 0) + (1 / (distance + 1))
61
62 combined_results = []
63
64 for i, doc in enumerate(vector_results["documents"][0]):
65 score = alpha * (1 - vector_results["distances"][0][i])
66 combined_results.append({
67 "document": doc,
68 "score": score,
69 "source": "vector",
70 "metadata": vector_results["metadatas"][0][i]
71 })
72
73 for node, score in sorted(graph_scores.items(), key=lambda x: -x[1])[:top_k//2]:
74 combined_results.append({
75 "document": f"Entity: {node}",
76 "score": (1 - alpha) * score,
77 "source": "graph"
78 })
79
80 combined_results.sort(key=lambda x: -x["score"])
81 return combined_results[:top_k]

Building a REST API

Expose your DeerFlow bank as a REST API:

python
1# bank/api_server.py
2from flask import Flask, request, jsonify
3from flask_cors import CORS
4from search_bank import DeerFlowSearch
5
6app = Flask(__name__)
7CORS(app)
8
9search = DeerFlowSearch("/path/to/bank")
10
11@app.route('/health', methods=['GET'])
12def health():
13 return jsonify({"status": "healthy", "service": "DeerFlow Bank API"})
14
15@app.route('/search', methods=['POST'])
16def search_endpoint():
17 data = request.json
18 query = data.get("query", "")
19 top_k = data.get("top_k", 10)
20 search_type = data.get("search_type", "hybrid")
21
22 if not query:
23 return jsonify({"error": "Query is required"}), 400
24
25 if search_type == "vector":
26 results = search.vector_search(query, top_k=top_k)
27 elif search_type == "graph":
28 results = search.graph_search(query, max_depth=2)
29 else:
30 results = search.hybrid_search(query, top_k=top_k)
31
32 return jsonify({"results": results, "query": query})
33
34@app.route('/stats', methods=['GET'])
35def stats():
36 vector_count = search.collection.count()
37 graph_nodes = search.G.number_of_nodes()
38 graph_edges = search.G.number_of_edges()
39
40 return jsonify({
41 "vector_documents": vector_count,
42 "graph_nodes": graph_nodes,
43 "graph_edges": graph_edges,
44 "total_knowledge_units": vector_count + graph_nodes
45 })
46
47if __name__ == '__main__':
48 app.run(host='0.0.0.0', port=5000, debug=True)

Testing Your API

bash
1# Start the server
2python bank/api_server.py
3
4# Health check
5curl http://localhost:5000/health
6
7# Vector search
8curl -X POST http://localhost:5000/search \
9 -H "Content-Type: application/json" \
10 -d '{"query": "local-first AI", "top_k": 5, "search_type": "vector"}'
11
12# Hybrid search
13curl -X POST http://localhost:5000/search \
14 -H "Content-Type: application/json" \
15 -d '{"query": "DeerFlow Ollama", "top_k": 10}'

Advanced Graph-Based Retrieval

Finding Connected Concepts

python
1class GraphAnalyzer:
2 def __init__(self, bank_path: str):
3 self.G = nx.read_gpickle(Path(bank_path) / "graph" / "knowledge_graph.pkl")
4
5 def find_centrality(self, top_k: int = 20):
6 """Find most important concepts by degree centrality."""
7 centrality = nx.degree_centrality(self.G)
8 return sorted(centrality.items(), key=lambda x: -x[1])[:top_k]
9
10 def find_shortest_path(self, source: str, target: str):
11 """Find the shortest conceptual path between two ideas."""
12 try:
13 path = nx.shortest_path(self.G, source, target)
14 return {"path": path, "length": len(path) - 1}
15 except nx.NetworkXNoPath:
16 return {"error": "No path found"}
17
18 def expand_concept(self, concept: str, max_depth: int = 3):
19 """Expand a concept to find all related ideas."""
20 if concept not in self.G:
21 return {"error": f"Concept '{concept}' not found"}
22
23 related = {}
24 for node in self.G.nodes():
25 if node != concept:
26 try:
27 distance = nx.shortest_path_length(self.G, concept, node)
28 if distance <= max_depth:
29 related[node] = distance
30 except nx.NetworkXNoPath:
31 pass
32
33 return {
34 "concept": concept,
35 "related": sorted(related.items(), key=lambda x: x[1])
36 }

Integration Patterns

Pattern 1: RAG-Powered Chatbot

python
1from langchain.llms import Ollama
2
3class RAGChatbot:
4 def __init__(self, bank_path: str, model: str = "llama3"):
5 self.search = DeerFlowSearch(bank_path)
6 self.llm = Ollama(model=model)
7
8 def answer_question(self, question: str):
9 results = self.search.vector_search(question, top_k=5)
10 context = "\n\n".join([doc[0] for doc in results["documents"]])
11
12 prompt = f"""
13 Based on the following context, answer the question.
14 If the answer is not in the context, say so.
15
16 Context:
17 {context}
18
19 Question: {question}
20
21 Answer:
22 """
23
24 return {
25 "question": question,
26 "answer": self.llm(prompt),
27 "sources": results["metadatas"][0]
28 }

Pattern 2: Agent with Memory

python
1from langchain.memory import ConversationBufferMemory
2
3class MemoryAgent:
4 def __init__(self, bank_path: str, model: str = "llama3"):
5 self.search = DeerFlowSearch(bank_path)
6 self.llm = Ollama(model=model)
7 self.memory = ConversationBufferMemory(
8 memory_key="chat_history",
9 return_messages=True
10 )
11 self.conversation_log = []
12
13 def recall(self, query: str, top_k: int = 5):
14 results = self.search.hybrid_search(query, top_k=top_k)
15 return [
16 {
17 "content": r["document"][:300],
18 "source": r.get("source", "unknown"),
19 "relevance": r.get("score", 0)
20 }
21 for r in results
22 ]
23
24 def chat(self, message: str):
25 recalled = self.recall(message, top_k=3)
26 context = "Relevant memories:\n" + "\n".join(
27 f"- {m['content']}" for m in recalled
28 ) if recalled else ""
29
30 history = self.memory.load_memory_variables({})
31
32 prompt = f"""
33 You are an AI agent with perfect recall.
34
35 {context}
36
37 Conversation history:
38 {history.get('chat_history', '')}
39
40 User: {message}
41 Agent:
42 """
43
44 response = self.llm(prompt)
45 self.memory.save_context({"input": message}, {"output": response})
46
47 return {
48 "response": response,
49 "memories_recalled": len(recalled)
50 }

Best Practices

Document Organization

| ✅ Do | ❌ Don't | |-------|---------| | Organize by source type (reddit/, openai/) | Mix different document types | | Use consistent naming (YYYY-MM-DD-topic.txt) | Use vague filenames (document1.txt) | | Add metadata tags during ingestion | Skip metadata enrichment |

Chunking Strategy

python
1chunk_size = {
2 "chat_context": 500, # Smaller for conversational RAG
3 "document_search": 1000, # Standard for document retrieval
4 "knowledge_graph": 2000, # Larger for concept extraction
5}
6
7# Always use 20% overlap to preserve context
8chunk_overlap = chunk_size * 0.2

Embedding Choices

python
1embedding_models = {
2 "fast": "sentence-transformers/all-MiniLM-L6-v2",
3 "balanced": "sentence-transformers/all-mpnet-base-v2",
4 "quality": "sentence-transformers/all-mpnet-base-v2",
5}

Query Optimization

python
1alpha_values = {
2 "semantic_focus": 0.8, # 80% vector, 20% graph
3 "balanced": 0.7, # 70% vector, 30% graph
4 "relationship_focus": 0.5, # 50/50 split
5}

Conclusion

DeerFlow 2.0 represents a significant shift toward model-agnostic, infrastructure-heavy autonomy. While it is built by ByteDance, it is MIT-licensed and highly flexible. The project's #1 spot on GitHub Trending is a testament to a shift in developer demand.

We are moving past the era of "chatting with AI" and into the era of "orchestrating AI." The question for the next generation of AI systems is clear: Does the future of productivity lie in a single, massive model, or in these orchestrated swarms of specialized agents operating within a structured, sandboxed harness?

If DeerFlow 2.0 is any indication, the "SuperAgent" harness is the new standard for real work.

Resources

Sovereign AI book cover

Sovereign AI: Building Local-First Intelligent Systems

by Daniel Kliewer · Paperback · 72 pages

The hands-on guide to building AI that runs on your hardware, keeps your data private, and eliminates cloud dependence. Working code included.