WheatField
WheatField

用 cursor 30 分钟写一个一键网页总结插件

September 18, 20241891 words, 10 min read
Authors

日常查资料时,时常会遇到一些看起来不错的文章,内容丰满,用词高端,但碍于时间与耐心有限,就希望能有工具一键总结文章内容,然后一目十行,快速了解核心要点。

网上其实有不少这样的插件,比如知名的 elmo chat,再有就是国内的 kimi chat 官方插件。 很多工具都自带电池,可以开箱即用,比如 elmo 的总结功能基于 LeptonAI,kimi chat 则使用了 kimi 自研的模型。

这些插件基本上日常够用,但如果想接入自己的 API,或者使用自定义 prompt,就有点费劲了,笔者是 groqsambanova.ai 的热心用户,日常使用 Llama 3.1 系列的模型比较多,但市面上鲜有插件适配支持第三方 API。

之前笔者也尝试过自己造一个轮子,但鉴于对 chrome 插件的了解有限,一直没有实现。最近赶上 Cursor 爆发,终于有机会再次尝试一下,发现实现起来还是比较简单的,所以花了点时间做了个简单插件: OneSummary,基本功能已经具备,可以作为生产力工具使用了。

功能

插件的功能与特点如下:

  • 一键生成网页摘要,可通过快捷键(e.g., Alt+S)唤醒
  • 支持自定义 API 设置(API URL、密钥、模型、系统 prompt、模型温度)
  • 支持生成结果保存及重新生成摘要
  • 支持一键复制摘要结果
  • 支持侧边栏展示
  • 支持模型配置保存,方便不同模型间进行切换

在实现原型版本时,仅考虑了摘要生成及保存单个 API 配置的功能,借力于 Cursor 强大的生成能力,从零到一构建第一版时仅用了不到 30 分钟。后续笔者又花了点时间,在第一版的基础上,逐步增加了保存配置、复制结果、侧边栏展示等特性。

自定义 API 配置

市场上 LLM API 服务商多如牛毛,很多服务商为了推广自家生态,会搞一套自己的 API 规范,这无可厚非,但重视用户体验的供应商通常会兼容 AI 一哥 OpenAI 的 API 规范,比如 deepseek, groq。但好在模型的输入都比较类似,核心参数无非是 model, messages, temperature 等,所以自定义 API 配置时,只要能通过以下请求格式与 API 服务商通信,就可以直接插件配置。

curl -X POST API_URL \
  -H "Authorization: Bearer API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "MODEL",
    "messages": [{"role": "user", "content": "Hello, world!"}],
    "temperature": TEMPERATURE
  }'

模型配置保存

考虑到额度、频率限制,用户可能会在多个不同的供应商之间来回切换,为避免每次切换都要重新配置 API,因此插件也增加了模型配置保存特性。

配置信息保存在 chrome.storage.local 中,后续会考虑通过 chrome.storage.sync 进行同步,这样在不同设备间切换时,也可以直接使用模型配置。

提到同步,其实笔者刚开始时确实尝试把配置信息通过 chrome.storage.sync 同步,但在保存配置时一直失败,debug 之后发现日志报出 'QUOTA_BYTES_PER_ITEM quota exceeded' 错误,原因是 chrome.storage.sync 接口有同步限制,单个条目最多保存 8K 数据。

本着简单直观的原则,笔者在存储配置信息时,把所有配置信息都保存到一个条目中(如下表所示),而 prompt 的篇幅又比较长,这样轻轻松松就超过了 8K 的限制。不过这个问题也好解决,一个方案是:单独存放 prompt,即把 prompt 以 provider_prompt 的形式分别存放到不同条目中,加载配置信息时,先找出当前 provider(e.g., deepseek),然后再加载 provider 加载对应的 provider_prompt。稍微增加点复杂度,但可以有效避免单个条目数据过大的问题。

providers = [
  {
    "name": "deepseek",
    "api_key": "sk-",
  "api_url": "https://api.deepseek.com/v1/chat/completions",
    "model": "deepseek-chat",
    "prompt": "You are a professional content analyst and summarizer. ...",
    "temperature": 0.5
  },
  {
    "name": "groq",
    "api_key": "sk-",
    "api_url": "https://api.groq.com/openai/v1/chat/completions",
    "model": "llama3-8b-8192",
    "prompt": "You are a professional content analyst and summarizer. ...",
    "temperature": 0.7
  },
  ...
]

侧边栏展示

一开始的版本中,内容以弹窗形式展示,但进行网页切换时,弹窗会消失,体验不是很好。后来笔者参考了 elmo chat 的实现,将内容以侧边栏形式展示,这样在进行网页切换时,侧边栏仍然可以展示,再结合总结结果缓存,体验也好了很多。

Cursor 的强大与局限

Cursor + Sonnect 3.5 的生成能力确实非常强大,作为一个 Chrome 插件开发新手,笔者在开发过程时,配合 Cursor 的自动补全,只用了不到 30 分钟就基本实现了插件的雏形,支持内容总结、基础配置保存。 后续的诸多特性实现,笔者也多是以产品经理的视角,与 Cursor 结对编程,根据需要进行调整。

Cursor 在将简单需求产品化方面确实非常出色,完全可以胜任一些简单的应用场景,比如编写脚本,开发 web 小工具。但就笔者的使用体验来看,Cursor 仍然无法完全平替开发人员,即使是像笔者这样的插件开发新手。开发者具备不仅是功能实现的能力,更多的是自主思考、项目统筹规划及分析总结能力。

在面对复杂问题时,特别是代码 debug 或者在复杂项目中添加、优化功能时,Cursor 就有些捉襟见肘。笔者在日常开发中时常遇到的一个问题是,当项目代码量达到一定程度时,Cursor 会非常依赖于已有代码的风格、技术方案及偏好,然后根据上下文,生成极其类似的代码,但实际运行时,经常跑不通。更多上下文给 LLM 提供了更多的参考信息,但同时也约束了模型的自由度。这是当前诸多 LLM 工具的通病,Cursor 背后的 Sonnet 也不例外。

对于稍微棘手的 bug,Cursor 经常对着几个不成熟的方案来来回回切换着尝试,但没有一个能实质性解决问题。更有甚者,Cursor 有时也会顾此失彼,在实现时需求引入额外的 bug。举个例子,笔者在实现模型配置保存特性时,给 Cursor 提示了网页结构(sidebar.html) 的代码,然后让 Cursor 补齐交互逻辑( sidebar.js),但实操时, Cursor 在逻辑层改写了网页部分元素的 id,但没有考虑到对网页结构的影响,导致已经实现的摘要总结功能也失效。笔者尝试把错误信息提交给 Cursor 参考,但生成的代码还是一样的问题。多次尝试无果后,笔者还是自己手动修复了代码。

小结

随着的 LLM 的更新迭代及应用框架的丰富,Cursor 这类工具会越来越强大,但目前来看,这类工具更适合用来做原型设计,以及快速实现简单的需求。面对稍微复杂一点的问题,还是需要开发人员有一定的自主思考能力,以及动手实践能力,这样才能从本质上解决问题。