# Ollama + n8n 工作流实战:从抓取网页 → 总结 → 分类存档 → 推送提醒,全程本地零云端
这篇不讲故事,直接上干货。把一个完整的工作流从 0 搭到能用的状态,每一步的命令和配置都列出来。
最终效果
跑起来之后,这个工作流会:
1. 定时抓取你指定的网页/RSS
2. AI 自动总结内容
3. 判断内容分类(科技/财经/工具/其他)
4. 存档到 SQLite 数据库
5. 如果命中你关心的关键词,额外推送通知
全程本地,不依赖任何云端 API。
前置环境
已经装好的:
- Ollama(qwen2.5:7b)
- n8n(Docker)
- 触发模式:
Every Day - 时间:
09:00(或者你喜欢的时间) On Error→RetryMax Retries→3Retry Interval→30s- 标题、摘要、分类
- 是否命中关键词
- 抓取时间
- Ollama 推理:约 30~60 秒
- n8n 内存峰值:约 400MB
- 磁盘占用:每天 10 条约 50KB(纯文本)
- 文章数量限制在 5 条以内
- 模型换成 qwen2.5:3b
- 执行间隔拉到 12 小时一次
还需要加两个服务:
mkdir -p /opt/n8n-services && cd /opt/n8n-servicescat > docker-compose.yml << 'EOF'
version: "3.8"
services:
# SQLite 不需要单独容器,n8n 内置支持
# 但如果想外部访问数据,可以加一个 sqlite-web
sqlite-web:
image: coleifer/sqlite-web
container_name: sqlite-web
restart: unless-stopped
ports:
- "8002:8080"
volumes:
- n8n-data:/data
environment:
- SQLITE_DATABASE=/data/n8n-sqlite.db
volumes:
n8n-data:
external: true
EOF
docker compose up -d
SQLite Web 只是方便查看数据,不是必须的。
第 1 步:创建数据库表
在 n8n 里加一个 Execute Command 节点,初始化数据库:
sqlite3 /home/node/.n8n/database.sqlite << 'SQL'
CREATE TABLE IF NOT EXISTS content_archive (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
summary TEXT,
category TEXT,
source_url TEXT,
keywords_matched INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);CREATE INDEX IF NOT EXISTS idx_category ON content_archive(category);
CREATE INDEX IF NOT EXISTS idx_created ON content_archive(created_at);
SQL
或者直接在 n8n 里用 SQLite 节点的 “Execute Query” 功能创建。
第 2 步:搭建工作流
打开 n8n,新建 Workflow,按顺序添加节点。
节点 1:Schedule(定时触发)
节点 2:RSS Feed Read(抓取内容)
添加 3~5 个你常看的源。我用的几个:
https://feeds.feedburner.com/36kr/news
https://rsshub.app/36kr/news/latest
https://rsshub.app/ithome/news
RSSHub 可以自己部署,
docker run -d -p 1200:1200 diygod/rsshub
节点 3:Code(数据清洗)
RSS 抓回来的数据需要整理:
// 合并所有 RSS 条目,去重
const items = $input.all();
const seen = new Set();
const unique = items.filter(item => {
const url = item.json.link || item.json.guid || '';
if (seen.has(url)) return false;
seen.add(url);
return true;
});// 每条提取关键字段
const articles = unique.map(item => ({
title: item.json.title || '无标题',
content: item.json.contentSnippet || item.json.content || '',
link: item.json.link || item.json.guid || '',
date: item.json.pubDate || item.json.isoDate || ''
}));
return [{ json: { articles, count: articles.length } }];
节点 4:Ollama Chat(AI 处理)
这是核心节点。System Prompt:
你是一个内容处理助手。请对以下文章列表进行处理:1. 为每篇文章生成 50 字以内的中文摘要
2. 判断分类:科技/财经/工具/其他
3. 提取 3 个关键词
输出格式为 JSON 数组,不要其他内容:
[
{
"title": "文章标题",
"summary": "摘要",
"category": "分类",
"keywords": ["关键词1", "关键词2", "关键词3"],
"link": "原文链接"
}
]
User Message:
以下是需要处理的文章列表:
{{ JSON.stringify($node["Code"].json.articles) }}
注意: 如果文章太多,一次性处理可能会超时。建议在 Code 节点里限制数量(比如取最新的 10 条)。
节点 5:Code(解析 AI 输出)
AI 返回的是 JSON 字符串,需要解析成 n8n 能处理的格式:
const raw = $input.first().json.content || $input.first().json.message?.content;
let articles;try {
// 有时候 AI 会在 JSON 外面包一些废话,用正则提取
const jsonMatch = raw.match(/[[sS]*]/);
articles = jsonMatch ? JSON.parse(jsonMatch[0]) : [];
} catch (e) {
articles = [];
}
// 拆分成多条,每条是一个文章
return articles.map(a => ({
json: {
title: a.title || '',
summary: a.summary || '',
category: a.category || '其他',
keywords: a.keywords || [],
link: a.link || ''
}
}));
节点 6:IF(关键词匹配)
检查文章是否包含你关心的关键词:
条件:keywords 数组包含以下任意一个
- "AI" 或 "人工智能" 或 "Ollama" 或 "Docker" 或 "Linux"
匹配到的文章走”是”分支,否则走”否”分支。
节点 7:SQLite(存档 – 所有文章)
“否”分支和”是”分支都连一个 SQLite 插入:
INSERT INTO content_archive (title, summary, category, source_url, keywords_matched)
VALUES ('{{ $json.title }}', '{{ $json.summary }}', '{{ $json.category }}', '{{ $json.link }}', 0);
“是”分支的 keywords_matched 设为 1。
节点 8:Telegram Bot(推送 – 仅命中关键词的文章)
只有命中关键词的文章才推送:
📌 关键词命中提醒标题:{{ $json.title }}
分类:{{ $json.category }}
摘要:{{ $json.summary }}
{{ $json.link }}
完整工作流结构
Schedule (每天 9:00)
↓
RSS Feed Read (3~5 个源)
↓
Code (去重 + 提取字段)
↓
Ollama Chat (总结 + 分类 + 关键词)
↓
Code (解析 JSON 输出)
↓
IF (关键词匹配?)
/
是 否
↓ ↓
SQLite SQLite
(标记1) (标记0)
↓
Telegram 推送
优化点
1. 分页处理
如果 RSS 源很多(20+ 条),建议分批处理:
// Code 节点里加一个分页器
const articles = $input.first().json.articles;
const PAGE_SIZE = 5;
const page = $execution.resumeData?.page || 0;
const slice = articles.slice(page * PAGE_SIZE, (page + 1) * PAGE_SIZE);if (slice.length === 0) {
return []; // 处理完毕
}
// 设置下次继续
$execution.resumeData = { page: page + 1 };
return [{ json: { articles: slice, hasMore: (page + 1) * PAGE_SIZE < articles.length } }];
2. 错误重试
n8n 支持节点级别的错误重试。在 Ollama Chat 节点设置里:
模型加载慢或者超时时自动重试,不用手动重跑。
3. 导出工作流
搭好的工作流可以导出备份:
n8n → Workflow → 右上角三点 → Download
导出的 JSON 文件就是你的工作流模板,换机器直接导入。
验证
跑完之后,打开 SQLite Web(http://IP:8002),应该能看到 content_archive 表里有记录了。
每条记录包含:
可以按分类筛选,看看 AI 分得准不准。
资源占用
一次完整执行(10 篇文章):
如果是 8G 内存的机器,建议:
扩展方向
这个工作流是基础版,后续可以:
1. 加去重逻辑——用 SQLite 的 title 做 UNIQUE 约束,避免重复存档
2. 加 Webhook 触发——不只是定时,有新内容时通过 Webhook 立即触发
3. 加邮件摘要——每周日把当周存档汇总成一封邮件
4. 接入多模态——用 LLaVA 模型处理网页里的截图/图片
工作流 JSON 模板就不贴了(太长),有需要的可以自己按上面的节点配置搭。每一步都不难,主要是把流程想清楚再动手。