开篇:我发现自己用 AI 的方式有问题

2026 年初,我做了一个统计:在一个普通的工作日里,我打开 ChatGPT/Claude/Cursor 的次数超过 50 次。

有些使用是合理的——调试一段难缠的代码、快速生成一个正则、解释一个我不熟悉的 API。但更多的使用属于"肌肉记忆":

  • 写 SQL 之前先问 AI(其实我自己想 10 秒就能写出来)
  • 报错了直接复制粘贴给 AI(其实看一眼错误信息就能解决)
  • 写 commit message 也让 AI 生成(这个真的不需要)

最让我警醒的是:我开始在"思考"之前先问 AI 了。不是先想清楚问题再求助 AI,而是直接把问题丢出去,让它替我想。

这个问题不是 AI 工具的错。它是我自己的使用习惯出了问题。

所以我决定做一个 Chrome 扩展——不是为了完全阻止我用 AI,而是让我在每次使用 AI 之前停一下,问自己三个问题:

  1. 我真的需要 AI 来完成这个任务吗?
  2. 如果自己先试试,我能解决吗?
  3. 如果求助 AI,我应该怎么描述问题才能学得最多?

这篇文章就是做这个扩展的全过程。


一、设计思路

1.1 核心原则

我设计这个扩展的原则只有三条:

  1. 不封堵、不禁止——AI 工具本身没错,错的是无意识使用
  2. 最小干预——每次使用 AI 之前弹出一个小提示,1 秒看完
  3. 可自定义——每个人使用 AI 的方式不同,规则应该可调

1.2 扩展的逻辑

用户打开 ChatGPT / Claude / Cursor
         ↓
扩展检测到 AI 工具的页面
         ↓
检查是否在"免打扰名单"中
     ├── 是 → 放行
     └── 否 → 检查这个域名的使用次数
         ├── 今天首次 → 跳过(不打扰)
         ├── 第 N 次 → 弹出"意图检查"提示
         └── 超过每日上限 → 弹出更强烈的提醒

二、Chrome 扩展基础结构

ai-intentional/
├── manifest.json          # 扩展配置
├── background.js          # 后台脚本 (Service Worker)
├── content.js             # 内容脚本 (注入到 AI 页面)
├── popup.html             # 弹窗 UI
├── popup.js               # 弹窗逻辑
├── options.html           # 设置页面
├── options.js             # 设置逻辑
└── icons/
    ├── icon16.png
    ├── icon48.png
    └── icon128.png

2.1 manifest.json

{
  "manifest_version": 3,
  "name": "Intentional AI",
  "version": "1.0.0",
  "description": "在每次使用 AI 工具之前,提醒你思考:我真的需要 AI 吗?",
  "permissions": [
    "storage",
    "tabs",
    "alarms"
  ],
  "host_permissions": [
    "https://chatgpt.com/*",
    "https://claude.ai/*",
    "https://chat.openai.com/*",
    "https://cursor.sh/*",
    "https://gemini.google.com/*",
    "https://www.perplexity.ai/*"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [
    {
      "matches": [
        "https://chatgpt.com/*",
        "https://claude.ai/*",
        "https://chat.openai.com/*",
        "https://gemini.google.com/*",
        "https://www.perplexity.ai/*"
      ],
      "js": ["content.js"],
      "run_at": "document_end"
    }
  ],
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "icons/icon16.png",
      "48": "icons/icon48.png",
      "128": "icons/icon128.png"
    }
  },
  "options_page": "options.html"
}

三、核心实现

3.1 后台统计:追踪 AI 使用量

// background.js
// 
// 追踪每日 AI 工具使用次数,用于触发意图检查

const AI_DOMAINS = {
  'chatgpt.com': 'ChatGPT',
  'chat.openai.com': 'ChatGPT',
  'claude.ai': 'Claude',
  'cursor.sh': 'Cursor',
  'gemini.google.com': 'Gemini',
  'perplexity.ai': 'Perplexity',
};

