1. 项目缘起:当AI需要“眼睛”和“手”
最近在折腾一个挺有意思的项目,核心目标很简单:让我的AI助手,无论是ChatGPT、Claude还是本地部署的大语言模型,能真正“看到”和“操作”我日常使用的那些网页和文档。听起来是不是有点科幻?其实背后的需求非常实在。
想象一下这个场景:你正在研究一个复杂的技术问题,资料散落在几十个浏览器标签页、几个PDF文档和一个在线笔记里。你想让AI帮你总结归纳,或者基于这些资料生成一份报告。传统的做法是,你得手动把所有内容复制粘贴到一个对话框里,不仅繁琐,还经常遇到格式错乱、字数超限、图片丢失的问题。更别提那些需要登录才能访问的付费内容、或者阅读器里做了大量笔记的电子书了,AI对这些内容根本“看不见”。
这就是我启动这个项目的初衷。我不想让AI只是一个在封闭对话盒里空想的“大脑”,我希望它能成为我的“数字副驾”,能直接接入我真实的工作流和信息源。经过一段时间的摸索和开发,我成功为AI接入了三个非常实用的“真实入口”:微信读书(WeRead)的笔记与书架、网页即时标记工具(ima)以及一个通用的网页桥接器(kimi webbridge)。这三个入口分别解决了不同场景下的信息获取难题,让AI的能力边界得到了实质性的扩展。
2. 核心需求拆解:AI需要什么样的“入口”?
在动手之前,我花了些时间梳理,一个理想的、供AI使用的“真实世界入口”应该具备哪些特性。这直接决定了后续的技术选型和架构设计。
2.1 信息获取的完整性与保真度AI处理信息的质量,首先取决于输入信息的质量。一个合格的入口必须能尽可能原汁原味地获取目标内容。这不仅仅是文本,还包括:
- 结构化信息:文章的标题、作者、发布时间、章节层级。
- 非文本内容:图片的
alt描述、表格数据、代码块的语言类型和高亮。 - 上下文信息:该内容所在的网站域名、页面URL、以及用户与该内容的交互状态(例如,在阅读器中是否划了线、写了笔记)。
简单粗暴的“复制-粘贴”或整个页面的innerText抓取,会丢失大量语义和结构,导致AI的理解出现偏差。因此,入口需要具备一定的“理解”能力,能解析页面的DOM结构,提取出有意义的语义块。
2.2 操作的便捷性与自动化入口不应该成为新的负担。理想情况是“一键触发”或“自动同步”。用户不应该为了喂数据给AI,而执行一系列复杂的操作。它需要:
- 低摩擦集成:最好以浏览器扩展、书签工具(Bookmarklet)或系统级服务的形式存在,与现有工作流无缝结合。
- 上下文感知:能自动识别用户当前正在浏览或聚焦的内容,减少手动选择的范围。
- 批处理能力:能处理一个书签文件夹里的所有链接,或一个书架上的所有书籍,而不是一次一个。
2.3 对权限和隐私的尊重这是红线。很多有价值的内容位于登录墙后,或者属于用户的私人数据(如读书笔记)。入口必须:
- 遵循官方途径:优先使用公开API或合法的数据导出方式。对于没有开放API的服务,需要极其谨慎地评估其
robots.txt和服务条款。 - 本地化处理:所有敏感操作(如认证、数据抓取、格式化)应尽可能在用户本地环境(浏览器或本地脚本)中完成,避免数据经过不可信的第三方服务器。
- 用户明确授权:任何涉及读取用户私人数据的操作,都必须有清晰、明确的用户授权步骤,不能静默进行。
2.4 输出格式的标准化从不同入口获取的信息,最终需要汇聚成一份AI能高效处理的“提示词(Prompt)”。因此,需要一个统一的、信息丰富的输出格式。我采用了类似Markdown但增强版的格式:
# 文档标题 **来源**:[网站名称] (URL) **获取时间**:2023-10-27 15:30:00 **摘要**:(可选,可由入口工具自动生成或用户添加) ## 正文内容 ...(保留标题、列表、代码块、表格等Markdown语法)  ## 用户交互数据(如适用) - **高亮段落**:“这里是用户划线的句子...” - **笔记**:“用户在此处的想法:...” - **标签**:#概念 #重要 #待核实这种格式既保持了可读性,又将元数据、正文和用户注解清晰地分隔开,极大提升了AI回复的上下文相关性和准确性。
基于以上四个原则,我开始了三个具体入口的实现。
3. 入口一:微信读书(WeRead)笔记与书架同步器
微信读书是我的主要电子书阅读平台,积累了大量的划线笔记和想法。让AI能基于我读过的书和写过的笔记来对话,一直是我的刚需。
3.1 挑战与官方途径的局限微信读书没有开放完整的公共API供第三方读取笔记和书架。早期尝试过一些逆向工程的方法,但不仅不稳定,更有封号风险,完全违背了“尊重隐私与权限”的原则。正当我苦恼时,发现微信读书提供了笔记导出功能,可以将单本书的笔记以Markdown或文本格式导出。这是一个合法的、用户主动触发的数据出口。
3.2 实现方案:浏览器扩展 + 本地服务我的思路是:不强行从微信读书“偷”数据,而是辅助用户更方便地使用官方导出功能,并自动整理导出的数据。
开发一个专用的浏览器扩展:这个扩展只做两件事:
- 在用户打开微信读书网页版(https://weread.qq.com)时,在书籍页面上添加一个“导出本书笔记至AI”的按钮。
- 当用户点击按钮时,扩展程序自动触发页面上的“导出笔记”功能(模拟点击),并监听下载事件。
构建一个本地HTTP服务(kimi webbridge的一部分):这个服务运行在用户的电脑上(例如
localhost:3000)。- 浏览器扩展将下载的笔记文件(Markdown格式)发送到这个本地服务。
- 本地服务对笔记文件进行解析和增强处理:
- 提取书籍元数据(书名、作者)。
- 将用户笔记与对应的原文段落进行关联(微信读书导出的Markdown已经做得不错)。
- 将处理后的数据存储到本地的向量数据库(例如ChromaDB或LanceDB)中,并为每一段笔记和原文生成向量嵌入(Embedding)。
工作流:
- 用户像往常一样在微信读书网页版阅读、划线、写想法。
- 读完一本书或想更新AI的知识库时,打开该书页面,点击扩展按钮。
- 几秒后,这本书的所有笔记和上下文就已进入本地向量数据库。
- 当用户向AI提问时,AI系统会先从这个本地数据库中进行语义搜索,找到与问题最相关的读书笔记片段,然后将这些片段作为上下文插入到提示词中,再请求大模型生成答案。
3.3 实操心得与避坑指南
- 不要模拟登录:浏览器扩展不应存储或处理微信读书的登录态。用户需要自己登录网页版。扩展只操作当前已登录的页面DOM,这是安全边界。
- 处理网络延迟:触发导出后,下载文件有一定延迟。扩展需要用
chrome.downloads.onChanged等API来监听下载完成事件,不能假设立即完成。 - 笔记去重:同一本书多次导出会产生重复数据。本地服务在存入向量数据库前,需要根据“书籍ID+章节+笔记内容哈希”进行去重判断。
- 隐私是核心卖点:在向用户介绍这个工具时,必须强调“所有数据仅在您自己的浏览器和电脑上处理,不会上传到任何第三方服务器”。这是获得用户信任的关键。
4. 入口二:网页即时标记工具(ima)
对于日常浏览网页时遇到的零散信息,我需要一个更轻量、更快速的工具,能够随时随地对网页上的任何片段进行“标记”并送给AI处理。这就是ima(Instant Mark & Ask)工具的由来。
4.1 工具定位:网页上的“荧光笔和便签”ima被设计成一个浏览器书签工具(Bookmarklet)。你只需要将它拖到书签栏,在任何网页上,选中一段文字,点击这个书签,就会弹出一个简洁的对话框。对话框里已经自动填入了你选中的文本、当前页面标题和URL。你可以:
- 直接点击“发送到AI”,这段文本会连同上下文信息被发送到你配置的AI对话端点(如OpenAI API、Ollama本地服务)。
- 或者,先在对话框里补充你的问题或指令(例如,“请用中文总结一下这段内容的核心观点”),再发送。
4.2 技术实现:纯前端的优雅方案Bookmarklet的本质是一段JavaScript代码,以javascript:开头。它的优势是无需安装扩展,跨浏览器兼容性好。ima的核心代码如下(简化版):
javascript:(function(){ // 获取用户选中的文本 const selectedText = window.getSelection().toString().trim(); if (!selectedText) { alert('请先选择一些文本'); return; } // 获取页面信息 const pageTitle = document.title; const pageUrl = window.location.href; // 创建一个模态对话框 const modal = document.createElement('div'); modal.style = 'position:fixed; top:20%; left:20%; width:60%; background:#fff; z-index:99999; padding:20px; border-radius:8px; box-shadow:0 5px 30px rgba(0,0,0,0.3);'; modal.innerHTML = ` <h3>发送到 AI 助手</h3> <p><strong>来源:</strong>${pageTitle}</p> <p><strong>URL:</strong><a href="${pageUrl}" target="_blank">${pageUrl}</a></p> <textarea id="aiContext" style="width:100%; height:100px; margin:10px 0;">${selectedText}</textarea> <p>附加指令(可选):</p> <input type="text" id="aiPrompt" style="width:100%; padding:5px;" placeholder="例如:总结、翻译成英文、解释这个术语..."> <div style="text-align:right; margin-top:15px;"> <button id="cancelBtn" style="margin-right:10px;">取消</button> <button id="sendBtn" style="background:#10a37f; color:white; border:none; padding:8px 15px; border-radius:4px;">发送</button> </div> `; document.body.appendChild(modal); // 事件处理:发送和取消 document.getElementById('sendBtn').onclick = function() { const context = document.getElementById('aiContext').value; const prompt = document.getElementById('aiPrompt').value; const finalPrompt = prompt ? `${prompt}:\n\n${context}` : `请处理以下信息:\n\n${context}`; // 这里是关键:调用本地WebBridge服务 fetch('http://localhost:3000/api/process', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: finalPrompt, source: pageTitle, url: pageUrl }) }) .then(response => response.json()) .then(data => { // 处理AI返回的结果,例如显示在另一个浮动窗口 console.log('AI回复:', data.reply); alert(`已发送!AI回复长度:${data.reply.length}字符`); }) .catch(err => { console.error('发送失败:', err); alert('发送失败,请检查本地服务是否运行。'); }); document.body.removeChild(modal); }; document.getElementById('cancelBtn').onclick = function() { document.body.removeChild(modal); }; })()这段代码完全在浏览器端执行,获取选中文本和页面信息,并通过一个fetch请求将数据发送到localhost上的本地服务。这意味着你的数据在到达你自己的AI服务之前,不会离开你的机器。
4.3 为何选择Bookmarklet而非扩展?对于这样一个轻量级、高频使用的工具,Bookmarklet有几个优势:
- 零安装:用户只需拖拽一次,无需去扩展商店、通过审核。
- 无权限担忧:它不像扩展那样需要声明
activeTab、storage等权限,用户心理负担小。 - 即时更新:我更新服务器上的Bookmarklet脚本代码,所有用户下次点击时自动生效,无需他们手动更新扩展。
- 当然,它也有缺点:无法后台运行,无法进行更复杂的DOM操作(但对我们这个场景足够了)。
5. 入口三:通用网页桥接器(kimi webbridge)
ima解决了片段抓取的问题,但有时我需要将整个网页或一个复杂应用页面的状态完整地送给AI分析。这就需要功能更强大的kimi webbridge。它不是一个简单的工具,而是一个小型的本地代理服务器/API网关。
5.1 核心功能:网页的“无损转译器”kimi webbridge运行在本地(如localhost:3000),提供一系列HTTP端点,主要完成两类任务:
- 智能网页内容提取:给定一个URL,它能返回一个结构清晰、包含主要内容的Markdown格式文本,而不是杂乱的HTML。
- 作为AI助手的统一接入点:接收来自
ima、浏览器扩展或其他工具的请求,转发给配置好的AI服务(OpenAI, Anthropic, 本地LLM等),并返回结果。
5.2 实现细节:内容提取的挑战与应对整个项目中最复杂的部分就是“智能网页内容提取”。直接下载HTML然后用BeautifulSoup或Readability这样的库解析,对于现代动态网页(React, Vue.js构建)和反爬虫策略(如Cloudflare)往往力不从心。
我的方案是采用“无头浏览器优先,静态解析降级”的策略。
主路径:使用Puppeteer(无头Chrome)。
// 伪代码示例 const puppeteer = require('puppeteer'); async function scrapeWithPuppeteer(url) { const browser = await puppeteer.launch({ headless: 'new' }); const page = await browser.newPage(); // 设置视口和User-Agent,模拟真实浏览器 await page.setViewport({ width: 1280, height: 800 }); await page.setUserAgent('Mozilla/5.0 ...'); // 导航到页面,等待网络空闲和主要内容加载 await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 }); // 执行页面内脚本,获取优化后的内容 const content = await page.evaluate(() => { // 尝试移除广告、侧边栏等噪音 document.querySelectorAll('nav, aside, footer, .ad-container').forEach(el => el.remove()); // 使用Readability-lib或自定义逻辑提取核心内容 return document.body.innerText; // 简化版,实际更复杂 }); await browser.close(); return content; }无头浏览器的好处是能完美执行JavaScript,看到和用户浏览器一模一样的内容。缺点是资源消耗大、速度慢。
降级路径:对已知友好网站使用静态解析。 对于一些结构简单、静态的网站(如文档站、某些博客),可以配置一个白名单。当请求这些网站的URL时,直接使用
axios获取HTML,然后用cheerio进行快速解析,提取<article>、<main>标签或特定选择器下的内容。这比启动无头浏览器快一个数量级。缓存层:对提取的内容进行哈希缓存(例如用Redis或本地文件),在TTL(生存时间)内,相同的URL请求直接返回缓存结果,极大提升响应速度并减少对目标网站的压力。
5.3 与AI服务的集成kimi webbridge的另一核心功能是路由AI请求。它的配置文件可能长这样:
ai_backends: openai: api_key: ${env:OPENAI_API_KEY} model: gpt-4-turbo-preview endpoint: https://api.openai.com/v1/chat/completions claude: api_key: ${env:ANTHROPIC_API_KEY} model: claude-3-opus-20240229 endpoint: https://api.anthropic.com/v1/messages ollama_local: model: llama2:13b endpoint: http://localhost:11434/api/generate当收到一个处理请求时,桥接器可以根据请求头、参数或用户配置,决定将提示词发送给哪个后端,并将统一格式的响应返回给调用者。这样,无论是ima、WeRead扩展还是其他未来开发的工具,都只需要和桥接器对话,无需关心后端AI的具体实现。
6. 系统整合与工作流示例
三个入口并非孤岛,它们通过本地的kimi webbridge服务连接在一起,并与我的AI主力应用(一个自定义的ChatGPT-like WebUI)协同工作。
6.1 典型工作流:从信息收集到AI问答
- 日常浏览:我在网上看到一篇关于“RAG模型优化”的长文。我用
ima工具高亮了几段关键定义和实验数据,并附加指令“保存这些关键点到知识库”。ima将这些片段发送到桥接器,桥接器将其存储到向量数据库。 - 深度阅读:我在微信读书上读完《机器学习系统设计》一书,并做了大量笔记。通过浏览器扩展,我将整本书的笔记导出并同步到本地向量数据库。
- 问题求解:几天后,我在设计自己的RAG系统时遇到了瓶颈。我打开AI聊天界面,直接提问:“在构建RAG系统时,如何根据查询动态选择最相关的文档片段?有哪些实用的策略?”
- 幕后过程:我的AI应用在收到问题后,首先将问题转换为向量,并在本地的向量数据库中搜索与之最相关的片段。搜索结果是:我之前用
ima保存的几段网络文章摘要,以及《机器学习系统设计》中关于“检索器-阅读器架构”和“重排序”的笔记。这些片段被作为“上下文”插入到最终发送给大语言模型(如GPT-4)的提示词中。 - 获得答案:大模型基于我提供的、来自真实阅读记录的精准上下文,生成一个非常具体、有引用来源的高质量回答。这个回答不再是模型凭空想象的,而是根植于我自己的知识储备。
6.2 配置与部署要点整个系统运行在我的个人开发机上,部署相对简单:
kimi webbridge:一个Node.js服务,使用PM2守护进程。- 向量数据库:使用
ChromaDB的本地嵌入模式,数据存储在本地目录。 - AI WebUI:另一个Node.js或Python服务,集成了聊天前端和检索增强生成(RAG)逻辑。
- 浏览器扩展和
ima书签工具:静态文件,配置中指向localhost:3000。
所有组件都通过本地网络(localhost)通信,敏感信息如API密钥通过环境变量管理,确保了数据的私密性。
7. 反思、局限与未来方向
这个项目极大地提升了我和AI协作的深度和效率,但它远非完美。
7.1 当前方案的局限性
- 覆盖范围有限:目前只深度集成了微信读书。对于其他阅读平台(如Kindle、得到)、笔记软件(Notion、Obsidian)或云文档(Google Docs、语雀),还需要开发单独的连接器。每个平台都有其独特的API和数据模型,这是一场持久战。
- 实时性挑战:目前的同步多是手动触发或基于页面的。理想状态是“无感同步”,例如微信读书上每添加一条笔记,后台能自动增量更新。但这需要更复杂的监听机制,可能涉及浏览器扩展的后台脚本(Service Worker)长期运行,资源消耗和稳定性需要权衡。
- 内容理解仍处表层:目前主要是文本提取和向量化。对于网页中的交互式图表、视频内容、复杂表格数据的理解,还无能为力。这需要结合多模态模型和更高级的解析技术。
- 对动态内容的无力:
kimi webbridge虽然用了无头浏览器,但对于那些需要复杂交互(如点击“加载更多”、登录后滚动)才能获取全部内容的页面,提取逻辑会变得非常复杂和脆弱。
7.2 值得尝试的改进方向
- 标准化连接器协议:设计一个通用的“信息源连接器”接口规范。任何符合该规范的脚本或服务,都可以将其数据导入系统。这样社区可以贡献针对不同平台(如豆瓣书评、Twitter线程、Youtube字幕)的连接器。
- 引入智能摘要与标签化:在内容存入向量数据库前,先用一个轻量级模型(如
gpt-3.5-turbo)对长文档生成摘要和关键词标签。这不仅能减少存储的向量数量,还能让检索更精准。 - 探索边缘AI:将一部分处理逻辑(如文本清洗、基础向量化)放在浏览器扩展内完成,减少对本地服务的依赖,提升响应速度,并进一步强化“数据不离线”的隐私特性。
这个项目让我深刻体会到,让AI真正变得有用,往往不在于模型本身有多强大,而在于如何为它搭建通向真实世界数据的桥梁。这三个入口——针对深度阅读的WeRead同步器、针对碎片信息的即时标记工具ima、以及作为中枢的通用网页桥接器——共同构成了一套虽不完美但切实可用的解决方案。它不再让AI困在对话的孤岛里,而是让它能够翻阅我的电子书,浏览我标记过的网页,基于我真实的认知积累来思考和回答。这个过程本身,也是对我自身信息管理方式的一次重构。