尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于本地AI的电脑活动记忆系统:原理、实现与隐私优先实践

基于本地AI的电脑活动记忆系统:原理、实现与隐私优先实践 最近在尝试将 ChatGPT 更深度地融入日常工作流时发现了一个痛点每次对话都像是“重启”一次需要反复向 AI 重复项目背景、代码片段或个人偏好效率大打折扣。如果 AI 能记住我电脑上的活动比如正在编辑的文档、浏览的网页或运行的代码那交互体验将发生质变。这正是“电脑活动记忆”功能试图解决的问题。本文将围绕这一前沿概念深入探讨其技术原理、实现思路并提供一个基于本地化、隐私优先的桌面应用原型开发教程。无论你是想为现有应用添加智能记忆层还是探索下一代人机交互方式都能从中获得一套完整的、可落地的技术方案。1. 背景与核心概念什么是“电脑活动记忆”在传统的 ChatGPT 或类似大模型应用中每一次对话都是独立的。模型不具备跨会话的记忆能力更无法感知用户在其本地设备上的操作和上下文。所谓“电脑活动记忆”Computer Activity Memory指的是一个 AI 助手能够持续地、在用户授权和隐私保护的前提下观察、记录并理解用户在电脑上的各种活动如打开的应用程序、浏览的网页、编辑的文档、终端命令等并利用这些信息来构建一个动态的、个性化的上下文知识库。当用户与 AI 交互时AI 可以主动引用或关联这些记忆提供更具连续性、相关性和深度的协助。核心价值与场景编程开发AI 能记住你当前项目的代码结构、最近修改的文件、遇到的编译错误并在你提问时直接基于这些上下文给出建议。研究与写作AI 能追踪你阅读的文献、收集的网页资料、正在撰写的文档草稿帮助你整合信息、生成大纲或润色文字。工作流自动化AI 通过学习你的日常操作习惯如每天上午先检查邮件然后打开某个数据分析工具可以预测你的需求甚至自动执行一些例行任务。个性化助手记住你的偏好设置、常用命令、项目术语减少重复性描述使对话更自然、高效。重要前提隐私与安全实现此功能的首要原则是“隐私优先本地处理”。所有对用户活动的监控和数据记录都应在用户设备本地完成敏感信息不应未经处理就上传至云端。核心的 AI 推理和记忆查询也尽可能在本地进行或使用安全的、用户可控的 API 方式。本文的实践方案将严格遵守这一原则。2. 环境准备与版本说明我们将构建一个跨平台的桌面应用原型演示如何捕获系统活动并与本地大模型或经过代理的 API结合。技术栈选择注重跨平台能力和开发效率。开发环境操作系统Windows 10/11, macOS 12, 或 Linux (Ubuntu 22.04)。本文示例命令以 macOS/Linux 为主Windows 会有相应说明。编程语言Python 3.9 (用于数据采集、处理和后端逻辑)桌面应用框架Flutter 3.13 (使用dart:ffi或平台通道与 Python 后端通信) 或 PyQt6/PySide6 (纯 Python 方案)。本文将以PyQt6为例便于快速集成 Python 生态。模型/API本地模型方案使用ollama运行本地大模型如llama3.2,qwen2.5等。API 方案通过配置访问 OpenAI API (或兼容的国产大模型 API)。请注意使用任何 API 都需自行解决网络访问和账号问题本文不涉及相关教程。关键 Python 库psutil: 跨平台获取系统进程信息。pynput/pyautogui: 监控键盘、鼠标和屏幕需谨慎使用并明确告知用户。watchdog: 监控文件系统变化。sqlite3: 本地存储活动记录和记忆向量。chromadb/faiss: 用于记忆的向量存储与检索。openai(可选): 调用 OpenAI API。pyqt6: GUI 框架。版本说明本文示例代码基于 Python 3.10 和 PyQt6 编写。由于系统监控和 AI 模型领域更新较快部分库的 API 可能有细微变化请根据你的实际环境调整。核心思路具有普适性。3. 核心原理与技术拆解实现“电脑活动记忆”功能可以拆解为四个核心模块3.1 活动捕获模块负责以非侵入、低功耗的方式收集用户活动数据。窗口焦点与标题获取当前最前端的应用程序窗口及其标题如 “Visual Studio Code - my_project”。这能知道用户正在“做什么”。文件访问与编辑监控特定工作目录的文件变化创建、修改、删除。结合编辑器或 IDE 的集成可以获取更精确的代码上下文。浏览器活动通过浏览器扩展如 Chrome/Firefox或监听特定端口如 DevTools Protocol获取当前标签页的 URL 和标题。必须获得用户明确授权。终端命令在用户使用的 Shell如 zsh, bash中通过 hook 方式如$PROMPT_COMMAND记录执行的命令及其输出。剪贴板内容监控剪贴板变化捕获复制的文本、代码片段。技术要点所有捕获操作都应提供开关允许用户选择监控哪些类型的数据。数据应立即进行匿名化或去敏感化处理如移除密码、密钥。3.2 记忆存储与向量化模块原始活动日志是时序文本流需要转化为可查询的“记忆”。结构化存储使用 SQLite 存储原始活动日志包含时间戳、活动类型、内容摘要等字段。文本向量化将活动内容如“在main.py第 30 行添加了函数calculate_score”通过嵌入模型Embedding Model转换为高维向量。本地可使用sentence-transformers库或ollama的嵌入端点。向量数据库将向量存入本地向量数据库如 ChromaDB。每条向量关联原始日志的 ID便于回溯。3.3 记忆检索与上下文构建模块当用户与 AI 对话时需要从海量记忆中找出最相关的部分。查询向量化将用户的当前问题或对话历史转换为向量。相似性检索在向量数据库中执行相似性搜索找出与当前查询最相关的 K 条历史记忆。上下文组装将检索到的记忆条目按时间或相关性排序组装成一段连贯的“背景故事”作为系统提示词的一部分提交给大模型。3.4 AI 集成与对话模块将构建好的上下文与用户问题一起发送给 AI并管理对话历史。提示词工程设计系统提示词明确告知 AI 其具备“记忆”能力并指导它如何利用提供的上下文。例如“你是一个拥有记忆的 AI 助手。以下是你观察到的用户近期电脑活动摘要[记忆上下文]。请基于这些信息回答用户的问题。”模型调用连接本地ollama服务或配置好的 API 端点。对话管理维护一个有限长度的对话历史实现多轮对话的连贯性。4. 完整实战案例构建一个简易记忆桌面助手我们将创建一个名为 “MemoAssistant” 的简易桌面应用它能在后台安静记录活跃窗口标题并在你提问时尝试从记忆中寻找相关线索来回答。4.1 项目结构与依赖安装创建项目目录并初始化虚拟环境mkdir memo_assistant cd memo_assistant python -m venv venv # Windows: venv\Scripts\activate source venv/bin/activate安装核心依赖pip install psutil pyqt6 chromadb sentence-transformers # 如果使用本地模型安装 ollama 并拉取模型 # curl -fsSL https://ollama.com/install.sh | sh # ollama pull llama3.2:3b # 拉取一个较小模型项目结构memo_assistant/ ├── main.py # 应用主入口 ├── activity_monitor.py # 活动监控模块 ├── memory_store.py # 记忆存储与检索模块 ├── ai_client.py # AI 客户端模块 ├── ui_main_window.py # 主窗口 UI └── database/ └── memories.db # SQLite 数据库文件4.2 核心模块实现1. 活动监控模块 (activity_monitor.py)此模块负责周期性获取当前活动窗口信息。import psutil import time import logging from datetime import datetime # 注意跨平台获取窗口标题需要额外库此处以 macOS 的 AppKit 和 Linux 的 ewmh 为例Windows 可用 pygetwindow # 为简化本例仅捕获进程名。实际项目需根据平台实现。 class ActivityMonitor: def __init__(self, callback): 初始化监控器。 :param callback: 当检测到活动变化时的回调函数接收活动数据字典。 self.callback callback self.last_activity None self.is_monitoring False logging.basicConfig(levellogging.INFO) def get_current_activity(self): 获取当前活动摘要简化版仅进程名 try: # 获取前台进程跨平台精确获取需平台特定代码 # 这里使用 psutil 遍历进程找出可能的前台应用启发式 for proc in psutil.process_iter([pid, name, create_time]): try: # 一个非常简单的判断最近有用户输入的进程 # 真实场景应使用平台API如Windows的GetForegroundWindow if proc.info[name] and bash not in proc.info[name].lower(): activity { timestamp: datetime.now().isoformat(), type: window_focus, process_name: proc.info[name], title: N/A # 实际需要平台API获取窗口标题 } return activity except (psutil.NoSuchProcess, psutil.AccessDenied): continue except Exception as e: logging.error(f获取活动失败: {e}) return None def start_monitoring(self, interval5): 开始监控每 interval 秒检查一次 self.is_monitoring True logging.info(活动监控已启动) while self.is_monitoring: current_act self.get_current_activity() if current_act and current_act ! self.last_activity: self.last_activity current_act self.callback(current_act) # 将活动数据传递给回调函数 logging.info(f活动变更: {current_act[process_name]}) time.sleep(interval) def stop_monitoring(self): 停止监控 self.is_monitoring False logging.info(活动监控已停止) # 示例回调函数 def on_activity_detected(activity_data): print(f[活动记录] {activity_data[timestamp]} - {activity_data[process_name]}) # 这里可以将 activity_data 传递给 memory_store 进行存储2. 记忆存储与检索模块 (memory_store.py)此模块负责将活动存储到 SQLite并利用向量数据库进行检索。import sqlite3 import json from datetime import datetime import chromadb from chromadb.config import Settings from sentence_transformers import SentenceTransformer import logging logging.basicConfig(levellogging.INFO) class MemoryStore: def __init__(self, db_pathdatabase/memories.db, chroma_persist_dir./chroma_db): self.db_path db_path self._init_sqlite() # 初始化向量数据库客户端 self.chroma_client chromadb.PersistentClient(pathchroma_persist_dir, settingsSettings(anonymized_telemetryFalse)) self.collection self.chroma_client.get_or_create_collection(nameactivity_memories) # 加载嵌入模型本地首次运行会下载 self.embedder SentenceTransformer(all-MiniLM-L6-v2) # 轻量级句子转换模型 logging.info(记忆存储模块初始化完成) def _init_sqlite(self): 初始化 SQLite 数据库表 conn sqlite3.connect(self.db_path) c conn.cursor() c.execute( CREATE TABLE IF NOT EXISTS activities (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp TEXT NOT NULL, type TEXT NOT NULL, content TEXT NOT NULL, raw_data TEXT) ) conn.commit() conn.close() def add_activity(self, activity_type, content, raw_dataNone): 添加一条活动记录到 SQLite 和向量数据库 timestamp datetime.now().isoformat() # 1. 存入 SQLite conn sqlite3.connect(self.db_path) c conn.cursor() c.execute(INSERT INTO activities (timestamp, type, content, raw_data) VALUES (?, ?, ?, ?), (timestamp, activity_type, content, json.dumps(raw_data) if raw_data else None)) activity_id c.lastrowid conn.commit() conn.close() # 2. 生成向量并存入 ChromaDB # 将内容和类型组合成文本进行向量化 text_to_embed f{activity_type}: {content} embedding self.embedder.encode(text_to_embed).tolist() # 使用 SQLite 的 rowid 作为 ChromaDB 的 id确保关联 self.collection.add( embeddings[embedding], metadatas[{type: activity_type, timestamp: timestamp, sqlite_id: activity_id}], documents[content], # 存储原始文本用于返回 ids[str(activity_id)] ) logging.info(f记忆已存储: ID{activity_id}, 内容{content[:50]}...) return activity_id def search_memories(self, query_text, n_results3): 根据查询文本搜索相关记忆 # 将查询文本向量化 query_embedding self.embedder.encode(query_text).tolist() # 在向量数据库中搜索 results self.collection.query( query_embeddings[query_embedding], n_resultsn_results ) # 组织返回结果 memories [] if results[documents]: for i in range(len(results[documents][0])): memory { content: results[documents][0][i], metadata: results[metadatas][0][i], distance: results[distances][0][i] } memories.append(memory) return memories def get_recent_activities(self, limit10): 从 SQLite 获取最近的活动记录 conn sqlite3.connect(self.db_path) c conn.cursor() c.execute(SELECT timestamp, type, content FROM activities ORDER BY timestamp DESC LIMIT ?, (limit,)) rows c.fetchall() conn.close() return [{timestamp: r[0], type: r[1], content: r[2]} for r in rows]3. AI 客户端模块 (ai_client.py)此模块封装与 AI 模型的交互。这里提供本地ollama和 OpenAI API 两种示例。import requests import json import logging from typing import List, Dict logging.basicConfig(levellogging.INFO) class AIClient: def __init__(self, modelocal, base_urlhttp://localhost:11434, api_keyNone, modelllama3.2): 初始化 AI 客户端。 :param mode: local 或 openai :param base_url: ollama 服务地址或 OpenAI 兼容 API 地址 :param api_key: OpenAI API Key (modeopenai 时必需) :param model: 模型名称 self.mode mode self.base_url base_url self.api_key api_key self.model model self.headers {Content-Type: application/json} if mode openai and api_key: self.headers[Authorization] fBearer {api_key} def generate_response(self, system_prompt: str, user_prompt: str, conversation_history: List[Dict] None) - str: 生成 AI 回复 messages [{role: system, content: system_prompt}] if conversation_history: messages.extend(conversation_history) messages.append({role: user, content: user_prompt}) if self.mode local: # 调用本地 ollama payload { model: self.model, messages: messages, stream: False } try: response requests.post(f{self.base_url}/api/chat, jsonpayload, headersself.headers) response.raise_for_status() return response.json()[message][content] except Exception as e: logging.error(f调用本地模型失败: {e}) return f错误: 无法连接本地AI服务。请确保 ollama 已运行且模型 {self.model} 已安装。 elif self.mode openai: # 调用 OpenAI 兼容 API payload { model: self.model, messages: messages, temperature: 0.7 } try: # 注意实际地址可能是 https://api.openai.com/v1/chat/completions 或其他代理地址 api_endpoint f{self.base_url}/v1/chat/completions response requests.post(api_endpoint, jsonpayload, headersself.headers) response.raise_for_status() return response.json()[choices][0][message][content] except Exception as e: logging.error(f调用 API 失败: {e}) return 错误: AI 服务调用失败请检查网络和配置。 else: return 错误: AI 客户端模式配置不正确。 # 示例使用本地 ollama # ai AIClient(modelocal, modelllama3.2) # 示例使用 OpenAI API (需自行解决访问问题) # ai AIClient(modeopenai, base_urlhttps://api.openai.com/v1, api_keyyour-sk-..., modelgpt-3.5-turbo)4.3 用户界面与主程序集成 (ui_main_window.py和main.py)主窗口 UI (ui_main_window.py):import sys from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QTextEdit, QLineEdit, QPushButton, QLabel, QListWidget) from PyQt6.QtCore import QThread, pyqtSignal from activity_monitor import ActivityMonitor from memory_store import MemoryStore from ai_client import AIClient class MonitorThread(QThread): 将活动监控放在单独线程避免阻塞UI activity_signal pyqtSignal(dict) def __init__(self, memory_store): super().__init__() self.memory_store memory_store self.monitor ActivityMonitor(self.on_activity) def on_activity(self, activity_data): # 当监控器检测到活动时存储并发射信号更新UI content f{activity_data[process_name]} (标题: {activity_data.get(title, N/A)}) self.memory_store.add_activity(activity_data[type], content, activity_data) self.activity_signal.emit(activity_data) def run(self): self.monitor.start_monitoring(interval10) # 每10秒检查一次 def stop(self): self.monitor.stop_monitoring() class MainWindow(QMainWindow): def __init__(self): super().__init__() self.memory_store MemoryStore() self.ai_client AIClient(modelocal) # 默认使用本地 ollama self.conversation_history [] self.init_ui() self.start_monitoring() def init_ui(self): self.setWindowTitle(MemoAssistant - 记忆助手) self.setGeometry(300, 300, 800, 600) central_widget QWidget() self.setCentralWidget(central_widget) layout QVBoxLayout() # 记忆显示区域 self.memory_list QListWidget() self.memory_list.setMaximumHeight(150) layout.addWidget(QLabel(近期活动记忆:)) layout.addWidget(self.memory_list) # 对话显示区域 self.chat_display QTextEdit() self.chat_display.setReadOnly(True) layout.addWidget(QLabel(与 AI 对话:)) layout.addWidget(self.chat_display) # 输入区域 self.input_field QLineEdit() self.input_field.setPlaceholderText(输入你的问题... (例如我刚才在用哪个软件)) self.input_field.returnPressed.connect(self.send_message) layout.addWidget(self.input_field) # 按钮 btn_send QPushButton(发送) btn_send.clicked.connect(self.send_message) btn_clear QPushButton(清空对话) btn_clear.clicked.connect(self.clear_chat) layout.addWidget(btn_send) layout.addWidget(btn_clear) central_widget.setLayout(layout) self.update_memory_list() def start_monitoring(self): self.monitor_thread MonitorThread(self.memory_store) self.monitor_thread.activity_signal.connect(self.on_new_activity) self.monitor_thread.start() def on_new_activity(self, activity_data): # 在UI线程中更新记忆列表 self.update_memory_list() def update_memory_list(self): self.memory_list.clear() recent self.memory_store.get_recent_activities(limit5) for act in recent: self.memory_list.addItem(f[{act[timestamp][11:19]}] {act[content]}) def send_message(self): user_input self.input_field.text().strip() if not user_input: return # 显示用户输入 self.chat_display.append(f\n**你:** {user_input}) self.input_field.clear() # 1. 检索相关记忆 relevant_memories self.memory_store.search_memories(user_input, n_results2) memory_context 无相关记忆。 if relevant_memories: memory_context 基于你的电脑活动我注意到\n for mem in relevant_memories: memory_context f- {mem[content]} (时间: {mem[metadata][timestamp][11:19]})\n # 2. 构建系统提示词 system_prompt f你是一个智能桌面助手能够访问用户电脑活动的记忆。 以下是与当前问题可能相关的近期活动记录 {memory_context} 请基于这些记忆如果相关和你的通用知识来回答用户的问题。如果记忆不相关请忽略它直接回答问题。 回答要简洁、有帮助。 # 3. 调用 AI self.chat_display.append(**AI:** 思考中...) QApplication.processEvents() # 让UI更新“思考中”提示 response self.ai_client.generate_response(system_prompt, user_input, self.conversation_history) # 4. 更新对话历史并显示回复 self.conversation_history.append({role: user, content: user_input}) self.conversation_history.append({role: assistant, content: response}) # 保持历史长度避免过长 if len(self.conversation_history) 10: self.conversation_history self.conversation_history[-10:] self.chat_display.append(f**助手:** {response}) def clear_chat(self): self.chat_display.clear() self.conversation_history [] self.chat_display.append(对话已清空。) def closeEvent(self, event): self.monitor_thread.stop() self.monitor_thread.wait() event.accept() def main(): app QApplication(sys.argv) window MainWindow() window.show() sys.exit(app.exec()) if __name__ __main__: main()应用主入口 (main.py):from ui_main_window import main if __name__ __main__: main()4.4 运行与验证确保环境就绪已安装所有 Python 依赖如果使用本地ollama请确保已安装并运行了ollama serve且已拉取模型如ollama pull llama3.2:3b。启动应用在项目根目录下运行python main.py界面操作应用启动后后台线程会自动开始记录你的活动窗口进程名。“近期活动记忆”列表会显示捕获到的活动。在下方输入框提问例如“我刚才在用什么软件” 或 “我今天下午都做了什么”。AI 会尝试从记忆库中检索相关信息并回答。观察日志控制台会输出活动捕获和记忆存储的日志信息。4.5 结果说明运行成功后你将看到一个简单的桌面窗口。它演示了“电脑活动记忆”的核心闭环捕获后台默默记录你的前台应用。存储与索引活动被存入 SQLite 并向量化后存入 ChromaDB。检索当你提问时问题被向量化并从记忆中找出最相关的几条。增强推理相关记忆作为上下文被注入给 AI 模型使回答更具个性化。交互通过图形界面完成对话。这只是一个原型实际产品级应用需要更精细的活动捕获、强大的隐私控制、更复杂的记忆组织如时间线、主题聚类以及更稳定的本地模型集成。5. 常见问题与排查思路问题现象可能原因解决思路应用启动报错ModuleNotFoundErrorPython 依赖未安装完整。使用pip install -r requirements.txt(需先创建该文件) 或逐一安装缺失的包。活动监控不记录任何信息psutil无法准确获取前台窗口或监控逻辑过于简单。1. 检查activity_monitor.py中的get_current_activity函数。2. 考虑使用平台特定的 GUI 库如 Windows 的pygetwindow macOS 的AppKit Linux 的Xlib来精确获取窗口标题。3. 增加日志输出调试捕获过程。向量数据库搜索返回空结果1. ChromaDB 集合未正确创建或持久化路径错误。2. 嵌入模型未加载或编码失败。3. 记忆库中确实没有相关数据。1. 检查chroma_persist_dir路径是否存在且有写入权限。2. 检查sentence-transformers模型是否自动下载成功首次运行需联网。3. 尝试存储几条记忆后直接调用memory_store.search_memories(“test”)看是否有返回。调用本地 ollama 失败提示连接错误1. ollama 服务未启动。2. 模型名称错误或未拉取。3. 端口被占用或防火墙阻止。1. 在终端运行ollama serve并确保它持续运行。2. 运行ollama list确认模型存在并在代码中使用正确的模型名。3. 检查base_url(默认http://localhost:11434) 是否能访问 (curl http://localhost:11434/api/tags)。AI 回复总是“无相关记忆”或回答不准确1. 系统提示词设计不佳。2. 向量搜索的相似度阈值不合适或返回结果数太少。3. 活动记录的内容太简单只有进程名缺乏语义信息。1. 优化system_prompt更清晰地指导 AI 如何使用记忆。2. 调整search_memories的n_results参数或对结果进行基于距离的过滤。3. 丰富活动记录的内容例如捕获窗口标题、文件路径等更有意义的文本。应用界面卡顿或无响应活动监控或 AI 推理在主 UI 线程中运行阻塞了事件循环。确保所有耗时操作如监控循环、网络请求都在单独的 QThread 中运行如示例中的MonitorThread。6. 最佳实践与工程建议将“电脑活动记忆”功能产品化需要远超原型的工程化考量。隐私与安全第一明确告知与授权应用首次启动必须有清晰的隐私协议和权限申请让用户选择监控哪些活动如文件、浏览器、键盘。数据本地化所有原始数据必须加密存储在用户本地。向量化过程也应在本地完成。敏感信息过滤在数据捕获层实现实时过滤器自动剔除密码、密钥、身份证号等敏感模式的内容。数据生命周期提供设置允许用户自动删除超过一定时间的记忆或一键清除所有数据。系统活动捕获的健壮性跨平台抽象层为 Windows、macOS、Linux 分别实现原生、高效的活动捕获接口并封装成统一的 API。性能与功耗监控频率要合理如非活跃时降低频率使用高效的事件驱动机制如文件系统事件watchdog而非轮询。错误恢复监控进程崩溃后应能自动重启并记录错误日志。记忆系统的智能性记忆分层区分短期工作记忆当前会话和长期知识记忆跨会话采用不同的存储和检索策略。记忆摘要与压缩定期对高频、重复的活动进行自动摘要避免向量数据库膨胀。关联与图谱不仅存储孤立事件还尝试建立事件之间的关联如“编辑文件A”后“运行了测试B”构建知识图谱。主动学习允许用户对 AI 的回答进行反馈“这个记忆有用/无用”利用反馈优化检索和提示词。AI 集成的稳定性与成本降级策略当本地大模型不可用或 API 调用失败时应有优雅降级方案如仅展示原始记忆不进行智能回答。上下文长度管理大模型有上下文窗口限制需要智能截断或总结过长的记忆上下文。本地模型优化探索量化、硬件加速如 GPU MPS来提升本地模型的推理速度。成本控制如果使用按 token 计费的云 API需要对输入上下文进行压缩和优化避免不必要的 token 消耗。用户体验与可控性记忆可视化提供时间线或图谱视图让用户直观查看、搜索和管理自己的记忆。记忆编辑与删除用户必须能查看、修正或删除任何一条错误的或不愿保留的记忆。情景模式允许用户创建不同的“情景”如“工作模式”、“学习模式”在不同模式下关注不同类型的活动。开发此类功能是一个持续迭代的过程应从最小可行原型MVP开始紧密围绕用户真实需求逐步增加功能和优化体验同时始终将用户隐私和数据主权放在核心位置。
返回列表