const STORAGE_KEY = 'ai_usage';

// 每次访问 AI 页面时,更新使用计数
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
  if (changeInfo.status !== 'complete' || !tab.url) return;

  const domain = getDomain(tab.url);
  if (!domain || !AI_DOMAINS[domain]) return;

  await incrementUsage(domain, AI_DOMAINS[domain]);
});

function getDomain(url) {
  try {
    return new URL(url).hostname.replace('www.', '');
  } catch {
    return null;
  }
}

async function incrementUsage(domain, name) {
  const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
  const storage = await chrome.storage.local.get(STORAGE_KEY);
  const usage = storage[STORAGE_KEY] || {};

  if (!usage[today]) {
    usage[today] = {};
  }

  if (!usage[today][domain]) {
    usage[today][domain] = { count: 0, name };
  }

  usage[today][domain].count += 1;

  await chrome.storage.local.set({ [STORAGE_KEY]: usage });
}

// 获取今日用量
async function getTodayUsage() {
  const today = new Date().toISOString().split('T')[0];
  const storage = await chrome.storage.local.get(STORAGE_KEY);
  const usage = storage[STORAGE_KEY] || {};
  return usage[today] || {};
}

// 消息处理
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.type === 'getUsage') {
    getTodayUsage().then(sendResponse);
    return true; // 保持通道开放
  }

  if (request.type === 'checkAndNotify') {
    shouldShowIntentPrompt(request.domain).then(sendResponse);
    return true;
  }
});

3.2 意图检查弹窗

// content.js
// 
// 在 AI 页面注入意图检查弹窗

const PROMPT_MESSAGES = [
  {
    threshold: 5,  // 今天第 5 次打开 AI
    title: "🧠 慢下来",
    message: "这是你今天第 {count} 次使用 AI。\n\n问自己:我试过自己解决了吗?",
    dismissText: "想好了,继续"
  },
  {
    threshold: 15,
    title: "⚡ 检查你的意图",
    message: "你已经使用了 {count} 次 AI。是不是有些问题可以自己先试试?",
    dismissText: "继续,但这个真的需要"
  },
  {
    threshold: 30,
    title: "🔋 充电提醒",
    message: "你今天已经用了 {count} 次 AI。\n\n停下来休息一下可能比继续用 AI 更有效。\n\n喝完水再回来。",
    dismissText: "好的,先休息",
    showAfter: 5000  // 展示 5 秒才能关闭
  },
];

async function init() {
  const domain = window.location.hostname;

  // 检查是否应该提示
  const response = await chrome.runtime.sendMessage({
    type: 'checkAndNotify',
    domain
  });

  if (!response || !response.shouldPrompt) return;

  const count = response.count;

  // 找到当前次数对应的提示
  const promptConfig = PROMPT_MESSAGES
    .filter(p => count >= p.threshold)
    .pop();

  if (!promptConfig) return;

  showIntentPrompt(promptConfig, count);
}

