feat: expose graph orchestration mode, fix pipeline multi-agent, add Feishu tools (Phase 3)
增强编排 + 飞书深度集成: - Graph 模式:暴露 orchestrator._graph() 到 run() 方法,workflow_integration 支持 graph nodes/edges - Pipeline 修复:多 Agent 按步骤轮转分配,不再只用 agents[0] - 4个飞书操作工具: feishu_create_doc / feishu_create_calendar_event / feishu_search_contacts / feishu_send_approval - 飞书 @mention→Goal:feishu/ orange WS handler 支持 "目标: xxx" 触发自动创建 Goal Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -151,8 +151,19 @@ class AgentOrchestrator:
|
||||
question: str,
|
||||
agents: List[OrchestratorAgentConfig],
|
||||
on_llm_call: Optional[Callable[[Dict[str, Any]], Any]] = None,
|
||||
graph_nodes: Optional[List[Dict[str, Any]]] = None,
|
||||
graph_edges: Optional[List[Dict[str, Any]]] = None,
|
||||
) -> OrchestratorResult:
|
||||
"""执行多 Agent 编排。"""
|
||||
"""执行多 Agent 编排。
|
||||
|
||||
Args:
|
||||
mode: route / sequential / debate / pipeline / graph
|
||||
question: 用户问题
|
||||
agents: Agent 配置列表
|
||||
on_llm_call: LLM 调用回调
|
||||
graph_nodes: graph 模式的节点定义(mode=graph 时必填)
|
||||
graph_edges: graph 模式的边定义(mode=graph 时必填)
|
||||
"""
|
||||
mode = mode.lower()
|
||||
if mode == "route":
|
||||
return await self._route(question, agents, on_llm_call)
|
||||
@@ -162,8 +173,12 @@ class AgentOrchestrator:
|
||||
return await self._debate(question, agents, on_llm_call)
|
||||
elif mode == "pipeline":
|
||||
return await self._pipeline(question, agents, on_llm_call)
|
||||
elif mode == "graph":
|
||||
if not graph_nodes:
|
||||
raise ValueError("graph 模式需要提供 graph_nodes 参数")
|
||||
return await self._graph(question, graph_nodes, graph_edges or [], on_llm_call)
|
||||
else:
|
||||
raise ValueError(f"不支持的编排模式: {mode},可选: route, sequential, debate, pipeline")
|
||||
raise ValueError(f"不支持的编排模式: {mode},可选: route, sequential, debate, pipeline, graph")
|
||||
|
||||
async def _route(
|
||||
self, question: str, agents: List[OrchestratorAgentConfig],
|
||||
@@ -500,11 +515,13 @@ class AgentOrchestrator:
|
||||
steps=steps,
|
||||
)
|
||||
|
||||
# ── 2. Executor:逐步骤执行 ──
|
||||
executor_cfg = agents[0] if agents else OrchestratorAgentConfig(
|
||||
id="executor", name="Executor",
|
||||
system_prompt="你是一个有用的AI助手。",
|
||||
)
|
||||
# ── 2. Executor:逐步骤执行(多 Agent 轮转分配)──
|
||||
executor_pool = agents if agents else [
|
||||
OrchestratorAgentConfig(
|
||||
id="executor", name="Executor",
|
||||
system_prompt="你是一个有用的AI助手。",
|
||||
)
|
||||
]
|
||||
|
||||
previous_output = "(尚无前序步骤)"
|
||||
execution_results = []
|
||||
@@ -514,6 +531,9 @@ class AgentOrchestrator:
|
||||
step_desc = step_info.get("description", f"步骤 {step_num}")
|
||||
step_expect = step_info.get("expected_output", "")
|
||||
|
||||
# 按步骤轮转分配 Agent:不同步骤可分配给不同 Agent(按专长匹配)
|
||||
executor_cfg = executor_pool[(step_num - 1) % len(executor_pool)]
|
||||
|
||||
executor_prompt = _EXECUTOR_STEP_PROMPT.format(
|
||||
original_question=question,
|
||||
plan_title=plan.get("plan_title", ""),
|
||||
@@ -555,6 +575,7 @@ class AgentOrchestrator:
|
||||
execution_results.append({
|
||||
"step": step_num,
|
||||
"description": step_desc,
|
||||
"agent": executor_cfg.name,
|
||||
"output": step_result.content,
|
||||
"error": step_result.error if not step_result.success else None,
|
||||
})
|
||||
@@ -562,7 +583,7 @@ class AgentOrchestrator:
|
||||
previous_output = step_result.content if step_result.success else f"(步骤{step_num}执行出错)"
|
||||
|
||||
if not step_result.success:
|
||||
logger.warning(f"Pipeline 步骤{step_num} 执行失败: {step_result.error}")
|
||||
logger.warning(f"Pipeline 步骤{step_num} ({executor_cfg.name}) 执行失败: {step_result.error}")
|
||||
|
||||
# ── 3. Reviewer:审查并交付 ──
|
||||
plan_steps_text = "\n".join(
|
||||
|
||||
@@ -192,8 +192,8 @@ async def run_orchestrator_node(
|
||||
|
||||
# 2. 解析编排模式
|
||||
mode = node_data.get("mode", "debate").lower()
|
||||
if mode not in ("route", "sequential", "debate", "pipeline"):
|
||||
return {"output": f"错误:不支持的编排模式 '{mode}',可选: route, sequential, debate, pipeline", "status": "error"}
|
||||
if mode not in ("route", "sequential", "debate", "pipeline", "graph"):
|
||||
return {"output": f"错误:不支持的编排模式 '{mode}',可选: route, sequential, debate, pipeline, graph", "status": "error"}
|
||||
|
||||
# 3. 解析 Agent 列表
|
||||
agent_ids = node_data.get("agents", [])
|
||||
@@ -266,33 +266,45 @@ async def run_orchestrator_node(
|
||||
temperature=0.3,
|
||||
),
|
||||
)
|
||||
|
||||
# graph 模式需要传递节点和边定义
|
||||
graph_nodes = node_data.get("graph_nodes") if mode == "graph" else None
|
||||
graph_edges = node_data.get("graph_edges") if mode == "graph" else None
|
||||
|
||||
result = await orchestrator.run(
|
||||
mode=mode,
|
||||
question=query,
|
||||
agents=agent_configs,
|
||||
on_llm_call=on_llm_invocation,
|
||||
graph_nodes=graph_nodes,
|
||||
graph_edges=graph_edges,
|
||||
)
|
||||
|
||||
# 6. 返回结构化结果
|
||||
meta: Dict[str, Any] = {
|
||||
"mode": result.mode,
|
||||
"agent_count": len(agent_configs),
|
||||
"steps": [
|
||||
{
|
||||
"agent_id": s.agent_id,
|
||||
"agent_name": s.agent_name,
|
||||
"input": s.input[:200] if s.input else "",
|
||||
"output": s.output[:500] if s.output else "",
|
||||
"iterations_used": s.iterations_used,
|
||||
"tool_calls_made": s.tool_calls_made,
|
||||
"error": s.error,
|
||||
}
|
||||
for s in result.steps
|
||||
],
|
||||
}
|
||||
if mode == "graph":
|
||||
meta["graph_node_count"] = len(graph_nodes) if graph_nodes else 0
|
||||
meta["graph_edge_count"] = len(graph_edges) if graph_edges else 0
|
||||
|
||||
return {
|
||||
"output": result.final_answer,
|
||||
"status": "success",
|
||||
"orchestrator_meta": {
|
||||
"mode": result.mode,
|
||||
"agent_count": len(agent_configs),
|
||||
"steps": [
|
||||
{
|
||||
"agent_id": s.agent_id,
|
||||
"agent_name": s.agent_name,
|
||||
"input": s.input[:200] if s.input else "",
|
||||
"output": s.output[:500] if s.output else "",
|
||||
"iterations_used": s.iterations_used,
|
||||
"tool_calls_made": s.tool_calls_made,
|
||||
"error": s.error,
|
||||
}
|
||||
for s in result.steps
|
||||
],
|
||||
},
|
||||
"orchestrator_meta": meta,
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user