From 729f40893e3ed0887ca05e3cf52d828c0f73e476 Mon Sep 17 00:00:00 2001 From: butubb <1422726308@qq.com> Date: Fri, 4 Sep 2026 15:12:55 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BB=8F=E9=AA=8C=E5=86=99=E5=85=A5?= =?UTF-8?q?=E5=8D=B3=E6=97=B6=E6=8F=90=E7=A4=BA=E2=80=94=E2=80=94=E6=8F=90?= =?UTF-8?q?=E7=82=BC+=E4=BF=9D=E5=AD=98=E6=8C=AA=E5=88=B0=20done=20?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E4=B9=8B=E5=89=8D=EF=BC=88=E5=8E=9F=E5=9C=A8?= =?UTF-8?q?=20done=20=E5=90=8E=E6=89=A7=E8=A1=8C=E3=80=81SSE=20=E5=B7=B2?= =?UTF-8?q?=E5=85=B3=E6=B5=81=EF=BC=8C=E7=94=A8=E6=88=B7=E7=9C=8B=E4=B8=8D?= =?UTF-8?q?=E5=88=B0=EF=BC=89=EF=BC=8C=E6=88=90=E5=8A=9F=E5=90=8E=E6=8E=A8?= =?UTF-8?q?=20=F0=9F=A7=A0=20=E7=BB=8F=E9=AA=8C=E8=AE=B0=E5=BF=86=20step?= =?UTF-8?q?=20=E5=8D=A1=E7=89=87=E3=80=8C=E5=B7=B2=E5=86=99=E5=85=A5?= =?UTF-8?q?=E8=AE=B0=E5=BF=86=E5=BA=93=EF=BC=8C=E4=B8=8B=E6=AC=A1=E7=9B=B8?= =?UTF-8?q?=E4=BC=BC=E4=BB=BB=E5=8A=A1=E8=87=AA=E5=8A=A8=E5=8F=82=E8=80=83?= =?UTF-8?q?=E3=80=8D=EF=BC=9B=5Fsave=5Fexperience=20=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E6=88=90=E5=8A=9F=E4=B8=8E=E5=90=A6=EF=BC=9B=E8=92=B8=E9=A6=8F?= =?UTF-8?q?=E8=B6=85=E6=97=B6=2060s=E2=86=9225s=20=E9=98=B2=E6=94=B6?= =?UTF-8?q?=E5=B0=BE=E6=8B=96=E6=B2=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/agent_api.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/web/agent_api.py b/web/agent_api.py index d8c1786..4e4b766 100644 --- a/web/agent_api.py +++ b/web/agent_api.py @@ -138,7 +138,7 @@ def _distill_experience(cfg, prompt, tool_seq): headers = {"Authorization": f"Bearer {cfg.get('api_key', '')}", "Content-Type": "application/json"} r = httpx.post(f"{(cfg.get('api_base') or 'https://api.deepseek.com').rstrip('/')}/chat/completions", - json=body, headers=headers, timeout=60) + json=body, headers=headers, timeout=25) if r.status_code != 200: return "" j = r.json() @@ -150,10 +150,10 @@ def _distill_experience(cfg, prompt, tool_seq): def _save_experience(prompt, recipe, tool_seq): - """保存经验(后台线程调用,包 app context)。""" + """保存经验(后台线程调用,包 app context)。返回是否保存成功。""" try: if _flask_app is None: - return + return False with _flask_app.app_context(): _ensure_exp_table() from datetime import datetime @@ -164,8 +164,10 @@ def _save_experience(prompt, recipe, tool_seq): "c": datetime.now().strftime("%Y-%m-%d %H:%M")}) db.session.commit() _log.info("经验已保存(配方 %d 字符)", len(recipe)) + return True except Exception as e: _log.warning(f"经验保存失败: {e}") + return False # ================== 配置 ================== @@ -355,16 +357,23 @@ def _agent_thread(run_id, prompt, serial, cfg): hist.append({"role": "user", "content": prompt[:2000]}) hist.append({"role": "assistant", "content": (answer or "")[:4000]}) _run["history"] = hist[-24:] - q.put(("done", {"answer": answer})) - # 自进化:成功后提炼操作配方存为经验(尽力而为,不阻塞/不影响结果) + # 自进化:成功执行过工具则提炼配方写入经验。必须在 done 之前完成—— + # done 发出后 SSE 关流,用户就看不到「已写入经验」的提示了。 + # 提炼/保存失败静默(不阻塞、不影响结果),只在成功时推送 🧠 卡片。 if tool_seq: try: recipe = _distill_experience(cfg, prompt, " -> ".join(tool_seq)) if recipe and "配方" not in recipe[:50]: - _save_experience(prompt, recipe, " -> ".join(tool_seq)) + if _save_experience(prompt, recipe, " -> ".join(tool_seq)): + _log.info("经验已写入记忆库,随事件流提示") + q.put(("step", {"tool": "🧠 经验记忆", + "args": "本轮操作已提炼为经验并写入记忆库" + "(下次相似任务会自动参考)", + "image": None})) except Exception as e: _log.warning(f"经验保存异常: {e}") + q.put(("done", {"answer": answer})) except Exception as e: _log.warning(f"Agent 运行异常: {e}") # 诊断:打印消息结构(tool_calls 与 tool 消息配对检查)