function showIntentPrompt(config, count) {
  // 创建遮罩层
  const overlay = document.createElement('div');
  overlay.style.cssText = `
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    background: rgba(0,0,0,0.5);
    z-index: 2147483647;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: -apple-system, system-ui, sans-serif;
  `;

  // 创建弹窗卡片
  const card = document.createElement('div');
  card.style.cssText = `
    background: white;
    border-radius: 16px;
    padding: 32px;
    max-width: 420px;
    width: 90%;
    box-shadow: 0 20px 60px rgba(0,0,0,0.3);
    text-align: center;
  `;

  const canDismiss = !config.showAfter;

  card.innerHTML = `
    <div style="font-size: 48px; margin-bottom: 16px;">${config.title.split(' ')[0]}</div>
    <h2 style="margin: 0 0 12px; color: #1a1a1a;">${config.title}</h2>
    <p style="color: #555; line-height: 1.6; margin: 0 0 24px; white-space: pre-line;">
      ${config.message.replace('{count}', count)}
    </p>
    <button id="intentional-dismiss"
      style="
        background: #333; color: white; border: none;
        padding: 12px 24px; border-radius: 8px;
        font-size: 15px; cursor: pointer;
        ${canDismiss ? '' : 'opacity: 0.5; pointer-events: none;'}
      ">
      ${config.dismissText}
      ${config.showAfter ? ` (${config.showAfter / 1000}s)` : ''}
    </button>
  `;

  overlay.appendChild(card);
  document.body.appendChild(overlay);

  // 如果没有设置延迟,直接可以关闭
  if (!config.showAfter) {
    document.getElementById('intentional-dismiss').onclick = () => {
      overlay.remove();
      saveDismissed();  // 记录这次提示
    };
  } else {
    // 延迟后可关闭
    setTimeout(() => {
      const btn = document.getElementById('intentional-dismiss');
      if (btn) {
        btn.style.opacity = '1';
        btn.style.pointerEvents = 'auto';
        btn.textContent = config.dismissText;
        btn.onclick = () => {
          overlay.remove();
          saveDismissed();
        };
      }
    }, config.showAfter);
  }
}

function saveDismissed() {
  // 记录提示已出示,避免过于频繁
  chrome.storage.local.set({ lastPrompt: Date.now() });
}

// 页面加载后执行
init();

3.3 后台检查逻辑

// background.js — checkAndNotify handler(接之前的部分)

async function shouldShowIntentPrompt(domain) {
  const usage = await getTodayUsage();
  const domainUsage = usage[domain];

  if (!domainUsage) return { shouldPrompt: false };

  const count = domainUsage.count;

  // 检查上次提示是否太近(至少间隔 3 次使用)
  const storage = await chrome.storage.local.get('lastPrompt');
  const lastPrompt = storage.lastPrompt || 0;

  // 如果上次提示在 5 分钟内,跳过
  if (Date.now() - lastPrompt < 5 * 60 * 1000) {
    return { shouldPrompt: false, count };
  }

  // 只在特定阈值触发
  const thresholds = [5, 10, 15, 20, 25, 30, 40, 50];
  const shouldPrompt = thresholds.includes(count);

  return { shouldPrompt, count };
}

四、设置页面

用户可以通过设置页自定义规则:

// options.js

document.addEventListener('DOMContentLoaded', loadSettings);
document.getElementById('save').addEventListener('click', saveSettings);

async function loadSettings() {
  const storage = await chrome.storage.local.get('settings');
  const settings = storage.settings || getDefaultSettings();

  document.getElementById('threshold-step').value = settings.thresholdStep || 5;
  document.getElementById('min-interval').value = settings.minIntervalMinutes || 3;
  document.getElementById('daily-limit').value = settings.dailyLimit || 0;
  document.getElementById('show-weekly-report').checked = settings.showWeeklyReport || false;

  // 加载免打扰域名列表
  const whitelist = document.getElementById('whitelist');
  (settings.whitelist || []).forEach(domain => {
    addWhitelistItem(domain);
  });
}

function getDefaultSettings() {
  return {
    thresholdStep: 5,       // 每 5 次提示一次
    minIntervalMinutes: 3,  // 最小提示间隔
    dailyLimit: 0,          // 每日上限(0=不限)
    showWeeklyReport: true, // 每周报告
    whitelist: [],
  };
}

