Files
ai-device/intelligent_cabin/archive/tests/test_agent_cloud_route.py
2026-06-11 16:28:00 +08:00

133 lines
4.8 KiB
Python

from __future__ import annotations
import unittest
from app.plugins.base import PluginRegistry
from app.schemas.chat import ChatRequest
from app.schemas.debug import IntentCandidate, MatcherStageDebug, RoutingDebug
from app.schemas.intent import IntentDefinition
from app.services.agent_service import AgentService
from app.services.intent_registry import IntentRegistry
from app.services.planner import PlanningResult
from app.services.session_store import InMemorySessionStore
class _RouteToCloudRouter:
def route(self, text: str):
_ = text
return type(
"RouteResult",
(),
{
"intent": None,
"debug": RoutingDebug(
selected_intent="cabin_nav_to",
matched_stage="fusion",
decision="route_to_cloud",
decision_reason="local signal is not stable enough, routing to cloud planner",
confidence_grade="low",
stages=[
MatcherStageDebug(
stage="fusion",
accepted=False,
selected_intent="cabin_nav_to",
score=0.88,
reason="route to cloud",
candidates=[
IntentCandidate(intent_id="cabin_nav_to", score=0.88, reason="fusion", model_name="fusion"),
IntentCandidate(intent_id="cabin_play_music", score=0.75, reason="fusion", model_name="fusion"),
],
)
],
),
},
)()
def extract_slots(self, text: str, intent: IntentDefinition) -> dict[str, object]:
_ = (text, intent)
return {}
class _PlannerRejects:
def plan(self, text: str, intents: list[IntentDefinition], context: dict[str, object] | None = None) -> PlanningResult:
_ = (text, intents, context)
return PlanningResult(
accepted=False,
workflow_type="single",
model_name="qwen3.5-plus",
backend="dashscope",
reason="cloud planner could not produce a stable executable step",
)
class _PlannerOutOfScope:
def plan(self, text: str, intents: list[IntentDefinition], context: dict[str, object] | None = None) -> PlanningResult:
_ = (text, intents, context)
return PlanningResult(
accepted=False,
workflow_type="single",
model_name="qwen3.5-plus",
backend="dashscope",
reason="The provided intent catalog only contains cabin and service actions. There is no matching intent for ordering food via a third-party app action.",
)
def _intent(intent_id: str) -> IntentDefinition:
return IntentDefinition(
intent_id=intent_id,
plugin_id=f"mock.{intent_id}",
domain="cabin",
keywords=[],
examples=[],
)
class AgentCloudRouteTests(unittest.TestCase):
def test_route_to_cloud_returns_explicit_clarify_feedback_when_planner_does_not_accept(self) -> None:
service = AgentService(
intent_registry=IntentRegistry([_intent("cabin_nav_to"), _intent("cabin_play_music")]),
router=_RouteToCloudRouter(),
plugins=PluginRegistry(),
session_store=InMemorySessionStore(),
planner=_PlannerRejects(),
)
response = service.handle_chat(
ChatRequest(
session_id="sess_cloud_route",
user_id="user_1",
input_text="带我过去",
)
)
self.assertEqual(response.decision, "route_to_cloud")
self.assertEqual(response.reply_type, "clarify")
self.assertEqual(response.status, "route_to_cloud")
self.assertIn("请确认一下", response.reply_text)
def test_route_to_cloud_rejects_when_planner_marks_request_out_of_scope(self) -> None:
service = AgentService(
intent_registry=IntentRegistry([_intent("cabin_nav_to"), _intent("cabin_play_music")]),
router=_RouteToCloudRouter(),
plugins=PluginRegistry(),
session_store=InMemorySessionStore(),
planner=_PlannerOutOfScope(),
)
response = service.handle_chat(
ChatRequest(
session_id="sess_cloud_route_reject",
user_id="user_1",
input_text="去美团叫个外卖",
)
)
self.assertEqual(response.reply_type, "reject")
self.assertEqual(response.decision, "reject")
self.assertEqual(response.status, "rejected")
self.assertIn("做不了", response.reply_text)
if __name__ == "__main__":
unittest.main()