<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SQLite &#8211; 95博客</title>
	<atom:link href="https://95bok.cn/tag/sqlite/feed/" rel="self" type="application/rss+xml" />
	<link>https://95bok.cn</link>
	<description>云烟</description>
	<lastBuildDate>Mon, 13 Apr 2026 08:23:34 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://95bok.cn/wp-content/uploads/2025/11/cropped-1740116058152-32x32.jpg</url>
	<title>SQLite &#8211; 95博客</title>
	<link>https://95bok.cn</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Ollama + n8n 工作流实战：从抓取网页 → 总结 → 分类存档 → 推送提醒，全程本地零云端</title>
		<link>https://95bok.cn/ollama-n8n-%e5%b7%a5%e4%bd%9c%e6%b5%81%e5%ae%9e%e6%88%98%ef%bc%9a%e4%bb%8e%e6%8a%93%e5%8f%96%e7%bd%91%e9%a1%b5-%e2%86%92-%e6%80%bb%e7%bb%93-%e2%86%92-%e5%88%86%e7%b1%bb%e5%ad%98%e6%a1%a3-%e2%86%92/</link>
					<comments>https://95bok.cn/ollama-n8n-%e5%b7%a5%e4%bd%9c%e6%b5%81%e5%ae%9e%e6%88%98%ef%bc%9a%e4%bb%8e%e6%8a%93%e5%8f%96%e7%bd%91%e9%a1%b5-%e2%86%92-%e6%80%bb%e7%bb%93-%e2%86%92-%e5%88%86%e7%b1%bb%e5%ad%98%e6%a1%a3-%e2%86%92/#respond</comments>
		
		<dc:creator><![CDATA[]]></dc:creator>
		<pubDate>Mon, 13 Apr 2026 08:23:34 +0000</pubDate>
				<category><![CDATA[Docker容器]]></category>
		<category><![CDATA[本地AI]]></category>
		<category><![CDATA[n8n]]></category>
		<category><![CDATA[Ollama]]></category>
		<category><![CDATA[RSS]]></category>
		<category><![CDATA[SQLite]]></category>
		<category><![CDATA[分类]]></category>
		<category><![CDATA[工作流]]></category>
		<category><![CDATA[自动化]]></category>
		<guid isPermaLink="false">https://95bok.cn/ollama-n8n-%e5%b7%a5%e4%bd%9c%e6%b5%81%e5%ae%9e%e6%88%98%ef%bc%9a%e4%bb%8e%e6%8a%93%e5%8f%96%e7%bd%91%e9%a1%b5-%e2%86%92-%e6%80%bb%e7%bb%93-%e2%86%92-%e5%88%86%e7%b1%bb%e5%ad%98%e6%a1%a3-%e2%86%92/</guid>

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