From 2b387f2dcfcefe78ff3186c63fcee7f010fc516c Mon Sep 17 00:00:00 2001 From: Liang Jiaqing Date: Mon, 9 Mar 2026 08:55:22 +0800 Subject: [PATCH] ref: simplify feishu history injection, tune web_scan/plan_sop/driver --- agentmain.py | 6 +-- assets/ljq_web_driver.user.js | 5 +- ga.py | 4 +- memory/memory_management_sop.md | 2 +- memory/plan_sop.md | 82 +++++++++++++++++++++++---------- memory/tmwebdriver_sop.md | 6 ++- 6 files changed, 69 insertions(+), 36 deletions(-) diff --git a/agentmain.py b/agentmain.py index b78ba60..371d8f2 100644 --- a/agentmain.py +++ b/agentmain.py @@ -102,11 +102,9 @@ class GeneraticAgent: handler.key_info += '\n[SYSTEM] 若开始新任务,先更新或清除工作记忆\n' self.handler = handler self.llmclient.backend = self.llmclient.backends[self.llm_no] - # 如果有历史记录且来自飞书,注入到首轮 user_input 中(支持/restore恢复上下文) user_input = raw_query - if source == 'feishu' and len(self.history) > 1: # 飞书场景且有之前的对话记录 - h_str = "\n".join(self.history[-20:]) - user_input = f"### [WORKING MEMORY]\n\n{h_str}\n\n\n### 用户当前消息\n{raw_query}" + if source == 'feishu' and len(self.history) > 1: # 如果有历史记录且来自飞书,注入到首轮 user_input 中(支持/restore恢复上下文) + user_input = handler._get_anchor_prompt() + f"\n\n### 用户当前消息\n{raw_query}" gen = agent_runner_loop(self.llmclient, sys_prompt, user_input, handler, TOOLS_SCHEMA, max_turns=40, verbose=self.verbose) try: diff --git a/assets/ljq_web_driver.user.js b/assets/ljq_web_driver.user.js index bb39ff8..2e90d36 100644 --- a/assets/ljq_web_driver.user.js +++ b/assets/ljq_web_driver.user.js @@ -45,16 +45,13 @@ console.log(log_prefix + `检测到opener,丢弃继承的window.name: ${window.name}`); window.name = ''; } else { - sid = (window.name && window.name.startsWith('ljq_')) ? - window.name : window.sessionStorage.getItem('ljq_driver_sid'); + sid = (window.name && window.name.startsWith('ljq_')) ? window.name : null; } if (!sid) { sid = `ljq_${Date.now().toString().slice(-2)}${Math.random().toString(36).slice(2, 4)}`; - window.sessionStorage.setItem('ljq_driver_sid', sid); window.name = sid; console.log(log_prefix + `创建新会话ID: ${sid}`); } else { - if (window.name !== sid) window.name = sid; console.log(log_prefix + `使用现有会话ID: ${sid}`); } diff --git a/ga.py b/ga.py index 7a445fb..20dfa79 100644 --- a/ga.py +++ b/ga.py @@ -135,7 +135,7 @@ def web_scan(tabs_only=False, switch_tab_id=None): "active_tab": driver.default_session_id } } - if not tabs_only: result["content"] = get_html(driver, cutlist=True, maxchars=23000) + if not tabs_only: result["content"] = get_html(driver, cutlist=True, maxchars=28000) return result except Exception as e: return {"status": "error", "msg": format_error(e)} @@ -485,7 +485,7 @@ class GenericAgentHandler(BaseHandler): return prompt def next_prompt_patcher(self, next_prompt, outcome, turn): - if turn % 30 == 0: + if turn % 35 == 0 and 'plan' not in str(self.related_sop): next_prompt += f"\n\n[DANGER] 已连续执行第 {turn} 轮。你必须总结情况进行ask_user,不允许继续重试。" elif turn % 7 == 0: next_prompt += f"\n\n[DANGER] 已连续执行第 {turn} 轮。禁止无效重试。若无有效进展,必须切换策略:1. 探测物理边界 2. 请求用户协助。如有需要,可调用 update_working_checkpoint 保存关键上下文。" diff --git a/memory/memory_management_sop.md b/memory/memory_management_sop.md index 0a3d7d6..1fcbd49 100644 --- a/memory/memory_management_sop.md +++ b/memory/memory_management_sop.md @@ -64,7 +64,7 @@ L3: ../memory/ (记录库层 - 包含 .md/.py 等各类文件) | L2/L3 修改值 | 若不影响场景定位则不动 L1 | | 发现通用避坑规律 | 压缩为一句加入 RULES | -> **同步红线**:L1 只写关键词/名称,禁搬细节。 +> **同步红线**:L1 只写关键词/名称,禁搬细节。需要评估L1中的token数和索引效用。 --- ## 信息分类快速决策树 diff --git a/memory/plan_sop.md b/memory/plan_sop.md index e1f2d9f..7208eff 100644 --- a/memory/plan_sop.md +++ b/memory/plan_sop.md @@ -1,36 +1,70 @@ # Plan Mode SOP -> 简单任务(1-2步可完成)无需本SOP,直接做。 +> 简单任务(1-2步可完成)禁用本SOP,直接做。 -## 0. 基本协议 +文件命名:`./plan_XXX.md`(XXX = 任务英文短名)。结果文件放 `./`,路径回填计划文件。禁建子目录。 -进入 plan mode 后,立即调用 `update_working_checkpoint`,内容包含: +--- -1. **PLAN**:初始为 `[ ] 规划` `[ ] 执行`,规划完成后展开为详细 checklist -2. **RULES**(以下三条原文写入,每次 update 必须保留): - - 一次只做一步,完成后标 [x] 并 update checkpoint - - 每次 checkpoint 必须保留完整 PLAN + RULES - - 全部 [x] 才可收尾 +## 规划态(按序执行,不可跳步) -## 1. 规划阶段 +[] **步骤1:存checkpoint(含格式模板)** -初始 checkpoint:`[ ] 规划` `[ ] 执行`。"规划"完成 = 展开执行步骤并 update checkpoint。 +调用 `update_working_checkpoint`,**必须**使用以下格式([格式]字段不可省略): +``` +[任务] 产出 plan_XXX.md | [需求] 用户原始需求一句话 +[格式] 骨架每项必须用 - [ ] 开头,禁止###标题。模板:- [ ] 项目简述 | 方法:做法 | 验证:判据 +[进度] 即将读领域SOP | ⚡写完plan后必须重读本SOP步骤3,按其模板切checkpoint再执行 +``` -### 1a. 读 SOP -查 insight 找相关 SOP 并读取——SOP 提供任务骨架,直接指导分解。无则跳过。不确定性最高的环节先探,其结果可能推翻整个计划。 +[] **步骤2:读领域SOP → 写plan骨架 `./plan_XXX.md`** -### 1b. 分类 -从依赖关系读出结构:有依赖→Sequential | 无依赖→MAP | 条件未知→Branch。可嵌套。 +先读取相关领域SOP了解步骤,然后**立即**写骨架。不需要完美,**允许方法写"⚠待确认"**。禁止以"还没调研清楚"为由推迟。 -### 1c. 分解 -按结构展开 checklist。**每个子任务必须具体列出,禁止笼统描述**(如"批量处理所有文件"必须展开为每个文件的具体条目)。每步须有独立完成判据,否则继续拆。update checkpoint 并标 `[x] 规划`。 -- Seq: `[ ]A → [ ]B → [ ]C` -- MAP: `[ ]D1 [ ]D2 [ ]D3 … → [ ]汇总`(汇总为最后一步,中心化执行) -- Branch: `[ ]尝试X → 成功:[ ]Y / 失败:[ ]Z` +**⚠ 骨架格式以checkpoint中[格式]字段为准,不要模仿领域SOP的排版。** -## 2. 执行注意 +骨架模板: +``` +# 任务标题 +需求:一句话 | 约束:关键限制 -- 计划有误时回到规划修正,不硬凑;不可逆操作前多验证一步 -- MAP 的子任务可用 subagent 并行执行 -- 步骤间用尽量用文件传递中间结果和汇总,不靠上下文记忆 -- 收尾:全部 `[x]` 后汇总结果,清理 checkpoint \ No newline at end of file +- [ ] 项目1简述 | 方法:具体做法 | 验证:完成判据 +- [ ] 项目2简述 | 方法:⚠待确认 | 验证:完成判据 +- [ ] 项目3简述 | 方法:具体做法 | 验证:完成判据 +``` + +- 有⚠待确认项 → 逐项探索补充,**每轮必须更新plan文件 + checkpoint的[进度]** +- 连续3轮探索无实质进展 → **必须停止**,用当前最佳方案替代 +- 无⚠待确认项 → 直接进入步骤3 + +**⛔ 写完骨架后禁止执行任何项目。必须先完成步骤3。** + +[] **步骤3:转入执行态(⛔ 不可跳过)** + +**写完plan骨架后,必须先执行此步骤再开始做任何项目。** +调用 `update_working_checkpoint`,只放**当前一步**(禁止塞全部步骤): +``` +[执行] plan_XXX.md | 当前:Step1简述 | ⚡完成后必须:1.file_patch plan把当前步[ ]改[x] 2.读plan找下个[ ] 3.update_working_checkpoint为下步(保留本模板格式) +``` + +**执行循环(每步重复):** +1. 读 `plan_XXX.md` → 定位当前 `- [ ]` 项 +2. 执行该项(参照领域SOP) +3. 按checkpoint中⚡指令完成收尾(标[x]→找下步→更新checkpoint) +4. 全部完成 → 汇总结果 → 清理checkpoint + +--- + +## 项目类型(三选一或嵌套) +- **步骤**:有先后依赖,顺序执行 +- **方面**:并行独立,无依赖 +- **分支**:条件未知,尝试X → 成功走Y / 失败走Z + +## 强制约束 + +- 每项**必须**有独立完成判据,禁止笼统描述 +- 禁止出现"处理所有文件"类表述,**必须**展开为具体条目 +- 一次只做一项,禁止批量执行 +- 计划有误回到规划态修正,禁止硬凑 +- 不可逆操作前多验证一步 +- 并行方面可用 subagent 执行 \ No newline at end of file diff --git a/memory/tmwebdriver_sop.md b/memory/tmwebdriver_sop.md index 395d7f4..b639a11 100644 --- a/memory/tmwebdriver_sop.md +++ b/memory/tmwebdriver_sop.md @@ -84,7 +84,11 @@ document.body.appendChild(el); // 响应写回el.textContent - 验证码canvas/img:JS `canvas.toDataURL()` 直接拿base64最干净 - 备选:`window.open(location.href,'_blank')` 前台开新标签→win32截图→完后close - GM_openInTab在web_execute_js不可用(非油猴上下文) - - 浏览器无JS API切标签页,只能开新的来保证前台 + +## 直接import(仅作调试使用) +- `sys.path.insert(0, GenericAgent根目录)`, `from TMWebDriver import TMWebDriver` +- `d=TMWebDriver()`, `d.set_session('url_pattern')`, `d.execute_js('code')` → 返回`{'data': value}`(非裸值) +- 配合simphtml:`str(simphtml.optimize_html_for_tokens(html))` → 注意返回BS4 Tag需str() ## 跨域iframe操控(postMessage中继) - 跨域iframe的contentDocument不可访问,web_execute_js只在顶层执行