feat: 添加swarms团队编排功能并优化agent委派系统

- 引入AgentTeamOrchestrator支持多agent协同任务执行
- 增加第三方swarms库依赖并配置git协议替换以改善包管理
- 扩展DelegationManager支持团队任务调度和进度跟踪
- 实现中文bigram分词算法提升中文任务检索准确性
- 调整A2AClient和DelegationManager超时时间从30秒增至600秒
- 优化AgentRunResult状态判断逻辑增加有意义摘要检测
- 修改Dockerfile配置npm仓库镜像地址和git协议映射
- 更新CLI命令行接口支持网关端口配置传递
- 调整提供者超时配置机制增强请求稳定性
- 移除过时的support_group字段简化agent描述符结构
- 增强错误处理和进度事件报告机制改进用户体验
This commit is contained in:
2026-04-14 14:34:23 +08:00
parent fee9007da6
commit cdfc222c9f
85 changed files with 5443 additions and 1392 deletions

View File

@ -21,6 +21,7 @@ from nanobot.agent.plugins import PluginLoader
from nanobot.agent.skills import SkillsLoader
_TOKEN_RE = re.compile(r"[a-z0-9_-]+")
_CJK_RE = re.compile(r"[\u4e00-\u9fff]+")
@dataclass
@ -55,7 +56,6 @@ class AgentDescriptor:
aliases: list[str] = field(default_factory=list)
capabilities: dict[str, Any] = field(default_factory=dict)
metadata: dict[str, Any] = field(default_factory=dict)
support_group: bool = True
support_streaming: bool = False
def matches(self, target: str) -> bool:
@ -236,7 +236,6 @@ class AgentRegistry:
kind="local_fallback",
protocol=None,
aliases=["subagent", "local"],
support_group=True,
)
)
@ -263,27 +262,51 @@ class AgentRegistry:
def suggest_agents(self, query: str, limit: int = 5) -> list[AgentDescriptor]:
"""基于简单词项打分为一段任务文本推荐 agent。"""
tokens = {token for token in _TOKEN_RE.findall((query or "").lower()) if len(token) > 2}
if not tokens:
return []
query_text = query or ""
query_lower = query_text.lower()
tokens = {token for token in _TOKEN_RE.findall(query_lower) if len(token) > 2}
query_cjk_bigrams = self._cjk_bigrams(query_text)
scored: list[tuple[int, AgentDescriptor]] = []
for agent in self.list_agents(include_local_fallback=False):
haystack = agent.searchable_text()
haystack_cjk_bigrams = self._cjk_bigrams(haystack)
score = 0
for token in tokens:
# token 命中一次给基础分。
if token in haystack:
score += 2
# 如果查询里直接出现了 agent 名或 id再给更高权重。
if agent.name.lower() in query.lower() or agent.id.lower() in query.lower():
if agent.name.lower() in query_lower or agent.id.lower() in query_lower:
score += 5
for phrase in [agent.name, agent.id, *agent.tags, *agent.aliases]:
phrase_text = str(phrase or "").strip()
if not phrase_text:
continue
if phrase_text.lower() in query_lower or phrase_text in query_text:
score += 3
if query_cjk_bigrams and haystack_cjk_bigrams:
# 中文任务没有空格分词,先用 bigram overlap 做粗粒度召回。
score += min(6, len(query_cjk_bigrams & haystack_cjk_bigrams))
if score > 0:
scored.append((score, agent))
scored.sort(key=lambda item: (-item[0], item[1].name.lower()))
return [agent for _, agent in scored[:limit]]
@staticmethod
def _cjk_bigrams(text: str) -> set[str]:
"""提取中文 bigram用于中文任务的轻量召回。"""
chunks = _CJK_RE.findall(str(text or ""))
result: set[str] = set()
for chunk in chunks:
if len(chunk) == 1:
result.add(chunk)
continue
for index in range(len(chunk) - 1):
result.add(chunk[index:index + 2])
return result
def build_agents_summary(self) -> str:
"""把 agent 列表格式化成 prompt 可直接嵌入的 XML 片段。"""
agents = self.list_agents()
@ -310,9 +333,6 @@ class AgentRegistry:
lines.append(f" <protocol>{esc(agent.protocol)}</protocol>")
if agent.tags:
lines.append(f" <tags>{esc(', '.join(agent.tags))}</tags>")
lines.append(
f" <supports-group>{str(agent.support_group).lower()}</supports-group>"
)
lines.append(" </agent>")
lines.append("</agents>")
return "\n".join(lines)
@ -358,7 +378,6 @@ class AgentRegistry:
],
capabilities=record.get("capabilities", {}) if isinstance(record.get("capabilities"), dict) else {},
metadata=record.get("metadata", {}) if isinstance(record.get("metadata"), dict) else {},
support_group=bool(record.get("support_group", True)),
support_streaming=bool(record.get("support_streaming", False)),
)
@ -396,6 +415,5 @@ class AgentRegistry:
],
capabilities=card.get("capabilities", {}) if isinstance(card.get("capabilities"), dict) else {},
metadata=card.get("metadata", {}) if isinstance(card.get("metadata"), dict) else {},
support_group=bool(card.get("support_group", True)),
support_streaming=bool(card.get("support_streaming", False)),
)