在CPU上运行7B模型的AI浏览器代理:LocalAgentBrowser实战经验

开源项目LocalAgentBrowser在无GPU的i5上让7B模型自主完成研究写作任务,并总结出六条小模型代理开发经验。
LocalAgentBrowser 是一个单文件 Python 浏览器代理,能在仅 Intel i5-9500 的消费级 CPU 上运行 Qwen2.5-7B-Instruct,自主完成搜索、阅读到撰写答案的全流程,四轮对话约十二分钟即可完成一次非洲最高峰研究任务,除搜索请求外所有计算和数据均留在本机。作者经过 30 个版本迭代,总结出核心经验:把可检查规则写进代码而非依赖提示词;利用 LM Studio 的提示词缓存机制追加对话而非重建,使同页轮次从 150-220 秒降至 35-120 秒;用进度检查、目标检查和离开前确认等外部机制帮助小模型判断何时完成;要求模型逐部分展示证据覆盖而非回答是或否;把写作作为独立模型调用,只传入目标与编号发现列表;并尽早用多种任务类型测试以避免提示词过拟合。
在消费级CPU上运行7B参数模型,驱动一个能自主完成研究和写作任务的浏览器代理——这听起来像是需要云端GPU集群才能做到的事。但开源项目LocalAgentBrowser证明,经过30个版本的迭代打磨,一台Intel i5-9500就能让Qwen2.5-7B-Instruct完成从搜索、阅读到撰写答案的完整流程。

