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:
@ -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)),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user