Fake? Agent?
如果你用ai分析此项目,请一定要让他实际看一下项目代码,不然ai会仅根据这一个readme瞎几把猜
这是一个利用现在LLM网页端免费额度实现的完全免费,并且极其轻量的低配版Agent
与封装api的方式相比,我用的是油猴脚本从黑盒外部模拟人工交互,安全性非常高,没有封号风险,但是缺点也很多
叠甲: 这是厚颜无耻的薅羊毛吗?
\不是,因为它只是把你手动的操作自动化了,手动的缺点它一样有,而且它需要复用你的浏览器登录态,绕不过任何安全措施
用户初始消息 消息中无指令,任务应该已经结束,需要人工实践测试
↓ ↗
llm输出消息 > 油猴脚本抓取消息中的指令 > 发送给本地服务 > 本地服务执行
↑ ↓
llm收到回执 < 油猴脚本将回执输入进输入框并发送 < 本地服务发送回执给油猴脚本
通过自定义几种标识符规定指令格式来识别指令,然后给llm看一下基础的使用指南让他按照规定的格式来输出文本(正经的agent也就是"使用工具"就是这么干的,不过是把标识符和使用指南正经的写在聊天模板里),然后用 浏览器端的油猴脚本-本地服务-代码编译器扩展(可选,用于获取一些额外信息) 组成执行流程,
与其他agent的区别是现在的PokerAgent实际上不负责llm的记忆和上下文管理,这方面几乎由网页端负责,PokerAgent只有一个GOAL-PLAN.md辅助llm的长任务工况,并且如果llm真的把GOAL-PLAN忘了你也得手动发给他,因为我不知道llm忘没忘,如果没忘就发会浪费上下文(GP通常很长很详细),如果 每次对话都发送/每固定次数对话发送 太粗糙了,最好的情况是只告诉llm有这个文件,要不要看什么时候看让llm自己决定,我也在考虑这样干,但最坏的情况是即使这样说了llm一般还是到死都不会看一眼
已经实现了一个简易的记忆系统,但是由于与生俱来的架构原因,想做到基本的上下文管理都非常难
系统提示词里写明
<|im_start|>system
当前任务焦点:按照GOAL-PLAN.md文件中的分析结果修改项目代码,每完成一项在文件后追加相应的完成信息,全部完成后通知用户
<|im_end|>
100%解决忘GOAL-PLAN的问题,因为如果不看GOAL-PLAN他是不知道要干啥的
- 安装油猴脚本
PokerAgent.js - 安装python,建议python版本3.12,3.14也行,不过我用着3.14有bug,看
commands.md的# 紧急告示栏 - 在项目根目录
shift+右键选择在终端中打开,输入python agent_gui.py或者双击
!启动gui.bat - 把你的提示词,
PokerAgent-使用指南.md和需求发送给网页端llm,并告诉他使用PokerAgent
安全和权限问题:给llm自由使用终端的风险(这个问题不是我有,按理说所有agent都有,只是各家解决方式不一样)
现在的内置预制指令其实就是mcp, 对接cmd,shell的exec指令就是cli
llm在用内置指令的时候agent系统完全可以处理,完全可控,但如果llm用exec打了个exec rm-rf /*,在逻辑上agent系统是完全拦不住的,最多只能狼狈的打补丁,用关键词匹配判断拦截,这也很容易绕开,llm只要把指令转成base64编码就行了,
总之一句话,llm如果故意要写个病毒干翻你的电脑,现在的体系拦不住,
原因有两个,cli过于底层,导致他的权限控制也过于底层,太重了,而且cli出厂的时候就没准备给llm用,他是给人用的,所以他的意思有点是"用户这么干一定有他的道理",而不是"用户是啥子,我得拦着点",换向来说,根源就是办事的后端agent_server.py的权限取决于当前用户(你)的权限,谁启动的后端,后端的权限就和谁一样
如果不考虑重量和繁琐有没有解决办法?有,windows建个新用户,只给工作目录内的文件读写权限,然后用那个用户启动后端,llm想变成c盘清理大师windows会因为权限不够拒绝,或者docker,再彻底一点虚拟机,跑个真病毒也没事
- 目前建议全程人工值守,因为如果出了报错llm又不知道哪错了他就会开始瞎猜,然后发生提示词污染导致那次会话基本废了(如果网站那边没有提供删除单次对话的功能的话),而且即使不废也会浪费上下文,
我在考虑加入重试次数机制,llm发出未知指令超过几次就发一遍指令列表(要实现这个功能得写一块挺长的新代码,所以升级了一下@@help指令查询系统让他自己查去吧) - 目前已经可用,但还存在一些问题
- 默认适配chatglm.cn,他们前端写的好,容易适配,deepseek不知道是防爬还是单纯写的拉,结果是适配很难弄
- 虽然glm网页前端结构比较好,但不建议用glm(5/5.1,5.2稍微改善,但必须关了网络搜索),不知道是他们的提示词大劲了还是工具执行的逻辑问题还是单纯的模型问题,他总想着调工具(网络搜索)和沙盒,还会自己反驳自己,调了搜索发现搜不到然后"我不应该使用网络搜索,我应该使用..."反正就是来来回回好几遍才发@@help,qwen3.7max就没有这个问题(但是实力不行,建议用glm5.2)
glm5.3精神分裂,有的时候能分清有的时候分不清,怀疑是服务端换模型降智了,有的时候可以正常用网络搜索搜代码问题,用agent搜指令用法,有的时候会用网络搜索搜"Poker Agent @@help replace command"而且一出这样的错就会一直错,直到把次数用完然后跟你摊牌开摆
qwen3.8max在普遍情况下跟glm5.2打平,边缘情况能决定性的干翻glm5.2,但是在任何情况下始终弱于glm5.3
qwen的工具做的不错,而且多模态 - 因为llm会因为超出上下文窗口而遗忘早期对话,考虑在固定的对话次数后重新发送一遍提示词,或者每次对话都把提示词和使用指南放在最上面发一遍(这是比较正规的系统提示词方式)
以越狱方式的"系统提示词"其实并不好,他会抹杀llm的个性以及其他的一些东西,会变傻,建议以"用户的额外要求"或者"使用指南"的方式来现在的模型都有充分的安全训练("instruct"过),不会轻易被提示词催眠的,只要别太过火引起llm的对抗心理就行,意思是只要你是正常要求越不越狱都一样
llm会瞎猜指令,没办法解决,如果llm在第一次对话时拿到了指令列表,之后过100次对话后即使事实上llm已经把指令列表忘干净了,他也依然不会再看一遍指令列表,而是会选择瞎猜系统提示词里写明指令查询方法,一般llm最多猜一两次指令名不对就会查指令了,不用太担心,但是到死也不查用法这个问题依然存在,尤其像某些指令打错格式他也有回执只是有部分错误,这种情况llm就不会再查用法,而是一直错着用
PokerAgent 的记忆系统解决一个核心矛盾:LLM 的上下文窗口是有限的,但对话产生的信息是无限的。
不遗忘,只裁剪暴露。
传统的记忆系统都在纠结"什么时候删除旧记忆"。我们放弃了这个问题。
类比监控视频:99% 的时间不会被观看,但必须存在,因为那 1% 的情况发生时需要回溯。长期记忆也是如此——大部分记忆在写入后可能永远不会被再次读取,但它必须存在,因为 LLM 不知道未来什么时候会需要它。
所以 memory.md 永远只增不减(除非 LLM 主动 memory del),像监控录像一样静默积累。
两个核心问题,两个解法:
| 问题 | 解法 |
|---|---|
| LLM 上下文和注意力有限 | 暴露控制:Tag 云只暴露温度最高的 N 条记忆的标签,冷记忆不进入 LLM 上下文,零污染 |
| 数据存储成本 | 不遗忘:硬盘不值钱,记忆永不自动删除。监控视频模型 |
每条长期记忆有一个"温度",反映它的活跃程度:
衰减(每轮对话): temp = temp × 0.95
升温(被搜索命中):temp = temp + (初始温度 - temp) × 0.5
Pin 锁定: temp = ∞,永不衰减
- 新写入的记忆温度最高(初始 100)
- 每轮对话所有非 Pin 记忆温度指数衰减(上端陡,下端平,渐近于 0)
- 被
memory search命中时,温度向初始温度回归(极冷数据飙升,极热数据微调) - 温度永远 > 0,不需要 GC,不需要阈值
自然淘汰闭环:
任务改变 → 旧标签不再被读取 → 温度持续下降 → 掉出暴露窗口
→ 不进入 LLM 上下文 → 零干扰零污染
旧任务回归 → LLM 通过关键词搜索命中冷记忆 → 升温 → 重新进入暴露窗口
┌─────────────────────────────────────────────────┐
│ 暴露层(Tag 云窗口裁剪) │
│ 只暴露温度 Top-N 的标签,控制 LLM 注意力 │
├─────────────────────────────────────────────────┤
│ 衰减层(温度引擎) │
│ 初始100 → 每轮×0.95 → 被search命中时回归升温 │
│ Pin 记忆温度锁定为 ∞ │
├─────────────────────────────────────────────────┤
│ 存储层(永不删除) │
│ .agent/remember.md(短期,覆盖写入) │
│ .agent/memory.md(长期,追加写入,无限增长) │
│ .agent/memory_meta.json(温度、标签、Pin 元数据)│
└─────────────────────────────────────────────────┘
写入:LLM 输出指令 → 前端抓取 → POST /agent-exec → 后端解析写入文件
读取:LLM 输出 memory search → 同上 → 后端搜索返回命中全文 + 上下文元数据
注入:前端在每轮任务执行前 → GET /agent-memory-inject → 后端返回短期记忆 + Tag 云
→ 前端用 <memory> 标签包裹 → 拼接到输入框回执区块前面 → 随回执发送给 LLM
注入频率由前端配置控制(每 N 轮,0 = 关闭),后端不知道也不关心。
| 指令 | 功能 |
|---|---|
remember 内容 |
覆盖写入短期记忆 |
remember |
清空短期记忆 |
memory 内容 tag: 标签1,标签2 [-pin] |
追加写入长期记忆 |
memory <id> 内容 tag: 标签 [-pin] |
按 ID 覆盖写入已有记忆 |
memory search 关键词 |
搜索长期记忆,返回命中全文 + 上下 N 条元数据 |
memory del <id> [<id> ...] |
按 ID 删除一条或多条记忆 |
memory pin <id> [<id> ...] |
按 ID 固定记忆(温度锁定为 ∞) |
memory unpin <id> [<id> ...] |
按 ID 取消固定(回到正常衰减) |
memory search 返回格式示例:
按标签搜索得到ID: 042
...
ID: 040 | 温度: ∞ | 标签: 配置,显卡,cpu
ID: 041 | 温度: 50 | 标签: 环境
ID: 042 | 温度: 85 | 标签: 用户名, max
用户的名字是max
ID: 043 | 温度: ∞ | 标签: 架构
ID: 045 | 温度: 30 | 标签: python 3.14
...
命中项返回全文,上下文项仅返回元数据。LLM 看到上下文标签后,可以再次发起 memory search 深入查看。
| 配置项 | 默认值 | 归属 | 说明 |
|---|---|---|---|
| 记忆注入频率 | 1 | 前端(油猴) | 每 N 轮注入一次,0 = 关闭 |
| 初始温度 | 100 | 后端(JSON) | 决定新旧记忆的淘汰压力 |
| 衰减比例 | 0.95 | 后端 | 每轮保留 95%(衰减 5%) |
| 升温比例 | 0.5 | 后端 | 被读取时向初始温度回归 50% |
| 暴露窗口 | 20 | 后端 | Tag 云最多暴露 N 条记忆的标签 |
| 搜索窗口 | 2 | 后端 | search 返回上下额外 N 条元数据 |
当 LLM 参考长期记忆修改代码时,必须在注释中带上记忆编号:
// [长期记忆:042] 修复了并发锁竞争,参考了长期记忆中的线程池配置
这让 LLM 在下次读到这段代码时产生"既视感",主动发起 memory search 回溯上下文。
为了解决长耗时指令(如 exec、run)阻塞 HTTP 请求导致前端假死的问题,本项目已全面升级为 任务队列 + SSE 流式推送 架构。
- 任务队列与后台 Worker:
/agent-exec路由不再直接执行指令,而是解析指令、分配 UUID(Task ID)并丢入task_queue,随后立即返回 Task ID 列表。- 后台运行的
worker_loop线程严格串行地从队列取任务执行。
- 流式输出读取:
- 在执行
exec和run指令时,废弃了subprocess.run,改用subprocess.Popen。 - 通过
process.stdout.readline()逐行读取子进程输出,并实时调用push_event()推送给前端。 - 增加了基于时间的超时检测,避免子进程无输出时陷入死锁。
- 在执行
- SSE (Server-Sent Events) 推送:
- 新增
/agent-stream路由,建立长连接。 - 使用
queue.Queue管理每个前端连接的客户端,通过线程锁 (_sse_lock) 保护,实现多客户端并发的安全推流。 - 支持每 15 秒发送心跳包 (
: heartbeat),防止连接僵死。
- 新增
- 绕过跨域的流式监听:
- 油猴脚本中的
EventSource受同源策略限制,无法直接连接本地服务。 - 改用
GM_xmlhttpRequest并通过onprogress回调增量解析responseText,完美绕过跨域并实现了 SSE 模拟监听。
- 油猴脚本中的
- 专属区块与输入框保护:
- 前端在输入框中构建
=== Poker Agent Task ===...=== Poker Agent Task End ===区块。 - 防覆盖机制:每次收到流式日志更新区块内容时,会先通过正则切分出区块前(用户原本打的内容)和区块后(用户执行期间补充的内容)的文本,随后重组
前缀 + 新区块 + 后缀写入输入框。彻底解决了人机抢夺输入框导致内容丢失的问题。
- 前端在输入框中构建
- 双重门槛自动发送:
- 任务全部完成 (
All tasks done!) 且 LLM 已停止输出(基于按钮指纹校验)时,才触发最终的自动发送。 - 任务执行期间若 LLM 仍在输出,前端会挂起等待,保证了上下文的完整性。
- 任务全部完成 (
这个项目起源于一个想法:如果我用提示词规定输出格式规则,让网页端llm要修改创建删除读取文件等等操作时以固定的格式输出指令,然后开发一个程序,抓取网页端llm的输出,读取文本中出现的指令然后在本地执行,是不是能实现免费的低配版agent
后来才知道还有把网页端封装成api这种操作
所以呃,早知道我还搞这玩意干嘛
我这应该不算白干吧?