Роутер работает нормально в process v2

This commit is contained in:
2026-04-07 14:09:51 +03:00
parent 0a25e42ea1
commit 8b7b72967e
1746 changed files with 216414 additions and 14037 deletions
@@ -2,9 +2,9 @@ from __future__ import annotations
import json
from app.modules.agent.intent_router_v2 import ConversationState, IntentRouterV2
from app.modules.agent.intent_router_v2.intent.classifier import IntentClassifierV2
from app.modules.agent.intent_router_v2.intent.llm_disambiguator import DocsLlmDisambiguator
from app.core.agent.intent_router import ConversationState, IntentRouterV2
from app.core.agent.intent_router.docs_mvp.llm_classifier import DocsMvpLlmClassifier
from app.core.agent.intent_router.intent.classifier import IntentClassifierV2
from tests.unit_tests.rag.intent_router_testkit import repo_context
@@ -21,75 +21,62 @@ class FakeLlm:
return self.response
def test_technical_query_keeps_deterministic_routing_without_llm_call() -> None:
llm = FakeLlm('{"sub_intent":"GENERIC_QA","reason":"unused","confidence":"low"}')
router = IntentRouterV2(
def _router(llm: FakeLlm) -> IntentRouterV2:
return IntentRouterV2(
classifier=IntentClassifierV2(),
llm_disambiguator=DocsLlmDisambiguator(llm),
docs_llm_classifier=DocsMvpLlmClassifier(llm),
enable_llm_disambiguation=True,
)
result = router.route("Объясни endpoint /health", ConversationState(), repo_context())
assert result.query_plan.sub_intent == "API_METHOD_EXPLAIN"
assert result.is_ambiguous is False
assert result.routing_mode == "deterministic"
def test_docs_technical_query_keeps_deterministic_routing_without_llm_call() -> None:
llm = FakeLlm("{}")
result = _router(llm).route("Объясни endpoint /health", ConversationState(), repo_context())
assert result.docs_routing is not None
assert result.docs_routing.sub_intent == "API_METHOD_EXPLAIN"
assert result.docs_routing.routing_mode == "deterministic"
assert result.llm_router_used is False
assert llm.calls == []
def test_ambiguous_query_can_be_resolved_by_llm() -> None:
llm = FakeLlm('{"sub_intent":"ENTITY_EXPLAIN","reason":"runtime health is a concept/entity here","confidence":"medium"}')
router = IntentRouterV2(
classifier=IntentClassifierV2(),
llm_disambiguator=DocsLlmDisambiguator(llm),
enable_llm_disambiguation=True,
llm = FakeLlm(
json.dumps(
{
"intent": "DOCS_DISCOVERY",
"sub_intent": "FIND_DOCUMENTS_BY_DOMAIN",
"confidence": 0.83,
"anchors": {"entity_name": "health", "doc_query": "документация по health"},
"scope": {"level": "domain"},
"reason_short": "health here is a docs topic",
},
ensure_ascii=False,
)
)
result = _router(llm).route("документация по health", ConversationState(), repo_context())
result = router.route("Объясни runtime health", ConversationState(), repo_context())
assert result.is_ambiguous is True
assert result.routing_mode == "llm_disambiguation"
assert result.docs_routing is not None
assert result.docs_routing.routing_mode == "llm_assisted"
assert result.docs_routing.sub_intent == "FIND_DOCUMENTS_BY_DOMAIN"
assert result.retrieval_plan is not None
assert result.retrieval_plan.plan_id == "docs_find_documents_by_domain_v1"
assert result.llm_router_used is True
assert result.deterministic_selected_sub_intent
assert result.llm_router_selected_sub_intent == "ENTITY_EXPLAIN"
assert result.query_plan.sub_intent == "ENTITY_EXPLAIN"
def test_ambiguous_query_falls_back_to_deterministic_when_llm_fails() -> None:
def test_ambiguous_query_falls_back_to_general_docs_when_llm_fails() -> None:
llm = FakeLlm("{}", fail=True)
router = IntentRouterV2(
classifier=IntentClassifierV2(),
llm_disambiguator=DocsLlmDisambiguator(llm),
enable_llm_disambiguation=True,
)
result = _router(llm).route("health документация", ConversationState(), repo_context())
result = router.route("Как работает health check runtime?", ConversationState(), repo_context())
assert result.is_ambiguous is True
assert result.routing_mode == "deterministic_fallback"
assert result.llm_router_used is False
assert result.llm_router_error == "llm unavailable"
assert result.query_plan.sub_intent == result.deterministic_selected_sub_intent
assert result.docs_routing is not None
assert result.docs_routing.routing_mode == "llm_fallback"
assert result.docs_routing.sub_intent == "GENERAL_DOCS_QA"
assert result.retrieval_plan is not None
assert result.retrieval_plan.plan_id == "docs_general_docs_qa_v1"
def test_overview_query_stays_in_generic_qa() -> None:
llm = FakeLlm('{"sub_intent":"GENERIC_QA","reason":"overview query","confidence":"high"}')
router = IntentRouterV2(
classifier=IntentClassifierV2(),
llm_disambiguator=DocsLlmDisambiguator(llm),
enable_llm_disambiguation=True,
)
def test_llm_classifier_rejects_unknown_labels() -> None:
llm = FakeLlm(json.dumps({"intent": "DOCS_QA", "sub_intent": "MADE_UP"}))
classifier = DocsMvpLlmClassifier(llm)
result = router.route("Какая структура документации?", ConversationState(), repo_context())
assert result.is_ambiguous is False or result.query_plan.sub_intent == "GENERIC_QA"
assert result.intent == "GENERAL_QA"
assert result.query_plan.sub_intent == "GENERIC_QA"
def test_llm_disambiguator_rejects_unknown_labels() -> None:
llm = FakeLlm(json.dumps({"sub_intent": "MADE_UP", "reason": "bad", "confidence": "high"}))
disambiguator = DocsLlmDisambiguator(llm)
assert disambiguator.choose({"query": "test"}) is None
assert classifier.classify({"query": "test"}) is None