async function saveSettings() {
  const settings = {
    thresholdStep: parseInt(document.getElementById('threshold-step').value) || 5,
    minIntervalMinutes: parseInt(document.getElementById('min-interval').value) || 3,
    dailyLimit: parseInt(document.getElementById('daily-limit').value) || 0,
    showWeeklyReport: document.getElementById('show-weekly-report').checked,
    whitelist: getWhitelist(),
  };

  await chrome.storage.local.set({ settings });

  // 保存确认
  const btn = document.getElementById('save');
  const original = btn.textContent;
  btn.textContent = '✓ 已保存';
  setTimeout(() => { btn.textContent = original; }, 2000);
}
<!-- options.html -->
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Intentional AI - 设置</title>
  <style>
    body { 
      width: 500px; padding: 24px; font-family: system-ui, sans-serif;
    }
    label { display: block; margin: 16px 0 4px; font-weight: 500; }
    input[type="number"] { width: 80px; padding: 6px; }
    input[type="checkbox"] { margin-right: 8px; }
    .section { margin: 24px 0; padding: 16px; background: #f5f5f5; border-radius: 8px; }
    .whitelist-item { display: flex; align-items: center; margin: 4px 0; }
    .whitelist-item button { margin-left: 8px; }
  </style>
</head>
<body>
  <h1>⚡ Intentional AI</h1>
  <p>让每一次 AI 使用都更有意识</p>

  <div class="section">
    <h3>提示频率</h3>
    <label>每使用 <input type="number" id="threshold-step" min="1" max="50"> 次提示一次</label>
    <label>提示最小间隔 <input type="number" id="min-interval" min="1" max="60"> 分钟</label>
    <label>每日 AI 上限:<input type="number" id="daily-limit" min="0" max="200"> 次(0=不限)</label>
  </div>

  <div class="section">
    <h3>统计</h3>
    <label><input type="checkbox" id="show-weekly-report"> 每周五发送 AI 使用报告</label>
  </div>

  <div class="section">
    <h3>免打扰列表</h3>
    <p style="color: #666; font-size: 13px;">这些域名不会显示提示</p>
    <div id="whitelist-container"></div>
    <div>
      <input type="text" id="new-domain" placeholder="example.com" style="width: 200px;">
      <button id="add-domain">新增</button>
    </div>
  </div>

  <button id="save" style="margin-top: 16px; padding: 10px 24px; background: #333; color: white; border: none; border-radius: 8px; cursor: pointer;">
    保存设置
  </button>

  <script src="options.js"></script>
</body>
</html>

五、每周报告

一周结束的周五下午 5 点,扩展会发送一份"AI 使用报告":

// background.js — weekly report (接之前)

// 每周五下午 5 点发送报告
chrome.alarms.create('weeklyReport', {
  periodInMinutes: 7 * 24 * 60,
  delayInMinutes: getDelayToNextFriday5PM()
});

chrome.alarms.onAlarm.addListener(async (alarm) => {
  if (alarm.name === 'weeklyReport') {
    await sendWeeklyReport();
  }
});

function getDelayToNextFriday5PM() {
  const now = new Date();
  const dayOfWeek = now.getDay(); // 0=Sun, 5=Fri
  const targetHour = 17; // 5 PM

  let daysUntilFriday = (5 - dayOfWeek + 7) % 7;
  if (daysUntilFriday === 0 && now.getHours() >= targetHour) {
    daysUntilFriday = 7;
  }

  const target = new Date(now);
  target.setDate(target.getDate() + daysUntilFriday);
  target.setHours(targetHour, 0, 0, 0);

  return (target - now) / 60000; // 转分钟
}

async function sendWeeklyReport() {
  const storage = await chrome.storage.local.get(STORAGE_KEY);
  const usage = storage[STORAGE_KEY] || {};

  // 计算本周数据
  const weekData = calculateWeeklyUsage(usage);

  // 构建报告
  const report = `
=== 🤖 Intentional AI 周报 ===
时间: ${weekData.startDate} ~ ${weekData.endDate}

本周 AI 使用总量: ${weekData.totalUses}
日均: ${weekData.dailyAverage}
对比上周: ${weekData.trendText}

按工具分布:
${weekData.breakdown.join('\n')}

每日趋势:
${weekData.dailyTrend.join('\n')}

建议: ${weekData.suggestion}

--- 
这个工具帮助你在使用 AI 时更有意识。
不是少用,是用得更好。
  `.trim();

  console.log(report);
  // 也可以发送通知
  chrome.notifications.create({
    type: 'basic',
    iconUrl: 'icons/icon48.png',
    title: 'Intentional AI 周报',
    message: `本周使用了 ${weekData.totalUses} 次 AI。${weekData.suggestion}`,
  });
}

function calculateWeeklyUsage(usage) {
  // 获取本周的日期
  const today = new Date();
  const startOfWeek = new Date(today);
  startOfWeek.setDate(today.getDate() - today.getDay() - 6);

  const dates = Object.keys(usage).sort();
  const weekDates = dates.filter(d => d >= startOfWeek.toISOString().split('T')[0]);

  // 计算总计
  let totalUses = 0;
  const perDay = [];
  const breakdown = {};

  weekDates.forEach(date => {
    const dayData = usage[date];
    let dayTotal = 0;

    Object.entries(dayData).forEach(([domain, data]) => {
      dayTotal += data.count;
      if (!breakdown[data.name]) breakdown[data.name] = 0;
      breakdown[data.name] += data.count;
    });

    perDay.push({ date, count: dayTotal });
    totalUses += dayTotal;
  });

  const dailyAverage = perDay.length > 0 
    ? (totalUses / perDay.length).toFixed(1) 
    : 0;

  let suggestion = '';
  if (totalUses > 200) {
    suggestion = '本周使用频率较高,建议适当增加独立解决问题的环节。';
  } else if (totalUses > 100) {
    suggestion = '使用频率适中。继续保持有意识的 AI 使用习惯。';
  } else {
    suggestion = '使用频率健康。你在使用 AI 的同时保持了独立思考。';
  }

  return {
    totalUses,
    dailyAverage,
    trendText: '待计算',
    breakdown: Object.entries(breakdown)
      .sort((a, b) => b[1] - a[1])
      .map(([name, count]) => `  - ${name}: ${count} 次`),
    dailyTrend: perDay.map(d => `  - ${d.date}: ${d.count} 次`),
    suggestion,
    startDate: weekDates[0] || '',
    endDate: weekDates[weekDates.length - 1] || '',
  };
}

六、我的个人数据

我自己用了这个扩展一个月,数据如下:

第一周: 307  (日均 44)
第二周: 271  (日均 39)   12%
第三周: 218  (日均 31)   20%
第四周: 195  (日均 28)   10%

四周变化: 307  195,减少了 36%

更重要的不是次数降低,而是质量变化

  • 前两周:"让我问一下 AI……"是默认行为
  • 后两周:"这个我自己试试"先出现,失败再求助 AI

最意外的收获:我写代码的速度没有因为少用 AI 而变慢。反而因为更少的上下文切换,进入 flow state 更快了。


七、我的观点:AI 工具的使用应该有意识

写这个扩展的时候,我想清楚了一件事:

AI 工具本身没有好坏,有坏的是无意识的使用习惯。

这和"社交媒体有害"的讨论结构一样——不是社交媒体的错,是它被设计来最大化你的使用时长,而你毫无防备地接受了。

AI 助手也在做类似的事:
- 对话式的界面鼓励你不断提问
- 即时回答让你习惯了"一秒反馈"
- 高质量的回答让你放弃了独立思考

我不是在说"不要用 AI"——恰恰相反,我在认真用它。但我觉得越重要的工具,越不应该无意识地使用。

这个扩展很小,代码不过 300 行。但它的设计理念值得思考:工具应该是帮助我们更好的工具,而不是我们习惯的默认选项。 一个简单的提示框就能改变使用习惯,说明问题不在技术,在于意识。


结尾

这个扩展的代码不到 300 行,完整版本(含设置面板和周报功能)也在 600 行以内。

但它的效果比我预期的好——不是因为代码写得多好,是因为它解决的不是技术问题,而是使用习惯问题。

如果你想试,可以自己用这 300 行代码跑起来。如果你不想试,也请你思考一个问题:你今天用 AI 的每一次,你都想清楚自己为什么用了吗?


文章由文字工作者编写。Chrome 扩展代码基于 Manifest V3 标准。使用数据来自个人实践,仅供参考。