---
title: 本地优先与云端 AI：从数据流理解隐私边界
description: 以 ChatCrystal 为例，分别检查存储、Embedding、摘要、关系发现与 Agent 回忆的数据流，判断本地优先究竟控制了哪些边界。
image: "https://zengliangyi.com/og/blog/local-first-ai-data-boundaries.png"
---

把对话存在自己的电脑上，是掌握数据的一步。但如果生成摘要时调用远端模型，或把检索结果交给云端 Agent，部分内容仍会离开这台电脑。讨论 AI 知识库的隐私，应该从一次操作经过哪些进程、连接哪些地址开始。

[ChatCrystal](/projects/chatcrystal) 将笔记和向量索引保存在应用的数据目录，同时允许配置模型提供方。这让存储与推理可以分别选择。本文按提交 [`7642768`](https://github.com/ZengLiangYi/ChatCrystal/tree/764276814e5c5a33ecbfeae63754f74b9261a3a8) 修订，讨论这些配置对应的数据流，不把“本地优先”当成所有内容都不出网的保证。

## 先区分三个位置

**记录在哪里保存、模型在哪里运行、结果最终交给谁，是三个问题。** 桌面窗口打开在本机，并不能回答后两个问题；文件位于应用服务的数据目录，也不意味着它就在每一个客户端所在的电脑上。

| 环节 | 涉及的内容 | 应检查的位置 |

| --- | --- | --- |

| 导入与存储 | 原始对话、笔记及元数据 | 导入进程、应用服务与数据目录 |

| 生成向量 | 笔记分块、搜索时的查询文本 | Embedding 提供方的实际端点 |

| 生成摘要 | 提交给模型的对话内容 | 摘要模型的实际端点 |

| 发现关系 | 新笔记信息和候选笔记摘要 | 关系发现所用的语言模型 |

| Agent 回忆 | 检索结果和按需读取的笔记 | MCP 客户端以及它调用的模型 |

这张表是检查路径，不是流量审计报告。具体发送哪些字段，应以对应版本的请求构造为准；换模型、改端点或改成远端应用服务后，都需要重新检查。

## 本地索引也可能依赖远端 Embedding

向量检索包含两个时间点：建立索引时，把用于检索的笔记文本转成向量；查询时，把当前问题转成向量，再与索引比较。[Embedding 实现](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/services/embedding.ts) 在这两个环节调用配置的模型。

这里的索引文本由标题、摘要、关键结论、标签和代码说明等字段拼成。任务记忆还会加入部分代码、原因、解决方案、错误特征和文件路径等信息，再进行分块。因此，评估传输范围时要检查这些字段，不能假定它只发送摘要，也不能把它描述成原始对话全文的逐段向量化。

如果模型运行在远端，索引文本分块或查询文本就会发往那个端点。把返回的向量存进本地 Vectra 索引，不能撤销前面的文本传输。向量也不应被直接视为匿名化数据；索引元数据中还保留标题、项目名等字段，备份和共享索引仍应按其来源内容管理。

相反，如果 Embedding 模型、所需文件和应用服务都已在本机准备好，检索可以不依赖远端模型服务。这里的条件需要实际验证：选择名为 Ollama 的提供方，并不足以证明其配置地址指向本机。

## 摘要与关系发现也要单独检查

ChatCrystal 将语言模型和 Embedding 分开配置，因此可以采用本地 Embedding、远端摘要模型的组合。这是一个明确的取舍：查询向量可在本地计算，但交给远端生成摘要的内容仍然会离开本地。

关系发现也不是纯粹的本地数据库查询。[当前实现](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/services/relations.ts) 先寻找候选笔记，再把新笔记的标题、摘要、结论及候选信息组成提示交给语言模型。评估出网范围时，不能只检查“生成摘要”按钮对应的请求。

还要继续追踪结果的接收端。本地 MCP 服务返回笔记之后，客户端可能把工具结果放进远端模型的上下文。这是新的传输边界，不能由知识库的存储方式替客户端作出保证。

## 离线能力应该按操作验证

“能打开应用”和“所有功能离线可用”不是同一个验收结果。可以先选一组已知数据，再断开外网，逐项检查：

- 能否打开已有笔记并读取已有关系。

- Embedding 模型已就绪时，能否对一个新问题执行语义搜索。

- 能否导入并解析新的本地对话。

- 生成新摘要和新关系所需的语言模型是否也可在本地运行。

- Agent 客户端本身是否需要远端模型才能继续工作。

失败时保留具体错误与涉及的端点。缺少模型文件、模型服务未启动、应用服务不可达，需要不同的处理；不能统一归为“知识库丢失记忆”。

## 成本和速度需要同场景测量

本地运行会减少对外部推理服务的依赖，但硬件、模型下载、电力、升级和恢复仍有成本。云端服务减少了部分基础设施工作，也带来网络、调用额度与服务可用性的约束。

不要仅凭“本地”断言延迟更低，也不要给出未经测试的显存最低要求。模型大小、量化、输入长度、并发和现有硬件都会影响结果。对个人知识库，更有意义的是拿一批真实问题，分别测首次加载、热查询耗时、摘要质量与失败恢复过程。

是否用于训练、保留多久、是否有人工访问，是服务政策与账户配置层面的问题，不能从“云端”两个字推断。在实际采用某个服务前，应核对对应产品、套餐与端点的现行说明；本文不替任何提供方作统一承诺。

## 把选择落实为可检查的配置

我更看重的本地优先能力，是数据有可定位的存储目录、能够导出、可以选择模型端点，并且能在失败后恢复。文件留在电脑上也需要访问控制、备份和磁盘保护；同步盘和备份目的地同样属于数据流的一部分。

一个可执行的起点，是列出应用服务地址、两类模型端点、数据目录和 Agent 客户端，再用一条不含敏感信息的测试笔记观察完整流程。每次改变部署方式，重新确认哪些内容会发送到哪里。

关于存储层的取舍，可继续阅读[本地向量数据库选型](/blog/local-vector-database-selection)；关于结果如何进入 Agent 上下文，见 [Agent 知识库设计](/blog/agent-knowledge-memory-loop)。

分享：

##  相关文章

[##  实现 Embedding 服务：文本、分块与提交边界

对照 ChatCrystal 的真实 Embedding 流程，区分文本选择、软分块、向量校验与提交，并用离线反例验证边界。          曾亮懿       2026年10月6日      阅读约 4 分钟

#ChatCrystal

#AI

#Node.js](/blog/embedding-service-design)    [##  结构化 JSON Prompt：把输出字段与来源证据一起设计

以 ChatCrystal 摘要和关系发现为例，设计字段契约、可见输入与反例样本，并用离线 Zod 练习区分格式验证和证据验证。          曾亮懿       2026年10月6日      阅读约 4 分钟

#ChatCrystal

#AI

#Node.js](/blog/structured-json-prompts)    [##  Vectra 本地搜索：用固定向量验证排序、过滤与持久化

在临时目录运行 Vectra 0.15.0 的确定性练习，检查余弦分数、元数据过滤、重新打开索引和取消更新。          曾亮懿       2026年10月6日      阅读约 4 分钟

#ChatCrystal

#AI

#Node.js](/blog/vectra-local-search)

##  从文章到代码

到我的 GitHub 看看 ChatCrystal、开发者工具和日常学习记录，欢迎交流实现细节。

[访问我的 GitHub](https://github.com/ZengLiangYi)

```json
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "ZengLiangYi Blog",
  "alternateName": [
    "Zeng Liangyi",
    "ZengLiangYi",
    "zengliangyi.com"
  ],
  "url": "https://zengliangyi.com",
  "description": "曾亮懿的个人网站。记录 AI Native 探索、开发者工具与全栈产品实践。"
}
{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "本地优先与云端 AI：从数据流理解隐私边界",
  "description": "以 ChatCrystal 为例，分别检查存储、Embedding、摘要、关系发现与 Agent 回忆的数据流，判断本地优先究竟控制了哪些边界。",
  "url": "https://zengliangyi.com/blog/local-first-ai-data-boundaries/",
  "image": "https://zengliangyi.com/images/blog/local-first-ai-data-boundaries.svg",
  "datePublished": "2026-06-04T00:30:00.000Z",
  "dateModified": "2026-10-03T00:00:00.000Z",
  "author": {
    "@type": "Person",
    "name": "曾亮懿",
    "url": "https://zengliangyi.com/about"
  },
  "publisher": {
    "@type": "Organization",
    "name": "ZengLiangYi Blog",
    "logo": {
      "@type": "ImageObject",
      "url": "https://zengliangyi.com/favicon-96x96.png"
    }
  },
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://zengliangyi.com/blog/local-first-ai-data-boundaries/"
  }
}
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "首页",
      "item": "https://zengliangyi.com/"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "文章",
      "item": "https://zengliangyi.com/blog"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "本地优先与云端 AI：从数据流理解隐私边界",
      "item": "https://zengliangyi.com/blog/local-first-ai-data-boundaries/"
    }
  ]
}
```
