From 8a9a0616620b8c0000ebd15a1b90087f41cfc506 Mon Sep 17 00:00:00 2001 From: qing <1776177662@qq.com> Date: Sat, 15 Aug 2026 14:27:27 +0800 Subject: [PATCH] =?UTF-8?q?fix(aibox):=20=E5=AD=90=E4=BB=A3=E7=90=86?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E6=88=AA=E6=96=AD=E4=BF=AE=E5=A4=8D=E2=80=94?= =?UTF-8?q?=E2=80=94=E6=94=B6=E5=B0=BE=E6=8A=A5=E5=91=8A=E8=87=AA=E7=94=9F?= =?UTF-8?q?=E6=88=90=E6=9B=BF=E6=8D=A2=E5=A4=96=E9=83=A8=E6=91=98=E8=A6=81?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aibox/aibox.py | 91 ++++++++++++++++----------------------------- aibox/llm_client.py | 2 +- 2 files changed, 34 insertions(+), 59 deletions(-) diff --git a/aibox/aibox.py b/aibox/aibox.py index d3cdca7..c6eb656 100644 --- a/aibox/aibox.py +++ b/aibox/aibox.py @@ -650,6 +650,8 @@ def run_full_subagent(role, task, config, logger=None, model=None, sub_chat.client = create_llm_client(config, api_key=None, logger=logger, model=model) # 轮次限制:防止工具调用无限循环 + # 注意:超限时不置 conversation_active=False——那会触发 think_and_respond + # 的对话重置逻辑,清空子代理上下文,导致后续收尾报告丢失全部过程信息 turn_count = [0] original_think = sub_chat.think_and_respond @@ -658,7 +660,6 @@ def run_full_subagent(role, task, config, logger=None, model=None, if turn_count[0] > max_turns: if logger: logger.warning(f"子代理达到最大轮次 {max_turns},强制结束") - sub_chat.conversation_active = False return "已达到最大对话轮次,任务结束。" return original_think(input_text, output_callback, is_continuation) @@ -689,11 +690,36 @@ def run_full_subagent(role, task, config, logger=None, model=None, sub_chat.think_and_respond(task, output_callback=sub_think_callback) if logger: - logger.info(f"子代理完成,共 {turn_count[0]} 轮,开始总结...") + logger.info(f"子代理完成,共 {turn_count[0]} 轮,请求子代理生成最终报告...") - # 总结子代理对话内容 - summary = _summarize_subagent_conversation(sub_chat.messages, config, logger, model) - return summary + # 收尾报告由子代理自己生成:它拥有全部上下文(工具输出、中间结论), + # 比外部摘要器(只能看到截断后的对话转录)更完整,也不会丢最终回答。 + # 走 original_think 绕过轮次限制:即使任务因 max_turns 被截断也能收尾。 + if _effective_output_callback is not None: + _effective_output_callback("line", "\n📝 [子代理收尾] 生成最终报告...\n") + wrap_up_prompt = ( + "【收尾】请不要再调用任何工具,基于以上完整执行过程,输出最终报告,包含:\n" + "1. 任务完成情况与结论\n" + "2. 关键过程:做了什么、重要命令/文件/数据\n" + "3. 产物清单(如有,附绝对路径)\n" + "4. 未解决的问题(如有)\n" + "这份报告将原样返回给派生你的主代理,请自包含、力求完整。" + ) + report = None + try: + report = original_think(wrap_up_prompt, output_callback=sub_think_callback, + is_continuation=True) + except Exception as e: + if logger: + logger.error(f"子代理收尾报告生成异常: {e}") + if report and str(report).strip(): + return str(report).strip() + + # 兜底:收尾失败时取最后一条有内容的助手消息 + for msg in reversed(sub_chat.messages): + if msg.get("role") == "assistant" and msg.get("content"): + return f"【子代理最终回答】\n{msg['content']}" + return "子代理未产生有效对话内容。" except Exception as e: if logger: @@ -701,63 +727,12 @@ def run_full_subagent(role, task, config, logger=None, model=None, return f"❌ 子代理执行失败: {str(e)}" -def _summarize_subagent_conversation(messages, config, logger=None, model=None) -> str: - """总结子代理对话内容,提取关键信息返回给父代理。""" - # 过滤掉 system 消息,保留对话部分 - conversation = [] - for msg in messages: - if msg["role"] == "system": - continue - role_label = "用户" if msg["role"] == "user" else \ - "助手" if msg["role"] == "assistant" else "工具" - content = msg.get("content", "") - if content: - if len(content) > 2000: - content = content[:2000] + "...(已截断)" - conversation.append(f"[{role_label}] {content}") - - if not conversation: - return "子代理未产生有效对话内容。" - - # 限制对话长度用于总结 - conversation_text = "\n".join(conversation) - if len(conversation_text) > 8000: - conversation_text = conversation_text[:8000] + "\n...(对话过长已截断)" - - try: - summary_client = create_llm_client(config, api_key=None, logger=logger, model=model) - summary_prompt = f"""请总结以下子代理对话的关键内容,提取: -1. 完成的任务或解决的问题 -2. 关键发现或结论 -3. 重要数据或信息 -4. 未解决的问题(如有) - -对话内容: -{conversation_text} - -请用简洁的要点形式总结,不超过500字。""" - - result = summary_client.chat_completion( - [{"role": "user", "content": summary_prompt}], - temperature=0.3, - max_tokens=800 - ) - - if result: - return f"【子代理执行总结】\n{result.strip()}" - return "【子代理执行总结】\n子代理已完成任务,但无法生成总结。" - except Exception as e: - if logger: - logger.error(f"子代理总结失败: {e}") - return f"【子代理执行总结】\n子代理已完成任务。(总结生成失败: {str(e)})" - - class SubAgentTool(Tool): """派生子代理工具 - 主代理可派生拥有全部工具和独立上下文的完整子代理执行任务。 子代理是完整的对话实例,拥有文件操作、命令执行、网页访问、技能扩展等 全部工具能力。独立上下文窗口(不污染主对话),多轮对话直到任务完成。 - 结束后自动总结对话内容,返回摘要给父代理。 + 结束后由子代理基于完整执行过程生成最终报告,返回给父代理。 """ def get_name(self) -> str: @@ -766,7 +741,7 @@ class SubAgentTool(Tool): def get_description(self) -> str: return """派生子代理执行任务。子代理拥有全部工具能力和独立的上下文窗口,不会污染主对话上下文。 适用场景:需要多步骤操作的任务(如文件处理、命令执行、信息检索)、需要独立上下文的复杂任务。 -子代理可进行多轮工具调用,任务完成后自动总结并返回摘要。 +子代理可进行多轮工具调用,任务完成后由子代理基于完整执行过程生成最终报告(结论/关键过程/产物清单/未解决问题)返回。 参数说明: - role:子代理的角色设定(作为系统提示词),如"你是一位资深代码审查专家" - task:要交给子代理执行的具体任务 diff --git a/aibox/llm_client.py b/aibox/llm_client.py index 3687ebc..8c88bef 100644 --- a/aibox/llm_client.py +++ b/aibox/llm_client.py @@ -126,7 +126,7 @@ class DeepSeekClient(LLMClient): self.base_url, headers=self._headers(), json=payload, - timeout=30, + timeout=self.timeout, proxies=self._resolve_proxies(), ) if response.status_code == 200: