n8n + Local LLM RSS Classifier: Importable Workflow, Deduplication & Retry Branches
A production-ready n8n workflow that fetches RSS feeds, deduplicates URLs, classifies items via local Ollama with strict JSON output, and handles queue timeouts.
Self-hosted n8n (Docker) + Local Ollama (Qwen2.5-7B-Instruct Q4_K_M)
Zero cloud LLM API token cost; article bodies never leave your machine.
- Sending 25+ RSS items simultaneously without serialized batching causes Ollama queue waits to exceed n8n default HTTP timeout.
- Without `"format": "json"` in the API payload, 7B models wrap output in ```json fences ~8% of the time.
1. Pipeline Architecture: Deduplicate First, Serialize Second
| Pipeline Configuration | Timeout Failures | JSON Parse Success | Hourly GPU Load |
|---|---|---|---|
| Naive (No Dedup, Unbounded Parallel, Prompt-Only JSON) | 19 / 30 failed (ETIMEDOUT) | 91.6% (Fence errors) | Re-runs all 30 items every hour |
| Tinker Verified (Link Dedup + Batch=1 + format:"json") | 0 / 30 failed (100% pass) | 100% grammar-enforced | Only processes 1–3 new items/hr |
[
{
"title": "Running Qwen2.5-14B on Mac M3 Pro with Q8_0 KV Cache",
"link": "https://example.com/posts/mac-q8-kv-cache",
"contentSnippet": "Benchmarking unified memory usage when num_ctx increases from 8K to 32K on macOS."
},
{
"title": "Fixing Docker host.docker.internal on Ubuntu 24.04 with UFW",
"link": "https://example.com/posts/docker-ufw-ollama",
"contentSnippet": "Why containers time out connecting to host port 11434 and how to whitelist 172.16.0.0/12."
}
]2. Enforcing Grammar-Constrained JSON & Error Branching
3. Stripping HTML Boilerplate & Keeping `keep_alive` Warm Across Schedules
Frequently Asked Questions & Edge Cases
Q: Why use an n8n HTTP Request node instead of the built-in LangChain Ollama Chat node for batch classification?
Direct HTTP Request gives you explicit control over Ollama native parameters (`format: "json"`, `num_ctx`, `keep_alive`), per-request timeout (`45000ms`), and native item batching (`batchSize: 1`) without hidden multi-turn agent overhead.
Q: Where does n8n store the deduplication history across runs?
n8n stores processed item hashes in its persistent database (`/home/node/.n8n/database.sqlite` or Postgres). As long as `/home/node/.n8n` is bind-mounted to the host, deduplication state survives container restarts and upgrades.
n8n + Local Ollama RSS Classifier & Deduplication Workflow
Importable n8n workflow JSON with URL hash deduplication, local Ollama HTTP node, JSON parse guard, and dead-letter retry branch.
{
"name": "Tinker AI — Local LLM RSS Classifier with Retry & Dedup",
"nodes": [
{
"parameters": {
"url": "https://hnrss.org/newest?points=100"
},
"name": "RSS Feed Read",
"type": "n8n-nodes-base.rssFeedRead",
"typeVersion": 1,
"position": [220, 300]
},
{
"parameters": {
"operation": "removeItemsSeenInPreviousExecutions",
"dedupeValue": "={{ $json.link }}"
},
"name": "Deduplicate by Link",
"type": "n8n-nodes-base.removeDuplicates",
"typeVersion": 2,
"position": [440, 300]
},
{
"parameters": {
"method": "POST",
"url": "http://host.docker.internal:11434/api/generate",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ model: 'qwen2.5:7b', format: 'json', stream: false, options: { temperature: 0.1, num_ctx: 4096 }, prompt: 'Classify this article into one category (local-ai, workflows, maker, ops) and provide a 1-sentence summary in JSON {category, summary}: ' + $json.title + ' - ' + ($json.contentSnippet || '') }) }}",
"options": {
"timeout": 45000
}
},
"name": "Local Ollama Classifier",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 3000,
"continueOnFail": true,
"position": [680, 300]
}
],
"connections": {
"RSS Feed Read": {
"main": [[{ "node": "Deduplicate by Link", "type": "main", "index": 0 }]]
},
"Deduplicate by Link": {
"main": [[{ "node": "Local Ollama Classifier", "type": "main", "index": 0 }]]
}
}
}