記憶系統(tǒng):原理、實(shí)現(xiàn)與隱私優(yōu)先實(shí)踐)
最近在嘗試將 ChatGPT 更深度地融入日常工作流時(shí)發(fā)現(xiàn)了一個(gè)痛點(diǎn)每次對(duì)話都像是“重啟”一次需要反復(fù)向 AI 重復(fù)項(xiàng)目背景、代碼片段或個(gè)人偏好效率大打折扣。如果 AI 能記住我電腦上的活動(dòng)比如正在編輯的文檔、瀏覽的網(wǎng)頁(yè)或運(yùn)行的代碼那交互體驗(yàn)將發(fā)生質(zhì)變。這正是“電腦活動(dòng)記憶”功能試圖解決的問(wèn)題。本文將圍繞這一前沿概念深入探討其技術(shù)原理、實(shí)現(xiàn)思路并提供一個(gè)基于本地化、隱私優(yōu)先的桌面應(yīng)用原型開(kāi)發(fā)教程。無(wú)論你是想為現(xiàn)有應(yīng)用添加智能記憶層還是探索下一代人機(jī)交互方式都能從中獲得一套完整的、可落地的技術(shù)方案。1. 背景與核心概念什么是“電腦活動(dòng)記憶”在傳統(tǒng)的 ChatGPT 或類似大模型應(yīng)用中每一次對(duì)話都是獨(dú)立的。模型不具備跨會(huì)話的記憶能力更無(wú)法感知用戶在其本地設(shè)備上的操作和上下文。所謂“電腦活動(dòng)記憶”Computer Activity Memory指的是一個(gè) AI 助手能夠持續(xù)地、在用戶授權(quán)和隱私保護(hù)的前提下觀察、記錄并理解用戶在電腦上的各種活動(dòng)如打開(kāi)的應(yīng)用程序、瀏覽的網(wǎng)頁(yè)、編輯的文檔、終端命令等并利用這些信息來(lái)構(gòu)建一個(gè)動(dòng)態(tài)的、個(gè)性化的上下文知識(shí)庫(kù)。當(dāng)用戶與 AI 交互時(shí)AI 可以主動(dòng)引用或關(guān)聯(lián)這些記憶提供更具連續(xù)性、相關(guān)性和深度的協(xié)助。核心價(jià)值與場(chǎng)景編程開(kāi)發(fā)AI 能記住你當(dāng)前項(xiàng)目的代碼結(jié)構(gòu)、最近修改的文件、遇到的編譯錯(cuò)誤并在你提問(wèn)時(shí)直接基于這些上下文給出建議。研究與寫(xiě)作AI 能追蹤你閱讀的文獻(xiàn)、收集的網(wǎng)頁(yè)資料、正在撰寫(xiě)的文檔草稿幫助你整合信息、生成大綱或潤(rùn)色文字。工作流自動(dòng)化AI 通過(guò)學(xué)習(xí)你的日常操作習(xí)慣如每天上午先檢查郵件然后打開(kāi)某個(gè)數(shù)據(jù)分析工具可以預(yù)測(cè)你的需求甚至自動(dòng)執(zhí)行一些例行任務(wù)。個(gè)性化助手記住你的偏好設(shè)置、常用命令、項(xiàng)目術(shù)語(yǔ)減少重復(fù)性描述使對(duì)話更自然、高效。重要前提隱私與安全實(shí)現(xiàn)此功能的首要原則是“隱私優(yōu)先本地處理”。所有對(duì)用戶活動(dòng)的監(jiān)控和數(shù)據(jù)記錄都應(yīng)在用戶設(shè)備本地完成敏感信息不應(yīng)未經(jīng)處理就上傳至云端。核心的 AI 推理和記憶查詢也盡可能在本地進(jìn)行或使用安全的、用戶可控的 API 方式。本文的實(shí)踐方案將嚴(yán)格遵守這一原則。2. 環(huán)境準(zhǔn)備與版本說(shuō)明我們將構(gòu)建一個(gè)跨平臺(tái)的桌面應(yīng)用原型演示如何捕獲系統(tǒng)活動(dòng)并與本地大模型或經(jīng)過(guò)代理的 API結(jié)合。技術(shù)棧選擇注重跨平臺(tái)能力和開(kāi)發(fā)效率。開(kāi)發(fā)環(huán)境操作系統(tǒng)Windows 10/11, macOS 12, 或 Linux (Ubuntu 22.04)。本文示例命令以 macOS/Linux 為主Windows 會(huì)有相應(yīng)說(shuō)明。編程語(yǔ)言Python 3.9 (用于數(shù)據(jù)采集、處理和后端邏輯)桌面應(yīng)用框架Flutter 3.13 (使用dart:ffi或平臺(tái)通道與 Python 后端通信) 或 PyQt6/PySide6 (純 Python 方案)。本文將以PyQt6為例便于快速集成 Python 生態(tài)。模型/API本地模型方案使用ollama運(yùn)行本地大模型如llama3.2,qwen2.5等。API 方案通過(guò)配置訪問(wèn) OpenAI API (或兼容的國(guó)產(chǎn)大模型 API)。請(qǐng)注意使用任何 API 都需自行解決網(wǎng)絡(luò)訪問(wèn)和賬號(hào)問(wèn)題本文不涉及相關(guān)教程。關(guān)鍵 Python 庫(kù)psutil: 跨平臺(tái)獲取系統(tǒng)進(jìn)程信息。pynput/pyautogui: 監(jiān)控鍵盤、鼠標(biāo)和屏幕需謹(jǐn)慎使用并明確告知用戶。watchdog: 監(jiān)控文件系統(tǒng)變化。sqlite3: 本地存儲(chǔ)活動(dòng)記錄和記憶向量。chromadb/faiss: 用于記憶的向量存儲(chǔ)與檢索。openai(可選): 調(diào)用 OpenAI API。pyqt6: GUI 框架。版本說(shuō)明本文示例代碼基于 Python 3.10 和 PyQt6 編寫(xiě)。由于系統(tǒng)監(jiān)控和 AI 模型領(lǐng)域更新較快部分庫(kù)的 API 可能有細(xì)微變化請(qǐng)根據(jù)你的實(shí)際環(huán)境調(diào)整。核心思路具有普適性。3. 核心原理與技術(shù)拆解實(shí)現(xiàn)“電腦活動(dòng)記憶”功能可以拆解為四個(gè)核心模塊3.1 活動(dòng)捕獲模塊負(fù)責(zé)以非侵入、低功耗的方式收集用戶活動(dòng)數(shù)據(jù)。窗口焦點(diǎn)與標(biāo)題獲取當(dāng)前最前端的應(yīng)用程序窗口及其標(biāo)題如 “Visual Studio Code - my_project”。這能知道用戶正在“做什么”。文件訪問(wèn)與編輯監(jiān)控特定工作目錄的文件變化創(chuàng)建、修改、刪除。結(jié)合編輯器或 IDE 的集成可以獲取更精確的代碼上下文。瀏覽器活動(dòng)通過(guò)瀏覽器擴(kuò)展如 Chrome/Firefox或監(jiān)聽(tīng)特定端口如 DevTools Protocol獲取當(dāng)前標(biāo)簽頁(yè)的 URL 和標(biāo)題。必須獲得用戶明確授權(quán)。終端命令在用戶使用的 Shell如 zsh, bash中通過(guò) hook 方式如$PROMPT_COMMAND記錄執(zhí)行的命令及其輸出。剪貼板內(nèi)容監(jiān)控剪貼板變化捕獲復(fù)制的文本、代碼片段。技術(shù)要點(diǎn)所有捕獲操作都應(yīng)提供開(kāi)關(guān)允許用戶選擇監(jiān)控哪些類型的數(shù)據(jù)。數(shù)據(jù)應(yīng)立即進(jìn)行匿名化或去敏感化處理如移除密碼、密鑰。3.2 記憶存儲(chǔ)與向量化模塊原始活動(dòng)日志是時(shí)序文本流需要轉(zhuǎn)化為可查詢的“記憶”。結(jié)構(gòu)化存儲(chǔ)使用 SQLite 存儲(chǔ)原始活動(dòng)日志包含時(shí)間戳、活動(dòng)類型、內(nèi)容摘要等字段。文本向量化將活動(dòng)內(nèi)容如“在main.py第 30 行添加了函數(shù)calculate_score”通過(guò)嵌入模型Embedding Model轉(zhuǎn)換為高維向量。本地可使用sentence-transformers庫(kù)或ollama的嵌入端點(diǎn)。向量數(shù)據(jù)庫(kù)將向量存入本地向量數(shù)據(jù)庫(kù)如 ChromaDB。每條向量關(guān)聯(lián)原始日志的 ID便于回溯。3.3 記憶檢索與上下文構(gòu)建模塊當(dāng)用戶與 AI 對(duì)話時(shí)需要從海量記憶中找出最相關(guān)的部分。查詢向量化將用戶的當(dāng)前問(wèn)題或?qū)υ挌v史轉(zhuǎn)換為向量。相似性檢索在向量數(shù)據(jù)庫(kù)中執(zhí)行相似性搜索找出與當(dāng)前查詢最相關(guān)的 K 條歷史記憶。上下文組裝將檢索到的記憶條目按時(shí)間或相關(guān)性排序組裝成一段連貫的“背景故事”作為系統(tǒng)提示詞的一部分提交給大模型。3.4 AI 集成與對(duì)話模塊將構(gòu)建好的上下文與用戶問(wèn)題一起發(fā)送給 AI并管理對(duì)話歷史。提示詞工程設(shè)計(jì)系統(tǒng)提示詞明確告知 AI 其具備“記憶”能力并指導(dǎo)它如何利用提供的上下文。例如“你是一個(gè)擁有記憶的 AI 助手。以下是你觀察到的用戶近期電腦活動(dòng)摘要[記憶上下文]。請(qǐng)基于這些信息回答用戶的問(wèn)題。”模型調(diào)用連接本地ollama服務(wù)或配置好的 API 端點(diǎn)。對(duì)話管理維護(hù)一個(gè)有限長(zhǎng)度的對(duì)話歷史實(shí)現(xiàn)多輪對(duì)話的連貫性。4. 完整實(shí)戰(zhàn)案例構(gòu)建一個(gè)簡(jiǎn)易記憶桌面助手我們將創(chuàng)建一個(gè)名為 “MemoAssistant” 的簡(jiǎn)易桌面應(yīng)用它能在后臺(tái)安靜記錄活躍窗口標(biāo)題并在你提問(wèn)時(shí)嘗試從記憶中尋找相關(guān)線索來(lái)回答。4.1 項(xiàng)目結(jié)構(gòu)與依賴安裝創(chuàng)建項(xiàng)目目錄并初始化虛擬環(huán)境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 # 拉取一個(gè)較小模型項(xiàng)目結(jié)構(gòu)memo_assistant/ ├── main.py # 應(yīng)用主入口 ├── activity_monitor.py # 活動(dòng)監(jiān)控模塊 ├── memory_store.py # 記憶存儲(chǔ)與檢索模塊 ├── ai_client.py # AI 客戶端模塊 ├── ui_main_window.py # 主窗口 UI └── database/ └── memories.db # SQLite 數(shù)據(jù)庫(kù)文件4.2 核心模塊實(shí)現(xiàn)1. 活動(dòng)監(jiān)控模塊 (activity_monitor.py)此模塊負(fù)責(zé)周期性獲取當(dāng)前活動(dòng)窗口信息。import psutil import time import logging from datetime import datetime # 注意跨平臺(tái)獲取窗口標(biāo)題需要額外庫(kù)此處以 macOS 的 AppKit 和 Linux 的 ewmh 為例Windows 可用 pygetwindow # 為簡(jiǎn)化本例僅捕獲進(jìn)程名。實(shí)際項(xiàng)目需根據(jù)平臺(tái)實(shí)現(xiàn)。 class ActivityMonitor: def __init__(self, callback): 初始化監(jiān)控器。 :param callback: 當(dāng)檢測(cè)到活動(dòng)變化時(shí)的回調(diào)函數(shù)接收活動(dòng)數(shù)據(jù)字典。 self.callback callback self.last_activity None self.is_monitoring False logging.basicConfig(levellogging.INFO) def get_current_activity(self): 獲取當(dāng)前活動(dòng)摘要簡(jiǎn)化版僅進(jìn)程名 try: # 獲取前臺(tái)進(jìn)程跨平臺(tái)精確獲取需平臺(tái)特定代碼 # 這里使用 psutil 遍歷進(jìn)程找出可能的前臺(tái)應(yīng)用啟發(fā)式 for proc in psutil.process_iter([pid, name, create_time]): try: # 一個(gè)非常簡(jiǎn)單的判斷最近有用戶輸入的進(jìn)程 # 真實(shí)場(chǎng)景應(yīng)使用平臺(tái)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 # 實(shí)際需要平臺(tái)API獲取窗口標(biāo)題 } return activity except (psutil.NoSuchProcess, psutil.AccessDenied): continue except Exception as e: logging.error(f獲取活動(dòng)失敗: {e}) return None def start_monitoring(self, interval5): 開(kāi)始監(jiān)控每 interval 秒檢查一次 self.is_monitoring True logging.info(活動(dòng)監(jiān)控已啟動(dòng)) 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) # 將活動(dòng)數(shù)據(jù)傳遞給回調(diào)函數(shù) logging.info(f活動(dòng)變更: {current_act[process_name]}) time.sleep(interval) def stop_monitoring(self): 停止監(jiān)控 self.is_monitoring False logging.info(活動(dòng)監(jiān)控已停止) # 示例回調(diào)函數(shù) def on_activity_detected(activity_data): print(f[活動(dòng)記錄](méi) {activity_data[timestamp]} - {activity_data[process_name]}) # 這里可以將 activity_data 傳遞給 memory_store 進(jìn)行存儲(chǔ)2. 記憶存儲(chǔ)與檢索模塊 (memory_store.py)此模塊負(fù)責(zé)將活動(dòng)存儲(chǔ)到 SQLite并利用向量數(shù)據(jù)庫(kù)進(jìn)行檢索。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() # 初始化向量數(shù)據(jù)庫(kù)客戶端 self.chroma_client chromadb.PersistentClient(pathchroma_persist_dir, settingsSettings(anonymized_telemetryFalse)) self.collection self.chroma_client.get_or_create_collection(nameactivity_memories) # 加載嵌入模型本地首次運(yùn)行會(huì)下載 self.embedder SentenceTransformer(all-MiniLM-L6-v2) # 輕量級(jí)句子轉(zhuǎn)換模型 logging.info(記憶存儲(chǔ)模塊初始化完成) def _init_sqlite(self): 初始化 SQLite 數(shù)據(jù)庫(kù)表 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): 添加一條活動(dòng)記錄到 SQLite 和向量數(shù)據(jù)庫(kù) 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 # 將內(nèi)容和類型組合成文本進(jìn)行向量化 text_to_embed f{activity_type}: {content} embedding self.embedder.encode(text_to_embed).tolist() # 使用 SQLite 的 rowid 作為 ChromaDB 的 id確保關(guān)聯(lián) self.collection.add( embeddings[embedding], metadatas[{type: activity_type, timestamp: timestamp, sqlite_id: activity_id}], documents[content], # 存儲(chǔ)原始文本用于返回 ids[str(activity_id)] ) logging.info(f記憶已存儲(chǔ): ID{activity_id}, 內(nèi)容{content[:50]}...) return activity_id def search_memories(self, query_text, n_results3): 根據(jù)查詢文本搜索相關(guān)記憶 # 將查詢文本向量化 query_embedding self.embedder.encode(query_text).tolist() # 在向量數(shù)據(jù)庫(kù)中搜索 results self.collection.query( query_embeddings[query_embedding], n_resultsn_results ) # 組織返回結(jié)果 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 獲取最近的活動(dòng)記錄 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 服務(wù)地址或 OpenAI 兼容 API 地址 :param api_key: OpenAI API Key (modeopenai 時(shí)必需) :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 回復(fù) messages [{role: system, content: system_prompt}] if conversation_history: messages.extend(conversation_history) messages.append({role: user, content: user_prompt}) if self.mode local: # 調(diào)用本地 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調(diào)用本地模型失敗: {e}) return f錯(cuò)誤: 無(wú)法連接本地AI服務(wù)。請(qǐng)確保 ollama 已運(yùn)行且模型 {self.model} 已安裝。 elif self.mode openai: # 調(diào)用 OpenAI 兼容 API payload { model: self.model, messages: messages, temperature: 0.7 } try: # 注意實(shí)際地址可能是 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調(diào)用 API 失敗: {e}) return 錯(cuò)誤: AI 服務(wù)調(diào)用失敗請(qǐng)檢查網(wǎng)絡(luò)和配置。 else: return 錯(cuò)誤: AI 客戶端模式配置不正確。 # 示例使用本地 ollama # ai AIClient(modelocal, modelllama3.2) # 示例使用 OpenAI API (需自行解決訪問(wèn)問(wèn)題) # 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): 將活動(dòng)監(jiān)控放在單獨(dú)線程避免阻塞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): # 當(dāng)監(jiān)控器檢測(cè)到活動(dòng)時(shí)存儲(chǔ)并發(fā)射信號(hào)更新UI content f{activity_data[process_name]} (標(biāo)題: {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) # 默認(rèn)使用本地 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() # 記憶顯示區(qū)域 self.memory_list QListWidget() self.memory_list.setMaximumHeight(150) layout.addWidget(QLabel(近期活動(dòng)記憶:)) layout.addWidget(self.memory_list) # 對(duì)話顯示區(qū)域 self.chat_display QTextEdit() self.chat_display.setReadOnly(True) layout.addWidget(QLabel(與 AI 對(duì)話:)) layout.addWidget(self.chat_display) # 輸入?yún)^(qū)域 self.input_field QLineEdit() self.input_field.setPlaceholderText(輸入你的問(wèn)題... (例如我剛才在用哪個(gè)軟件)) self.input_field.returnPressed.connect(self.send_message) layout.addWidget(self.input_field) # 按鈕 btn_send QPushButton(發(fā)送) btn_send.clicked.connect(self.send_message) btn_clear QPushButton(清空對(duì)話) 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. 檢索相關(guān)記憶 relevant_memories self.memory_store.search_memories(user_input, n_results2) memory_context 無(wú)相關(guān)記憶。 if relevant_memories: memory_context 基于你的電腦活動(dòng)我注意到\n for mem in relevant_memories: memory_context f- {mem[content]} (時(shí)間: {mem[metadata][timestamp][11:19]})\n # 2. 構(gòu)建系統(tǒng)提示詞 system_prompt f你是一個(gè)智能桌面助手能夠訪問(wèn)用戶電腦活動(dòng)的記憶。 以下是與當(dāng)前問(wèn)題可能相關(guān)的近期活動(dòng)記錄 {memory_context} 請(qǐng)基于這些記憶如果相關(guān)和你的通用知識(shí)來(lái)回答用戶的問(wèn)題。如果記憶不相關(guān)請(qǐng)忽略它直接回答問(wèn)題。 回答要簡(jiǎn)潔、有幫助。 # 3. 調(diào)用 AI self.chat_display.append(**AI:** 思考中...) QApplication.processEvents() # 讓UI更新“思考中”提示 response self.ai_client.generate_response(system_prompt, user_input, self.conversation_history) # 4. 更新對(duì)話歷史并顯示回復(fù) self.conversation_history.append({role: user, content: user_input}) self.conversation_history.append({role: assistant, content: response}) # 保持歷史長(zhǎng)度避免過(guò)長(zhǎng) 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(對(duì)話已清空。) 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()應(yīng)用主入口 (main.py):from ui_main_window import main if __name__ __main__: main()4.4 運(yùn)行與驗(yàn)證確保環(huán)境就緒已安裝所有 Python 依賴如果使用本地ollama請(qǐng)確保已安裝并運(yùn)行了ollama serve且已拉取模型如ollama pull llama3.2:3b。啟動(dòng)應(yīng)用在項(xiàng)目根目錄下運(yùn)行python main.py界面操作應(yīng)用啟動(dòng)后后臺(tái)線程會(huì)自動(dòng)開(kāi)始記錄你的活動(dòng)窗口進(jìn)程名。“近期活動(dòng)記憶”列表會(huì)顯示捕獲到的活動(dòng)。在下方輸入框提問(wèn)例如“我剛才在用什么軟件” 或 “我今天下午都做了什么”。AI 會(huì)嘗試從記憶庫(kù)中檢索相關(guān)信息并回答。觀察日志控制臺(tái)會(huì)輸出活動(dòng)捕獲和記憶存儲(chǔ)的日志信息。4.5 結(jié)果說(shuō)明運(yùn)行成功后你將看到一個(gè)簡(jiǎn)單的桌面窗口。它演示了“電腦活動(dòng)記憶”的核心閉環(huán)捕獲后臺(tái)默默記錄你的前臺(tái)應(yīng)用。存儲(chǔ)與索引活動(dòng)被存入 SQLite 并向量化后存入 ChromaDB。檢索當(dāng)你提問(wèn)時(shí)問(wèn)題被向量化并從記憶中找出最相關(guān)的幾條。增強(qiáng)推理相關(guān)記憶作為上下文被注入給 AI 模型使回答更具個(gè)性化。交互通過(guò)圖形界面完成對(duì)話。這只是一個(gè)原型實(shí)際產(chǎn)品級(jí)應(yīng)用需要更精細(xì)的活動(dòng)捕獲、強(qiáng)大的隱私控制、更復(fù)雜的記憶組織如時(shí)間線、主題聚類以及更穩(wěn)定的本地模型集成。5. 常見(jiàn)問(wèn)題與排查思路問(wèn)題現(xiàn)象可能原因解決思路應(yīng)用啟動(dòng)報(bào)錯(cuò)ModuleNotFoundErrorPython 依賴未安裝完整。使用pip install -r requirements.txt(需先創(chuàng)建該文件) 或逐一安裝缺失的包。活動(dòng)監(jiān)控不記錄任何信息psutil無(wú)法準(zhǔn)確獲取前臺(tái)窗口或監(jiān)控邏輯過(guò)于簡(jiǎn)單。1. 檢查activity_monitor.py中的get_current_activity函數(shù)。2. 考慮使用平臺(tái)特定的 GUI 庫(kù)如 Windows 的pygetwindow macOS 的AppKit Linux 的Xlib來(lái)精確獲取窗口標(biāo)題。3. 增加日志輸出調(diào)試捕獲過(guò)程。向量數(shù)據(jù)庫(kù)搜索返回空結(jié)果1. ChromaDB 集合未正確創(chuàng)建或持久化路徑錯(cuò)誤。2. 嵌入模型未加載或編碼失敗。3. 記憶庫(kù)中確實(shí)沒(méi)有相關(guān)數(shù)據(jù)。1. 檢查chroma_persist_dir路徑是否存在且有寫(xiě)入權(quán)限。2. 檢查sentence-transformers模型是否自動(dòng)下載成功首次運(yùn)行需聯(lián)網(wǎng)。3. 嘗試存儲(chǔ)幾條記憶后直接調(diào)用memory_store.search_memories(“test”)看是否有返回。調(diào)用本地 ollama 失敗提示連接錯(cuò)誤1. ollama 服務(wù)未啟動(dòng)。2. 模型名稱錯(cuò)誤或未拉取。3. 端口被占用或防火墻阻止。1. 在終端運(yùn)行ollama serve并確保它持續(xù)運(yùn)行。2. 運(yùn)行ollama list確認(rèn)模型存在并在代碼中使用正確的模型名。3. 檢查base_url(默認(rèn)http://localhost:11434) 是否能訪問(wèn) (curl http://localhost:11434/api/tags)。AI 回復(fù)總是“無(wú)相關(guān)記憶”或回答不準(zhǔn)確1. 系統(tǒng)提示詞設(shè)計(jì)不佳。2. 向量搜索的相似度閾值不合適或返回結(jié)果數(shù)太少。3. 活動(dòng)記錄的內(nèi)容太簡(jiǎn)單只有進(jìn)程名缺乏語(yǔ)義信息。1. 優(yōu)化system_prompt更清晰地指導(dǎo) AI 如何使用記憶。2. 調(diào)整search_memories的n_results參數(shù)或?qū)Y(jié)果進(jìn)行基于距離的過(guò)濾。3. 豐富活動(dòng)記錄的內(nèi)容例如捕獲窗口標(biāo)題、文件路徑等更有意義的文本。應(yīng)用界面卡頓或無(wú)響應(yīng)活動(dòng)監(jiān)控或 AI 推理在主 UI 線程中運(yùn)行阻塞了事件循環(huán)。確保所有耗時(shí)操作如監(jiān)控循環(huán)、網(wǎng)絡(luò)請(qǐng)求都在單獨(dú)的 QThread 中運(yùn)行如示例中的MonitorThread。6. 最佳實(shí)踐與工程建議將“電腦活動(dòng)記憶”功能產(chǎn)品化需要遠(yuǎn)超原型的工程化考量。隱私與安全第一明確告知與授權(quán)應(yīng)用首次啟動(dòng)必須有清晰的隱私協(xié)議和權(quán)限申請(qǐng)讓用戶選擇監(jiān)控哪些活動(dòng)如文件、瀏覽器、鍵盤。數(shù)據(jù)本地化所有原始數(shù)據(jù)必須加密存儲(chǔ)在用戶本地。向量化過(guò)程也應(yīng)在本地完成。敏感信息過(guò)濾在數(shù)據(jù)捕獲層實(shí)現(xiàn)實(shí)時(shí)過(guò)濾器自動(dòng)剔除密碼、密鑰、身份證號(hào)等敏感模式的內(nèi)容。數(shù)據(jù)生命周期提供設(shè)置允許用戶自動(dòng)刪除超過(guò)一定時(shí)間的記憶或一鍵清除所有數(shù)據(jù)。系統(tǒng)活動(dòng)捕獲的健壯性跨平臺(tái)抽象層為 Windows、macOS、Linux 分別實(shí)現(xiàn)原生、高效的活動(dòng)捕獲接口并封裝成統(tǒng)一的 API。性能與功耗監(jiān)控頻率要合理如非活躍時(shí)降低頻率使用高效的事件驅(qū)動(dòng)機(jī)制如文件系統(tǒng)事件watchdog而非輪詢。錯(cuò)誤恢復(fù)監(jiān)控進(jìn)程崩潰后應(yīng)能自動(dòng)重啟并記錄錯(cuò)誤日志。記憶系統(tǒng)的智能性記憶分層區(qū)分短期工作記憶當(dāng)前會(huì)話和長(zhǎng)期知識(shí)記憶跨會(huì)話采用不同的存儲(chǔ)和檢索策略。記憶摘要與壓縮定期對(duì)高頻、重復(fù)的活動(dòng)進(jìn)行自動(dòng)摘要避免向量數(shù)據(jù)庫(kù)膨脹。關(guān)聯(lián)與圖譜不僅存儲(chǔ)孤立事件還嘗試建立事件之間的關(guān)聯(lián)如“編輯文件A”后“運(yùn)行了測(cè)試B”構(gòu)建知識(shí)圖譜。主動(dòng)學(xué)習(xí)允許用戶對(duì) AI 的回答進(jìn)行反饋“這個(gè)記憶有用/無(wú)用”利用反饋優(yōu)化檢索和提示詞。AI 集成的穩(wěn)定性與成本降級(jí)策略當(dāng)本地大模型不可用或 API 調(diào)用失敗時(shí)應(yīng)有優(yōu)雅降級(jí)方案如僅展示原始記憶不進(jìn)行智能回答。上下文長(zhǎng)度管理大模型有上下文窗口限制需要智能截?cái)嗷蚩偨Y(jié)過(guò)長(zhǎng)的記憶上下文。本地模型優(yōu)化探索量化、硬件加速如 GPU MPS來(lái)提升本地模型的推理速度。成本控制如果使用按 token 計(jì)費(fèi)的云 API需要對(duì)輸入上下文進(jìn)行壓縮和優(yōu)化避免不必要的 token 消耗。用戶體驗(yàn)與可控性記憶可視化提供時(shí)間線或圖譜視圖讓用戶直觀查看、搜索和管理自己的記憶。記憶編輯與刪除用戶必須能查看、修正或刪除任何一條錯(cuò)誤的或不愿保留的記憶。情景模式允許用戶創(chuàng)建不同的“情景”如“工作模式”、“學(xué)習(xí)模式”在不同模式下關(guān)注不同類型的活動(dòng)。開(kāi)發(fā)此類功能是一個(gè)持續(xù)迭代的過(guò)程應(yīng)從最小可行原型MVP開(kāi)始緊密圍繞用戶真實(shí)需求逐步增加功能和優(yōu)化體驗(yàn)同時(shí)始終將用戶隱私和數(shù)據(jù)主權(quán)放在核心位置。