guantao 23 часов назад
Родитель
Сommit
4dce5dd7c2

+ 48 - 6
agent/core/runner.py

@@ -2018,12 +2018,54 @@ class AgentRunner:
         # 深拷贝避免修改原始数据
         import copy
         import hashlib
+        import asyncio
         messages = copy.deepcopy(messages)
 
         # 统计优化情况
         stats = {"kept": 0, "downscaled": 0, "described": 0, "cache_hit": 0}
 
-        # 遍历最后一条 assistant 之前的所有 tool messages
+        # 收集需要降分辨率的图片(用于并发处理)
+        downscale_jobs = []  # [(msg_idx, block_idx, image_url, cache_key)]
+
+        # 第一遍:扫描并收集需要处理的图片
+        for i in range(last_assistant_idx):
+            msg = messages[i]
+            if msg.get("role") != "tool":
+                continue
+
+            content = msg.get("content")
+            if not isinstance(content, list):
+                continue
+
+            rounds_ago = assistant_count_after[i]
+
+            for block_idx, block in enumerate(content):
+                if isinstance(block, dict) and block.get("type") == "image_url":
+                    image_url_obj = block.get("image_url", {})
+                    image_url = image_url_obj.get("url", "")
+
+                    if image_url.startswith("data:"):
+                        cache_key = hashlib.md5(image_url[:200].encode()).hexdigest()
+                    else:
+                        cache_key = hashlib.md5(image_url.encode()).hexdigest()
+
+                    # 3-5 轮需要降分辨率
+                    if 2 < rounds_ago <= 5:
+                        cached = self._image_opt_cache.get(cache_key, {})
+                        if "downscaled" not in cached and image_url.startswith("data:"):
+                            downscale_jobs.append((i, block_idx, image_url, cache_key))
+
+        # 并发处理所有降分辨率任务
+        if downscale_jobs:
+            downscale_results = await asyncio.gather(
+                *[self._downscale_image(url) for _, _, url, _ in downscale_jobs],
+                return_exceptions=True
+            )
+            for (_, _, _, cache_key), result in zip(downscale_jobs, downscale_results):
+                if not isinstance(result, Exception) and result is not None:
+                    self._image_opt_cache.setdefault(cache_key, {})["downscaled"] = result
+
+        # 第二遍:应用处理结果
         for i in range(last_assistant_idx):
             msg = messages[i]
             if msg.get("role") != "tool":
@@ -2105,7 +2147,7 @@ class AgentRunner:
                     new_content.append(block)
 
             msg["content"] = new_content
-
+        print(f"[Image Opt Check] 扫描到 {stats['kept'] + stats['downscaled'] + stats['described']} 张图片上下文")
         if stats["downscaled"] > 0 or stats["described"] > 0:
             logger.info(
                 f"[Image Optimization] 保留 {stats['kept']} 张,"
@@ -2155,16 +2197,16 @@ class AgentRunner:
                 new_height = max_size
                 new_width = int(width * max_size / height)
 
-            # 缩放图片
-            img_resized = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
+            # 缩放图片(使用更快的 BILINEAR 算法)
+            img_resized = img.resize((new_width, new_height), Image.Resampling.BILINEAR)
 
             # 转换为 RGB(如果是 RGBA)
             if img_resized.mode == "RGBA":
                 img_resized = img_resized.convert("RGB")
 
-            # 重新编码为 JPEG(压缩率更高
+            # 重新编码为 JPEG(降低质量以加快速度
             buffer = io.BytesIO()
-            img_resized.save(buffer, format="JPEG", quality=85, optimize=True)
+            img_resized.save(buffer, format="JPEG", quality=60, optimize=False)
             new_data = base64.b64encode(buffer.getvalue()).decode("utf-8")
 
             return f"data:image/jpeg;base64,{new_data}"

+ 1 - 1
examples/research/research.prompt

@@ -138,4 +138,4 @@ $system$
 ## 注意事项
 
 - 登陆时,或不确定时联系关涛(feishu)
-- `search_posts` 不好用时改用 `browser-use`
+- 可以多用search_posts,在不同渠道搜索信息

Разница между файлами не показана из-за своего большого размера
+ 491 - 671
frontend/react-template/src/components/FlowChart/FlowChart.tsx


+ 2 - 15
frontend/react-template/src/components/FlowChart/hooks/useFlowChartData.ts

@@ -150,8 +150,8 @@ export const useFlowChartData = (traceId: string | null, refreshTrigger?: number
       const messagesRoot = isRecord(messagesJson) ? messagesJson : {};
       const list = Array.isArray(messagesRoot.messages) ? (messagesRoot.messages as Message[]) : [];
 
-      const filtered = list.filter((message) => (message as { status?: string }).status !== "abandoned");
-      const nextMessages = [...filtered].sort(messageComparator);
+      // const filtered = list.filter((message) => (message as { status?: string }).status !== "abandoned");
+      const nextMessages = [...list].sort(messageComparator);
 
       const { availableData: finalMessages, invalidBranches: invalidBranchesTemp } = processRetryLogic(nextMessages);
 
@@ -174,19 +174,6 @@ export const useFlowChartData = (traceId: string | null, refreshTrigger?: number
       });
       setMsgGroups(grouped);
 
-      if (grouped.START && grouped.START.length > 0) {
-        setGoals((prev) => {
-          if (prev.some((g) => g.id === "START")) return prev;
-          const startGoal: Goal = {
-            id: "START",
-            description: "START",
-            status: "completed",
-            created_at: "",
-          };
-          return [startGoal, ...prev];
-        });
-      }
-
       // REST 请求完成后,允许建立 WebSocket 连接
       setReadyToConnect(true);
     } finally {

Некоторые файлы не были показаны из-за большого количества измененных файлов