该项目作者记录了整个开发过程,每次修改都在真实运行中测试和测量。最终成果是:一个四轮对话、约十二分钟完成的非洲最高峰研究任务,全程只有搜索请求离开了本机。
系统架构:单文件Python代理
整个代理就是一个Python文件。每一轮对话中,模型接收目标、已发现的信息、近期操作日志和当前页面内容,然后输出一个JSON格式的动作指令。
代理支持五种动作:SEARCH(搜索)、NAVIGATE(导航到链接)、READ_MORE(阅读长页面下一部分)、DISCOVER(记录发现)和FINISH(完成)。LM Studio通过JSON schema约束模型输出格式,Playwright则在可见的Chromium窗口中执行每个动作。
这个基础架构并不复杂,真正的挑战在于如何让7B模型始终保持正轨——小模型很容易陷入重复搜索、忘记记录、偏离主题的困境。
lmstudio 与 JSON Schema 输出约束:LM Studio 是一个本地大模型运行环境,底层基于 llama.cpp。它支持在推理时传入一个 JSON Schema,服务器会强制模型的输出符合该结构——这在代理设计中至关重要,因为 7B 模型原生输出经常夹杂解释性文字、缺少引号或字段名拼写错误,导致解析失败。结构化输出把「模型输出能否被程序消费」这一问题从概率性变为确定性,使得动作分发逻辑可以简单可靠地按 action 字段进行路由。同理,Playwright 是微软开源的浏览器自动化框架,可驱动真实 Chromium 实例,支持导航、点击、提取 DOM 文本等操作,与本项目「可见窗口中执行动作」的可观测设计相配合。
核心经验一:规则要写进代码,而不是提示词
作者最初的尝试是在提示词中写明"不要重复搜索",但模型照旧重复。对于小模型来说,读取一条规则然后仍然做最可能的事情是常态,尤其是在长提示词中经过多轮对话之后。
解决方案是把每一条可以检查的规则都用代码强制执行:重复搜索被拦截、打开当前已在的页面被拒绝、同一URL访问超过三次被阻止、空白发现和重复发现(通过词对识别,因此改写或重新排序无法绕过)都会被过滤。被拒绝的动作会附上原因返回给模型。
这里有两个代价不小的教训。一是检查器本身也需要测试:早期版本的重复URL检查忽略了查询字符串,导致第一次搜索之后的每次搜索都被判定为重复——35轮中有34轮被拦截。二是当模型反复犯同样的错误时,回放提示词:模型总是发送空的DISCOVER参数,回放后发现它以为DISCOVER是一个会自动提取信息的命令。在提示词中加一句话说明"必须把信息本身写入参数"就彻底解决了。
核心经验二:CPU上提示词读取是主要成本
这台机器上模型读取速度约为每秒8个token,而读取提示词占每次模型调用时间的约90%。一个4,000 token的提示词需要几分钟才能让模型开始输出第一个字。
但LM Studio(以及其他基于llama.cpp的服务器)会跳过提示词中与上一次相同的前缀部分。因此代理不会每轮重建提示词,而是维护一个持续增长的对话,只追加变化的部分:一行结果、页面的下一段、新页面。只有在对话接近上下文限制时才重建新提示词。
| 优化措施 | 效果 |
|---|---|
| 调整提示词顺序,让连续轮次共享更长的相同前缀 | 每轮约快25% |
| 延续对话而非重建 | 同一页面轮次从150-220秒降至35-120秒 |
| 在同一对话中纠正被拒动作("廉价重试") | 25-45秒,而非浪费一整轮150-200秒 |
| 新提示词中缩短旧发现;使用75%上下文后再重建 | 新提示词平均从234秒降至162秒 |
"廉价重试"机制的重要性超出表面。小模型经常出错,如果每次拒绝都浪费一整轮,代理大部分时间都在被拒绝中消耗。如果只需追加一条简短说明,犯错的成本就变得极低。
提示词缓存与 KV Cache 复用:基于 llama.cpp 的推理服务器会在内存中保存上一次请求的键值缓存(KV Cache)。当新请求的提示词前缀与上一次完全相同时,这部分 token 无需重新计算。代理「持续增长的对话」策略正是利用这一点:每一轮只追加新增内容,历史部分保持不变,因此只有新增的几百个 token 需要重新读取。这也解释了为什么调整提示词顺序能提速——把稳定内容(系统说明、目标)放在前面、变化内容(页面文本、结果)放在后面,可最大化连续轮次间的相同前缀长度。理解这一机制是慢速硬件上设计代理的关键前提。
核心经验三:小模型不知道什么时候该停
这是真正的瓶颈。代理会找到好材料后继续闲逛,或漂移到关联性不强的页面,或离开页面时什么都不记录。三个机制让它第一次学会完成:
- 进度检查:连续四轮没有新发现后,要求它对比发现与目标,然后要么完成,要么说出缺少什么并去找
- 每八轮目标检查:即使发现持续产出也要执行,因为松散相关的发现会不断重置进度检查
- 离开前确认:从页面离开却没有记录任何内容时,触发一个简短问题要求记录或确认离开
有了这些机制,1.27版本自主完成了一个文档研究任务:13轮,约36分钟,输出了要求的命令和文件布局。
但相反的问题随即出现。面对山峰问题时,代理在第3轮就记录了完整答案,在自己的推理中写道"目标已达成",却继续阅读33个部分的文章找有趣细节。解决方案是在每次新发现后加一条提醒:如果你的发现已覆盖目标的每个部分,立即完成。下一次运行:第4轮就完成了。
核心经验四:要求展示证据,而非回答是或否
问7B模型"你的发现是否满足目标?"它太容易回答"是"。在一个研究精神传统如何看待猫并形成观点的任务中,它只读了一篇没有提到任何具体传统的博客文章就完成了,交了一份摘要而非观点。
更有效的做法是要求它展示工作过程。完成前必须把目标拆解为若干部分,逐一写出每个部分及覆盖它的发现,或者标注"未覆盖"。同时告知其发现来自多少个独立来源。下一次运行中,它列出了来自两个来源的六种传统并给出了观点。
模型仍会找漏洞。在一个比较任务中,它自己的检查写道"可用库:未覆盖。在FINISH时写入",然后照样完成了——它把本应用于自己观点的措辞扩展到了尚未找到的信息上。现在的处理方式是:如果完成的推理中出现"未覆盖",就把它送回继续工作那个部分,每次运行最多两次,确保真正不在网络上的内容不会永远阻塞。
核心经验五:写作是独立的工作
最初,代理的FINISH文本就是最终结果。小模型在写作是唯一任务时表现好得多,因此最终结果现在是一个独立的模型调用,只看到目标和编号的发现列表,附带一个简短的编号规则列表。
每条规则都来自真实失败。当写作步骤延续浏览对话(以复用缓存)时,它使用了代理读过但从未记录的页面文本,并引用了并未支持其声明的发现——修复方案是使用只含发现的全新提示词。在一个酸面团教程任务中,它凭空编造了第一次的用水量"45克(约1/4杯)",而45克实际上是每日喂养量。对于要求三个Photoshop替代品的任务,它列出了四个还加了没人要求的意见——原因是一条长段落中埋没了规则,改为简短的编号列表后下一次正好三个、没有多余意见。
上下文污染与关注点分离:当写作步骤沿用浏览对话时,模型能「看到」它读过但未记录的全部页面文本,从而把未经验证的内容当作已有证据使用。这在认知上类似于上下文污染——无关或未确认的信息干扰了当前任务的判断。把小模型的单次调用拆分为职责单一的步骤(收集、写作、校验),本质上是关注点分离:每次调用只携带该步骤必需的上下文,模型不必在「该不该用这段信息」上做复杂判断。这与大模型可依赖长上下文自我约束不同,小模型对上下文中混杂信息的抗干扰能力弱得多。
核心经验六:测试不同类型的任务
直到1.29版本,所有测试都使用同一个目标——这正是过拟合提示词的方式。六种不同类型的任务各自暴露了新问题:
- 文档研究:13轮完成(约36分钟),包含命令、角色和文件布局
- 多来源观点:来自两个来源的六种传统加观点,18轮(37分钟)
- 事实性问题:正确且带引用的答案,4轮(约12分钟)
- 比较与推荐:带引用的比较和推荐,16轮(33分钟),一个部分未覆盖
- 列表任务:恰好三个要求项,全部带引用,9轮(24分钟)
- 分步教程:7轮(约19分钟)的清晰计划,有一个编造的用量,由此引入了数字检查
过拟合提示词(Prompt Overfitting):当开发者反复针对同一个任务目标调整提示词、规则和检查器时,系统会逐渐适配那一类任务的表层特征,而非真正学会通用的研究流程。表现为在训练目标上表现良好,一旦换成事实问答、列表任务或分步教程就暴露新缺陷。这与机器学习中的过拟合同源:优化信号过于集中,泛化能力被牺牲。解法是尽早、主动地引入多样化任务集作为「测试集」,让每次改动都接受跨任务验证,而不是只对着单一目标反复打磨。
尚未解决的问题
代理目前的主要弱点是阅读但不记录——即使页面标题大纲就在眼前,它有时会逐段阅读长页面却不记录相关部分。此外,面对"未完全验证前不要完成"这类严格目标,它会不断搜索网络上可能不存在的细节。判断力方面,结果很大程度上取决于搜索返回的前几个页面,7B模型有时会引用错误的发现编号,因此需要人工核对声明与发现列表。
对小模型代理开发者的建议
作者总结了六条经验:把每条可检查的规则写进代码并告知模型被拒原因;让犯错成本低廉,在同一对话中纠正;在慢速硬件上为提示词缓存而设计——追加而非重建;不要问"完成了吗",而是要求逐部分展示目标覆盖情况;把收集和写作分离,只给写作者证据;尽早测试不同类型的任务并测量每次改动。
项目已在GitHub开源(SnowFXXX/LocalAgentBrowser),可通过pip install localagentbrowser安装,需要LM Studio加载模型和Python 3.10以上环境。作者使用Claude作为编码伙伴从1.13版本起参与开发。这些经验对于任何在资源受限环境中构建AI代理的开发者都具有参考价值,尤其是那些希望数据和计算完全本地化的场景。
相关推荐

强化学习通关《抡大锤》:63%进度背后的分布式训练策略
开发者用深度强化学习挑战《抡大锤》,智能体从底部攀爬至63%进度,卡在铁砧部分。项目开源,采用分治训练和CPU训练策略,寻求社区协作突破瓶颈。

AAAI 2027二审放榜在即:社区热议评审公平与投稿生态
AAAI 2027第二阶段评审结果即将公布,Reddit社区热议评审一致性与流程透明度。本文梳理放榜前的社区情绪、顶会评审的结构性矛盾,以及作者应对二审结果的务实策略。

Sigma FP2发布:全球最小全画幅相机迎来传感器与屏幕升级
Sigma发布FP2全画幅相机,延续全球最小最轻设计,带来改进型传感器、翻转LCD屏和更长续航三大升级,专为便携视频创作者打造,补齐初代fp的体验短板。