Refactor workflow agent and routing components for improved functionality

- Introduce WorkflowAgentStage to manage agent stage configurations and enhance interaction with the workflow engine.
- Implement WorkflowEdgeEvaluator for priority-aware edge evaluation, improving routing decisions based on conditions and user turns.
- Update WorkflowBrain to handle user turns and routing more effectively, ensuring agents cannot have only one default path.
- Enhance CallEndCoordinator to track speech events and manage call termination based on queued speech.
- Add new models and output handling for workflow interactions, improving clarity and maintainability.
- Update tests to validate the new routing logic and agent behavior under various scenarios.
This commit is contained in:
Xin Wang
2026-07-17 22:37:15 +08:00
parent 162a3d8bec
commit bdf3d3dd9c
23 changed files with 1374 additions and 475 deletions

View File

@@ -15,6 +15,8 @@ from loguru import logger
from models import AssistantConfig
from openai import AsyncOpenAI
from services.workflow.models import LLMRouteResult, RouteStatus
STAY_ON_CURRENT_NODE = "workflow_stay_on_current_node"
# Compatibility alias for callers saved before all source nodes supported LLM edges.
@@ -38,10 +40,10 @@ class WorkflowLLMRouter:
variables: dict[str, Any],
edge_name: Callable[[dict[str, Any]], str],
edge_description: Callable[[dict[str, Any]], str],
) -> str | None:
"""Return an edge function name, STAY, or None when routing failed."""
) -> LLMRouteResult:
"""Return a typed match, no-match or technical error."""
if not edges:
return STAY_ON_CURRENT_NODE
return LLMRouteResult(status=RouteStatus.NO_MATCH)
names = {edge_name(edge) for edge in edges}
stay_name = STAY_ON_CURRENT_NODE
@@ -116,16 +118,28 @@ class WorkflowLLMRouter:
tool_calls = response.choices[0].message.tool_calls or []
if not tool_calls:
logger.warning("Workflow 路由 LLM 未返回函数调用,留在当前节点")
return STAY_ON_CURRENT_NODE
return LLMRouteResult(
status=RouteStatus.ERROR,
error="路由模型没有返回函数调用",
)
selected = str(tool_calls[0].function.name or "")
if selected == stay_name:
return STAY_ON_CURRENT_NODE
return LLMRouteResult(status=RouteStatus.NO_MATCH)
if selected not in names:
logger.warning(f"Workflow 路由 LLM 返回未知函数:{selected}")
return STAY_ON_CURRENT_NODE
return selected
return LLMRouteResult(
status=RouteStatus.ERROR,
error=f"路由模型返回未知函数:{selected}",
)
return LLMRouteResult(
status=RouteStatus.MATCHED,
function_name=selected,
)
except Exception as exc: # noqa: BLE001 - routing failure must not end the call
logger.warning(f"Workflow LLM 边判断失败,留在当前节点:{exc}")
return None
return LLMRouteResult(
status=RouteStatus.ERROR,
error=f"大模型路由失败:{type(exc).__name__}",
)
finally:
await client.close()