PMFlow/backend/tests/test_adaptive_rag_mainline_...

6955 lines
258 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json
import pytest
import time
from datetime import datetime
from types import SimpleNamespace
from app.config.ai_prompts import PROMPT_AI_PMO_QA, PROMPT_RAG_QUERY_SEMANTICS
from app.services.adaptive_rag_service.mixin_answer_entry import AdaptiveRAGAnswerEntryMixin
from app.services.adaptive_rag_service.mixin_answer_mainline import AdaptiveRAGAnswerMainlineMixin
from app.services.adaptive_rag_service.mixin_answer_payload import AdaptiveRAGAnswerPayloadMixin
from app.services.adaptive_rag_service.mixin_answer_precheck import AdaptiveRAGAnswerPrecheckMixin
from app.services.adaptive_rag_service.mixin_answer_retrieval import AdaptiveRAGAnswerRetrievalMixin
from app.services.adaptive_rag_service.mixin_conversation_utils_a_p1 import AdaptiveRAGConversationUtilsAMixinP1
from app.services.adaptive_rag_service.mixin_deep_guard_answer import AdaptiveRAGDeepGuardAnswerMixin
from app.services.adaptive_rag_service.mixin_deep_guard_rules import AdaptiveRAGDeepGuardRulesMixin
from app.services.adaptive_rag_service.mixin_core_intent import AdaptiveRAGCoreIntentMixin
from app.services.adaptive_rag_service.mixin_deterministic_query_core import (
AdaptiveRAGDeterministicQueryCoreMixin,
)
from app.services.adaptive_rag_service.mixin_deterministic_query_count import (
AdaptiveRAGDeterministicQueryCountMixin,
)
from app.services.adaptive_rag_service.mixin_deterministic_query_list import (
AdaptiveRAGDeterministicQueryListMixin,
)
from app.services.adaptive_rag_service.mixin_manifest_feature_p2 import AdaptiveRAGManifestFeatureMixinP2
from app.services.adaptive_rag_service.mixin_manifest_feature_p1 import AdaptiveRAGManifestFeatureMixinP1
from app.services.adaptive_rag_service.mixin_multistep_core import AdaptiveRAGMultiStepCoreMixin
from app.services.adaptive_rag_service.mixin_multistep_flow import AdaptiveRAGMultiStepFlowMixin
from app.services.adaptive_rag_service.mixin_query_route_gateway import AdaptiveRAGQueryRouteGatewayMixin
from app.services.adaptive_rag_service.mixin_requirement_ack_core import AdaptiveRAGRequirementAckCoreMixin
from app.services.adaptive_rag_service.mixin_retrieval_router_db import AdaptiveRAGRetrievalRouterDBMixin
from app.services.adaptive_rag_service.mixin_retrieval_vector import AdaptiveRAGRetrievalVectorMixin
from app.services.adaptive_rag_service.mixin_followup_anchor import FollowupAnchorResolution
from app.services.adaptive_rag_service.mixin_followup_anchor import AdaptiveRAGFollowupAnchorMixin
from app.services.adaptive_rag_service.mixin_fast_answer_project_main import AdaptiveRAGFastAnswerProjectMainMixin
from app.services.adaptive_rag_service.mixin_fast_answer_project_utils import AdaptiveRAGFastAnswerProjectUtilsMixin
from app.services.adaptive_rag_service.internal_query_context import InternalContextPacket
from app.services.adaptive_rag_service.mixin_target_resolution import AdaptiveRAGTargetResolutionMixin
from app.services.adaptive_rag_service.shared_part_02 import RetrievedItem
from app.services.adaptive_rag_service.shared_part_02 import ACTION_MODE_READ, DEEP_RETRIEVAL_STEPS, DEEP_VECTOR_TOP_K
from app.services.ai_pmo.workflow_semantic_planner import WorkflowSemanticPlanner
def _make_internal_context_packet(
*,
query_type: str,
answer_contract: str,
target_ref: str | None = None,
) -> InternalContextPacket:
target_resolution = {}
if target_ref:
target_resolution = {
"target_entity_type": "project",
"target_ref": target_ref,
"resolution_mode": "deterministic",
"confidence": 0.96,
}
return InternalContextPacket.model_validate(
{
"packet_version": "v1",
"question": "",
"scope": {
"tenant_id": 1,
"project_id": None,
"session_id": 11,
"conversation_scope_key": None,
"reply_to_message_id": None,
"root_message_id": None,
},
"route_decision": {
"route_mode": "internal",
"effective_source_policy": "internal",
},
"operation_contract": {
"query_type": query_type,
},
"target_resolution": target_resolution,
"query_plan": {
"plan_version": "v2",
"query_type": query_type,
"entity_type": "project",
"answer_contract": answer_contract,
"target_ref": target_ref,
"filters": [],
},
"executor_summary": {},
"verifier_summary": {},
"uncertainties": [],
}
)
class _FakeAdaptiveRAGService(
AdaptiveRAGAnswerEntryMixin,
AdaptiveRAGAnswerMainlineMixin,
):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 9
self.ack_calls = 0
self.base_calls = 0
self.base_kwargs: dict[str, object] = {}
def _normalize_thinking_mode(self, thinking_mode: str) -> str:
return "deep" if str(thinking_mode or "").strip().lower() == "deep" else "normal"
async def _prepare_answer_runtime(self, **kwargs):
clean_q = str(kwargs.get("clean_q") or "").strip()
action_mode = str(kwargs.get("action_mode") or "").strip().lower()
return {
"session_id": 101,
"turn_index": 2,
"context_session_id": 101,
"conversation": [],
"state_row": None,
"resolved_question": clean_q,
"effective_q": clean_q,
"rewrite_meta": {"mode": "direct"},
"query_type": "explain",
"effective_action_mode": action_mode,
"anchor_resolution": None,
}
async def _handle_ack_first_requirement(self, **kwargs):
self.ack_calls += 1
_ = kwargs
return {"answer": "ack-required", "processing_stage": "ack_only"}
async def _execute_base_answer_mainline(self, **kwargs):
self.base_calls += 1
self.base_kwargs = dict(kwargs)
return {"answer": "base-answer", "processing_stage": "qa"}
@pytest.mark.asyncio
async def test_answer_entry_read_mainline_skips_requirement_ack() -> None:
service = _FakeAdaptiveRAGService()
result = await service.answer_question(
question="现在有哪些阻塞?",
asked_by=1,
asked_via="pmflow_manual",
action_mode="read",
sync_requirement=True,
)
assert result["processing_stage"] == "qa"
assert service.ack_calls == 0
assert service.base_calls == 1
@pytest.mark.asyncio
async def test_answer_entry_write_mode_uses_requirement_ack_gate() -> None:
service = _FakeAdaptiveRAGService()
result = await service.answer_question(
question="请同步写入一条风险",
asked_by=1,
asked_via="pmflow_manual",
action_mode="write",
sync_requirement=True,
)
assert result["processing_stage"] == "ack_only"
assert service.ack_calls == 1
assert service.base_calls == 0
@pytest.mark.asyncio
async def test_answer_entry_high_accuracy_channel_respects_requested_normal_mode() -> None:
service = _FakeAdaptiveRAGService()
result = await service.answer_question(
question="最近有哪些项目?",
asked_by=1,
asked_via="pmflow",
thinking_mode="normal",
sync_requirement=True,
)
assert result["processing_stage"] == "qa"
assert service.ack_calls == 0
assert service.base_calls == 1
assert service.base_kwargs["active_thinking_mode"] == "normal"
assert service.base_kwargs["deep_thinking"] is False
assert int(service.base_kwargs["deep_retrieval_steps"]) == DEEP_RETRIEVAL_STEPS
assert int(service.base_kwargs["deep_vector_top_k"]) == DEEP_VECTOR_TOP_K
@pytest.mark.asyncio
async def test_answer_entry_forwards_consultant_mode_preference_to_mainline() -> None:
service = _FakeAdaptiveRAGService()
result = await service.answer_question(
question="这个方案怎么做更稳妥?",
asked_by=1,
asked_via="pmflow",
thinking_mode="normal",
consultant_mode_preference="advise",
)
assert result["processing_stage"] == "qa"
assert service.base_calls == 1
assert service.base_kwargs["consultant_mode_preference"] == "advise"
@pytest.mark.asyncio
async def test_answer_entry_mixed_request_skips_requirement_ack_gate() -> None:
service = _FakeAdaptiveRAGService()
result = await service.answer_question(
question="现在进展如何,并且新增任务确认流",
asked_by=1,
asked_via="pmflow_manual",
action_mode="read_write",
sync_requirement=True,
message_intent="mixed",
)
assert result["processing_stage"] == "qa"
assert service.ack_calls == 0
assert service.base_calls == 1
assert service.base_kwargs["active_thinking_mode"] == "normal"
assert service.base_kwargs["deep_thinking"] is False
@pytest.mark.asyncio
async def test_fast_project_progress_answer_skips_signal_source_inventory_questions() -> None:
class _FakeService(AdaptiveRAGFastAnswerProjectMainMixin):
async def _resolve_project_scope_for_question(self, **kwargs): # noqa: ANN001
_ = kwargs
return 81, "测试产能警告", "测试产能警告"
async def _build_project_progress_snapshot(self, **kwargs): # noqa: ANN001
_ = kwargs
raise AssertionError("signal source inventory question should bypass project progress fast answer")
service = _FakeService()
result = await service._try_fast_project_progress_answer(
clean_q="测试产能警告这个项目现在是什么情况?",
project_id=81,
query_semantics={
"status_focus": "progress",
"subject_focus": "project",
"interaction_level": "recommendation",
"goal_kind": "recommendation",
"resource_role": "signal_source",
"expected_answer_shape": "inventory",
},
)
assert result is None
@pytest.mark.asyncio
async def test_answer_entry_feishu_write_mode_still_goes_base_mainline() -> None:
service = _FakeAdaptiveRAGService()
result = await service.answer_question(
question="请在飞书里补一条风险",
asked_by=1,
asked_via="feishu",
action_mode="write",
sync_requirement=True,
)
assert result["processing_stage"] == "qa"
assert service.ack_calls == 0
assert service.base_calls == 1
assert service.base_kwargs["active_thinking_mode"] == "normal"
assert service.base_kwargs["deep_thinking"] is False
assert int(service.base_kwargs["deep_retrieval_steps"]) == DEEP_RETRIEVAL_STEPS
assert int(service.base_kwargs["deep_vector_top_k"]) == DEEP_VECTOR_TOP_K
@pytest.mark.asyncio
async def test_requirement_ack_auto_mode_respects_structured_query_bundle(monkeypatch: pytest.MonkeyPatch) -> None:
class _ModeService(AdaptiveRAGRequirementAckCoreMixin):
pass
async def _fake_aplan_message(cls, *, message_text: str, source_system: str, metadata=None):
_ = (cls, message_text, source_system, metadata)
return WorkflowSemanticPlanner.deserialize_bundle(
{
"bundle_id": "semantic-test",
"semantic_version": "v1",
"source_system": "adaptive_rag_ack",
"primary_workflow": "query_flow",
"workflows": [
{
"workflow_type": "query_flow",
"workflow_action": "answer",
"target_scope": "global",
"operation_codes": ["query.answer"],
"requires_confirmation": False,
"confidence": 0.91,
"clarification_needed": False,
"metadata": {},
}
],
"message_gate": "auto",
"reply_contract": {"mode": "text", "template_key": "workflow_bundle", "summary": "query_flow"},
"diagnostics": {"message_intent": "question"},
}
)
monkeypatch.setattr(WorkflowSemanticPlanner, "aplan_message", classmethod(_fake_aplan_message))
mode = await _ModeService._resolve_action_mode_async(
requested_mode="auto",
question="先不要创建任务,告诉我当前进展和风险",
effective_question="先不要创建任务,告诉我当前进展和风险",
asked_via="pmflow_manual",
)
assert mode == ACTION_MODE_READ
def test_query_runtime_planner_prefers_fast_path_for_list_question_even_if_requested_deep() -> None:
class _FakePlannerService(AdaptiveRAGAnswerMainlineMixin):
pass
service = _FakePlannerService()
decision = service._plan_query_runtime(
question="现在有哪些项目?",
effective_question="现在有哪些项目?",
query_type="list",
requested_thinking_mode="deep",
enforce_scene_prompt_only=False,
)
assert decision.answer_mode == "fast_path"
assert decision.thinking_mode == "normal"
assert decision.allow_fast_path is True
def test_query_runtime_planner_bypasses_fast_path_when_consultant_mode_preference_present() -> None:
class _FakePlannerService(AdaptiveRAGAnswerMainlineMixin):
pass
service = _FakePlannerService()
decision = service._plan_query_runtime(
question="现在有哪些项目?",
effective_question="现在有哪些项目?",
query_type="list",
requested_thinking_mode="normal",
enforce_scene_prompt_only=False,
consultant_mode_preference="advise",
)
assert decision.answer_mode == "retrieval_normal"
assert decision.thinking_mode == "normal"
assert decision.allow_fast_path is False
def test_query_runtime_planner_ignores_legacy_consultant_mode_for_internal_existence_query() -> None:
class _FakePlannerService(AdaptiveRAGAnswerMainlineMixin):
pass
service = _FakePlannerService()
decision = service._plan_query_runtime(
question="当前系统内是否有为采购经理提出的需求?",
effective_question="当前系统内是否有为采购经理提出的需求?",
query_type="existence",
requested_thinking_mode="normal",
enforce_scene_prompt_only=False,
consultant_mode_preference="analytical",
)
assert decision.answer_mode == "fast_path"
assert decision.thinking_mode == "normal"
assert decision.allow_fast_path is True
def test_query_runtime_planner_prefers_fast_path_for_existence_question() -> None:
class _FakePlannerService(AdaptiveRAGAnswerMainlineMixin):
pass
service = _FakePlannerService()
decision = service._plan_query_runtime(
question="系统里有没有A股项目?",
effective_question="系统里有没有A股项目?",
query_type="existence",
requested_thinking_mode="normal",
enforce_scene_prompt_only=False,
)
assert decision.answer_mode == "fast_path"
assert decision.thinking_mode == "normal"
assert decision.allow_fast_path is True
def test_internal_query_plan_builds_project_existence_contract() -> None:
class _FakePlannerService(
AdaptiveRAGAnswerMainlineMixin,
AdaptiveRAGFastAnswerProjectUtilsMixin,
):
pass
service = _FakePlannerService()
plan = service._build_internal_query_plan(
question="系统里有没有A股项目?",
project_id=None,
query_semantics={
"query_type": "existence",
"scope_hint": "global",
"effective_source_policy": "internal",
"goal_kind": "status_lookup",
"target_scope": "current_project",
"resource_role": "project_object",
"project_binding": 17,
},
)
assert plan is not None
assert plan["query_type"] == "existence"
assert plan["entity_type"] == "project"
assert plan["answer_contract"] == "yes_no_with_evidence"
assert plan["retrieval_policy"]["facts_first"] is True
assert plan["filters"] == []
def test_internal_query_plan_builds_project_inventory_contract_for_recipe_system_inputs_question() -> None:
class _FakePlannerService(
AdaptiveRAGAnswerMainlineMixin,
AdaptiveRAGFastAnswerProjectUtilsMixin,
):
pass
service = _FakePlannerService()
plan = service._build_internal_query_plan(
question="健身食谱推荐系统现在主要靠哪些输入在跑?",
project_id=None,
query_semantics={
"query_type": "status",
"scope_hint": "project",
"effective_source_policy": "internal",
"goal_kind": "status_lookup",
"target_scope": "explicit_project",
"resource_role": "project_object",
"expected_answer_shape": "inventory",
"project_binding": 31,
},
target_resolution={
"target_entity_type": "project",
"target_ref": "project:31",
"resolution_mode": "deterministic",
"confidence": 0.95,
},
)
assert plan is not None
assert plan["query_type"] == "status"
assert plan["entity_type"] == "project"
assert plan["answer_contract"] == "entity_snapshot"
assert plan["target_ref"] == "project:31"
assert plan["filters"] == [
{
"field": "project_id",
"operator": "equals",
"value": 31,
"value_source": "target_resolution",
}
]
def test_operation_contract_preserves_structured_existence_before_target_resolution() -> None:
class _FakeService(
AdaptiveRAGTargetResolutionMixin,
AdaptiveRAGAnswerMainlineMixin,
):
pass
service = _FakeService()
contract = service._build_operation_contract(
question="帮我看看系统里面有没有开票系统。",
query_semantics={
"query_type": "existence",
"effective_source_policy": "internal",
"object_mentions": ["开票系统"],
},
)
assert contract["query_type"] == "existence"
assert contract["answer_contract"] == "yes_no_with_evidence"
assert contract["object_mentions"] == ["开票系统"]
def test_operation_contract_does_not_promote_model_config_reference_from_referenced_objects_only() -> None:
class _FakeService(
AdaptiveRAGTargetResolutionMixin,
AdaptiveRAGAnswerMainlineMixin,
):
pass
service = _FakeService()
contract = service._build_operation_contract(
question="我们系统当前接的是哪个模型配置?",
query_semantics={
"query_type": "existence",
"effective_source_policy": "internal",
"object_mentions": ["模型配置"],
"query_profile": {
"referenced_objects": ["system_config", "model_routing"],
},
},
)
assert contract["query_type"] == "existence"
assert contract["answer_contract"] == "yes_no_with_evidence"
assert contract["object_mentions"] == ["模型配置"]
def test_operation_contract_promotes_business_frame_config_role_to_status_without_object_list() -> None:
class _FakeService(
AdaptiveRAGTargetResolutionMixin,
AdaptiveRAGAnswerMainlineMixin,
):
pass
service = _FakeService()
contract = service._build_operation_contract(
question="当前模型配置是啥?",
query_semantics={
"query_type": "unknown",
"effective_source_policy": "internal",
"object_mentions": ["当前模型配置"],
"resource_role": "config",
"goal_kind": "status_lookup",
"expected_answer_shape": "bounded_explanation",
},
)
assert contract["query_type"] == "status"
assert contract["answer_contract"] == "entity_snapshot"
assert contract["resource_role"] == "config"
@pytest.mark.asyncio
async def test_internal_target_resolution_prefers_project_candidate_for_existence_query() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
async def _collect_internal_target_candidates(self, **kwargs):
_ = kwargs
return [
{
"target_entity_type": "project",
"target_ref": "project:6",
"resolved_label": "自动开票系统",
"score": 0.96,
"source_kind": "semantic_facts",
},
{
"target_entity_type": "feature",
"target_ref": "feature:/invoice",
"resolved_label": "开票系统",
"score": 0.82,
"source_kind": "feature_catalog",
},
]
service = _FakeService()
resolution = await service._resolve_internal_target(
question="帮我看看系统里面有没有开票系统。",
project_id=None,
query_semantics={"effective_source_policy": "internal"},
system_snapshot={},
operation_contract={
"query_type": "existence",
"answer_contract": "yes_no_with_evidence",
"object_mentions": ["开票系统"],
},
)
assert resolution["target_entity_type"] == "project"
assert resolution["target_ref"] == "project:6"
assert resolution["resolved_label"] == "自动开票系统"
assert resolution["resolution_mode"] == "deterministic"
@pytest.mark.asyncio
async def test_internal_target_resolution_prefers_session_followup_project_binding_from_business_frame() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
async def _collect_internal_target_candidates(self, **kwargs):
_ = kwargs
return []
service = _FakeService()
resolution = await service._resolve_internal_target(
question="继续围绕刚才那个项目说。",
project_id=None,
query_semantics={
"effective_source_policy": "internal",
"goal_kind": "bounded_explanation",
"target_scope": "current_project",
"resource_role": "project_object",
"expected_answer_shape": "bounded_explanation",
"project_binding": 123,
"session_followup_context": {
"rewrite_mode": "state_subject",
"last_subject": "采购经理每日实时库存上报服务",
"last_entity_ids": [123],
},
},
system_snapshot={},
operation_contract={
"query_type": "status",
"answer_contract": "status_summary",
"object_mentions": [],
"goal_kind": "bounded_explanation",
"target_scope": "current_project",
"resource_role": "project_object",
"project_binding": 123,
},
)
assert resolution["target_entity_type"] == "project"
assert resolution["target_ref"] == "project:123"
assert resolution["resolved_label"] == "采购经理每日实时库存上报服务"
assert resolution["binding_source"] == "session_followup_context"
@pytest.mark.asyncio
async def test_internal_target_resolution_keeps_signal_domain_for_project_scoped_followup() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
async def _collect_internal_target_candidates(self, **kwargs):
_ = kwargs
return []
service = _FakeService()
resolution = await service._resolve_internal_target(
question="继续看刚才那个项目里的信号。",
project_id=None,
query_semantics={
"effective_source_policy": "internal",
"goal_kind": "status_lookup",
"target_scope": "current_project",
"resource_role": "signal",
"expected_answer_shape": "inventory",
"project_binding": 123,
"session_followup_context": {
"rewrite_mode": "state_subject",
"last_subject": "采购经理每日实时库存上报服务",
"last_entity_ids": [123],
},
},
system_snapshot={},
operation_contract={
"query_type": "list",
"answer_contract": "entity_list",
"object_mentions": [],
"goal_kind": "status_lookup",
"target_scope": "current_project",
"resource_role": "signal",
"project_binding": 123,
},
)
assert resolution["target_entity_type"] == "signal"
assert resolution["target_ref"] == "domain:signal"
assert resolution["binding_source"] == "session_followup_context"
@pytest.mark.asyncio
async def test_internal_target_resolution_requires_business_frame_for_session_followup_project_binding() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
async def _collect_internal_target_candidates(self, **kwargs):
_ = kwargs
return []
service = _FakeService()
resolution = await service._resolve_internal_target(
question="围绕“采购经理每日实时库存上报服务”回答:那个需求是否存在系统?",
project_id=None,
query_semantics={
"effective_source_policy": "internal",
"subject_focus": "project",
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"referenced_objects": ["project_object"],
},
"session_followup_context": {
"rewrite_mode": "state_subject",
"last_subject": "采购经理每日实时库存上报服务",
"last_entity_ids": [123],
},
},
system_snapshot={},
operation_contract={
"query_type": "existence",
"answer_contract": "yes_no_with_evidence",
"object_mentions": ["采购经理每日实时库存上报服务"],
},
)
assert resolution["target_entity_type"] == "unknown"
assert resolution["target_ref"] is None
assert resolution["resolution_mode"] == "clarify"
def test_config_target_candidates_ignore_referenced_objects_without_business_frame() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
pass
service = _FakeService()
rows = service._collect_config_target_candidates(
query_semantics={
"query_profile": {
"referenced_objects": ["system_config", "model_routing"],
}
},
operation_contract={
"object_mentions": ["当前模型配置"],
},
)
assert rows == []
def test_config_target_candidates_expand_catalog_for_generic_config_domain() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
pass
service = _FakeService()
rows = service._collect_config_target_candidates(
query_semantics={
"resource_role": "config",
"goal_kind": "status_lookup",
},
operation_contract={
"object_mentions": ["当前模型配置"],
"resource_role": "config",
},
)
assert {str(item.get("target_ref") or "") for item in rows} == {
"config:model_routing",
"config:mcp_template_center",
}
@pytest.mark.asyncio
async def test_resolve_internal_target_returns_clarify_for_generic_config_domain_catalog() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
def __init__(self) -> None:
self.tenant_id = 1
async def _collect_semantic_fact_target_candidates(self, **kwargs):
_ = kwargs
return []
async def _collect_project_target_candidates(self, **kwargs):
_ = kwargs
return []
async def _collect_kg_target_candidates(self, **kwargs):
_ = kwargs
return []
service = _FakeService()
resolution = await service._resolve_internal_target(
question="系统里现在有哪些配置?",
project_id=None,
query_semantics={
"effective_source_policy": "internal",
"business_frame": {
"goal_kind": "status_lookup",
"target_scope": "global",
"resource_role": "config",
"source_kind": "internal",
"expected_answer_shape": "bounded_explanation",
"conversation_posture": "business_operating",
},
},
system_snapshot={},
operation_contract={
"query_type": "status",
"answer_contract": "entity_snapshot",
"object_mentions": ["系统配置"],
},
)
assert resolution["resolution_mode"] == "clarify"
assert {str(item.get("target_ref") or "") for item in list(resolution.get("candidate_summary") or [])} == {
"config:model_routing",
"config:mcp_template_center",
}
def test_config_target_candidates_accept_explicit_model_routing_object_binding() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
pass
service = _FakeService()
rows = service._collect_config_target_candidates(
query_semantics={
"business_frame": {
"goal_kind": "status_lookup",
"target_scope": "global",
"resource_role": "config",
"source_kind": "internal",
"expected_answer_shape": "bounded_explanation",
"conversation_posture": "business_operating",
"object_binding": "config:model_routing",
}
},
operation_contract={
"object_mentions": ["当前模型配置"],
},
)
assert len(rows) == 1
assert rows[0]["target_ref"] == "config:model_routing"
assert rows[0]["resolved_label"] == "当前模型配置"
def test_config_target_candidates_accept_explicit_mcp_config_object_binding() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
pass
service = _FakeService()
rows = service._collect_config_target_candidates(
query_semantics={
"business_frame": {
"goal_kind": "status_lookup",
"target_scope": "global",
"resource_role": "config",
"source_kind": "internal",
"expected_answer_shape": "bounded_explanation",
"conversation_posture": "business_operating",
"object_binding": "config:mcp_template_center",
}
},
operation_contract={
"object_mentions": ["MCP 配置"],
},
)
assert len(rows) == 1
assert rows[0]["target_ref"] == "config:mcp_template_center"
assert rows[0]["resolved_label"] == "MCP 配置"
def test_internal_answer_contract_guard_payload_builds_internal_target_selection_protocol() -> None:
class _FakeService(AdaptiveRAGAnswerPayloadMixin):
pass
service = _FakeService()
payload = service._build_internal_answer_contract_guard_payload(
query_type="status",
reason_code="target_resolution_clarify",
missing_fields=["target_resolution"],
target_resolution={
"target_entity_type": "unknown",
"target_ref": None,
"resolved_label": None,
"resolution_mode": "clarify",
"candidate_summary": [
{
"target_entity_type": "config",
"target_ref": "config:model_routing",
"resolved_label": "模型路由配置",
"score": 0.88,
"source_kind": "system_config",
},
{
"target_entity_type": "config",
"target_ref": "config:mcp_template_center",
"resolved_label": "MCP 配置",
"score": 0.87,
"source_kind": "system_config",
},
],
},
)
assert payload["answer_mode"] == "clarify"
assert "模型路由配置" in str(payload["answer"])
assert "MCP 配置" in str(payload["answer"])
assert payload["clarification_protocol"]["kind"] == "internal_target_selection"
assert payload["clarification_protocol"]["option_map"] == {
"A": "config:model_routing",
"B": "config:mcp_template_center",
}
def test_internal_answer_contract_guard_payload_builds_generic_internal_target_selection_protocol() -> None:
class _FakeService(AdaptiveRAGAnswerPayloadMixin):
pass
service = _FakeService()
payload = service._build_internal_answer_contract_guard_payload(
query_type="status",
reason_code="target_resolution_clarify",
missing_fields=["target_resolution"],
target_resolution={
"target_entity_type": "unknown",
"target_ref": None,
"resolved_label": None,
"resolution_mode": "clarify",
"candidate_summary": [
{
"target_entity_type": "project",
"target_ref": "project:12",
"resolved_label": "智能现金流管家",
"score": 0.88,
"source_kind": "project_db",
},
{
"target_entity_type": "feature",
"target_ref": "feature:cash_forecast",
"resolved_label": "现金流预测模块",
"score": 0.84,
"source_kind": "feature_catalog",
},
],
},
)
assert "智能现金流管家" in str(payload["answer"])
assert "现金流预测模块" in str(payload["answer"])
options = list(payload["clarification_protocol"]["options"])
assert options[0]["query_semantics_overrides"]["business_frame"]["project_binding"] == 12
assert options[1]["query_semantics_overrides"]["business_frame"]["object_binding"] == "feature:cash_forecast"
def test_semantic_filter_target_uses_business_frame_project_binding_without_subject_focus() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
pass
service = _FakeService()
target = service._build_semantic_filter_target(
query_semantics={
"goal_kind": "status_lookup",
"target_scope": "current_project",
"resource_role": "project_object",
"project_binding": 81,
},
operation_contract={
"query_type": "status",
"answer_contract": "status_summary",
"object_mentions": [],
"project_binding": 81,
"resource_role": "project_object",
},
)
assert target is not None
assert target["target_entity_type"] == "project"
assert target["target_ref"] == "project:81"
assert target["resolved_label"] is None
assert target["resolution_mode"] == "semantic_filter"
def test_semantic_filter_target_uses_task_role_without_collapsing_to_project() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
pass
service = _FakeService()
target = service._build_semantic_filter_target(
query_semantics={
"goal_kind": "status_lookup",
"target_scope": "current_project",
"resource_role": "task",
"project_binding": 81,
"expected_answer_shape": "inventory",
},
operation_contract={
"query_type": "list",
"answer_contract": "entity_list",
"object_mentions": [],
"project_binding": 81,
"resource_role": "task",
},
)
assert target is not None
assert target["target_entity_type"] == "task"
assert target["target_ref"] == "domain:task"
assert target["resolution_mode"] == "semantic_filter"
def test_semantic_filter_target_uses_signal_role_without_collapsing_to_project() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
pass
service = _FakeService()
target = service._build_semantic_filter_target(
query_semantics={
"goal_kind": "status_lookup",
"target_scope": "current_project",
"resource_role": "signal",
"project_binding": 81,
"expected_answer_shape": "inventory",
},
operation_contract={
"query_type": "list",
"answer_contract": "entity_list",
"object_mentions": [],
"project_binding": 81,
"resource_role": "signal",
},
)
assert target is not None
assert target["target_entity_type"] == "signal"
assert target["target_ref"] == "domain:signal"
assert target["resolution_mode"] == "semantic_filter"
def test_semantic_filter_target_uses_people_role_as_user_domain() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
pass
service = _FakeService()
target = service._build_semantic_filter_target(
query_semantics={
"goal_kind": "status_lookup",
"target_scope": "global",
"resource_role": "people",
"expected_answer_shape": "inventory",
},
operation_contract={
"query_type": "list",
"answer_contract": "entity_list",
"object_mentions": [],
"resource_role": "people",
},
)
assert target is not None
assert target["target_entity_type"] == "user"
assert target["target_ref"] == "domain:user"
assert target["resolution_mode"] == "semantic_filter"
def test_semantic_filter_target_uses_doc_role_as_doc_domain() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
pass
service = _FakeService()
target = service._build_semantic_filter_target(
query_semantics={
"goal_kind": "status_lookup",
"target_scope": "global",
"resource_role": "doc",
"expected_answer_shape": "inventory",
},
operation_contract={
"query_type": "list",
"answer_contract": "entity_list",
"object_mentions": [],
"resource_role": "doc",
},
)
assert target is not None
assert target["target_entity_type"] == "doc"
assert target["target_ref"] == "domain:doc"
assert target["resolution_mode"] == "semantic_filter"
def test_semantic_filter_target_uses_feature_role_without_explicit_object_binding() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
pass
service = _FakeService()
target = service._build_semantic_filter_target(
query_semantics={
"goal_kind": "bounded_explanation",
"target_scope": "global",
"resource_role": "feature",
"expected_answer_shape": "bounded_explanation",
},
operation_contract={
"query_type": "explain",
"answer_contract": "explanation_with_citations",
"object_mentions": [],
"resource_role": "feature",
},
)
assert target is not None
assert target["target_entity_type"] == "feature"
assert target["target_ref"] == "domain:feature"
assert target["resolution_mode"] == "semantic_filter"
def test_semantic_filter_target_ignores_subject_focus_without_business_frame_binding() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
pass
service = _FakeService()
target = service._build_semantic_filter_target(
query_semantics={
"subject_focus": "project",
"query_profile": {
"referenced_objects": ["project_object"],
},
},
operation_contract={
"query_type": "status",
"answer_contract": "status_summary",
"object_mentions": ["自动开票系统"],
},
)
assert target is None
def test_internal_query_runtime_metrics_include_contract_and_resolution_summaries() -> None:
class _FakeService(AdaptiveRAGTargetResolutionMixin):
pass
service = _FakeService()
metrics = service._inject_internal_query_runtime_summaries(
retrieval_metrics={"db_query_ms": 12},
query_semantics={
"operation_contract": {
"query_type": "existence",
"answer_contract": "yes_no_with_evidence",
"object_mentions": ["开票系统"],
},
"target_resolution": {
"target_entity_type": "project",
"target_ref": "project:6",
"resolved_label": "自动开票系统",
"resolution_mode": "deterministic",
"confidence": 0.96,
},
"query_plan": {
"plan_version": "v2",
"query_type": "existence",
"entity_type": "project",
"target_ref": "project:6",
"answer_contract": "yes_no_with_evidence",
"filters": [{"field": "project_id", "operator": "equals", "value": 6}],
},
},
)
assert metrics["db_query_ms"] == 12
assert metrics["operation_contract_summary"]["query_type"] == "existence"
assert metrics["target_resolution_summary"]["target_ref"] == "project:6"
assert metrics["query_plan_summary"]["plan_version"] == "v2"
def test_internal_query_plan_uses_resolved_project_target_ref() -> None:
class _FakePlannerService(
AdaptiveRAGAnswerMainlineMixin,
AdaptiveRAGFastAnswerProjectUtilsMixin,
):
pass
service = _FakePlannerService()
plan = service._build_internal_query_plan(
question="帮我看看系统里面有没有开票系统。",
project_id=None,
query_semantics={
"query_type": "explain",
"subject_focus": "feature",
"scope_hint": "global",
"effective_source_policy": "internal",
},
operation_contract={
"query_type": "existence",
"answer_contract": "yes_no_with_evidence",
"object_mentions": ["开票系统"],
},
target_resolution={
"target_entity_type": "project",
"target_ref": "project:6",
"resolved_label": "自动开票系统",
"resolution_mode": "deterministic",
},
)
assert plan is not None
assert plan["plan_version"] == "v2"
assert plan["query_type"] == "existence"
assert plan["entity_type"] == "project"
assert plan["target_ref"] == "project:6"
assert plan["filters"][0]["field"] == "project_id"
assert plan["filters"][0]["value"] == 6
def test_internal_query_plan_skips_lexical_project_filter_fallback() -> None:
class _FakePlannerService(AdaptiveRAGAnswerMainlineMixin):
@staticmethod
def _extract_project_lookup_keyword(question: str) -> str: # pragma: no cover - should not be called
raise AssertionError(f"lexical keyword fallback should be skipped: {question}")
@staticmethod
def _extract_query_terms(question: str, *, preferred: str = "") -> list[str]: # pragma: no cover - should not be called
raise AssertionError(f"lexical term fallback should be skipped: {question}, {preferred}")
service = _FakePlannerService()
plan = service._build_internal_query_plan(
question="系统里有没有A股项目?",
project_id=None,
query_semantics={
"query_type": "existence",
"subject_focus": "project",
"scope_hint": "global",
"effective_source_policy": "internal",
},
operation_contract={
"query_type": "existence",
"answer_contract": "yes_no_with_evidence",
"object_mentions": [],
},
)
assert plan is not None
assert plan["filters"] == []
@pytest.mark.asyncio
async def test_deterministic_query_prefers_project_created_at_answer() -> None:
calls: list[str] = []
class _FakeDeterministicService(AdaptiveRAGDeterministicQueryCoreMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
async def _try_fast_project_created_at_answer(
self,
*,
clean_q: str,
project_id,
query_semantics=None,
internal_context_packet=None,
):
calls.append("created_at")
_ = (clean_q, project_id, query_semantics, internal_context_packet)
return {"answer": "创建于 2026-03-01 09:30。", "sources": [], "missing_fields": []}
async def _try_fast_project_progress_answer(
self,
*,
clean_q: str,
project_id,
query_semantics=None,
internal_context_packet=None,
):
calls.append("progress")
_ = (clean_q, project_id, query_semantics, internal_context_packet)
return {"answer": "进度回答", "sources": []}
async def _try_fast_project_existence_answer(
self,
*,
clean_q: str,
project_id,
query_semantics=None,
internal_context_packet=None,
):
calls.append("existence")
_ = (clean_q, project_id, query_semantics, internal_context_packet)
return {"answer": "存在性回答", "sources": []}
service = _FakeDeterministicService()
result = await service._run_deterministic_query(
question="他是什么时候创建的?",
project_id=7,
query_type="status",
internal_context_packet=_make_internal_context_packet(
query_type="status",
answer_contract="entity_snapshot",
target_ref="project:7",
),
)
assert result is not None
assert "创建于 2026-03-01 09:30" in str(result["answer"])
assert calls[0] == "created_at"
@pytest.mark.asyncio
async def test_deterministic_query_runs_project_existence_for_existence_type() -> None:
calls: list[str] = []
class _FakeDeterministicService(AdaptiveRAGDeterministicQueryCoreMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
async def _try_fast_project_existence_answer(
self,
*,
clean_q: str,
project_id,
query_semantics=None,
internal_context_packet=None,
):
calls.append("existence")
_ = (clean_q, project_id, query_semantics, internal_context_packet)
return {"answer": "有,匹配到 1 个项目。", "sources": []}
service = _FakeDeterministicService()
result = await service._run_deterministic_query(
question="系统里有没有A股项目?",
project_id=None,
query_type="existence",
query_semantics={"subject_focus": "project"},
internal_context_packet=_make_internal_context_packet(
query_type="existence",
answer_contract="yes_no_with_evidence",
),
)
assert result is not None
assert "匹配到 1 个项目" in str(result["answer"])
assert calls == ["existence"]
@pytest.mark.asyncio
async def test_deterministic_query_defers_internal_project_existence_to_semantic_snapshot() -> None:
calls: list[str] = []
class _FakeDeterministicService(AdaptiveRAGDeterministicQueryCoreMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
async def _try_fast_project_existence_answer(self, *, clean_q: str, project_id, query_semantics=None):
calls.append("existence")
_ = (clean_q, project_id, query_semantics)
return {"answer": "有,匹配到 1 个项目。", "sources": []}
service = _FakeDeterministicService()
result = await service._run_deterministic_query(
question="系统里有没有采购经理每日实时库存上报服务?",
project_id=None,
query_type="existence",
query_semantics={
"source_policy": "internal",
"effective_source_policy": "internal",
"goal_kind": "status_lookup",
"target_scope": "current_project",
"resource_role": "project_object",
"project_binding": 123,
"operation_contract": {
"query_type": "existence",
"answer_contract": "yes_no_with_evidence",
"object_mentions": ["采购经理每日实时库存上报服务"],
},
},
)
assert result is None
assert calls == []
@pytest.mark.asyncio
async def test_project_existence_answer_prefers_resolved_project_target() -> None:
class _ScalarResult:
def __init__(self, row):
self._row = row
def scalar_one_or_none(self):
return self._row
class _FakeSession:
def __init__(self, row):
self._row = row
async def execute(self, stmt):
_ = stmt
return _ScalarResult(self._row)
project_row = SimpleNamespace(
id=72,
title="企业知识库问答AI项目",
name="企业知识库问答AI项目",
status="active",
)
class _FakeService(AdaptiveRAGFastAnswerProjectMainMixin, AdaptiveRAGFastAnswerProjectUtilsMixin):
def __init__(self) -> None:
self.db = _FakeSession(project_row)
self.tenant_id = 1
service = _FakeService()
result = await service._try_fast_project_existence_answer(
clean_q="系统里有没有知识库?",
project_id=None,
query_semantics={
"query_type": "existence",
"subject_focus": "unknown",
"target_resolution": {
"target_entity_type": "project",
"target_ref": "project:72",
"resolved_label": "企业知识库问答AI项目",
},
},
)
assert result is not None
assert "#72 企业知识库问答AI项目" in str(result["answer"])
assert result["sources"][0]["metadata"]["project_id"] == 72
@pytest.mark.asyncio
async def test_project_existence_answer_uses_structured_mentions_without_lexical_extractors() -> None:
class _FakeService(
AdaptiveRAGFastAnswerProjectMainMixin,
AdaptiveRAGFastAnswerProjectUtilsMixin,
):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
@staticmethod
def _extract_project_lookup_keyword(question: str) -> str: # pragma: no cover - should not be called
raise AssertionError(f"lexical keyword fallback should be skipped: {question}")
@staticmethod
def _extract_query_terms(question: str, *, preferred: str = "") -> list[str]: # pragma: no cover - should not be called
raise AssertionError(f"lexical term fallback should be skipped: {question}, {preferred}")
async def _try_fast_project_existence_answer_from_semantic_facts(self, *, query_terms: list[str], project_id):
assert query_terms == ["A股项目"]
assert project_id is None
return {
"answer": "有,当前匹配到 1 个相关项目:\n#101 A股趋势打分工具(状态:active)",
"sources": [{"metadata": {"table": "semantic_facts", "match_count": 1}}],
}
async def _search_projects_by_keyword(self, *, keyword: str, project_id, limit: int): # pragma: no cover - should not be called
raise AssertionError(f"text fallback should be skipped: {keyword}, {project_id}, {limit}")
service = _FakeService()
result = await service._try_fast_project_existence_answer(
clean_q="系统里有没有A股项目?",
project_id=None,
query_semantics={
"query_type": "existence",
"scope_hint": "global",
"business_frame": {
"goal_kind": "status_lookup",
"target_scope": "global",
"resource_role": "project_object",
"expected_answer_shape": "inventory",
},
"operation_contract": {
"query_type": "existence",
"object_mentions": ["A股项目"],
},
},
)
assert result is not None
assert "#101 A股趋势打分工具" in str(result["answer"])
@pytest.mark.asyncio
async def test_execute_mainline_skips_snapshot_direct_for_project_existence_target() -> None:
class _FakeContextCache:
async def get_system_snapshot(self, **kwargs):
_ = kwargs
return {"platform_profile": {"feature_catalog": [{"name": "智能配置", "route": "/settings/ai"}]}}
async def get_user_snapshot(self, **kwargs):
_ = kwargs
return {"projects": []}
class _FakeService(
AdaptiveRAGAnswerMainlineMixin,
AdaptiveRAGTargetResolutionMixin,
):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.context_cache = _FakeContextCache()
self.retrieval_called = False
def _plan_query_runtime(self, **kwargs):
_ = kwargs
return SimpleNamespace(
thinking_mode="normal",
retrieval_answer_mode="retrieval_normal",
budget=SimpleNamespace(max_steps=2, vector_top_k=3),
allow_fast_path=True,
reason="deterministic_query_type",
)
def _build_followup_clarification_payload(self, **kwargs):
_ = kwargs
return None
def _build_route_clarification_payload(self, **kwargs):
_ = kwargs
return None
async def _build_meta_followup_payload(self, **kwargs):
_ = kwargs
return None
async def _maybe_return_clarification_response(self, **kwargs):
_ = kwargs
return None
async def _maybe_return_meta_followup_response(self, **kwargs):
_ = kwargs
return None
def _get_active_external_qa_context(self):
return {}
def _build_operation_contract(self, *, question: str, query_semantics):
_ = (question, query_semantics)
return {
"query_type": "existence",
"answer_contract": "yes_no_with_evidence",
"object_mentions": ["开票系统"],
}
async def _resolve_internal_target(self, **kwargs):
_ = kwargs
return {
"target_entity_type": "project",
"target_ref": "project:6",
"resolved_label": "自动开票系统",
"resolution_mode": "deterministic",
"confidence": 0.96,
"candidate_summary": [],
}
async def _run_deterministic_query(self, **kwargs):
_ = kwargs
return None
async def _build_retrieval_response(self, **kwargs):
self.retrieval_called = True
assert kwargs["query_type"] == "existence"
assert kwargs["query_semantics"]["target_resolution"]["target_ref"] == "project:6"
return {"processing_stage": "retrieval"}
def _build_snapshot_direct_answer(self, *args, **kwargs):
raise AssertionError("snapshot direct answer should be skipped for project existence target")
async def _maybe_return_snapshot_direct_response(self, **kwargs):
raise AssertionError("snapshot direct response should be skipped for project existence target")
async def _build_internal_model_config_fast_answer(self, **kwargs):
_ = kwargs
return None
async def _try_fast_project_semantic_answer(self, **kwargs):
_ = kwargs
return None
service = _FakeService()
result = await service._execute_base_answer_mainline(
clean_q="帮我看看系统里面有没有开票系统。",
asked_by=1,
asked_via="pmflow",
project_id=None,
source_chat_id=None,
session_id=11,
turn_index=3,
context_session_id=11,
conversation=[],
state_row=None,
effective_q="帮我看看系统里面有没有开票系统。",
rewrite_meta={},
query_type="explain",
query_semantics={
"source_policy": "internal",
"effective_source_policy": "internal",
"subject_focus": "feature",
"object_mentions": ["开票系统"],
},
retrieval_domains=["db", "pmflow"],
scene_semantics={"scene_key": "ai_pmo", "snapshot_focus": "feature", "deep_intent": "none"},
thinking_mode="normal",
active_thinking_mode="normal",
deep_thinking=False,
enforce_scene_prompt_only=False,
deep_retrieval_steps=2,
deep_vector_top_k=3,
started=0.0,
message_intent="question",
mixed_signal_part=None,
consultant_mode_preference=None,
route_decision={
"route_mode": "internal",
"effective_source_policy": "internal",
"reply_contract": {"head": "内部知识库查询:", "tail_hint": None},
},
)
assert result["processing_stage"] == "retrieval"
assert service.retrieval_called is True
@pytest.mark.asyncio
async def test_query_semantics_prefers_structured_model_output_over_hint_tables(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class _FakeLLM:
async def generate(self, prompt: str, **kwargs):
_ = (prompt, kwargs)
return (
'{"intent":"question","question_part":"我感觉很多重复的项目在系统,你能列一下吗?",'
'"statement_part":"","query_type":"list","retrieval_domains":["db","graph"],'
'"subject_focus":"project","scope_hint":"global","feature_focus":"none"}'
)
class _FakeService(AdaptiveRAGCoreIntentMixin, AdaptiveRAGDeterministicQueryCoreMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
async def _fake_aplan_message(cls, *, message_text: str, source_system: str, metadata=None):
_ = (cls, message_text, source_system, metadata)
return WorkflowSemanticPlanner.deserialize_bundle(
{
"bundle_id": "semantic-query-type",
"semantic_version": "v1",
"source_system": "adaptive_rag",
"primary_workflow": "query_flow",
"workflows": [
{
"workflow_type": "query_flow",
"workflow_action": "answer",
"target_scope": "global",
"operation_codes": ["query.answer"],
"requires_confirmation": False,
"confidence": 0.93,
"clarification_needed": False,
"metadata": {},
}
],
"message_gate": "auto",
"reply_contract": {"mode": "text", "template_key": "workflow_bundle", "summary": "query_flow"},
"diagnostics": {"message_intent": "question"},
}
)
monkeypatch.setattr(WorkflowSemanticPlanner, "aplan_message", classmethod(_fake_aplan_message))
service = _FakeService()
semantics = await service._resolve_query_semantics(
message="我感觉很多重复的项目在系统,你能列一下吗?",
source_system="pmflow",
)
assert semantics["query_type"] == "list"
assert semantics["retrieval_domains"] == ["db", "graph"]
assert semantics["intent"] == "question"
assert semantics["scope_hint"] == "global"
assert semantics["feature_focus"] == "none"
assert "subject_focus" not in semantics
@pytest.mark.asyncio
async def test_query_semantics_accepts_existence_query_type_from_structured_output(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class _FakeLLM:
async def generate(self, prompt: str, **kwargs):
_ = (prompt, kwargs)
return (
'{"intent":"question","question_part":"系统里有没有A股项目?",'
'"statement_part":"","query_type":"existence","retrieval_domains":["db","graph"],'
'"object_mentions":["A股项目"],'
'"subject_focus":"project","scope_hint":"global","feature_focus":"none",'
'"query_profile":{"needs_private_context":true,"needs_freshness":false,"referenced_objects":["project_object"],"confidence":0.81},'
'"confidence":0.91}'
)
class _FakeService(AdaptiveRAGCoreIntentMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
async def _fake_aplan_message(cls, *, message_text: str, source_system: str, metadata=None):
_ = (cls, message_text, source_system, metadata)
return WorkflowSemanticPlanner.deserialize_bundle(
{
"bundle_id": "semantic-query-existence",
"semantic_version": "v1",
"source_system": "adaptive_rag",
"primary_workflow": "query_flow",
"workflows": [
{
"workflow_type": "query_flow",
"workflow_action": "answer",
"target_scope": "global",
"operation_codes": ["query.answer"],
"requires_confirmation": False,
"confidence": 0.89,
"clarification_needed": False,
"metadata": {},
}
],
"message_gate": "auto",
"reply_contract": {"mode": "text", "template_key": "workflow_bundle", "summary": "query_flow"},
"diagnostics": {"message_intent": "question"},
}
)
monkeypatch.setattr(WorkflowSemanticPlanner, "aplan_message", classmethod(_fake_aplan_message))
service = _FakeService()
semantics = await service._resolve_query_semantics(
message="系统里有没有A股项目?",
source_system="pmflow",
)
assert semantics["query_type"] == "existence"
assert semantics["object_mentions"] == ["A股项目"]
assert semantics["retrieval_domains"] == ["db", "graph"]
assert semantics["query_profile"]["needs_private_context"] is True
assert "referenced_objects" not in semantics["query_profile"]
@pytest.mark.asyncio
async def test_query_semantics_reuses_cached_result_for_identical_request(
monkeypatch: pytest.MonkeyPatch,
) -> None:
planner_calls: list[dict[str, object]] = []
llm_calls: list[str] = []
class _FakeLLM:
async def generate(self, prompt: str, **kwargs):
_ = kwargs
llm_calls.append(prompt)
return (
'{"intent":"question","question_part":"系统里有没有采购经理每日实时库存上报服务?",'
'"statement_part":"","query_type":"existence","retrieval_domains":["db","pmflow"],'
'"object_mentions":["采购经理每日实时库存上报服务"],'
'"subject_focus":"project","scope_hint":"global","feature_focus":"none",'
'"source_policy":"internal","effective_source_policy":"internal",'
'"query_profile":{"needs_private_context":true,"needs_freshness":false,"referenced_objects":["project_object"],"confidence":0.93},'
'"confidence":0.96}'
)
class _FakeService(AdaptiveRAGCoreIntentMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
async def _fake_aplan_message(cls, *, message_text: str, source_system: str, metadata=None):
_ = cls
planner_calls.append(
{
"message_text": message_text,
"source_system": source_system,
"metadata": dict(metadata or {}),
}
)
return WorkflowSemanticPlanner.deserialize_bundle(
{
"bundle_id": "semantic-query-cache",
"semantic_version": "v1",
"source_system": "adaptive_rag",
"primary_workflow": "query_flow",
"workflows": [
{
"workflow_type": "query_flow",
"workflow_action": "answer",
"target_scope": "global",
"operation_codes": ["query.answer"],
"requires_confirmation": False,
"confidence": 0.94,
"clarification_needed": False,
"metadata": {},
}
],
"message_gate": "auto",
"reply_contract": {"mode": "text", "template_key": "workflow_bundle", "summary": "query_flow"},
"diagnostics": {"message_intent": "question"},
}
)
monkeypatch.setattr(WorkflowSemanticPlanner, "aplan_message", classmethod(_fake_aplan_message))
service = _FakeService()
first = await service._resolve_query_semantics(
message="系统里有没有采购经理每日实时库存上报服务?",
source_system="pmflow",
metadata={"project_id": 1},
)
second = await service._resolve_query_semantics(
message="系统里有没有采购经理每日实时库存上报服务?",
source_system="pmflow",
metadata={"project_id": 1},
)
assert first == second
assert len(planner_calls) == 1
assert len(llm_calls) == 1
@pytest.mark.asyncio
async def test_query_semantics_prompt_contract_guides_internal_project_source_policy(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class _FakeLLM:
async def generate(self, prompt: str, **kwargs):
_ = kwargs
if '"source_policy"' in prompt and '"effective_source_policy"' in prompt:
return (
'{"intent":"question","question_part":"系统里有没有采购经理每日实时库存上报服务?",'
'"statement_part":"","query_type":"existence","retrieval_domains":["db","pmflow"],'
'"object_mentions":["采购经理每日实时库存上报服务"],'
'"subject_focus":"project","scope_hint":"global","feature_focus":"none",'
'"source_policy":"internal","effective_source_policy":"internal",'
'"query_profile":{"needs_private_context":true,"needs_freshness":false,"referenced_objects":["project_object"],"confidence":0.93},'
'"confidence":0.96}'
)
return (
'{"intent":"question","question_part":"系统里有没有采购经理每日实时库存上报服务?",'
'"statement_part":"","query_type":"existence","retrieval_domains":["db","pmflow"],'
'"object_mentions":["采购经理每日实时库存上报服务"],'
'"subject_focus":"project","scope_hint":"global","feature_focus":"none",'
'"query_profile":{"needs_private_context":true,"needs_freshness":false,"referenced_objects":["project_object"],"confidence":0.93},'
'"confidence":0.96}'
)
class _FakeService(AdaptiveRAGCoreIntentMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
async def _fake_aplan_message(cls, *, message_text: str, source_system: str, metadata=None):
_ = (cls, message_text, source_system, metadata)
return WorkflowSemanticPlanner.deserialize_bundle(
{
"bundle_id": "semantic-query-internal-project",
"semantic_version": "v1",
"source_system": "adaptive_rag",
"primary_workflow": "query_flow",
"workflows": [
{
"workflow_type": "query_flow",
"workflow_action": "answer",
"target_scope": "global",
"operation_codes": ["query.answer"],
"requires_confirmation": False,
"confidence": 0.94,
"clarification_needed": False,
"metadata": {},
}
],
"message_gate": "auto",
"reply_contract": {"mode": "text", "template_key": "workflow_bundle", "summary": "query_flow"},
"diagnostics": {"message_intent": "question"},
}
)
monkeypatch.setattr(WorkflowSemanticPlanner, "aplan_message", classmethod(_fake_aplan_message))
service = _FakeService()
semantics = await service._resolve_query_semantics(
message="系统里有没有采购经理每日实时库存上报服务?",
source_system="pmflow",
)
assert '"source_policy"' in PROMPT_RAG_QUERY_SEMANTICS
assert '"effective_source_policy"' in PROMPT_RAG_QUERY_SEMANTICS
assert semantics["source_policy"] == "internal"
assert semantics["effective_source_policy"] == "internal"
def test_feature_catalog_match_skips_lexical_query_term_fallback() -> None:
class _FakeService(AdaptiveRAGManifestFeatureMixinP1):
@staticmethod
def _extract_query_terms(question: str, *, preferred: str = "") -> list[str]: # pragma: no cover - should not be called
raise AssertionError(f"feature lexical term fallback should be skipped: {question}, {preferred}")
service = _FakeService()
rows = service._match_feature_catalog_entries(
question="智能配置入口在哪?",
system_snapshot={
"platform_profile": {
"feature_catalog": [
{
"name": "智能配置",
"route": "/ai-config",
"summary": "管理模型和提示词配置",
"aliases": ["模型设置"],
}
]
}
},
)
assert rows
assert rows[0]["name"] == "智能配置"
def test_feature_catalog_match_skips_generic_project_list_for_unrelated_project_mention() -> None:
class _FakeService(AdaptiveRAGManifestFeatureMixinP1):
pass
service = _FakeService()
rows = service._match_feature_catalog_entries(
question="A股项目",
system_snapshot={
"platform_profile": {
"feature_catalog": [
{
"name": "项目列表",
"route": "/projects",
"summary": "查看全部项目",
},
{
"name": "智能配置",
"route": "/ai-config",
"summary": "管理模型配置",
},
]
}
},
)
assert rows == []
def test_internal_answer_contract_verifier_blocks_total_count_substitution_for_existence() -> None:
class _FakeVerifier(AdaptiveRAGAnswerPayloadMixin, AdaptiveRAGQueryRouteGatewayMixin):
pass
service = _FakeVerifier()
verdict = service._verify_internal_answer_contract(
query_type="existence",
answer="当前系统里项目总数为 42 个。",
sources=[
{
"source": "db",
"label": "Project database",
"score": 0.99,
"metadata": {"table": "projects"},
}
],
route_decision={"route_mode": "internal", "effective_source_policy": "internal"},
internal_context_packet=_make_internal_context_packet(
query_type="existence",
answer_contract="yes_no_with_evidence",
),
)
assert verdict["ok"] is False
assert verdict["reason_code"] == "no_total_count_substitution"
def test_internal_answer_contract_verifier_allows_project_snapshot_with_task_totals_for_existence() -> None:
class _FakeVerifier(AdaptiveRAGAnswerPayloadMixin, AdaptiveRAGQueryRouteGatewayMixin):
pass
service = _FakeVerifier()
verdict = service._verify_internal_answer_contract(
query_type="existence",
answer=(
"有。项目ID 123,项目名“采购经理每日实时库存上报服务”,状态 active,负责人 系统管理员,"
"最近更新 2026-04-13T14:27:59.301650,任务总数 4,已完成 0,进行中 0,待处理 4。"
),
sources=[
{
"source": "db",
"label": "Project database",
"score": 0.99,
"metadata": {"table": "projects", "matched_project_ids": [123]},
}
],
route_decision={"route_mode": "internal", "effective_source_policy": "internal"},
internal_context_packet=_make_internal_context_packet(
query_type="existence",
answer_contract="yes_no_with_evidence",
target_ref="project:123",
),
)
assert verdict["ok"] is True
assert verdict["reason_code"] is None
def test_internal_answer_contract_verifier_allows_evidence_backed_existence_answer() -> None:
class _FakeVerifier(AdaptiveRAGAnswerPayloadMixin, AdaptiveRAGQueryRouteGatewayMixin):
pass
service = _FakeVerifier()
verdict = service._verify_internal_answer_contract(
query_type="existence",
answer="有,当前匹配到 1 个相关项目:#101 A股趋势打分工具(状态:active)",
sources=[
{
"source": "db",
"label": "Project database",
"score": 0.99,
"metadata": {"table": "projects", "match_count": 1},
}
],
route_decision={"route_mode": "internal", "effective_source_policy": "internal"},
internal_context_packet=_make_internal_context_packet(
query_type="existence",
answer_contract="yes_no_with_evidence",
target_ref="project:101",
),
)
assert verdict["ok"] is True
assert verdict["reason_code"] is None
@pytest.mark.asyncio
async def test_classify_intent_prefers_structured_semantics_without_rule_split(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class _FakeLLM:
async def generate(self, prompt: str, **kwargs):
_ = (prompt, kwargs)
return (
'{"intent":"mixed","question_part":"现在进展如何?","statement_part":"并新增任务确认流",'
'"query_type":"status","retrieval_domains":["db","graph","pmflow"]}'
)
class _FakeService(AdaptiveRAGCoreIntentMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
async def _fake_aplan_message(cls, *, message_text: str, source_system: str, metadata=None):
_ = (cls, message_text, source_system, metadata)
return WorkflowSemanticPlanner.deserialize_bundle(
{
"bundle_id": "semantic-intent",
"semantic_version": "v1",
"source_system": "adaptive_rag",
"primary_workflow": "query_flow",
"workflows": [
{
"workflow_type": "query_flow",
"workflow_action": "answer",
"target_scope": "global",
"operation_codes": ["query.answer"],
"requires_confirmation": False,
"confidence": 0.88,
"clarification_needed": False,
"metadata": {},
}
],
"message_gate": "auto",
"reply_contract": {"mode": "text", "template_key": "workflow_bundle", "summary": "query_flow"},
"diagnostics": {"message_intent": "business_review"},
}
)
monkeypatch.setattr(WorkflowSemanticPlanner, "aplan_message", classmethod(_fake_aplan_message))
service = _FakeService()
result = await service.classify_intent("现在进展如何?并新增任务确认流")
assert result == {
"intent": "mixed",
"confidence": 0.88,
"question_part": "现在进展如何?",
"statement_part": "并新增任务确认流",
}
@pytest.mark.asyncio
async def test_vector_retrieval_skips_legacy_fallback_for_non_postgresql_session() -> None:
class _FakeLLM:
async def get_embedding_async(self, question: str, **kwargs):
_ = (question, kwargs)
return [0.1, 0.2, 0.3]
class _FakeService(AdaptiveRAGRetrievalVectorMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
self.legacy_called = False
def _map_domains_to_source_types(self, domains: list[str]) -> list[str]:
return list(domains)
def _is_postgresql_session(self) -> bool:
return False
async def _retrieve_vector_context_legacy(self, **kwargs):
_ = kwargs
self.legacy_called = True
return ["legacy-hit"]
service = _FakeService()
result = await service._retrieve_vector_context(
"查询项目文档",
domains=["doc"],
project_id=None,
source_chat_id=None,
)
assert result == []
assert service.legacy_called is False
@pytest.mark.asyncio
async def test_vector_retrieval_skips_legacy_fallback_when_pg_query_errors() -> None:
class _FakeLLM:
async def get_embedding_async(self, question: str, **kwargs):
_ = (question, kwargs)
return [0.1, 0.2, 0.3]
class _FakeService(AdaptiveRAGRetrievalVectorMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
self.legacy_called = False
def _map_domains_to_source_types(self, domains: list[str]) -> list[str]:
return list(domains)
def _is_postgresql_session(self) -> bool:
return True
async def _retrieve_vector_context_pg(self, **kwargs):
_ = kwargs
return None
async def _retrieve_vector_context_legacy(self, **kwargs):
_ = kwargs
self.legacy_called = True
return ["legacy-hit"]
service = _FakeService()
result = await service._retrieve_vector_context(
"查询项目文档",
domains=["doc"],
project_id=None,
source_chat_id=None,
)
assert result == []
assert service.legacy_called is False
@pytest.mark.asyncio
async def test_deep_guard_answer_raises_on_empty_llm_response() -> None:
class _FakeLLM:
async def generate(self, prompt: str, **kwargs):
_ = (prompt, kwargs)
return ""
class _FakeService(AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
def _normalize_thinking_mode(self, thinking_mode: str) -> str:
return "normal" if str(thinking_mode or "").strip().lower() != "deep" else "deep"
async def get_project_manifest(self, project_id):
_ = project_id
return {}
async def _select_scene_prompt(self, **kwargs):
_ = kwargs
return "external_trend", "请回答问题"
def _enforce_feature_evidence_in_answer(self, **kwargs):
return str(kwargs.get("answer_text") or "")
service = _FakeService()
with pytest.raises(ValueError, match="adaptive_rag_answer_empty_response"):
await service._generate_answer(
question="最近AI行业有什么动态",
retrieved=[],
conversation=[],
project_id=None,
asked_via="feishu",
)
@pytest.mark.asyncio
async def test_deep_guard_answer_uses_low_first_routing_meta_for_deep_thinking() -> None:
class _FakeLLM:
def __init__(self) -> None:
self.kwargs: dict[str, object] = {}
async def generate(self, prompt: str, **kwargs):
_ = prompt
self.kwargs = dict(kwargs)
return "low-tier answer"
class _FakeService(AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
def _normalize_thinking_mode(self, thinking_mode: str) -> str:
return "deep" if str(thinking_mode or "").strip().lower() == "deep" else "normal"
async def get_project_manifest(self, project_id):
_ = project_id
return {}
async def _select_scene_prompt(self, **kwargs):
_ = kwargs
return "external_trend", "请回答问题"
def _enforce_feature_evidence_in_answer(self, **kwargs):
return str(kwargs.get("answer_text") or "")
service = _FakeService()
result = await service._generate_answer(
question="最近AI行业有什么动态",
retrieved=[],
conversation=[],
project_id=None,
asked_via="feishu",
thinking_mode="deep",
)
assert result == "low-tier answer"
assert service.llm.kwargs["function_name"] == "adaptive_rag_answer_deep"
routing_meta = service.llm.kwargs["routing_meta"]
assert isinstance(routing_meta, dict)
assert routing_meta["tier_alias"] == "low"
assert routing_meta["planned_tier"] == "low"
assert routing_meta["response_contract"] == "complete"
assert routing_meta["fallback_policy"] == "low_to_high"
assert routing_meta["execution_mode"] == "query"
assert routing_meta["routing_decision"] == "force_low_first"
@pytest.mark.asyncio
async def test_deep_guard_answer_external_route_uses_external_presenter_without_internal_context() -> None:
class _FakePresenter:
def __init__(self) -> None:
self.calls: list[dict[str, object]] = []
async def present(self, *, question: str, context_packet: dict, thinking_mode: str, answer_max_tokens=None):
self.calls.append(
{
"question": question,
"context_packet": dict(context_packet),
"thinking_mode": thinking_mode,
"answer_max_tokens": answer_max_tokens,
}
)
return {
"answer_text": "只基于外部证据生成的回答",
"prompt_variant_id": "external_summary_with_sources",
}
class _FakeService(AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = object()
self.presenter = _FakePresenter()
self.prompt_variant = "unknown"
def _normalize_thinking_mode(self, thinking_mode: str) -> str:
_ = thinking_mode
return "normal"
async def get_project_manifest(self, project_id): # pragma: no cover - should not be called
raise AssertionError(f"manifest should be skipped for external route: {project_id}")
async def _resolve_answer_scene_semantics(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"scene semantics should be skipped for external route: {kwargs}")
async def _select_scene_prompt(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"scene prompt should be skipped for external route: {kwargs}")
def _build_external_answer_presenter(self):
return self.presenter
def _remember_answer_prompt_variant(self, prompt_variant_id: str) -> None:
self.prompt_variant = prompt_variant_id
def _enforce_feature_evidence_in_answer(self, **kwargs):
return str(kwargs.get("answer_text") or "")
service = _FakeService()
result = await service._generate_answer(
question="最近 AI 编程模型有什么新动态?",
retrieved=[],
conversation=[],
project_id=7,
asked_via="feishu",
query_semantics={"effective_source_policy": "external"},
external_context_packet={
"question": "最近 AI 编程模型有什么新动态?",
"plan": {
"answer_contract": "summary_with_sources",
"time_range_hint": "最近",
},
"adapter_attempts": [{"adapter": "live_search", "status": "success"}],
"verified_evidence": [
{
"source_type": "url",
"source_label": "OpenAI Developers",
"title": "Models - Codex | OpenAI Developers",
"target_url": "https://developers.openai.com/codex/models",
"snippet": "Latest: GPT-5.4",
}
],
"verifier": {"ok": True},
"uncertainties": [],
},
)
assert result == "只基于外部证据生成的回答"
assert service.prompt_variant == "external_summary_with_sources"
assert len(service.presenter.calls) == 1
assert service.presenter.calls[0]["question"] == "最近 AI 编程模型有什么新动态?"
@pytest.mark.asyncio
async def test_retrieval_response_external_insufficient_evidence_keeps_external_clarify_contract() -> None:
class _FakeDB:
def add(self, obj) -> None:
obj.id = 1
async def flush(self) -> None:
return None
async def commit(self) -> None:
return None
async def refresh(self, obj) -> None:
_ = obj
return None
class _FakeContextCache:
async def append_session_messages(self, **kwargs) -> None:
_ = kwargs
return None
class _FakeService(
AdaptiveRAGAnswerRetrievalMixin,
AdaptiveRAGAnswerPayloadMixin,
AdaptiveRAGQueryRouteGatewayMixin,
AdaptiveRAGDeepGuardRulesMixin,
):
def __init__(self) -> None:
self.db = _FakeDB()
self.context_cache = _FakeContextCache()
self.tenant_id = 1
def _normalize_thinking_mode(self, thinking_mode: str) -> str:
return "deep" if str(thinking_mode or "").strip().lower() == "deep" else "normal"
async def _execute_external_query_gateway(self, **kwargs):
_ = kwargs
return [], {
"mode": "external_query_gateway_verifier_blocked",
"external_context_packet": {
"question": "OpenAI 最近发布了哪些新模型?",
"plan": {
"answer_contract": "summary_with_sources",
},
"adapter_attempts": [{"adapter": "live_search", "status": "empty"}],
"verified_evidence": [],
"verifier": {
"ok": False,
"reason_code": "insufficient_evidence",
"missing_fields": ["external_evidence"],
},
"uncertainties": ["insufficient_evidence"],
},
"tool_trace": [],
"domains_used": ["url"],
}
async def _generate_answer(self, *args, **kwargs):
_ = (args, kwargs)
return "当前关于“OpenAI 最近发布了哪些新模型?”的外部证据不足。请补充更明确的对象、范围或继续提供可核验来源后,我再继续分析。"
def _peek_answer_prompt_variant(self):
return "external_clarify"
def _peek_last_answer_routing_snapshot(self):
return {}
def _dedupe_sources(self, retrieved):
_ = retrieved
return []
def _build_qa_record_runtime_fields(self, **kwargs):
return {
"policy_version": "test",
"citations": [],
"sources_used": list(kwargs.get("sources") or []),
"evidence_pack": {},
"tool_trace": list(kwargs.get("tool_trace") or []),
}
def _build_qa_record_external_fields(self, **kwargs):
_ = kwargs
return {}
async def _update_session_state_after_turn(self, **kwargs):
_ = kwargs
return None
def _build_response_payload(self, **kwargs):
return kwargs
service = _FakeService()
result = await service._build_retrieval_response(
clean_q="OpenAI 最近发布了哪些新模型?",
effective_q="OpenAI 最近发布了哪些新模型?",
asked_by=1,
asked_via="feishu",
project_id=None,
source_chat_id=None,
session_id=11,
turn_index=2,
context_session_id=11,
conversation=[],
state_row=None,
rewrite_meta={"mode": "direct"},
query_type="explain",
query_semantics={"effective_source_policy": "external"},
retrieval_domains=["url"],
scene_semantics={"scene_key": "default", "deep_intent": "none"},
thinking_mode="normal",
active_thinking_mode="normal",
deep_thinking=False,
forced_deep_reason="",
deep_retrieval_steps=2,
deep_vector_top_k=3,
system_snapshot={},
user_snapshot=None,
started=0.0,
message_intent=None,
mixed_signal_part=None,
answer_mode="retrieval_normal",
consultant_mode_preference=None,
route_decision={
"route_mode": "external",
"effective_source_policy": "external",
"decision_origin": "query_semantics_contract",
"reply_contract": {"head": "外部实时查询:", "tail_hint": None},
"query_profile": {"needs_freshness": True, "referenced_objects": ["public_api"]},
},
)
assert result["answer_mode"] == "clarify"
assert result["grounding_status"] == "insufficient_evidence"
assert result["sources"] == []
assert result["sources_used"] == []
assert "系统快照" not in result["answer"]
assert "外部证据不足" in result["answer"]
assert result["answer"].startswith("外部实时查询:")
assert result["missing_fields"] == ["external_evidence"]
@pytest.mark.asyncio
async def test_retrieval_response_exposes_fit_brief_and_external_recommendation_blocks() -> None:
class _FakeDB:
def add(self, obj) -> None:
obj.id = 2
async def flush(self) -> None:
return None
async def commit(self) -> None:
return None
async def refresh(self, obj) -> None:
_ = obj
return None
class _FakeContextCache:
async def append_session_messages(self, **kwargs) -> None:
_ = kwargs
return None
class _FakeService(
AdaptiveRAGAnswerRetrievalMixin,
AdaptiveRAGAnswerPayloadMixin,
AdaptiveRAGQueryRouteGatewayMixin,
AdaptiveRAGDeepGuardRulesMixin,
):
def __init__(self) -> None:
self.db = _FakeDB()
self.context_cache = _FakeContextCache()
self.tenant_id = 1
self.fit_brief_seen = None
def _normalize_thinking_mode(self, thinking_mode: str) -> str:
return "deep" if str(thinking_mode or "").strip().lower() == "deep" else "normal"
def _to_float(self, value, default=0.0):
try:
return float(value)
except Exception:
return float(default)
def _build_policy_version(self, *, prompt_variant_id: str | None = None) -> str:
return f"retrieval-v2.1|routing:unknown|prompt:{prompt_variant_id or 'unknown'}"
def _normalize_query_route_decision(self, payload):
return dict(payload or {})
async def _build_project_fit_brief(self, **kwargs):
_ = kwargs
return {
"project_summary": "当前项目:PMFlow AI 管家,聚焦项目内问答与需求流转。",
"repo_summary": "当前仓库:FastAPI 后端 + React 前端。",
"current_capabilities": ["AI 管家", "智能配置"],
"constraints": ["只允许基于外部公开证据给出推荐。"],
"recommendation_focus": ["判断 Responses API 是否适合当前项目接入"],
}
async def _execute_external_query_gateway(self, **kwargs):
self.fit_brief_seen = kwargs.get("fit_brief")
return [
RetrievedItem(
source="url",
content="Responses API 支持工具调用与结构化输出。",
score=0.93,
source_label="OpenAI Docs",
metadata={
"target_url": "https://platform.openai.com/docs/guides/responses",
},
)
], {
"mode": "external_query_gateway",
"external_context_packet": {
"question": "这个项目适不适合接 OpenAI Responses API?",
"plan": {
"answer_contract": "summary_with_sources",
"topic": "Responses API 适配性",
},
"adapter_attempts": [{"adapter": "live_search", "status": "success"}],
"verified_evidence": [
{
"source_type": "url",
"source_label": "OpenAI Docs",
"title": "Responses API guide",
"target_url": "https://platform.openai.com/docs/guides/responses",
"snippet": "Responses API supports tool calls and structured outputs.",
}
],
"verifier": {"ok": True},
"uncertainties": [],
"retrieval_status": "evidence_found",
},
"tool_trace": [],
"domains_used": ["url"],
}
async def _generate_answer(self, *args, **kwargs):
_ = (args, kwargs)
return "外部公开资料显示 Responses API 值得关注,但目前还需要先做项目映射验证。"
def _peek_answer_prompt_variant(self):
return "external_summary_with_sources"
def _peek_last_answer_routing_snapshot(self):
return {}
def _dedupe_sources(self, retrieved):
_ = retrieved
return [
{
"source": "url",
"label": "OpenAI Docs",
"score": 0.93,
"metadata": {
"target_url": "https://platform.openai.com/docs/guides/responses",
},
}
]
def _build_qa_record_runtime_fields(self, **kwargs):
return {
"policy_version": "test",
"citations": [],
"sources_used": list(kwargs.get("sources") or []),
"evidence_pack": {},
"tool_trace": list(kwargs.get("tool_trace") or []),
}
def _build_qa_record_external_fields(self, **kwargs):
_ = kwargs
return {}
async def _update_session_state_after_turn(self, **kwargs):
_ = kwargs
return None
service = _FakeService()
result = await service._build_retrieval_response(
clean_q="这个项目适不适合接 OpenAI Responses API?",
effective_q="这个项目适不适合接 OpenAI Responses API?",
asked_by=1,
asked_via="feishu",
project_id=17,
source_chat_id=None,
session_id=12,
turn_index=1,
context_session_id=12,
conversation=[],
state_row=None,
rewrite_meta={"mode": "direct"},
query_type="explain",
query_semantics={
"effective_source_policy": "external",
"project_operating_context": {
"current_project_id": 17,
"current_repo_scope": "pmflow-main",
"page_anchor": {"project_id": 17},
"thread_anchor": {},
"fit_scope": "current_project_and_repo",
"decision_strategy": "answer_then_offer_plan",
},
"execution_recipe": {
"primary_lane": "external",
"fit_brief_required": True,
"external_evidence_required": True,
"plan_handoff_mode": "offer_after_answer",
},
},
retrieval_domains=["url"],
scene_semantics={"scene_key": "default", "deep_intent": "none"},
thinking_mode="normal",
active_thinking_mode="normal",
deep_thinking=False,
forced_deep_reason="",
deep_retrieval_steps=2,
deep_vector_top_k=3,
system_snapshot={},
user_snapshot=None,
started=time.perf_counter(),
message_intent=None,
mixed_signal_part=None,
answer_mode="retrieval_normal",
consultant_mode_preference=None,
route_decision={
"route_mode": "external",
"effective_source_policy": "external",
"decision_origin": "query_semantics_contract",
"reply_contract": {"head": "外部实时查询:", "tail_hint": None},
"query_profile": {"needs_freshness": True, "referenced_objects": ["public_api"]},
},
)
assert service.fit_brief_seen is not None
assert result["fit_brief"]["project_summary"].startswith("当前项目:PMFlow AI 管家")
assert result["fit_brief"]["current_capabilities"] == ["AI 管家", "智能配置"]
assert result["external_recommendation"]["retrieval_status"] == "evidence_found"
assert result["external_recommendation"]["impact_status"] == "indirect_only"
assert result["external_recommendation"]["affected_signal_sources"] == []
assert "映射验证" in str(result["external_recommendation"]["external_action"])
@pytest.mark.asyncio
async def test_retrieval_response_can_disable_fit_brief_external_recommendation(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class _FakeDB:
def add(self, obj) -> None:
obj.id = 2
async def flush(self) -> None:
return None
async def commit(self) -> None:
return None
async def refresh(self, obj) -> None:
_ = obj
return None
class _FakeContextCache:
async def append_session_messages(self, **kwargs) -> None:
_ = kwargs
return None
class _FakeService(
AdaptiveRAGAnswerRetrievalMixin,
AdaptiveRAGAnswerPayloadMixin,
AdaptiveRAGQueryRouteGatewayMixin,
AdaptiveRAGDeepGuardRulesMixin,
):
def __init__(self) -> None:
self.db = _FakeDB()
self.context_cache = _FakeContextCache()
self.tenant_id = 1
self.fit_brief_seen = "unset"
def _normalize_thinking_mode(self, thinking_mode: str) -> str:
return "deep" if str(thinking_mode or "").strip().lower() == "deep" else "normal"
def _to_float(self, value, default=0.0):
try:
return float(value)
except Exception:
return float(default)
def _build_policy_version(self, *, prompt_variant_id: str | None = None) -> str:
return f"retrieval-v2.1|routing:unknown|prompt:{prompt_variant_id or 'unknown'}"
def _normalize_query_route_decision(self, payload):
return dict(payload or {})
async def _build_project_fit_brief(self, **kwargs):
_ = kwargs
raise AssertionError("fit brief builder should be bypassed when rollback flag is off")
async def _execute_external_query_gateway(self, **kwargs):
self.fit_brief_seen = kwargs.get("fit_brief")
return [
RetrievedItem(
source="url",
content="Responses API 支持工具调用与结构化输出。",
score=0.93,
source_label="OpenAI Docs",
metadata={
"target_url": "https://platform.openai.com/docs/guides/responses",
},
)
], {
"mode": "external_query_gateway",
"external_context_packet": {
"question": "这个项目适不适合接 OpenAI Responses API?",
"plan": {
"answer_contract": "summary_with_sources",
"topic": "Responses API 适配性",
},
"adapter_attempts": [{"adapter": "live_search", "status": "success"}],
"verified_evidence": [
{
"source_type": "url",
"source_label": "OpenAI Docs",
"title": "Responses API guide",
"target_url": "https://platform.openai.com/docs/guides/responses",
"snippet": "Responses API supports tool calls and structured outputs.",
}
],
"verifier": {"ok": True},
"uncertainties": [],
"retrieval_status": "evidence_found",
},
"tool_trace": [],
"domains_used": ["url"],
}
async def _generate_answer(self, *args, **kwargs):
_ = (args, kwargs)
return "外部公开资料显示 Responses API 值得关注,但目前还需要先做项目映射验证。"
def _peek_answer_prompt_variant(self):
return "external_summary_with_sources"
def _peek_last_answer_routing_snapshot(self):
return {}
def _dedupe_sources(self, retrieved):
_ = retrieved
return [
{
"source": "url",
"label": "OpenAI Docs",
"score": 0.93,
"metadata": {
"target_url": "https://platform.openai.com/docs/guides/responses",
},
}
]
def _build_qa_record_runtime_fields(self, **kwargs):
return {
"policy_version": "test",
"citations": [],
"sources_used": list(kwargs.get("sources") or []),
"evidence_pack": {},
"tool_trace": list(kwargs.get("tool_trace") or []),
}
def _build_qa_record_external_fields(self, **kwargs):
_ = kwargs
return {}
async def _update_session_state_after_turn(self, **kwargs):
_ = kwargs
return None
monkeypatch.setenv("PMFLOW_ENABLE_FIT_BRIEF_EXTERNAL_RECOMMENDATION", "0")
service = _FakeService()
result = await service._build_retrieval_response(
clean_q="这个项目适不适合接 OpenAI Responses API?",
effective_q="这个项目适不适合接 OpenAI Responses API?",
asked_by=1,
asked_via="feishu",
project_id=17,
source_chat_id=None,
session_id=12,
turn_index=1,
context_session_id=12,
conversation=[],
state_row=None,
rewrite_meta={"mode": "direct"},
query_type="explain",
query_semantics={
"effective_source_policy": "external",
"project_operating_context": {
"current_project_id": 17,
"current_repo_scope": "pmflow-main",
"page_anchor": {"project_id": 17},
"thread_anchor": {},
"fit_scope": "current_project_and_repo",
"decision_strategy": "answer_then_offer_plan",
},
"execution_recipe": {
"primary_lane": "external",
"fit_brief_required": True,
"external_evidence_required": True,
"plan_handoff_mode": "offer_after_answer",
},
},
retrieval_domains=["url"],
scene_semantics={"scene_key": "default", "deep_intent": "none"},
thinking_mode="normal",
active_thinking_mode="normal",
deep_thinking=False,
forced_deep_reason="",
deep_retrieval_steps=2,
deep_vector_top_k=3,
system_snapshot={},
user_snapshot=None,
started=time.perf_counter(),
message_intent=None,
mixed_signal_part=None,
answer_mode="retrieval_normal",
consultant_mode_preference=None,
route_decision={
"route_mode": "external",
"effective_source_policy": "external",
"decision_origin": "query_semantics_contract",
"reply_contract": {"head": "外部实时查询:", "tail_hint": None},
"query_profile": {"needs_freshness": True, "referenced_objects": ["public_api"]},
},
)
assert service.fit_brief_seen == {}
assert result["fit_brief"] == {}
assert result["external_recommendation"] == {}
def test_external_recommendation_does_not_treat_capability_name_as_direct_match_without_formal_anchor() -> None:
result = AdaptiveRAGAnswerPayloadMixin._build_external_recommendation(
external_context_packet={
"retrieval_status": "evidence_found",
"verified_evidence": [
{
"source_type": "url",
"source_label": "OpenAI Docs",
"title": "AI 管家接入 Responses API",
"target_url": "https://platform.openai.com/docs/guides/responses",
"snippet": "AI 管家可以通过 Responses API 编排工具调用。",
}
],
"verifier": {"ok": True},
},
fit_brief={
"project_summary": "当前项目:PMFlow AI 管家",
"current_capabilities": ["AI 管家"],
"signal_source_anchors": [],
"constraints": [],
"recommendation_focus": [],
},
)
assert result["retrieval_status"] == "evidence_found"
assert result["impact_status"] == "indirect_only"
assert result["affected_signal_sources"] == []
def test_external_recommendation_uses_formal_signal_source_anchor_for_direct_match() -> None:
result = AdaptiveRAGAnswerPayloadMixin._build_external_recommendation(
external_context_packet={
"retrieval_status": "evidence_found",
"verified_evidence": [
{
"source_type": "url",
"source_label": "OpenAI Docs",
"title": "Responses API guide",
"target_url": "https://platform.openai.com/docs/guides/responses",
"snippet": "OpenAI Docs 说明 Responses API 支持结构化输出与工具调用。",
}
],
"verifier": {"ok": True},
},
fit_brief={
"project_summary": "当前项目:PMFlow AI 管家",
"current_capabilities": ["AI 管家"],
"signal_source_anchors": ["OpenAI Docs"],
"constraints": [],
"recommendation_focus": [],
},
)
assert result["retrieval_status"] == "evidence_found"
assert result["impact_status"] == "direct_match"
assert result["affected_signal_sources"] == ["OpenAI Docs"]
@pytest.mark.asyncio
async def test_deep_guard_answer_prefers_member_workload_direct_answer() -> None:
class _FakeResult:
def __init__(self, rows=None, scalar=None):
self._rows = rows or []
self._scalar = scalar
def all(self):
return self._rows
def first(self):
return self._rows[0] if self._rows else None
def scalar_one_or_none(self):
return self._scalar
class _FakeDB:
def __init__(self) -> None:
self.calls = 0
async def execute(self, stmt, params=None): # noqa: ANN001
self.calls += 1
if self.calls == 1:
return _FakeResult(rows=[SimpleNamespace(id=24, name="杨宇", username="yangyu")])
return _FakeResult(rows=[(265.56, 95.6, 60.0)])
class _FakeLLM:
async def generate(self, prompt: str, **kwargs): # pragma: no cover - should not be called
raise AssertionError("LLM should not be called for direct member workload answer")
class _FakeService(AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = _FakeDB()
self.tenant_id = 1
self.llm = _FakeLLM()
def _normalize_thinking_mode(self, thinking_mode: str) -> str:
return "normal"
async def get_project_manifest(self, project_id):
_ = project_id
return {}
async def _resolve_answer_scene_semantics(self, **kwargs):
_ = kwargs
return {
"scene_key": "member_workload",
"snapshot_focus": "none",
"deep_intent": "none",
"confidence": 0.96,
"reason": "structured-scene",
}
async def _select_scene_prompt(self, **kwargs):
_ = kwargs
return "member_workload", "member workload prompt"
def _enforce_feature_evidence_in_answer(self, **kwargs):
return str(kwargs.get("answer_text") or "")
service = _FakeService()
result = await service._generate_answer(
question="杨宇现在负载情况如何?",
retrieved=[],
conversation=[],
project_id=None,
asked_via="feishu",
)
assert "杨宇当前负载265.56%" in result
assert "严重超载" in result
@pytest.mark.asyncio
async def test_deep_guard_answer_prefers_structured_member_workload_scene_without_keyword_hints() -> None:
class _FakeResult:
def __init__(self, rows=None):
self._rows = rows or []
def all(self):
return self._rows
def first(self):
return self._rows[0] if self._rows else None
class _FakeDB:
def __init__(self) -> None:
self.calls = 0
async def execute(self, stmt, params=None): # noqa: ANN001
_ = (stmt, params)
self.calls += 1
if self.calls == 1:
return _FakeResult(rows=[SimpleNamespace(id=24, name="杨宇", username="yangyu")])
return _FakeResult(rows=[(82.0, 41.0, 50.0)])
class _FakeService(AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = _FakeDB()
self.tenant_id = 1
def _normalize_thinking_mode(self, thinking_mode: str) -> str:
_ = thinking_mode
return "normal"
async def get_project_manifest(self, project_id):
_ = project_id
return {}
async def _resolve_answer_scene_semantics(self, **kwargs):
_ = kwargs
return {
"scene_key": "member_workload",
"snapshot_focus": "none",
"deep_intent": "none",
"confidence": 0.95,
"reason": "structured-scene",
}
async def _select_scene_prompt(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError("scene prompt should not be rendered for direct workload answer")
def _enforce_feature_evidence_in_answer(self, **kwargs):
return str(kwargs.get("answer_text") or "")
service = _FakeService()
result = await service._generate_answer(
question="杨宇现在忙不忙?",
retrieved=[],
conversation=[],
project_id=None,
asked_via="feishu",
)
assert "杨宇当前负载82.00%" in result
assert "负载偏高" in result
@pytest.mark.asyncio
async def test_structured_db_retrieval_prefers_structured_people_focus_without_keyword_hints() -> None:
class _FakeScalarResult:
def __init__(self, rows):
self._rows = rows
def scalars(self):
return self
def all(self):
return self._rows
class _FakeDB:
async def execute(self, stmt, params=None): # noqa: ANN001
_ = (stmt, params)
return _FakeScalarResult(
[
SimpleNamespace(id=7, name="杨宇", role="backend", updated_at=None),
SimpleNamespace(id=8, name="林宇航", role="pm", updated_at=None),
]
)
class _FakeService(AdaptiveRAGRetrievalRouterDBMixin):
def __init__(self) -> None:
self.db = _FakeDB()
self.tenant_id = 1
def _query_subject_focus(self, query_semantics): # noqa: ANN001
return str((query_semantics or {}).get("subject_focus") or "unknown")
def _query_scope_hint(self, query_semantics): # noqa: ANN001
return str((query_semantics or {}).get("scope_hint") or "none")
def _normalize_source_registry_metadata(self, *, source_type: str, metadata: dict, explicit_updated_at=None):
_ = (source_type, explicit_updated_at)
return dict(metadata)
service = _FakeService()
rows = await service._retrieve_structured_db(
"他们都有哪些人?",
project_id=None,
query_semantics={
"scope_hint": "global",
"feature_focus": "none",
"goal_kind": "status_lookup",
"resource_role": "people",
"expected_answer_shape": "inventory",
},
)
assert len(rows) == 1
assert "成员清单" in rows[0].content
assert "杨宇" in rows[0].content
@pytest.mark.asyncio
async def test_count_query_prefers_structured_signal_role_without_subject_focus() -> None:
class _ScalarResult:
def __init__(self, value):
self._value = value
def scalar(self):
return self._value
class _FakeDB:
async def execute(self, stmt): # noqa: ANN001
_ = stmt
return _ScalarResult(3)
class _FakeService(AdaptiveRAGDeterministicQueryCountMixin):
def __init__(self) -> None:
self.db = _FakeDB()
self.tenant_id = 1
def _query_scope_hint(self, query_semantics): # noqa: ANN001
return str((query_semantics or {}).get("scope_hint") or "none")
async def _resolve_project_scope_for_question(self, **kwargs): # noqa: ANN001
_ = kwargs
return None, None, ""
service = _FakeService()
result = await service._run_count_query(
question="现在有多少信号?",
project_id=None,
query_semantics={
"goal_kind": "status_lookup",
"resource_role": "signal",
"expected_answer_shape": "inventory",
"scope_hint": "global",
},
)
assert result is not None
assert "信号总数为 3 条" in str(result["answer"])
@pytest.mark.asyncio
async def test_list_query_prefers_structured_signal_role_without_subject_focus() -> None:
class _SignalResult:
def __init__(self, rows):
self._rows = rows
def scalars(self):
return self
def all(self):
return self._rows
class _FakeDB:
async def execute(self, stmt): # noqa: ANN001
_ = stmt
return _SignalResult(
[
SimpleNamespace(id=1, title="开票失败", summary="开票失败告警", status="open", updated_at=None),
SimpleNamespace(id=2, title="发送失败", summary="邮件发送失败", status="pending", updated_at=None),
]
)
class _FakeService(AdaptiveRAGDeterministicQueryListMixin):
def __init__(self) -> None:
self.db = _FakeDB()
self.tenant_id = 1
def _query_scope_hint(self, query_semantics): # noqa: ANN001
return str((query_semantics or {}).get("scope_hint") or "none")
async def _resolve_project_scope_for_question(self, **kwargs): # noqa: ANN001
_ = kwargs
return None, None, ""
service = _FakeService()
result = await service._run_list_query(
question="把现在的信号列出来",
project_id=None,
query_semantics={
"goal_kind": "status_lookup",
"resource_role": "signal",
"expected_answer_shape": "inventory",
"scope_hint": "global",
},
)
assert result is not None
assert "可列举的信号" not in str(result["answer"])
assert "开票失败" in str(result["answer"])
def test_project_status_subject_prefers_structured_project_binding_without_subject_focus() -> None:
class _FakeService(AdaptiveRAGFastAnswerProjectMainMixin):
pass
assert _FakeService._is_project_status_subject(
{
"goal_kind": "status_lookup",
"target_scope": "current_project",
"resource_role": "project_object",
"project_binding": 81,
}
)
def test_feature_evidence_prefers_structured_scene_without_keyword_hints() -> None:
class _FakeService(AdaptiveRAGManifestFeatureMixinP2):
def _query_subject_focus(self, query_semantics): # noqa: ANN001
return str((query_semantics or {}).get("subject_focus") or "unknown")
def _query_feature_focus(self, query_semantics): # noqa: ANN001
return str((query_semantics or {}).get("feature_focus") or "none")
def _collect_feature_evidence(self, *, question: str, retrieved, system_snapshot):
_ = (question, retrieved, system_snapshot)
return [
{
"feature_name": "智能配置",
"route": "/ai-config",
"page_file": "frontend/src/pages/AIConfig.tsx",
"apis": ["/api/v1/ai-config"],
}
]
service = _FakeService()
text = service._enforce_feature_evidence_in_answer(
question="这个模块怎么进?",
answer_text="先看说明。",
retrieved=[],
system_snapshot={},
scene_semantics={"snapshot_focus": "feature"},
)
assert "证据补充(Feature Catalog)" in text
assert "/ai-config" in text
@pytest.mark.asyncio
async def test_deep_guard_answer_feishu_direct_prefers_manifest_and_compact_focus_context() -> None:
class _FakeLLM:
def __init__(self) -> None:
self.prompt = ""
async def generate(self, prompt: str, **kwargs):
_ = kwargs
self.prompt = prompt
return "信息不足,缺少:目标对象"
class _FakeService(AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
def _normalize_thinking_mode(self, thinking_mode: str) -> str:
return "normal"
async def get_project_manifest(self, project_id):
_ = project_id
return {
"manifest_text": "项目#7 Alpha(进行中);功能 18 个;KG 实体 12,关系 19。"
}
async def _render_scene_prompt(self, *, prompt_key: str, fallback_template: str, **kwargs):
_ = prompt_key
return str(fallback_template).format(**kwargs).strip()
def _enforce_feature_evidence_in_answer(self, **kwargs):
return str(kwargs.get("answer_text") or "")
service = _FakeService()
system_snapshot = {
"assistant_profile": {"name": "PMFlow", "identity": "项目管理顾问"},
"platform_profile": {
"backend": {"module_counts": {"projects": 28, "tasks": 146, "signals": 41}},
"feature_catalog": [
{"name": "项目管理", "route": "/projects"},
{"name": "信号接入", "route": "/signals"},
{"name": "任务看板", "route": "/board"},
{"name": "知识图谱", "route": "/kg"},
{"name": "训练中心", "route": "/training"},
],
},
}
user_snapshot = {
"current_user": {"name": "林宇航"},
"projects": [{"id": idx, "title": f"项目{idx}"} for idx in range(1, 15)],
"tasks": [{"id": idx, "title": f"任务{idx}"} for idx in range(1, 10)],
}
result = await service._generate_answer(
question="信息不全,继续提供",
retrieved=[],
conversation=[
{"question": "上一次你缺什么", "answer": "缺目标对象和验收口径"},
{"question": "现在呢", "answer": "还缺时间边界"},
],
project_id=7,
system_snapshot=system_snapshot,
user_snapshot=user_snapshot,
asked_via="feishu",
)
assert result == "信息不足,缺少:目标对象"
assert "项目画像:" in service.llm.prompt
assert "项目#7 Alpha(进行中)" in service.llm.prompt
assert "系统摘要:" in service.llm.prompt
assert "用户焦点:" in service.llm.prompt
assert "林宇航" in service.llm.prompt
assert '"projects"' not in service.llm.prompt
assert "项目14" not in service.llm.prompt
@pytest.mark.asyncio
async def test_select_scene_prompt_applies_consultant_mode_preference_wrapper() -> None:
class _FakeService(AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
async def _render_scene_prompt(self, *, prompt_key: str, fallback_template: str, **kwargs):
_ = (fallback_template, kwargs)
return f"PROMPT::{prompt_key}"
service = _FakeService()
scene_key, prompt = await service._select_scene_prompt(
question="这个方案怎么做更稳妥?",
project_id=7,
asked_via="pmflow",
message_intent=None,
mixed_signal_part=None,
conversation_text="无",
context_blocks_text="无",
system_snapshot={},
user_snapshot={},
system_snapshot_text="{}",
user_snapshot_text="{}",
relevance_max=0.61,
query_type="explain",
consultant_mode_preference="advise",
)
assert scene_key == "default_consultant_advise"
assert "PROMPT::PROMPT_RAG_ANSWER" in prompt
assert "稳妥建议" in prompt
def test_ai_pmo_qa_prompt_includes_five_lenses_and_runtime_state_guard() -> None:
assert "事实源在哪" in PROMPT_AI_PMO_QA
assert "输出模板在哪" in PROMPT_AI_PMO_QA
assert "检索范围在哪" in PROMPT_AI_PMO_QA
assert "执行器在哪" in PROMPT_AI_PMO_QA
assert "反馈回流在哪" in PROMPT_AI_PMO_QA
assert "静态资料" in PROMPT_AI_PMO_QA
assert "运行态配置" in PROMPT_AI_PMO_QA
@pytest.mark.asyncio
async def test_select_scene_prompt_routes_business_review_to_ai_pmo_prompt() -> None:
class _FakeService(AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
async def _render_scene_prompt(self, *, prompt_key: str, fallback_template: str, **kwargs):
_ = fallback_template
return (
f"PROMPT::{prompt_key}|"
f"business_review={kwargs.get('business_review_mode')}|"
f"framework={kwargs.get('review_framework')}"
)
service = _FakeService()
scene_key, prompt = await service._select_scene_prompt(
question="我要做一个大模型 API 聚合平台,帮我分析下要怎么做",
project_id=None,
asked_via="feishu",
message_intent="business_review",
mixed_signal_part=None,
conversation_text="用户上一轮提到要做 API 聚合平台",
context_blocks_text="无",
system_snapshot={},
user_snapshot={},
system_snapshot_text="{}",
user_snapshot_text="{}",
relevance_max=0.51,
query_type="explain",
consultant_mode_preference="clarify",
)
assert scene_key == "ai_pmo_business_review_consultant_clarify"
assert "PROMPT::PROMPT_AI_PMO_QA" in prompt
assert "business_review=true" in prompt
assert "framework=five_lenses" in prompt
def test_runtime_state_query_guard_blocks_static_catalog_evidence() -> None:
class _FakeService(AdaptiveRAGDeepGuardRulesMixin):
pass
service = _FakeService()
decision = service._evaluate_post_retrieval_guard(
deep_intent="runtime_state_query",
sources=[
{"source": "feature_catalog", "label": "Feature Catalog", "metadata": {}},
{"source": "graph", "label": "Knowledge Graph", "metadata": {"path": "1->uses->2"}},
],
relevance_max=0.96,
)
assert decision["should_block_with_guard"] is True
assert decision["guard_focus"] == "runtime_state"
assert "无法仅凭静态资料确认" in service._build_evidence_guard_answer(
"高级模型路由是否启用?",
guard_focus=str(decision["guard_focus"]),
)
def test_runtime_state_query_guard_allows_routing_config_evidence() -> None:
class _FakeService(AdaptiveRAGDeepGuardRulesMixin):
pass
service = _FakeService()
decision = service._evaluate_post_retrieval_guard(
deep_intent="runtime_state_query",
sources=[
{
"source": "doc",
"label": "Routing Config",
"metadata": {"source_id": "backend/.control_plane/pmflow-routing-rules.json"},
}
],
relevance_max=0.74,
)
assert decision["should_block_with_guard"] is False
def test_engine_process_guard_requests_auto_retry_on_snapshot_only_sources() -> None:
class _FakeService(AdaptiveRAGDeepGuardRulesMixin):
pass
service = _FakeService()
decision = service._evaluate_post_retrieval_guard(
deep_intent="engine_process_query",
sources=[
{"source": "system", "label": "System Snapshot", "metadata": {}},
{"source": "system", "label": "User Snapshot", "metadata": {}},
],
relevance_max=0.41,
)
assert decision["auto_retry_reason"] == "snapshot_only"
def test_chat_external_fact_scene_policy_preserves_anchored_external_scene_without_question_heuristics() -> None:
class _FakeService(AdaptiveRAGAnswerMainlineMixin):
pass
service = _FakeService()
normalized = service._apply_chat_external_fact_scene_policy(
question="不对吧,截止当前日期都已经有 codex5.4 了",
project_id=None,
scene_semantics={
"scene_key": "ai_pmo_correction",
"snapshot_focus": "feature",
"deep_intent": "correction_turn",
"confidence": 0.95,
},
anchor_prompt_variant="external_trend",
)
assert normalized["scene_key"] == "industry_trend"
assert normalized["deep_intent"] == "none"
assert normalized["external_fact_chat"] is True
def test_chat_external_fact_scene_policy_keeps_existing_external_scene() -> None:
class _FakeService(AdaptiveRAGAnswerMainlineMixin):
pass
service = _FakeService()
normalized = service._apply_chat_external_fact_scene_policy(
question="当前codex最新的模型用的是什么?",
project_id=None,
scene_semantics={
"scene_key": "industry_trend",
"snapshot_focus": "none",
"deep_intent": "none",
"confidence": 0.92,
},
anchor_prompt_variant=None,
)
assert normalized["scene_key"] == "industry_trend"
assert normalized["snapshot_focus"] == "none"
assert normalized["external_fact_chat"] is True
def test_chat_external_fact_scene_policy_keeps_non_external_scene_unchanged() -> None:
class _FakeService(AdaptiveRAGAnswerMainlineMixin):
pass
service = _FakeService()
normalized = service._apply_chat_external_fact_scene_policy(
question="我们系统当前接的是哪个 codex 模型配置?",
project_id=None,
scene_semantics={
"scene_key": "ai_pmo",
"snapshot_focus": "identity",
"deep_intent": "none",
"confidence": 0.92,
},
anchor_prompt_variant=None,
)
assert normalized["scene_key"] == "ai_pmo"
assert normalized["snapshot_focus"] == "identity"
assert normalized.get("external_fact_chat") is not True
def test_external_fact_freshness_guard_rejects_internal_only_sources() -> None:
class _FakeService(AdaptiveRAGDeepGuardRulesMixin):
pass
service = _FakeService()
assert service._requires_external_freshness(
question="codex 目前最高模型出到什么了",
scene_semantics={"scene_key": "industry_trend", "requires_freshness": True},
) is True
assert service._has_external_grounding_sources(
[
{"source": "graph", "label": "Knowledge Graph", "metadata": {"path": "1->belongs_to->2"}},
{"source": "feature_catalog", "label": "Feature Catalog", "metadata": {}},
]
) is False
answer = service._build_external_freshness_guard_answer("codex 目前最高模型出到什么了")
assert "当前未接入实时外部数据" in answer
assert "backend/app/services" not in answer
@pytest.mark.asyncio
async def test_second_pass_query_skips_internal_hints_for_external_freshness_only() -> None:
class _FakeService(AdaptiveRAGMultiStepCoreMixin):
async def entity_resolution(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"entity_resolution should be skipped: {kwargs}")
async def get_project_manifest(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"get_project_manifest should be skipped: {kwargs}")
service = _FakeService()
revised, meta = await service._build_second_pass_query(
question="codex 目前最高模型出到什么了",
project_id=None,
query_semantics={"external_freshness_only": True},
)
assert revised == "codex 目前最高模型出到什么了"
assert meta["mode"] == "freshness_guard_skip_internal_hint"
@pytest.mark.asyncio
async def test_live_external_freshness_context_fetches_url_rows_before_guard() -> None:
class _FakeService(AdaptiveRAGAnswerRetrievalMixin, AdaptiveRAGDeepGuardRulesMixin):
async def _retrieve_live_external_context(self, *, question: str, max_results: int = 3, max_pages: int = 3):
_ = (question, max_results, max_pages)
return (
[
RetrievedItem(
source="url",
content="OpenAI 在官方文章中说明 GPT-5.4 正在 rollout 到 Codex。",
score=0.93,
source_label="URL[Introducing GPT-5.4]",
metadata={
"url": "https://openai.com/index/introducing-gpt-5-4/",
"target_url": "https://openai.com/index/introducing-gpt-5-4/",
"title": "Introducing GPT-5.4",
},
)
],
{"query": question, "result_count": 1, "fetched_pages": 1},
)
service = _FakeService()
rows, meta = await service._maybe_fetch_live_external_freshness_context(
question="当前codex最新的模型用的是什么?",
effective_question="当前codex最新的模型用的是什么?",
query_semantics={},
scene_semantics={"scene_key": "industry_trend", "requires_freshness": True},
)
assert len(rows) == 1
assert rows[0].source == "url"
assert rows[0].metadata["target_url"] == "https://openai.com/index/introducing-gpt-5-4/"
assert meta["mode"] == "live_external_context"
@pytest.mark.asyncio
async def test_live_external_freshness_context_prefers_external_query_gateway() -> None:
class _FakeService(AdaptiveRAGAnswerRetrievalMixin, AdaptiveRAGDeepGuardRulesMixin):
async def _execute_external_query_gateway(
self,
*,
question: str,
query_semantics: dict | None = None,
result_limit: int = 3,
max_pages: int = 3,
):
_ = (question, query_semantics, result_limit, max_pages)
return (
[
RetrievedItem(
source="url",
content="OpenAI 官方页面显示 Codex 最新模型是 GPT-5.4。",
score=0.94,
source_label="URL[Models - Codex | OpenAI Developers]",
metadata={
"url": "https://developers.openai.com/codex/models",
"target_url": "https://developers.openai.com/codex/models",
"title": "Models - Codex | OpenAI Developers",
},
)
],
{
"mode": "external_query_gateway",
"adapter": "live_search",
"search_result_count": 1,
"fetched_pages": 1,
"query": "codex latest model",
},
)
service = _FakeService()
rows, meta = await service._maybe_fetch_live_external_freshness_context(
question="当前codex最新的模型用的是什么?",
effective_question="当前codex最新的模型用的是什么?",
query_semantics={},
scene_semantics={"scene_key": "industry_trend", "requires_freshness": True},
)
assert len(rows) == 1
assert rows[0].metadata["target_url"] == "https://developers.openai.com/codex/models"
assert meta["mode"] == "external_query_gateway"
assert meta["adapter"] == "live_search"
@pytest.mark.asyncio
async def test_external_query_gateway_falls_back_to_live_search_when_mcp_has_no_evidence() -> None:
from app.services.external_query_service.gateway import ExternalQueryGateway
from app.services.external_query_service.registry import ExternalProviderRegistry
from app.services.external_query_service.schemas import (
ExternalAdapterResult,
ExternalEvidenceItem,
ExternalQueryPlan,
)
plan = ExternalQueryPlan(
plan_version="v1",
query_kind="model",
answer_contract="summary_with_sources",
freshness_required=True,
topic="codex 最新模型",
subject_entities=["Codex"],
location_hint=None,
time_range_hint="截至今天",
preferred_domains=["openai.com"],
search_queries=["codex latest model"],
result_limit=3,
requires_multi_source=False,
clarify_on_ambiguity=False,
)
class _Planner:
async def build_plan(self, *, question: str, query_semantics: dict | None = None) -> ExternalQueryPlan:
_ = (question, query_semantics)
return plan
class _MCPAdapter:
adapter_name = "mcp"
async def execute(self, plan: ExternalQueryPlan) -> ExternalAdapterResult:
_ = plan
return ExternalAdapterResult(adapter_name="mcp", status="unavailable", evidence=[], meta={"reason": "no_client"})
class _LiveSearchAdapter:
adapter_name = "live_search"
async def execute(self, plan: ExternalQueryPlan) -> ExternalAdapterResult:
_ = plan
return ExternalAdapterResult(
adapter_name="live_search",
status="success",
evidence=[
ExternalEvidenceItem(
source_type="url",
source_label="OpenAI Developers",
title="Models - Codex | OpenAI Developers",
target_url="https://developers.openai.com/codex/models",
snippet="Latest: GPT-5.4",
retrieved_at="2026-04-15T10:00:00+08:00",
freshness_score=0.98,
authority_score=0.96,
grounded_fields=["latest_model"],
raw_metadata={"provider": "live_search"},
)
],
meta={"provider": "live_search"},
)
gateway = ExternalQueryGateway(
planner=_Planner(),
registry=ExternalProviderRegistry(adapters=[_MCPAdapter(), _LiveSearchAdapter()]),
)
result = await gateway.execute(
question="当前 codex 最新的模型用的是什么?",
query_semantics={"query_profile": {"needs_freshness": True, "referenced_objects": ["public_model"]}},
)
assert result.adapter_name == "live_search"
assert result.verifier["ok"] is True
assert len(result.evidence) == 1
assert result.meta["fallback_used"] is True
def test_external_route_source_filter_is_fail_closed() -> None:
class _FakeService(AdaptiveRAGQueryRouteGatewayMixin):
pass
service = _FakeService()
filtered = service._filter_sources_for_route(
sources=[
{"source": "feishu", "label": "Feishu history", "score": 0.8},
{"source": "pmflow", "label": "PMFlow records", "score": 0.7},
],
route_decision={"effective_source_policy": "external"},
)
assert filtered == []
@pytest.mark.asyncio
async def test_live_external_search_uses_proxy_aware_http_client(monkeypatch) -> None:
captured: dict[str, object] = {}
class _FakeResponse:
def __init__(self, text: str) -> None:
self.text = text
def raise_for_status(self) -> None:
return None
class _FakeAsyncClient:
def __init__(self, *args, **kwargs) -> None:
_ = args
captured.update(kwargs)
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc, tb) -> None:
_ = (exc_type, exc, tb)
return None
async def get(self, url: str, headers: dict[str, str]):
captured["url"] = url
captured["headers"] = headers
return _FakeResponse('<a class="result__a" href="https://example.com/post">OpenAI Codex latest model</a>')
monkeypatch.setattr(
"app.services.adaptive_rag_service.mixin_conversation_utils_a_p1.httpx.AsyncClient",
_FakeAsyncClient,
)
class _FakeService(AdaptiveRAGConversationUtilsAMixinP1):
pass
rows = await _FakeService()._search_live_external_results(
query="OpenAI Codex latest model",
max_results=1,
)
assert captured["trust_env"] is True
assert rows == [{"url": "https://example.com/post", "title": "OpenAI Codex latest model"}]
@pytest.mark.asyncio
async def test_live_external_fetch_uses_proxy_aware_http_client(monkeypatch) -> None:
captured: dict[str, object] = {}
class _FakeResponse:
def __init__(self) -> None:
self.headers = {"content-type": "text/html"}
self.text = "<html><body><h1>Fresh external fact</h1></body></html>"
def raise_for_status(self) -> None:
return None
class _FakeAsyncClient:
def __init__(self, *args, **kwargs) -> None:
_ = args
captured.update(kwargs)
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc, tb) -> None:
_ = (exc_type, exc, tb)
return None
async def get(self, url: str, headers: dict[str, str]):
captured["url"] = url
captured["headers"] = headers
return _FakeResponse()
monkeypatch.setattr(
"app.services.adaptive_rag_service.mixin_conversation_utils_a_p1.httpx.AsyncClient",
_FakeAsyncClient,
)
class _FakeService(AdaptiveRAGConversationUtilsAMixinP1):
pass
text = await _FakeService()._fetch_url_text("https://example.com/post")
assert captured["trust_env"] is True
assert captured["url"] == "https://example.com/post"
assert "Fresh external fact" in text
def test_live_external_search_result_score_prefers_official_domain_for_model_brand_query() -> None:
official = AdaptiveRAGConversationUtilsAMixinP1._score_live_external_search_result(
question="当前 codex 最新的模型用的是什么?",
title="Codex 全面升级 - OpenAI",
url="https://openai.com/zh-Hans-CN/index/introducing-upgrades-to-codex/",
)
third_party = AdaptiveRAGConversationUtilsAMixinP1._score_live_external_search_result(
question="当前 codex 最新的模型用的是什么?",
title="Codex 模型选择 - 菜鸟教程",
url="https://www.runoob.com/codex/codex-models.html",
)
assert official > third_party
def test_live_external_search_result_score_prefers_codex_models_reference_page_for_latest_model_question() -> None:
reference_page = AdaptiveRAGConversationUtilsAMixinP1._score_live_external_search_result(
question="当前 codex 最新的模型用的是什么?",
title="Models - Codex | OpenAI Developers",
url="https://developers.openai.com/codex/models",
)
announcement_page = AdaptiveRAGConversationUtilsAMixinP1._score_live_external_search_result(
question="当前 codex 最新的模型用的是什么?",
title="Introducing GPT-5.3-Codex - OpenAI",
url="https://openai.com/index/introducing-gpt-5-3-codex/",
)
assert reference_page > announcement_page
def test_live_external_search_queries_prefer_official_site_for_model_brand_question() -> None:
queries = AdaptiveRAGConversationUtilsAMixinP1._build_live_external_search_queries(
"当前 codex 最新的模型用的是什么?"
)
assert queries
assert queries[0] == "site:openai.com codex latest model"
assert any(query == "当前 codex 最新的模型用的是什么" for query in queries)
def test_live_external_search_queries_strip_internal_runtime_tokens_for_model_brand_question() -> None:
queries = AdaptiveRAGConversationUtilsAMixinP1._build_live_external_search_queries(
"围绕“_sync_pmflow_rag_async->backend/app/api/sstc.py”回答:当前codex最新的模型用的是什么?"
)
assert queries
assert queries[0] == "site:openai.com codex latest model"
assert all("backend/app/api/sstc.py" not in query for query in queries)
assert all("_sync_pmflow_rag_async" not in query for query in queries)
def test_live_external_chunk_score_prefers_latest_fact_chunk_for_chinese_model_question() -> None:
latest_chunk = (
"Models – Codex | OpenAI Developers Latest: GPT-5.4 "
"Prompt guidance Core concepts Text generation Code generation"
)
nav_chunk = (
"Codex Docs Guides, concepts, and product docs for Codex "
"Use cases Example workflows and tasks teams hand to Codex"
)
latest_score = AdaptiveRAGConversationUtilsAMixinP1._score_live_external_chunk(
question="当前codex最新的模型用的是什么?",
title="Models - Codex | OpenAI Developers",
content=latest_chunk,
url="https://developers.openai.com/codex/models",
)
nav_score = AdaptiveRAGConversationUtilsAMixinP1._score_live_external_chunk(
question="当前codex最新的模型用的是什么?",
title="Models - Codex | OpenAI Developers",
content=nav_chunk,
url="https://developers.openai.com/codex/models",
)
assert latest_score > nav_score
def test_external_model_fact_direct_answer_prefers_explicit_latest_evidence() -> None:
retrieved = [
RetrievedItem(
source="url",
content=(
"Models – Codex | OpenAI Developers Latest: GPT-5.4 "
"Prompt guidance Core concepts Text generation"
),
score=0.94,
source_label="URL[Models - Codex | OpenAI Developers]",
metadata={
"url": "https://developers.openai.com/codex/models",
"target_url": "https://developers.openai.com/codex/models",
},
)
]
answer = AdaptiveRAGDeepGuardAnswerMixin._build_external_model_fact_direct_answer(
question="当前codex最新的模型用的是什么?",
retrieved=retrieved,
scene_semantics={"scene_key": "industry_trend"},
)
assert answer is not None
assert "GPT-5.4" in answer
assert "OpenAI" in answer
@pytest.mark.asyncio
async def test_live_external_context_prefers_official_candidate_beyond_base_page_window() -> None:
class _FakeService(AdaptiveRAGConversationUtilsAMixinP1):
async def _search_live_external_results(self, *, query: str, max_results: int = 5):
_ = (query, max_results)
return [
{"url": "https://example.com/codex-guide", "title": "Codex 全面上手指南"},
{"url": "https://example.com/codex-models", "title": "Codex 模型选择"},
{"url": "https://example.com/codex-news", "title": "Codex 最新动态"},
{
"url": "https://openai.com/zh-Hans-CN/index/introducing-upgrades-to-codex/",
"title": "Codex 全面升级 - OpenAI",
},
]
async def _fetch_url_text(self, url: str) -> str:
if "openai.com" in url:
return "OpenAI 官方说明 Codex 当前使用 GPT-5.4。"
return "第三方教程,只介绍 Codex 的一般用法。"
rows, meta = await _FakeService()._retrieve_live_external_context(
question="当前 codex 最新的模型用的是什么?",
max_results=1,
max_pages=1,
)
assert rows
assert rows[0].metadata["url"] == "https://openai.com/zh-Hans-CN/index/introducing-upgrades-to-codex/"
assert meta["fetched_pages"] >= 1
@pytest.mark.asyncio
async def test_query_semantics_respects_upstream_explicit_external_contract(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class _FakeLLM:
async def generate(self, prompt: str, **kwargs):
_ = (prompt, kwargs)
return (
'{"intent":"question","question_part":"今天荔湾区天气如何?","statement_part":"",'
'"query_type":"status","retrieval_domains":["db","graph","url"],'
'"subject_focus":"unknown","scope_hint":"none","feature_focus":"none",'
'"source_policy":"external",'
'"query_profile":{"needs_private_context":false,"needs_freshness":true,"referenced_objects":["weather"],"confidence":0.96}}'
)
class _FakeService(AdaptiveRAGCoreIntentMixin, AdaptiveRAGAnswerMainlineMixin, AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
async def _fake_aplan_message(cls, *, message_text: str, source_system: str, metadata=None):
_ = (cls, message_text, source_system, metadata)
return WorkflowSemanticPlanner.deserialize_bundle(
{
"bundle_id": "semantic-weather-external",
"semantic_version": "v1",
"source_system": "adaptive_rag",
"primary_workflow": "query_flow",
"workflows": [
{
"workflow_type": "query_flow",
"workflow_action": "answer",
"target_scope": "global",
"operation_codes": ["query.answer"],
"requires_confirmation": False,
"confidence": 0.92,
"clarification_needed": False,
"metadata": {},
}
],
"message_gate": "auto",
"reply_contract": {"mode": "text", "template_key": "workflow_bundle", "summary": "query_flow"},
"diagnostics": {"message_intent": "question"},
}
)
monkeypatch.setattr(WorkflowSemanticPlanner, "aplan_message", classmethod(_fake_aplan_message))
service = _FakeService()
semantics = await service._resolve_query_semantics(
message="今天荔湾区天气如何?",
source_system="pmflow",
)
assert semantics["source_policy"] == "external"
assert semantics["effective_source_policy"] == "external"
assert semantics["retrieval_domains"] == ["url"]
assert semantics["query_profile"]["needs_freshness"] is True
assert semantics["decision_origin"] == "query_semantics_contract"
assert semantics["source_reason"] == "query_semantics_contract"
assert "referenced_objects" not in semantics["query_profile"]
@pytest.mark.asyncio
async def test_query_semantics_keeps_uncertain_contract_uncertain_without_default_external_first(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class _FakeLLM:
async def generate(self, prompt: str, **kwargs):
_ = (prompt, kwargs)
return (
'{"intent":"question","question_part":"当前 codex 最新的模型用的是什么?","statement_part":"",'
'"query_type":"status","retrieval_domains":["db","pmflow"],'
'"subject_focus":"feature","scope_hint":"global","feature_focus":"purpose",'
'"query_profile":{"needs_private_context":false,"needs_freshness":true,"referenced_objects":["public_model"],"confidence":0.95}}'
)
class _FakeService(AdaptiveRAGCoreIntentMixin, AdaptiveRAGAnswerMainlineMixin, AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
async def _fake_aplan_message(cls, *, message_text: str, source_system: str, metadata=None):
_ = (cls, message_text, source_system, metadata)
return WorkflowSemanticPlanner.deserialize_bundle(
{
"bundle_id": "semantic-public-model-fact",
"semantic_version": "v1",
"source_system": "adaptive_rag",
"primary_workflow": "query_flow",
"workflows": [
{
"workflow_type": "query_flow",
"workflow_action": "answer",
"target_scope": "global",
"operation_codes": ["query.answer"],
"requires_confirmation": False,
"confidence": 0.9,
"clarification_needed": False,
"metadata": {},
}
],
"message_gate": "auto",
"reply_contract": {"mode": "text", "template_key": "workflow_bundle", "summary": "query_flow"},
"diagnostics": {"message_intent": "question"},
}
)
monkeypatch.setattr(WorkflowSemanticPlanner, "aplan_message", classmethod(_fake_aplan_message))
service = _FakeService()
semantics = await service._resolve_query_semantics(
message="当前 codex 最新的模型用的是什么?",
source_system="pmflow",
)
assert semantics["source_policy"] == "uncertain"
assert semantics["effective_source_policy"] == "uncertain"
assert semantics["retrieval_domains"] == ["db", "pmflow"]
assert semantics["query_profile"]["needs_freshness"] is True
assert semantics["decision_origin"] == "query_semantics_contract"
assert semantics["source_reason"] == "query_semantics_contract"
assert "referenced_objects" not in semantics["query_profile"]
@pytest.mark.asyncio
async def test_query_semantics_promotes_url_only_freshness_contract_to_external_without_object_mapping(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class _FakeLLM:
async def generate(self, prompt: str, **kwargs):
_ = (prompt, kwargs)
return (
'{"intent":"question","question_part":"帮我看看未来5天的广州天气如何","statement_part":"",'
'"query_type":"status","retrieval_domains":["url"],'
'"subject_focus":"signal","scope_hint":"global","feature_focus":"none",'
'"query_profile":{"needs_private_context":false,"needs_freshness":true,"referenced_objects":["weather"],"confidence":0.95}}'
)
class _FakeService(AdaptiveRAGCoreIntentMixin, AdaptiveRAGAnswerMainlineMixin, AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
async def _fake_aplan_message(cls, *, message_text: str, source_system: str, metadata=None):
_ = (cls, message_text, source_system, metadata)
return WorkflowSemanticPlanner.deserialize_bundle(
{
"bundle_id": "semantic-url-only-freshness",
"semantic_version": "v1",
"source_system": "adaptive_rag",
"primary_workflow": "query_flow",
"workflows": [
{
"workflow_type": "query_flow",
"workflow_action": "answer",
"target_scope": "global",
"operation_codes": ["query.answer"],
"requires_confirmation": False,
"confidence": 0.94,
"clarification_needed": False,
"metadata": {},
}
],
"message_gate": "auto",
"reply_contract": {"mode": "text", "template_key": "workflow_bundle", "summary": "query_flow"},
"diagnostics": {"message_intent": "weather_query"},
}
)
monkeypatch.setattr(WorkflowSemanticPlanner, "aplan_message", classmethod(_fake_aplan_message))
service = _FakeService()
semantics = await service._resolve_query_semantics(
message="帮我看看未来5天的广州天气如何",
source_system="feishu",
)
assert semantics["source_policy"] == "external"
assert semantics["effective_source_policy"] == "external"
assert semantics["retrieval_domains"] == ["url"]
assert semantics["source_reason"] == "query_semantics_url_only_external_contract"
assert semantics["decision_origin"] == "query_semantics_contract_normalized"
@pytest.mark.asyncio
async def test_query_semantics_preserves_internal_runtime_query_profile_for_runtime_question(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class _FakeLLM:
async def generate(self, prompt: str, **kwargs):
_ = (prompt, kwargs)
return (
'{"intent":"question","question_part":"我们系统当前接的是哪个 codex 模型配置?","statement_part":"",'
'"query_type":"status","retrieval_domains":["url","db","pmflow"],'
'"subject_focus":"feature","scope_hint":"project","feature_focus":"catalog",'
'"source_policy":"internal",'
'"query_profile":{"needs_private_context":true,"needs_freshness":false,"referenced_objects":["system_config","model_routing"],"confidence":0.97}}'
)
class _FakeService(AdaptiveRAGCoreIntentMixin, AdaptiveRAGAnswerMainlineMixin, AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
async def _fake_aplan_message(cls, *, message_text: str, source_system: str, metadata=None):
_ = (cls, message_text, source_system, metadata)
return WorkflowSemanticPlanner.deserialize_bundle(
{
"bundle_id": "semantic-model-config-internal",
"semantic_version": "v1",
"source_system": "adaptive_rag",
"primary_workflow": "query_flow",
"workflows": [
{
"workflow_type": "query_flow",
"workflow_action": "answer",
"target_scope": "global",
"operation_codes": ["query.answer"],
"requires_confirmation": False,
"confidence": 0.9,
"clarification_needed": False,
"metadata": {},
}
],
"message_gate": "auto",
"reply_contract": {"mode": "text", "template_key": "workflow_bundle", "summary": "query_flow"},
"diagnostics": {"message_intent": "question"},
}
)
monkeypatch.setattr(WorkflowSemanticPlanner, "aplan_message", classmethod(_fake_aplan_message))
service = _FakeService()
semantics = await service._resolve_query_semantics(
message="我们系统当前接的是哪个 codex 模型配置?",
source_system="pmflow",
)
assert semantics["source_policy"] == "internal"
assert semantics["effective_source_policy"] == "internal"
assert semantics["retrieval_domains"] == ["db", "pmflow"]
assert semantics["query_profile"]["needs_private_context"] is True
assert semantics["decision_origin"] == "query_semantics_contract"
assert "referenced_objects" not in semantics["query_profile"]
@pytest.mark.asyncio
async def test_internal_model_config_fast_answer_reads_runtime_engine_bundle() -> None:
class _FakeLLM:
async def _get_or_init_bundle(self, db, *, tenant_id: int):
_ = (db, tenant_id)
return object(), {
"active_engine_id": "low-1",
"engines": [
{
"id": "low-1",
"name": "Qwen 低阶引擎",
"provider": "dashscope",
"model": "qwen-plus",
"base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1",
},
{
"id": "high-1",
"name": "OpenAI 高阶引擎",
"provider": "openai",
"model": "GLM-5",
"base_url": "https://api.edgefn.net/v1",
},
],
"settings": {
"enable_local_kb_qa": False,
},
}
def _resolve_active_engine_from_bundle(self, bundle: dict[str, object]):
engines = list(bundle.get("engines") or [])
return dict(engines[0])
async def _resolve_engine_for_call(self, db, *, tenant_id: int, function_name: str, routing_meta=None):
_ = (db, tenant_id, routing_meta)
if function_name == "adaptive_rag_answer_deep":
return {
"name": "Qwen 低阶引擎",
"provider": "dashscope",
"model": "qwen-plus",
"_routing_meta": {"planned_tier": "low", "executed_tier": "low"},
}
return {
"name": "Qwen 低阶引擎",
"provider": "dashscope",
"model": "qwen-plus",
"_routing_meta": {"planned_tier": "low", "executed_tier": "low"},
}
class _FakeService(AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
service = _FakeService()
fast_result = await service._build_internal_model_config_fast_answer(
question="我们系统当前接的是哪个 codex 模型配置?",
query_semantics={
"effective_source_policy": "internal",
"query_type": "status",
"business_frame": {
"goal_kind": "status_lookup",
"target_scope": "global",
"resource_role": "config",
"expected_answer_shape": "bounded_explanation",
},
"operation_contract": {
"query_type": "status",
},
"target_resolution": {
"target_entity_type": "config",
"target_ref": "config:model_routing",
},
},
)
assert isinstance(fast_result, dict)
assert "qwen-plus" in str(fast_result["answer"])
assert "adaptive_rag_answer_normal" in str(fast_result["answer"])
assert "enable_local_kb_qa=false" in str(fast_result["answer"])
assert fast_result["query_type"] == "status"
assert fast_result["prompt_variant_id"] == "internal_model_config_direct"
labels = [str(item.get("label") or "") for item in list(fast_result.get("sources") or [])]
assert "Integration[llm_engine]" in labels
assert "Integration[model_routing:adaptive_rag_answer_normal]" in labels
@pytest.mark.asyncio
async def test_internal_model_config_fast_answer_returns_mcp_config_summary_for_mcp_target() -> None:
class _FakeService(AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = object()
class _FakeMcpConfigService:
def __init__(self, db, *, tenant_id: int):
_ = (db, tenant_id)
async def list_servers(self) -> list[dict[str, object]]:
return [
{
"id": "mcp_01",
"name": "microsoft_learn_prod",
"display_name": "Microsoft Learn",
"template_id": "microsoft_learn",
},
{
"id": "mcp_02",
"name": "duckduckgo_backup",
"display_name": "DuckDuckGo",
"template_id": "duckduckgo",
},
]
import app.services.adaptive_rag_service.mixin_deep_guard_answer as deep_guard_module
original_service = getattr(deep_guard_module, "McpConfigService", None)
deep_guard_module.McpConfigService = _FakeMcpConfigService
try:
service = _FakeService()
packet = InternalContextPacket.model_validate(
{
"packet_version": "v1",
"question": "当前系统有没有 MCP 配置?",
"scope": {
"tenant_id": 1,
"project_id": None,
"session_id": 11,
"conversation_scope_key": "scope:mcp:1",
"reply_to_message_id": None,
"root_message_id": None,
},
"route_decision": {
"route_mode": "internal",
"effective_source_policy": "internal",
},
"operation_contract": {
"query_type": "status",
"answer_contract": "entity_snapshot",
},
"target_resolution": {
"target_entity_type": "config",
"target_ref": "config:mcp_template_center",
"resolution_mode": "deterministic",
"confidence": 0.98,
},
"query_plan": {
"plan_version": "v2",
"query_type": "status",
"entity_type": "config",
"answer_contract": "entity_snapshot",
"target_ref": "config:mcp_template_center",
"filters": [],
},
"executor_summary": {},
"verifier_summary": {},
"uncertainties": [],
}
)
fast_result = await service._build_internal_model_config_fast_answer(
question="当前系统有没有 MCP 配置?",
query_semantics={
"effective_source_policy": "internal",
"query_type": "status",
"business_frame": {
"goal_kind": "status_lookup",
"target_scope": "global",
"resource_role": "config",
"source_kind": "internal",
"expected_answer_shape": "bounded_explanation",
"conversation_posture": "business_operating",
"object_binding": "config:mcp_template_center",
"evidence_mode": "verified",
},
"operation_contract": {
"query_type": "status",
},
"target_resolution": {
"target_entity_type": "config",
"target_ref": "config:mcp_template_center",
},
},
internal_context_packet=packet,
)
finally:
if original_service is None:
delattr(deep_guard_module, "McpConfigService")
else:
deep_guard_module.McpConfigService = original_service
assert isinstance(fast_result, dict)
answer = str(fast_result["answer"] or "")
assert "当前系统里已有 2 个 MCP 配置" in answer
assert "Microsoft Learn" in answer
assert "DuckDuckGo" in answer
labels = [str(item.get("label") or "") for item in list(fast_result.get("sources") or [])]
assert "Integration[mcp_template_center]" in labels
@pytest.mark.asyncio
async def test_internal_model_config_fast_answer_skips_non_config_target_resolution() -> None:
class _FakeLLM:
async def _get_or_init_bundle(self, db, *, tenant_id: int): # pragma: no cover - should not be called
raise AssertionError(f"bundle lookup should be skipped: {db}, {tenant_id}")
def _resolve_active_engine_from_bundle(self, bundle: dict[str, object]): # pragma: no cover - should not be called
raise AssertionError(f"active engine should be skipped: {bundle}")
async def _resolve_engine_for_call(self, db, *, tenant_id: int, function_name: str, routing_meta=None): # pragma: no cover - should not be called
raise AssertionError(f"engine lookup should be skipped: {function_name}, {routing_meta}")
class _FakeService(AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
service = _FakeService()
fast_result = await service._build_internal_model_config_fast_answer(
question="系统里有没有知识库?",
query_semantics={
"effective_source_policy": "internal",
"query_type": "existence",
"business_frame": {
"goal_kind": "status_lookup",
"target_scope": "current_project",
"resource_role": "project_object",
"project_binding": 72,
},
"operation_contract": {
"query_type": "existence",
},
"target_resolution": {
"target_entity_type": "project",
"target_ref": "project:72",
},
},
)
assert fast_result is None
@pytest.mark.asyncio
async def test_internal_model_config_fast_answer_ignores_referenced_objects_without_structured_config_role() -> None:
class _FakeLLM:
async def _get_or_init_bundle(self, db, *, tenant_id: int): # pragma: no cover - should not be called
raise AssertionError(f"bundle lookup should be skipped: {db}, {tenant_id}")
def _resolve_active_engine_from_bundle(self, bundle: dict[str, object]): # pragma: no cover - should not be called
raise AssertionError(f"active engine should be skipped: {bundle}")
async def _resolve_engine_for_call(self, db, *, tenant_id: int, function_name: str, routing_meta=None): # pragma: no cover - should not be called
raise AssertionError(f"engine lookup should be skipped: {function_name}, {routing_meta}")
class _FakeService(AdaptiveRAGDeepGuardAnswerMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
service = _FakeService()
fast_result = await service._build_internal_model_config_fast_answer(
question="我们系统当前接的是哪个 codex 模型配置?",
query_semantics={
"effective_source_policy": "internal",
"query_type": "status",
"operation_contract": {
"query_type": "status",
},
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"referenced_objects": ["system_config", "model_routing"],
},
},
)
assert fast_result is None
@pytest.mark.asyncio
async def test_fast_project_progress_answer_supports_structured_impact_judgment_queries(
monkeypatch,
) -> None:
project = SimpleNamespace(
id=91,
title="采购经理每日实时库存上报服务",
name="采购经理每日实时库存上报服务",
status="active",
owner_id=11,
updated_at=datetime(2026, 4, 12, 10, 0),
description="围绕采购经理的库存上报、波动预警和异常协同。",
)
owner = SimpleNamespace(name="供应链负责人")
tasks = [
SimpleNamespace(status="进行中", updated_at=datetime(2026, 4, 12, 9, 0), created_at=datetime(2026, 4, 12, 8, 0)),
SimpleNamespace(status="待处理", updated_at=datetime(2026, 4, 12, 9, 30), created_at=datetime(2026, 4, 12, 8, 30)),
]
signals = [
("处理中", False, "processing"),
("待处理", False, "pending"),
]
class FakeScalarResult:
def __init__(self, *, scalar=None, rows=None) -> None:
self._scalar = scalar
self._rows = list(rows or [])
def scalar_one_or_none(self):
return self._scalar
def scalars(self):
return SimpleNamespace(all=lambda: list(self._rows))
def all(self):
return list(self._rows)
class FakeDB:
async def execute(self, stmt):
sql = str(stmt).lower()
if "from projects" in sql:
return FakeScalarResult(scalar=project)
if "from users" in sql:
return FakeScalarResult(scalar=owner)
if "from tasks" in sql:
return FakeScalarResult(rows=tasks)
if "from signals" in sql:
return FakeScalarResult(rows=signals)
raise AssertionError(sql)
async def _fake_render_prompt(self, *, fallback_template: str, **kwargs):
_ = self
return str(fallback_template).format(**kwargs).strip()
monkeypatch.setattr(
"app.services.prompt_release.service.PromptReleaseService.render_prompt",
_fake_render_prompt,
)
class _FakeLLM:
async def generate(self, prompt: str, **kwargs):
_ = (prompt, kwargs)
return json.dumps(
{
"handled": True,
"summary": "WMS 接口波动会先冲击库存上报的输入链路。",
"stage_judgement": "外部依赖敏感阶段",
"evidence_summary": "当前库存上报项目仍依赖 WMS 明细输入,项目里还有进行中的接入任务。",
"core_gap": "一旦上游接口抖动,库存上报会先出现输入不完整和异常延迟。",
"external_impact": "最先受影响的是每日库存上报和异常预警两段。",
"actions": [
{"slot": "this_week", "text": "先把 WMS 数据缺失时的降级和补拉链路补齐。"},
{"slot": "owner_decision", "text": "明确接口波动时谁来兜底确认库存数据。"},
{"slot": "protect_priority", "text": "优先保住异常库存预警这一段。"},
],
},
ensure_ascii=False,
)
class FakeRAG(
AdaptiveRAGFastAnswerProjectMainMixin,
AdaptiveRAGConversationUtilsAMixinP1,
):
def __init__(self) -> None:
self.db = FakeDB()
self.tenant_id = 1
self.llm = _FakeLLM()
async def _resolve_project_scope_for_question(self, **kwargs):
_ = kwargs
return (91, "采购经理每日实时库存上报服务", "采购经理每日实时库存上报服务")
async def _execute_external_query_gateway(self, **kwargs):
_ = kwargs
return ([], {"mode": "external_query_gateway_empty"})
rag = FakeRAG()
result = await rag._try_fast_project_progress_answer(
clean_q="WMS接口波动,会不会先影响采购经理每日实时库存上报服务?",
project_id=None,
query_semantics={
"business_frame": {
"goal_kind": "impact_judgment",
"target_scope": "explicit_project",
"resource_role": "project_object",
"source_kind": "hybrid",
"expected_answer_shape": "impact_chain",
"conversation_posture": "business_operating",
"project_binding": 91,
"evidence_mode": "verified",
},
},
)
assert result is not None
answer = str(result["answer"] or "")
assert "项目 #91《采购经理每日实时库存上报服务》" in answer
assert "WMS 接口波动会先冲击库存上报的输入链路。" in answer
assert "对项目的直接影响:最先受影响的是每日库存上报和异常预警两段。" in answer
@pytest.mark.asyncio
async def test_second_pass_query_skips_internal_hints_for_effective_external_source_policy() -> None:
class _FakeService(AdaptiveRAGMultiStepCoreMixin):
async def entity_resolution(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"entity_resolution should be skipped: {kwargs}")
async def get_project_manifest(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"get_project_manifest should be skipped: {kwargs}")
service = _FakeService()
revised, meta = await service._build_second_pass_query(
question="今天荔湾区天气如何?",
project_id=None,
query_semantics={"effective_source_policy": "external"},
)
assert revised == "今天荔湾区天气如何?"
assert meta["mode"] == "external_source_policy_skip_internal_hint"
@pytest.mark.asyncio
async def test_multi_step_search_skips_internal_enrichment_for_effective_external_source_policy() -> None:
class _FakeService(AdaptiveRAGMultiStepFlowMixin, AdaptiveRAGMultiStepCoreMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.context_cache = SimpleNamespace(
get_system_snapshot=self._unexpected_system_snapshot,
)
async def _unexpected_system_snapshot(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"system snapshot should be skipped: {kwargs}")
async def entity_resolution(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"entity_resolution should be skipped: {kwargs}")
async def get_project_manifest(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"get_project_manifest should be skipped: {kwargs}")
def _match_feature_catalog_entries(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"feature catalog should be skipped: {kwargs}")
def _retrieve_feature_catalog_context(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"feature retrieval should be skipped: {kwargs}")
async def _run_single_retrieval_pass(self, **kwargs):
_ = kwargs
return (
[
RetrievedItem(
source="url",
content="广州荔湾区今日天气:多云转阵雨。",
score=0.93,
source_label="URL[weather.example]",
metadata={"url": "https://weather.example/liwan"},
)
],
{
"db_query_ms": 0,
"vector_search_ms": 12,
"graph_query_ms": 0,
"db_timeout": False,
"vector_timeout": False,
"graph_timeout": False,
},
)
service = _FakeService()
rows, meta = await service._multi_step_search(
question="今天荔湾区天气如何?",
domains=["url"],
project_id=None,
source_chat_id=None,
query_semantics={"effective_source_policy": "external"},
session_state=None,
)
assert len(rows) == 1
assert rows[0].source == "url"
assert meta["domains_used"] == ["url"]
assert all(item.get("tool") != "freshness_guard" for item in meta["tool_trace"])
@pytest.mark.asyncio
async def test_answer_scene_semantics_uses_source_policy_without_llm_call() -> None:
class _FakeLLM:
async def generate(self, prompt: str, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"scene semantics should not hit llm: {prompt} | {kwargs}")
class _FakeService(AdaptiveRAGDeepGuardAnswerMixin, AdaptiveRAGAnswerMainlineMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
service = _FakeService()
semantics = await service._resolve_answer_scene_semantics(
question="今天荔湾区天气如何?",
effective_question="今天荔湾区天气如何?",
asked_via="pmflow",
message_intent="casual_chat",
query_type="status",
conversation_text="无",
source_policy="external",
)
assert semantics["scene_key"] == "industry_trend"
assert semantics["confidence"] == 1.0
assert semantics["reason"] == "source_policy:external"
@pytest.mark.asyncio
async def test_answer_scene_semantics_uses_query_scope_for_external_project_scene() -> None:
class _FakeLLM:
async def generate(self, prompt: str, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"scene semantics should not hit llm: {prompt} | {kwargs}")
class _FakeService(AdaptiveRAGDeepGuardAnswerMixin, AdaptiveRAGAnswerMainlineMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = _FakeLLM()
service = _FakeService()
semantics = await service._resolve_answer_scene_semantics(
question="现在这个情况会有什么影响?",
effective_question="现在这个情况会有什么影响?",
asked_via="pmflow",
message_intent="question",
query_type="explain",
conversation_text="无",
source_policy="external",
project_id=12,
query_semantics={"scope_hint": "project"},
)
assert semantics["scene_key"] == "external_trend"
assert semantics["reason"] == "source_policy:external"
@pytest.mark.asyncio
async def test_query_route_gateway_uses_upstream_internal_contract_without_runtime_probes() -> None:
class _FakeService(AdaptiveRAGQueryRouteGatewayMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
async def _run_internal_route_probe(self, **kwargs):
raise AssertionError(f"runtime internal probe should not be called: {kwargs}")
async def _run_external_route_probe(self, **kwargs):
raise AssertionError(f"runtime external probe should not be called: {kwargs}")
async def _retrieve_query_route_memory_prior(self, **kwargs):
raise AssertionError(f"route memory prior should not be called: {kwargs}")
service = _FakeService()
decision = await service._run_query_route_gateway(
question="我们系统当前接的是哪个 codex 模型配置?",
asked_via="pmflow_manual",
project_id=None,
source_chat_id=None,
query_semantics={
"source_policy": "internal",
"effective_source_policy": "internal",
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"referenced_objects": ["system_config", "model_routing"],
}
},
source_policy_hint=None,
)
assert decision["route_mode"] == "internal"
assert decision["effective_source_policy"] == "internal"
assert decision["decision_origin"] == "query_semantics_contract"
assert decision["reply_contract"]["head"] == "内部知识库查询:"
assert decision["probe_snapshot"]["contract"]["source_policy"] == "internal"
@pytest.mark.asyncio
async def test_query_route_gateway_keeps_uncertain_contract_as_clarify_without_external_first_fallback() -> None:
class _FakeService(AdaptiveRAGQueryRouteGatewayMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
async def _run_internal_route_probe(self, **kwargs):
raise AssertionError(f"runtime internal probe should not be called: {kwargs}")
async def _run_external_route_probe(self, **kwargs):
raise AssertionError(f"runtime external probe should not be called: {kwargs}")
async def _retrieve_query_route_memory_prior(self, **kwargs):
raise AssertionError(f"route memory prior should not be called: {kwargs}")
service = _FakeService()
decision = await service._run_query_route_gateway(
question="当前 codex 最新的模型用的是什么?",
asked_via="pmflow_manual",
project_id=None,
source_chat_id=None,
query_semantics={
"source_policy": "uncertain",
"effective_source_policy": "uncertain",
"query_profile": {
"needs_private_context": False,
"needs_freshness": True,
"referenced_objects": ["public_model"],
}
},
source_policy_hint=None,
)
assert decision["route_mode"] == "uncertain"
assert decision["effective_source_policy"] == "uncertain"
assert decision["decision_origin"] == "query_semantics_contract"
assert decision["reply_contract"]["mode"] == "clarify"
assert "系统内部配置" in str(decision["clarification_text"])
assert decision["probe_snapshot"]["contract"]["source_policy"] == "uncertain"
@pytest.mark.asyncio
async def test_query_route_gateway_builds_external_execution_recipe_for_current_project() -> None:
class _FakeService(AdaptiveRAGQueryRouteGatewayMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
service = _FakeService()
decision = await service._run_query_route_gateway(
question="这个方案适不适合我们当前项目?",
asked_via="pmflow_manual",
project_id=17,
source_chat_id="pmflow-project-17",
query_semantics={
"message_intent": "question",
"query_type": "explain",
"source_policy": "external",
"effective_source_policy": "external",
"query_profile": {
"needs_private_context": False,
"needs_freshness": True,
"referenced_objects": ["public_solution"],
},
},
source_policy_hint=None,
)
packet = decision["project_operating_context"]
recipe = decision["execution_recipe"]
assert packet["current_project_id"] == 17
assert packet["page_anchor"]["project_id"] == 17
assert packet["page_anchor"]["source_chat_id"] == "pmflow-project-17"
assert recipe == {
"primary_lane": "external",
"fit_brief_required": True,
"external_evidence_required": True,
"plan_handoff_mode": "offer_after_answer",
}
@pytest.mark.asyncio
async def test_query_route_gateway_keeps_explicit_requirement_plan_recipe() -> None:
class _FakeService(AdaptiveRAGQueryRouteGatewayMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
service = _FakeService()
decision = await service._run_query_route_gateway(
question="那按这个结论继续收需求",
asked_via="pmflow_manual",
project_id=17,
source_chat_id="pmflow-project-17",
query_semantics={
"message_intent": "requirement_plan",
"query_type": "plan",
"source_policy": "internal",
"effective_source_policy": "internal",
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"referenced_objects": ["project_requirement"],
},
},
source_policy_hint=None,
)
assert decision["execution_recipe"] == {
"primary_lane": "plan",
"fit_brief_required": False,
"external_evidence_required": False,
"plan_handoff_mode": "explicit_plan_now",
}
@pytest.mark.asyncio
async def test_query_route_gateway_can_disable_unified_execution_recipe(monkeypatch: pytest.MonkeyPatch) -> None:
class _FakeService(AdaptiveRAGQueryRouteGatewayMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
monkeypatch.setenv("PMFLOW_ENABLE_UNIFIED_EXECUTION_RECIPE", "0")
service = _FakeService()
decision = await service._run_query_route_gateway(
question="这个方案适不适合当前项目?",
asked_via="pmflow_manual",
project_id=17,
source_chat_id="pmflow-project-17",
query_semantics={
"message_intent": "question",
"query_type": "explain",
"source_policy": "external",
"effective_source_policy": "external",
"query_profile": {
"needs_private_context": False,
"needs_freshness": True,
"referenced_objects": ["public_solution"],
},
},
source_policy_hint=None,
)
assert decision["execution_recipe"] == {
"primary_lane": "external",
"fit_brief_required": False,
"external_evidence_required": True,
"plan_handoff_mode": "none",
}
@pytest.mark.asyncio
async def test_query_route_clarification_response_stores_pending_route_protocol() -> None:
class _FakeDB:
def add(self, obj) -> None:
obj.id = 1
async def flush(self) -> None:
return None
async def commit(self) -> None:
return None
async def refresh(self, obj) -> None:
_ = obj
return None
class _FakeContextCache:
async def append_session_messages(self, **kwargs) -> None:
_ = kwargs
return None
class _FakeService(
AdaptiveRAGAnswerPrecheckMixin,
AdaptiveRAGQueryRouteGatewayMixin,
AdaptiveRAGFollowupAnchorMixin,
):
def __init__(self) -> None:
self.db = _FakeDB()
self.tenant_id = 1
self.context_cache = _FakeContextCache()
def _to_naive_utc(self, value):
return value
def _build_qa_record_runtime_fields(self, **kwargs):
_ = kwargs
return {
"policy_version": "test",
"citations": [],
"sources_used": [],
"evidence_pack": {},
"tool_trace": [],
}
def _build_qa_record_external_fields(self, **kwargs):
_ = kwargs
return {}
def _build_response_payload(self, **kwargs):
return kwargs
async def _update_session_state_after_turn(self, **kwargs):
_ = kwargs
return None
service = _FakeService()
state = SimpleNamespace(
last_subject=None,
last_entity_ids=[],
last_intent=None,
ambiguity="unknown",
rewrite_history=[],
pending_clarification=None,
pending_clarification_expires_at=None,
)
result = await service._maybe_return_clarification_response(
clarification_payload={
"answer": "你是想问外部公开事实,还是系统内部配置/项目对象?",
"code": "query_route_clarify",
"candidates": [],
"missing_fields": ["query_route"],
},
started=0.0,
clean_q="当前系统内是否有为采购经理提出的需求?",
effective_q="当前系统内是否有为采购经理提出的需求?",
query_type="existence",
asked_by=1,
asked_via="feishu",
project_id=None,
session_id=11,
turn_index=2,
state_row=state,
rewrite_meta={"mode": "direct"},
context_session_id=11,
active_thinking_mode="normal",
route_decision={
"route_mode": "uncertain",
"effective_source_policy": "uncertain",
"reply_contract": {
"mode": "clarify",
"clarification_text": "你是想问外部公开事实,还是系统内部配置/项目对象?",
},
},
)
assert result["clarification_code"] == "query_route_clarify"
assert state.pending_clarification["kind"] == "query_route_selection"
assert state.pending_clarification["original_question"] == "当前系统内是否有为采购经理提出的需求?"
assert state.pending_clarification["option_map"] == {"A": "external", "B": "internal"}
assert state.pending_clarification["options"] == [
{
"key": "A",
"label": "外部公开事实",
"query_semantics_overrides": {
"source_policy": "external",
"effective_source_policy": "external",
"source_reason": "query_route_clarification_selection",
"decision_origin": "query_route_clarification_selection",
},
},
{
"key": "B",
"label": "系统内部配置/项目对象",
"query_semantics_overrides": {
"source_policy": "internal",
"effective_source_policy": "internal",
"source_reason": "query_route_clarification_selection",
"decision_origin": "query_route_clarification_selection",
},
},
]
@pytest.mark.asyncio
async def test_target_resolution_clarification_response_stores_pending_internal_target_protocol() -> None:
class _FakeDB:
def add(self, obj) -> None:
obj.id = 1
async def flush(self) -> None:
return None
async def commit(self) -> None:
return None
async def refresh(self, obj) -> None:
_ = obj
return None
class _FakeContextCache:
async def append_session_messages(self, **kwargs) -> None:
_ = kwargs
return None
class _FakeService(
AdaptiveRAGAnswerPrecheckMixin,
AdaptiveRAGQueryRouteGatewayMixin,
AdaptiveRAGFollowupAnchorMixin,
):
def __init__(self) -> None:
self.db = _FakeDB()
self.tenant_id = 1
self.context_cache = _FakeContextCache()
def _to_naive_utc(self, value):
return value
def _build_qa_record_runtime_fields(self, **kwargs):
_ = kwargs
return {
"policy_version": "test",
"citations": [],
"sources_used": [],
"evidence_pack": {},
"tool_trace": [],
}
def _build_qa_record_external_fields(self, **kwargs):
_ = kwargs
return {}
def _build_response_payload(self, **kwargs):
return kwargs
async def _update_session_state_after_turn(self, **kwargs):
_ = kwargs
return None
service = _FakeService()
state = SimpleNamespace(
last_subject=None,
last_entity_ids=[],
last_intent=None,
ambiguity="unknown",
rewrite_history=[],
pending_clarification=None,
pending_clarification_expires_at=None,
)
result = await service._maybe_return_clarification_response(
clarification_payload={
"answer": "当前内部配置对象还不够明确,我先按配置域给你列两个入口:\nA. 模型路由配置\nB. MCP 配置\n你补一个我再继续往里查。",
"code": "target_resolution_clarify",
"candidates": [],
"missing_fields": ["target_resolution"],
"clarification_protocol": {
"kind": "internal_target_selection",
"option_map": {
"A": "config:model_routing",
"B": "config:mcp_template_center",
},
"options": [
{
"key": "A",
"label": "模型路由配置",
"query_semantics_overrides": {
"source_policy": "internal",
"effective_source_policy": "internal",
"business_frame": {
"resource_role": "config",
"object_binding": "config:model_routing",
},
},
},
{
"key": "B",
"label": "MCP 配置",
"query_semantics_overrides": {
"source_policy": "internal",
"effective_source_policy": "internal",
"business_frame": {
"resource_role": "config",
"object_binding": "config:mcp_template_center",
},
},
},
],
},
},
started=0.0,
clean_q="系统里现在有哪些配置?",
effective_q="系统里现在有哪些配置?",
query_type="status",
asked_by=1,
asked_via="feishu",
project_id=None,
session_id=11,
turn_index=2,
state_row=state,
rewrite_meta={"mode": "direct"},
context_session_id=11,
active_thinking_mode="normal",
route_decision={
"route_mode": "internal",
"effective_source_policy": "internal",
"reply_contract": {
"mode": "clarify",
"clarification_text": "当前内部配置对象还不够明确。",
},
},
)
assert result["clarification_code"] == "target_resolution_clarify"
assert state.pending_clarification["kind"] == "internal_target_selection"
assert state.pending_clarification["original_question"] == "系统里现在有哪些配置?"
assert state.pending_clarification["option_map"] == {
"A": "config:model_routing",
"B": "config:mcp_template_center",
}
@pytest.mark.asyncio
async def test_query_route_pending_clarification_consumes_protocol_option_label() -> None:
class _FakeService(AdaptiveRAGFollowupAnchorMixin):
def _to_naive_utc(self, value):
return value
async def _resolve_pending_clarification_selection_semantics(self, **kwargs):
_ = kwargs
return {
"selection_status": "resolved",
"selected_key": "B",
"selected_index": 0,
"confidence": 0.91,
"reason": "test_double",
}
service = _FakeService()
state = SimpleNamespace(
pending_clarification={
"kind": "query_route_selection",
"original_question": "当前系统内是否有为采购经理提出的需求?",
"attempts": 1,
"option_map": {"A": "external", "B": "internal"},
"options": [
{
"key": "A",
"label": "外部公开事实",
"query_semantics_overrides": {
"source_policy": "external",
"effective_source_policy": "external",
},
},
{
"key": "B",
"label": "系统内部配置/项目对象",
"query_semantics_overrides": {
"source_policy": "internal",
"effective_source_policy": "internal",
},
},
],
},
pending_clarification_expires_at=None,
)
consumed = await service._consume_pending_clarification_selection(
question="内部配置",
session_state=state,
)
assert consumed == {
"effective_question": "当前系统内是否有为采购经理提出的需求?",
"source_policy_hint": "internal",
"query_semantics_overrides": {
"source_policy": "internal",
"effective_source_policy": "internal",
},
}
assert state.pending_clarification is None
@pytest.mark.asyncio
async def test_internal_target_pending_clarification_consumes_protocol_option_label() -> None:
class _FakeService(AdaptiveRAGFollowupAnchorMixin):
def _to_naive_utc(self, value):
return value
async def _resolve_pending_clarification_selection_semantics(self, **kwargs):
_ = kwargs
return {
"selection_status": "resolved",
"selected_key": "B",
"selected_index": 0,
"confidence": 0.93,
"reason": "test_double",
}
service = _FakeService()
state = SimpleNamespace(
pending_clarification={
"kind": "internal_target_selection",
"original_question": "系统里现在有哪些配置?",
"attempts": 1,
"option_map": {
"A": "config:model_routing",
"B": "config:mcp_template_center",
},
"options": [
{
"key": "A",
"label": "模型路由配置",
"query_semantics_overrides": {
"source_policy": "internal",
"effective_source_policy": "internal",
"business_frame": {
"resource_role": "config",
"object_binding": "config:model_routing",
},
},
},
{
"key": "B",
"label": "MCP 配置",
"query_semantics_overrides": {
"source_policy": "internal",
"effective_source_policy": "internal",
"business_frame": {
"resource_role": "config",
"object_binding": "config:mcp_template_center",
},
},
},
],
},
pending_clarification_expires_at=None,
)
consumed = await service._consume_pending_clarification_selection(
question="我问的是 MCP 配置。",
session_state=state,
)
assert consumed == {
"effective_question": "系统里现在有哪些配置?",
"source_policy_hint": "internal",
"query_semantics_overrides": {
"source_policy": "internal",
"effective_source_policy": "internal",
"business_frame": {
"resource_role": "config",
"object_binding": "config:mcp_template_center",
},
},
}
assert state.pending_clarification is None
@pytest.mark.asyncio
async def test_prepare_answer_runtime_passes_consumed_query_route_hint_to_preview() -> None:
class _FakeService(AdaptiveRAGAnswerMainlineMixin, AdaptiveRAGFollowupAnchorMixin):
def __init__(self) -> None:
self.preview_kwargs: dict[str, object] = {}
self.state_row = SimpleNamespace(
last_subject=None,
last_entity_ids=[],
last_intent=None,
ambiguity="unknown",
rewrite_history=[],
pending_clarification={
"kind": "query_route_selection",
"original_question": "当前系统内是否有为采购经理提出的需求?",
"attempts": 1,
"option_map": {"A": "external", "B": "internal"},
"options": [
{
"key": "A",
"label": "外部公开事实",
"query_semantics_overrides": {
"source_policy": "external",
"effective_source_policy": "external",
},
},
{
"key": "B",
"label": "系统内部配置/项目对象",
"query_semantics_overrides": {
"source_policy": "internal",
"effective_source_policy": "internal",
},
},
],
},
pending_clarification_expires_at=None,
)
def _to_naive_utc(self, value):
return value
def _build_external_conversation_key(self, **kwargs):
_ = kwargs
return "scope:feishu:test"
def _set_active_external_qa_context(self, **kwargs):
_ = kwargs
async def _touch_session_for_new_record(self, **kwargs):
_ = kwargs
return 11, 2
def _external_session_id_from_key(self, key: str):
_ = key
return 11
async def _load_recent_conversation(self, **kwargs):
_ = kwargs
return []
async def _ensure_session_state(self, **kwargs):
_ = kwargs
return self.state_row
async def _resolve_pending_clarification_selection_semantics(self, **kwargs):
_ = kwargs
return {
"selection_status": "resolved",
"selected_key": "B",
"selected_index": 0,
"confidence": 0.91,
"reason": "test_double",
}
async def _resolve_followup_anchor(self, **kwargs):
_ = kwargs
return FollowupAnchorResolution()
def _rewrite_question_with_state(self, **kwargs):
return kwargs["question"], {"mode": "direct"}
async def preview_query_route_decision(self, **kwargs):
self.preview_kwargs = dict(kwargs)
return {
"query_semantics": {
"source_policy": "internal",
"effective_source_policy": "internal",
"query_type": "existence",
"retrieval_domains": ["db", "pmflow"],
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"referenced_objects": ["system_config"],
},
},
"route_decision": {
"route_mode": "internal",
"effective_source_policy": "internal",
"decision_origin": "upstream_hint",
"reply_contract": {
"mode": "explicit_source",
"head": "内部知识库查询:",
"tail_hint": None,
},
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"referenced_objects": ["system_config"],
},
"probe_snapshot_summary": {},
"probe_snapshot": {},
},
}
async def _resolve_answer_scene_semantics(self, **kwargs):
_ = kwargs
return {"scene_key": "ai_pmo", "deep_intent": "none"}
def _normalize_action_mode(self, value: str) -> str:
return str(value or "").strip().lower() or "auto"
async def _resolve_action_mode_async(self, **kwargs):
_ = kwargs
return ACTION_MODE_READ
service = _FakeService()
runtime = await service._prepare_answer_runtime(
clean_q="内部配置",
asked_by=1,
asked_via="feishu",
project_id=None,
source_chat_id="oc_test_chat",
session_id=11,
conversation_key=None,
force_new_session=False,
action_mode="auto",
)
assert runtime["resolved_question"] == "当前系统内是否有为采购经理提出的需求?"
assert service.preview_kwargs["question"] == "当前系统内是否有为采购经理提出的需求?"
assert service.preview_kwargs["source_policy_hint"] == "internal"
assert service.state_row.pending_clarification is None
@pytest.mark.asyncio
async def test_prepare_answer_runtime_recomputes_route_after_consuming_query_route_selection() -> None:
class _FakeService(
AdaptiveRAGAnswerMainlineMixin,
AdaptiveRAGFollowupAnchorMixin,
AdaptiveRAGQueryRouteGatewayMixin,
):
def __init__(self) -> None:
self.preview_kwargs: dict[str, object] = {}
self.state_row = SimpleNamespace(
last_subject=None,
last_entity_ids=[],
last_intent=None,
ambiguity="unknown",
rewrite_history=[],
pending_clarification={
"kind": "query_route_selection",
"original_question": "当前系统内是否有为采购经理提出的需求?",
"attempts": 1,
"option_map": {"A": "external", "B": "internal"},
"options": [
{
"key": "A",
"label": "外部公开事实",
"query_semantics_overrides": {
"source_policy": "external",
"effective_source_policy": "external",
},
},
{
"key": "B",
"label": "系统内部配置/项目对象",
"query_semantics_overrides": {
"source_policy": "internal",
"effective_source_policy": "internal",
},
},
],
},
pending_clarification_expires_at=None,
)
def _to_naive_utc(self, value):
return value
def _build_external_conversation_key(self, **kwargs):
_ = kwargs
return "scope:feishu:test"
def _set_active_external_qa_context(self, **kwargs):
_ = kwargs
async def _touch_session_for_new_record(self, **kwargs):
_ = kwargs
return 11, 2
def _external_session_id_from_key(self, key: str):
_ = key
return 11
async def _load_recent_conversation(self, **kwargs):
_ = kwargs
return []
async def _ensure_session_state(self, **kwargs):
_ = kwargs
return self.state_row
async def _resolve_pending_clarification_selection_semantics(self, **kwargs):
_ = kwargs
return {
"selection_status": "resolved",
"selected_key": "B",
"selected_index": 0,
"confidence": 0.91,
"reason": "test_double",
}
async def _resolve_followup_anchor(self, **kwargs):
_ = kwargs
return FollowupAnchorResolution()
def _rewrite_question_with_state(self, **kwargs):
return kwargs["question"], {"mode": "direct"}
async def preview_query_route_decision(self, **kwargs):
self.preview_kwargs = dict(kwargs)
return {
"query_semantics": {
"source_policy": "internal",
"effective_source_policy": "internal",
"query_type": "existence",
"retrieval_domains": ["db", "pmflow"],
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"referenced_objects": ["project_object"],
},
},
"route_decision": {
"route_mode": "internal",
"effective_source_policy": "internal",
"decision_origin": "upstream_hint",
"reply_contract": {
"mode": "explicit_source",
"head": "内部知识库查询:",
"tail_hint": None,
},
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"referenced_objects": ["project_object"],
},
"probe_snapshot_summary": {},
"probe_snapshot": {},
},
}
async def _resolve_answer_scene_semantics(self, **kwargs):
_ = kwargs
return {"scene_key": "ai_pmo", "deep_intent": "none"}
def _normalize_action_mode(self, value: str) -> str:
return str(value or "").strip().lower() or "auto"
async def _resolve_action_mode_async(self, **kwargs):
_ = kwargs
return ACTION_MODE_READ
service = _FakeService()
runtime = await service._prepare_answer_runtime(
clean_q="内部配置",
asked_by=1,
asked_via="feishu",
project_id=None,
source_chat_id="oc_test_chat",
session_id=11,
conversation_key=None,
force_new_session=False,
action_mode="auto",
precomputed_query_semantics={
"source_policy": "uncertain",
"effective_source_policy": "uncertain",
"query_type": "explain",
"retrieval_domains": ["db", "pmflow", "doc"],
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"referenced_objects": ["system_config"],
"confidence": 0.9,
},
},
route_decision={
"route_mode": "uncertain",
"effective_source_policy": "uncertain",
"decision_origin": "query_semantics_contract",
"reply_contract": {
"mode": "clarify",
"clarification_text": "你是想问外部公开事实,还是系统内部配置/项目对象?",
},
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"referenced_objects": ["system_config"],
"confidence": 0.9,
},
"probe_snapshot_summary": {},
"probe_snapshot": {},
},
)
assert runtime["resolved_question"] == "当前系统内是否有为采购经理提出的需求?"
assert service.preview_kwargs["question"] == "当前系统内是否有为采购经理提出的需求?"
assert service.preview_kwargs["source_policy_hint"] == "internal"
assert service.preview_kwargs["query_semantics"] == {}
assert runtime["query_semantics"]["source_policy"] == "internal"
assert runtime["query_semantics"]["effective_source_policy"] == "internal"
assert runtime["query_type"] == "existence"
assert runtime["route_decision"]["route_mode"] == "internal"
assert service.state_row.pending_clarification is None
@pytest.mark.asyncio
async def test_prepare_answer_runtime_recomputes_internal_target_after_consuming_internal_target_selection() -> None:
class _FakeService(
AdaptiveRAGAnswerMainlineMixin,
AdaptiveRAGFollowupAnchorMixin,
AdaptiveRAGQueryRouteGatewayMixin,
):
def __init__(self) -> None:
self.preview_kwargs: dict[str, object] = {}
self.state_row = SimpleNamespace(
last_subject=None,
last_entity_ids=[],
last_intent=None,
ambiguity="unknown",
rewrite_history=[],
pending_clarification={
"kind": "internal_target_selection",
"original_question": "系统里现在有哪些配置?",
"attempts": 1,
"option_map": {
"A": "config:model_routing",
"B": "config:mcp_template_center",
},
"options": [
{
"key": "A",
"label": "模型路由配置",
"query_semantics_overrides": {
"source_policy": "internal",
"effective_source_policy": "internal",
"business_frame": {
"goal_kind": "status_lookup",
"target_scope": "global",
"resource_role": "config",
"source_kind": "internal",
"expected_answer_shape": "bounded_explanation",
"conversation_posture": "business_operating",
"object_binding": "config:model_routing",
},
},
},
{
"key": "B",
"label": "MCP 配置",
"query_semantics_overrides": {
"source_policy": "internal",
"effective_source_policy": "internal",
"business_frame": {
"goal_kind": "status_lookup",
"target_scope": "global",
"resource_role": "config",
"source_kind": "internal",
"expected_answer_shape": "bounded_explanation",
"conversation_posture": "business_operating",
"object_binding": "config:mcp_template_center",
},
},
},
],
},
pending_clarification_expires_at=None,
)
def _to_naive_utc(self, value):
return value
def _build_external_conversation_key(self, **kwargs):
_ = kwargs
return "scope:feishu:test"
def _set_active_external_qa_context(self, **kwargs):
_ = kwargs
async def _touch_session_for_new_record(self, **kwargs):
_ = kwargs
return 11, 2
def _external_session_id_from_key(self, key: str):
_ = key
return 11
async def _load_recent_conversation(self, **kwargs):
_ = kwargs
return []
async def _ensure_session_state(self, **kwargs):
_ = kwargs
return self.state_row
async def _resolve_pending_clarification_selection_semantics(self, **kwargs):
_ = kwargs
return {
"selection_status": "resolved",
"selected_key": "B",
"selected_index": 0,
"confidence": 0.92,
"reason": "test_double",
}
async def _resolve_followup_anchor(self, **kwargs):
_ = kwargs
return FollowupAnchorResolution()
def _rewrite_question_with_state(self, **kwargs):
return kwargs["question"], {"mode": "direct"}
async def preview_query_route_decision(self, **kwargs):
self.preview_kwargs = dict(kwargs)
return {
"query_semantics": {
"source_policy": "internal",
"effective_source_policy": "internal",
"query_type": "status",
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"confidence": 0.9,
},
},
"route_decision": {
"route_mode": "internal",
"effective_source_policy": "internal",
"decision_origin": "upstream_hint",
"reply_contract": {
"mode": "explicit_source",
"head": "内部知识库查询:",
"tail_hint": None,
},
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"confidence": 0.9,
},
"probe_snapshot_summary": {},
"probe_snapshot": {},
},
"project_operating_context": {},
"execution_recipe": {},
}
async def _resolve_answer_scene_semantics(self, **kwargs):
_ = kwargs
return {"scene_key": "ai_pmo", "deep_intent": "none"}
def _normalize_action_mode(self, value: str) -> str:
return str(value or "").strip().lower() or "auto"
async def _resolve_action_mode_async(self, **kwargs):
_ = kwargs
return ACTION_MODE_READ
service = _FakeService()
runtime = await service._prepare_answer_runtime(
clean_q="我问的是 MCP 配置。",
asked_by=1,
asked_via="feishu",
project_id=None,
source_chat_id="oc_test_chat",
session_id=11,
conversation_key=None,
force_new_session=False,
action_mode="auto",
)
assert runtime["resolved_question"] == "系统里现在有哪些配置?"
assert service.preview_kwargs["question"] == "系统里现在有哪些配置?"
assert service.preview_kwargs["source_policy_hint"] == "internal"
assert runtime["query_semantics"]["business_frame"]["object_binding"] == "config:mcp_template_center"
assert runtime["query_semantics"]["business_frame"]["resource_role"] == "config"
assert service.state_row.pending_clarification is None
@pytest.mark.asyncio
async def test_prepare_answer_runtime_passes_selected_followup_anchor_id_to_resolver() -> None:
class _FakeService(
AdaptiveRAGAnswerMainlineMixin,
AdaptiveRAGFollowupAnchorMixin,
AdaptiveRAGQueryRouteGatewayMixin,
):
def __init__(self) -> None:
self.anchor_kwargs: dict[str, object] = {}
self.state_row = SimpleNamespace(
last_subject=None,
last_entity_ids=[],
last_intent=None,
ambiguity="unknown",
rewrite_history=[],
pending_clarification={
"kind": "followup_anchor_selection",
"original_question": "我问你这个是哪个模型执行回复的?",
"attempts": 1,
"candidates": [
{"index": 1, "qa_id": 101, "label": "系统架构那条"},
{"index": 2, "qa_id": 102, "label": "系统模型那条"},
],
},
pending_clarification_expires_at=None,
)
def _to_naive_utc(self, value):
return value
def _build_external_conversation_key(self, **kwargs):
_ = kwargs
return "scope:feishu:test"
def _set_active_external_qa_context(self, **kwargs):
_ = kwargs
async def _touch_session_for_new_record(self, **kwargs):
_ = kwargs
return 11, 2
def _external_session_id_from_key(self, key: str):
_ = key
return 11
async def _load_recent_conversation(self, **kwargs):
_ = kwargs
return []
async def _ensure_session_state(self, **kwargs):
_ = kwargs
return self.state_row
async def _resolve_pending_clarification_selection_semantics(self, **kwargs):
_ = kwargs
return {
"selection_status": "resolved",
"selected_key": "",
"selected_index": 2,
"confidence": 0.91,
"reason": "test_double",
}
async def _resolve_followup_anchor(self, **kwargs):
self.anchor_kwargs = dict(kwargs)
return FollowupAnchorResolution(
followup_mode="referential",
anchor_mode="clarification_selection",
anchor_reply_id=102,
anchor_reply={"qa_id": 102, "label": "系统模型那条", "question": "系统有什么模型?"},
)
def _rewrite_question_with_state(self, **kwargs):
return kwargs["question"], {"mode": "direct"}
async def preview_query_route_decision(self, **kwargs):
return {
"query_semantics": {
"source_policy": "internal",
"effective_source_policy": "internal",
"query_type": "existence",
"retrieval_domains": ["db", "pmflow"],
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"referenced_objects": ["system_config"],
},
},
"route_decision": {
"route_mode": "internal",
"effective_source_policy": "internal",
"decision_origin": "query_semantics_contract",
"reply_contract": {
"mode": "explicit_source",
"head": "内部知识库查询:",
"tail_hint": None,
},
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"referenced_objects": ["system_config"],
},
"probe_snapshot_summary": {},
"probe_snapshot": {},
},
}
async def _resolve_answer_scene_semantics(self, **kwargs):
_ = kwargs
return {"scene_key": "ai_pmo", "deep_intent": "none"}
def _normalize_action_mode(self, value: str) -> str:
return str(value or "").strip().lower() or "auto"
async def _resolve_action_mode_async(self, **kwargs):
_ = kwargs
return ACTION_MODE_READ
service = _FakeService()
runtime = await service._prepare_answer_runtime(
clean_q="第二条",
asked_by=1,
asked_via="feishu",
project_id=None,
source_chat_id="oc_test_chat",
session_id=11,
conversation_key=None,
force_new_session=False,
action_mode="auto",
)
assert runtime["resolved_question"] == "我问你这个是哪个模型执行回复的?"
assert service.anchor_kwargs["selected_anchor_reply_id"] == 102
assert runtime["anchor_resolution"].anchor_reply_id == 102
@pytest.mark.asyncio
async def test_render_answer_with_route_contract_adds_explicit_source_prefix_and_summary() -> None:
class _FakeService(AdaptiveRAGQueryRouteGatewayMixin):
pass
service = _FakeService()
formatted = service._render_answer_with_route_contract(
answer="当前活动引擎是 Qwen 低阶引擎。",
sources=[
{"source": "db", "label": "Integration[llm_engine]", "score": 0.99},
{"source": "db", "label": "Integration[model_routing:adaptive_rag_answer_normal]", "score": 0.98},
],
route_decision={
"route_mode": "internal",
"reply_contract": {
"head": "内部知识库查询:",
"tail_hint": None,
},
},
)
assert formatted.startswith("内部知识库查询:")
assert "来源摘要:" in formatted
assert "Integration[llm_engine]" in formatted
def test_build_response_payload_exposes_execution_recipe_and_plan_handoff() -> None:
class _FakeService(AdaptiveRAGAnswerPayloadMixin):
def _to_float(self, value, default=0.0):
try:
return float(value)
except Exception:
return float(default)
def _normalize_thinking_mode(self, thinking_mode: str) -> str:
return "deep" if str(thinking_mode or "").strip().lower() == "deep" else "normal"
def _normalize_query_route_decision(self, payload):
return dict(payload or {})
def _build_policy_version(self, *, prompt_variant_id: str | None = None) -> str:
return f"retrieval-v2.1|routing:unknown|prompt:{prompt_variant_id or 'unknown'}"
service = _FakeService()
payload = service._build_response_payload(
answer="建议先做一轮小范围验证。",
sources=[
{
"source": "url",
"label": "OpenAI Docs",
"score": 0.93,
"metadata": {"target_url": "https://platform.openai.com/docs"},
}
],
domains_used=["url"],
response_time_ms=32,
db_query_ms=0,
vector_search_ms=0,
query_type="explain",
confidence=0.93,
route_decision={"route_mode": "external", "effective_source_policy": "external"},
project_operating_context={
"current_project_id": 17,
"current_repo_scope": "pmflow-main",
"page_anchor": {"project_id": 17},
"thread_anchor": {},
"fit_scope": "current_project_and_repo",
"decision_strategy": "answer_then_offer_plan",
},
execution_recipe={
"primary_lane": "external",
"fit_brief_required": True,
"external_evidence_required": True,
"plan_handoff_mode": "offer_after_answer",
},
fit_brief={
"project_summary": "Alpha 聚焦统一项目上下文和 handoff。",
"repo_summary": "当前仓库负责前后台联动。",
"current_capabilities": ["需求 intake", "统一 handoff"],
},
external_recommendation={
"retrieval_status": "evidence_found",
"impact_status": "indirect_only",
"external_summary": "外部案例显示 handoff 入口正在收敛。",
"external_impact": "当前只支持背景相关,还不能直接映射到 Alpha 的正式对象。",
},
)
assert payload["project_operating_context"]["current_project_id"] == 17
assert payload["execution_recipe"]["primary_lane"] == "external"
assert payload["analysis_packet"]["packet_type"] == "project_fit_analysis"
assert payload["analysis_packet"]["fit_verdict"] == "fit_later"
assert payload["analysis_packet"]["focus_objects"] == []
assert payload["analysis_packet"]["missing_mapping"] == "至少还缺一个能对上的业务步骤或信号源。"
assert payload["handoff_mode"] == "offer_after_answer"
assert payload["can_enter_plan"] is True
assert "进入 plan" in payload["recommended_next_step"]
def test_response_payload_can_disable_default_offer_plan_rendering(monkeypatch: pytest.MonkeyPatch) -> None:
class _FakeService(AdaptiveRAGAnswerPayloadMixin):
def _to_float(self, value, default: float = 0.0) -> float:
try:
return float(value)
except Exception:
return float(default)
def _normalize_thinking_mode(self, thinking_mode: str) -> str:
return "deep" if str(thinking_mode or "").strip().lower() == "deep" else "normal"
def _normalize_query_route_decision(self, payload):
return dict(payload or {})
def _build_policy_version(self, *, prompt_variant_id: str | None = None) -> str:
return f"retrieval-v2.1|routing:unknown|prompt:{prompt_variant_id or 'unknown'}"
monkeypatch.setenv("PMFLOW_ENABLE_DEFAULT_PLAN_HANDOFF_RENDERING", "0")
service = _FakeService()
payload = service._build_response_payload(
answer="建议先做一轮小范围验证。",
sources=[
{
"source": "url",
"label": "OpenAI Docs",
"score": 0.93,
"metadata": {"target_url": "https://platform.openai.com/docs"},
}
],
domains_used=["url"],
response_time_ms=32,
db_query_ms=0,
vector_search_ms=0,
query_type="explain",
confidence=0.93,
route_decision={"route_mode": "external", "effective_source_policy": "external"},
project_operating_context={
"current_project_id": 17,
"current_repo_scope": "pmflow-main",
"page_anchor": {"project_id": 17},
"thread_anchor": {},
"fit_scope": "current_project_and_repo",
"decision_strategy": "answer_then_offer_plan",
},
execution_recipe={
"primary_lane": "external",
"fit_brief_required": True,
"external_evidence_required": True,
"plan_handoff_mode": "offer_after_answer",
},
)
assert payload["handoff_mode"] is None
assert payload["can_enter_plan"] is False
assert payload["recommended_next_step"] is None
def test_build_response_payload_preserves_signal_source_recommendation_candidate_set() -> None:
class _FakeService(AdaptiveRAGAnswerPayloadMixin):
def _to_float(self, value, default=0.0):
try:
return float(value)
except Exception:
return float(default)
def _normalize_thinking_mode(self, thinking_mode: str) -> str:
return "deep" if str(thinking_mode or "").strip().lower() == "deep" else "normal"
def _normalize_query_route_decision(self, payload):
return dict(payload or {})
def _build_policy_version(self, *, prompt_variant_id: str | None = None) -> str:
return f"retrieval-v2.1|routing:unknown|prompt:{prompt_variant_id or 'unknown'}"
service = _FakeService()
payload = service._build_response_payload(
answer="如果只是先给建议,我会先看这 3 类外部信号。",
sources=[],
domains_used=["url"],
response_time_ms=12,
db_query_ms=0,
vector_search_ms=0,
query_type="status",
confidence=0.84,
route_decision={"route_mode": "external", "effective_source_policy": "external"},
signal_source_recommendation={
"candidate_set_id": "recset_001",
"project_binding": 17,
"resource_role": "signal_source",
"source_kind": "external",
"evidence_mode": "advisory",
"candidates": [
{
"candidate_ref": "cand_a",
"display_name": "开票失败或重试回执",
"business_value": "它最早告诉你票是不是卡在开票动作本身。",
"why_now": "现在最容易先暴露真正失败的位置。",
"materialization_payload": {
"display_name": "开票失败或重试回执",
"source_origin": "recommendation",
},
}
],
"caveat": "这些先算建议,不代表已经接入或验证完成。",
},
)
assert payload["signal_source_recommendation"]["candidate_set_id"] == "recset_001"
assert payload["signal_source_recommendation"]["project_binding"] == 17
assert payload["signal_source_recommendation"]["candidates"][0]["candidate_ref"] == "cand_a"
assert payload["signal_source_recommendation"]["candidates"][0]["display_name"] == "开票失败或重试回执"
assert (
payload["signal_source_recommendation"]["candidates"][0]["materialization_payload"]["source_origin"]
== "recommendation"
)
def test_build_qa_record_external_fields_preserves_signal_source_recommendation_candidate_set() -> None:
class _FakeService(AdaptiveRAGCoreIntentMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.llm = object()
self.context_cache = object()
self._active_external_qa_context = {}
self._last_answer_prompt_variant_id = "unknown"
self._last_external_answer_presentation = {}
self._query_semantics_runtime_cache = {}
def _get_active_external_qa_context(self):
return {
"source_message_id": "om_candidate_set",
"source_chat_id": "chat_123",
"source_sender_open_id": "ou_abc",
"reply_to_message_id": "om_prev",
"root_message_id": "om_root",
"conversation_scope_key": "scope:chat_123",
}
def _build_query_route_audit_snapshot(self, *, route_decision):
_ = route_decision
return {
"route_mode": "external",
"effective_source_policy": "external",
"decision_origin": "semantic_frame",
}
service = _FakeService()
fields = service._build_qa_record_external_fields(
route_decision={"route_mode": "external"},
response_payload={
"signal_source_recommendation": {
"candidate_set_id": "recset_002",
"project_binding": 6,
"resource_role": "signal_source",
"source_kind": "external",
"evidence_mode": "advisory",
"candidates": [
{
"candidate_ref": "cand_invoice_receipt",
"display_name": "开票失败或重试回执",
"business_value": "它最早告诉你票是不是卡在开票动作本身。",
"why_now": "现在最容易先暴露真正失败的位置。",
"materialization_payload": {
"display_name": "开票失败或重试回执",
"source_origin": "recommendation",
},
}
],
"caveat": "这些先算建议,不代表已经接入或验证完成。",
}
},
)
assert fields["routing_snapshot"]["response_payload"]["signal_source_recommendation"]["candidate_set_id"] == "recset_002"
assert fields["routing_snapshot"]["response_payload"]["signal_source_recommendation"]["project_binding"] == 6
assert (
fields["routing_snapshot"]["response_payload"]["signal_source_recommendation"]["candidates"][0]["candidate_ref"]
== "cand_invoice_receipt"
)
@pytest.mark.asyncio
async def test_meta_followup_without_real_anchor_does_not_return_no_route_record_answer() -> None:
class _FakeService(AdaptiveRAGFollowupAnchorMixin):
async def _resolve_anchor_qa_record(self, **kwargs):
_ = kwargs
return None
service = _FakeService()
payload = await service._build_meta_followup_payload(
question="我们系统当前接的是哪个 codex 模型配置?",
anchor_resolution=FollowupAnchorResolution(
followup_mode="meta",
anchor_mode="no_anchor",
is_meta_followup=True,
meta_followup_kind="reply_model_identity",
),
conversation_scope_key="scope:test",
)
assert payload is None
@pytest.mark.asyncio
async def test_execute_mainline_skips_followup_clarification_after_state_subject_rewrite() -> None:
class _FakeContextCache:
async def get_system_snapshot(self, **kwargs):
_ = kwargs
return {}
async def get_user_snapshot(self, **kwargs):
_ = kwargs
return {}
class _FakeService(
AdaptiveRAGAnswerMainlineMixin,
AdaptiveRAGFollowupAnchorMixin,
):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.context_cache = _FakeContextCache()
self.clarification_payload = None
self.retrieval_kwargs: dict[str, object] = {}
def _plan_query_runtime(self, **kwargs):
_ = kwargs
return SimpleNamespace(
thinking_mode="normal",
retrieval_answer_mode="retrieval_normal",
budget=SimpleNamespace(max_steps=2, vector_top_k=3),
allow_fast_path=False,
reason="consultant_mode",
)
def _build_route_clarification_payload(self, **kwargs):
_ = kwargs
return None
async def _build_meta_followup_payload(self, **kwargs):
_ = kwargs
return None
async def _maybe_return_clarification_response(self, **kwargs):
self.clarification_payload = kwargs.get("clarification_payload")
if self.clarification_payload is not None:
return {
"processing_stage": "clarification",
"answer": self.clarification_payload.get("answer"),
}
return None
async def _maybe_return_meta_followup_response(self, **kwargs):
_ = kwargs
return None
def _get_active_external_qa_context(self):
return {}
def _build_operation_contract(self, *, question: str, query_semantics):
_ = (question, query_semantics)
return {
"query_type": "existence",
"answer_contract": "yes_no_with_evidence",
}
async def _resolve_internal_target(self, **kwargs):
_ = kwargs
return {}
def _mirror_internal_context_to_query_semantics(self, *, query_semantics, **kwargs):
_ = kwargs
return dict(query_semantics)
def _build_internal_query_plan(self, **kwargs):
_ = kwargs
return {}
def _build_internal_query_context_packet(self, **kwargs):
_ = kwargs
return None
async def _maybe_return_internal_context_precheck_response(self, **kwargs):
_ = kwargs
return None
async def _build_internal_model_config_fast_answer(self, **kwargs):
_ = kwargs
return None
def _build_snapshot_direct_answer(self, *args, **kwargs):
_ = (args, kwargs)
return None
async def _maybe_return_snapshot_direct_response(self, **kwargs):
_ = kwargs
return None
async def _try_fast_project_semantic_answer(self, **kwargs):
_ = kwargs
return None
async def _build_retrieval_response(self, **kwargs):
self.retrieval_kwargs = dict(kwargs)
return {
"processing_stage": "retrieval",
"answer": "内部知识库查询:当前系统内已存在采购经理提出的需求。",
}
service = _FakeService()
rewritten_question = "围绕“采购经理每日实时库存上报服务”回答:帮我看下采购经理那个需求是否存在系统?"
result = await service._execute_base_answer_mainline(
clean_q="帮我看下采购经理那个需求是否存在系统?",
asked_by=1,
asked_via="feishu",
project_id=None,
source_chat_id="chat-1",
session_id=11,
turn_index=2,
context_session_id=11,
conversation=[],
state_row=SimpleNamespace(
last_subject="采购经理每日实时库存上报服务",
last_entity_ids=[123],
last_intent="question",
ambiguity="clear",
rewrite_history=[],
pending_clarification=None,
pending_clarification_expires_at=None,
),
effective_q=rewritten_question,
rewrite_meta={"mode": "state_subject", "subject": "采购经理每日实时库存上报服务"},
query_type="existence",
query_semantics={
"source_policy": "internal",
"effective_source_policy": "internal",
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"referenced_objects": ["project_object"],
},
},
retrieval_domains=["db", "pmflow"],
scene_semantics={"scene_key": "ai_pmo", "snapshot_focus": "none", "deep_intent": "none"},
thinking_mode="normal",
active_thinking_mode="normal",
deep_thinking=False,
enforce_scene_prompt_only=False,
deep_retrieval_steps=2,
deep_vector_top_k=3,
started=0.0,
message_intent="question",
mixed_signal_part=None,
anchor_resolution=FollowupAnchorResolution(
followup_mode="referential",
anchor_mode="no_anchor",
clarification_code="no_anchor_found",
),
consultant_mode_preference=None,
route_decision={
"route_mode": "internal",
"effective_source_policy": "internal",
"reply_contract": {"head": "内部知识库查询:", "tail_hint": None},
},
)
assert result["processing_stage"] == "retrieval"
assert service.clarification_payload is None
assert service.retrieval_kwargs["effective_q"] == rewritten_question
@pytest.mark.asyncio
async def test_internal_model_config_fast_answer_bypasses_fast_path_gate_when_route_is_internal() -> None:
class _FakeContextCache:
async def get_system_snapshot(self, **kwargs):
_ = kwargs
return {}
async def get_user_snapshot(self, **kwargs):
_ = kwargs
return {}
class _FakeService(AdaptiveRAGAnswerMainlineMixin):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.context_cache = _FakeContextCache()
self.builder_calls = 0
self.retrieval_called = False
def _plan_query_runtime(self, **kwargs):
_ = kwargs
return SimpleNamespace(
thinking_mode="normal",
retrieval_answer_mode="retrieval_normal",
budget=SimpleNamespace(max_steps=2, vector_top_k=3),
allow_fast_path=False,
reason="consultant_mode",
)
def _build_followup_clarification_payload(self, **kwargs):
_ = kwargs
return None
def _build_route_clarification_payload(self, **kwargs):
_ = kwargs
return None
async def _build_meta_followup_payload(self, **kwargs):
_ = kwargs
return None
async def _maybe_return_clarification_response(self, **kwargs):
_ = kwargs
return None
async def _maybe_return_meta_followup_response(self, **kwargs):
_ = kwargs
return None
def _get_active_external_qa_context(self):
return {}
async def _build_internal_model_config_fast_answer(self, **kwargs):
_ = kwargs
self.builder_calls += 1
return {
"answer": "当前活动引擎是 qwen-plus。",
"sources": [{"source": "db", "label": "Integration[llm_engine]", "score": 0.99}],
}
async def _persist_fast_answer(self, **kwargs):
return {
"processing_stage": "fast_path",
"answer": kwargs["fast_result"]["answer"],
}
async def _build_retrieval_response(self, **kwargs):
_ = kwargs
self.retrieval_called = True
return {"processing_stage": "retrieval"}
async def _maybe_return_snapshot_direct_response(self, **kwargs):
_ = kwargs
return None
def _build_snapshot_direct_answer(self, *args, **kwargs):
_ = (args, kwargs)
return None
service = _FakeService()
result = await service._execute_base_answer_mainline(
clean_q="我们系统当前接的是哪个 codex 模型配置?",
asked_by=1,
asked_via="pmflow_manual",
project_id=None,
source_chat_id=None,
session_id=11,
turn_index=3,
context_session_id=11,
conversation=[],
state_row=None,
effective_q="我们系统当前接的是哪个 codex 模型配置?",
rewrite_meta={},
query_type="explain",
query_semantics={
"source_policy": "internal",
"effective_source_policy": "internal",
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"referenced_objects": ["system_config", "model_routing"],
},
},
retrieval_domains=["db", "pmflow"],
scene_semantics={"scene_key": "ai_pmo", "snapshot_focus": "feature", "deep_intent": "none"},
thinking_mode="none",
active_thinking_mode="normal",
deep_thinking=False,
enforce_scene_prompt_only=False,
deep_retrieval_steps=2,
deep_vector_top_k=3,
started=0.0,
message_intent="system_configuration_inquiry",
mixed_signal_part=None,
consultant_mode_preference="informative",
route_decision={
"route_mode": "internal",
"effective_source_policy": "internal",
"reply_contract": {"head": "内部知识库查询:", "tail_hint": None},
"query_profile": {
"needs_private_context": True,
"needs_freshness": False,
"referenced_objects": ["system_config", "model_routing"],
},
},
)
assert result["processing_stage"] == "fast_path"
assert "qwen-plus" in result["answer"]
assert service.builder_calls == 1
assert service.retrieval_called is False
@pytest.mark.asyncio
async def test_execute_mainline_blocks_internal_route_when_internal_context_packet_missing() -> None:
class _FakeContextCache:
async def get_system_snapshot(self, **kwargs):
_ = kwargs
return {}
async def get_user_snapshot(self, **kwargs):
_ = kwargs
return {}
class _FakeService(
AdaptiveRAGAnswerMainlineMixin,
AdaptiveRAGAnswerPayloadMixin,
):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.context_cache = _FakeContextCache()
self.persist_kwargs: dict[str, object] = {}
def _plan_query_runtime(self, **kwargs):
_ = kwargs
return SimpleNamespace(
thinking_mode="normal",
retrieval_answer_mode="retrieval_normal",
budget=SimpleNamespace(max_steps=2, vector_top_k=3),
allow_fast_path=True,
reason="deterministic_query_type",
)
def _build_followup_clarification_payload(self, **kwargs):
_ = kwargs
return None
def _build_route_clarification_payload(self, **kwargs):
_ = kwargs
return None
async def _build_meta_followup_payload(self, **kwargs):
_ = kwargs
return None
async def _maybe_return_clarification_response(self, **kwargs):
_ = kwargs
return None
async def _maybe_return_meta_followup_response(self, **kwargs):
_ = kwargs
return None
def _get_active_external_qa_context(self):
return {}
def _build_operation_contract(self, *, question: str, query_semantics):
_ = (question, query_semantics)
return {
"query_type": "existence",
"answer_contract": "yes_no_with_evidence",
"object_mentions": ["开票系统"],
}
async def _resolve_internal_target(self, **kwargs):
_ = kwargs
return {
"target_entity_type": "project",
"target_ref": "project:6",
"resolved_label": "自动开票系统",
"resolution_mode": "deterministic",
"confidence": 0.96,
"candidate_summary": [],
}
def _build_internal_query_context_packet(self, **kwargs):
_ = kwargs
return None
async def _persist_fast_answer(self, **kwargs):
self.persist_kwargs = dict(kwargs)
return {
"processing_stage": "fast_path",
"answer": kwargs["fast_result"]["answer"],
"answer_mode": kwargs["answer_mode"],
"missing_fields": list(kwargs["fast_result"].get("missing_fields") or []),
}
async def _run_deterministic_query(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"deterministic query should be blocked: {kwargs}")
async def _build_internal_model_config_fast_answer(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"internal model config fast answer should be blocked: {kwargs}")
async def _try_fast_project_semantic_answer(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"provider semantic fast answer should be blocked: {kwargs}")
async def _build_retrieval_response(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"retrieval should be blocked: {kwargs}")
async def _maybe_return_snapshot_direct_response(self, **kwargs):
_ = kwargs
return None
def _build_snapshot_direct_answer(self, *args, **kwargs):
_ = (args, kwargs)
return None
service = _FakeService()
result = await service._execute_base_answer_mainline(
clean_q="帮我看看系统里面有没有开票系统。",
asked_by=1,
asked_via="pmflow_manual",
project_id=None,
source_chat_id=None,
session_id=11,
turn_index=3,
context_session_id=11,
conversation=[],
state_row=None,
effective_q="帮我看看系统里面有没有开票系统。",
rewrite_meta={},
query_type="explain",
query_semantics={
"source_policy": "internal",
"effective_source_policy": "internal",
"subject_focus": "project",
},
retrieval_domains=["db", "pmflow"],
scene_semantics={"scene_key": "ai_pmo", "snapshot_focus": "none", "deep_intent": "none"},
thinking_mode="normal",
active_thinking_mode="normal",
deep_thinking=False,
enforce_scene_prompt_only=False,
deep_retrieval_steps=2,
deep_vector_top_k=3,
started=0.0,
message_intent="question",
mixed_signal_part=None,
consultant_mode_preference=None,
route_decision={
"route_mode": "internal",
"effective_source_policy": "internal",
"reply_contract": {"head": "内部知识库查询:", "tail_hint": None},
},
)
assert result["processing_stage"] == "fast_path"
assert result["answer_mode"] == "clarify"
assert service.persist_kwargs["fast_result"]["reason_code"] == "missing_internal_context_packet"
assert service.persist_kwargs["fast_result"]["missing_fields"] == ["internal_context_packet"]
@pytest.mark.asyncio
async def test_execute_mainline_blocks_internal_route_when_query_plan_contract_missing() -> None:
class _FakeContextCache:
async def get_system_snapshot(self, **kwargs):
_ = kwargs
return {}
async def get_user_snapshot(self, **kwargs):
_ = kwargs
return {}
class _FakeService(
AdaptiveRAGAnswerMainlineMixin,
AdaptiveRAGAnswerPayloadMixin,
):
def __init__(self) -> None:
self.db = object()
self.tenant_id = 1
self.context_cache = _FakeContextCache()
self.persist_kwargs: dict[str, object] = {}
def _plan_query_runtime(self, **kwargs):
_ = kwargs
return SimpleNamespace(
thinking_mode="normal",
retrieval_answer_mode="retrieval_normal",
budget=SimpleNamespace(max_steps=2, vector_top_k=3),
allow_fast_path=True,
reason="deterministic_query_type",
)
def _build_followup_clarification_payload(self, **kwargs):
_ = kwargs
return None
def _build_route_clarification_payload(self, **kwargs):
_ = kwargs
return None
async def _build_meta_followup_payload(self, **kwargs):
_ = kwargs
return None
async def _maybe_return_clarification_response(self, **kwargs):
_ = kwargs
return None
async def _maybe_return_meta_followup_response(self, **kwargs):
_ = kwargs
return None
def _get_active_external_qa_context(self):
return {}
def _build_operation_contract(self, *, question: str, query_semantics):
_ = (question, query_semantics)
return {
"query_type": "existence",
"answer_contract": "yes_no_with_evidence",
"object_mentions": ["开票系统"],
}
async def _resolve_internal_target(self, **kwargs):
_ = kwargs
return {
"target_entity_type": "project",
"target_ref": "project:6",
"resolved_label": "自动开票系统",
"resolution_mode": "deterministic",
"confidence": 0.96,
"candidate_summary": [],
}
def _build_internal_query_context_packet(self, **kwargs):
payload = dict(kwargs)
return InternalContextPacket.model_validate(
{
"packet_version": "v1",
"question": str(payload.get("question") or ""),
"scope": {
"tenant_id": 1,
"project_id": None,
"session_id": 11,
"conversation_scope_key": None,
"reply_to_message_id": None,
"root_message_id": None,
},
"route_decision": dict(payload.get("route_decision") or {}),
"operation_contract": dict(payload.get("operation_contract") or {}),
"target_resolution": dict(payload.get("target_resolution") or {}),
"query_plan": {
"plan_version": "v2",
"query_type": "existence",
"entity_type": "project",
"answer_contract": "",
"target_ref": "project:6",
"filters": [{"field": "project_id", "operator": "equals", "value": 6}],
},
"executor_summary": {},
"verifier_summary": {},
"uncertainties": [],
}
)
async def _persist_fast_answer(self, **kwargs):
self.persist_kwargs = dict(kwargs)
return {
"processing_stage": "fast_path",
"answer": kwargs["fast_result"]["answer"],
"answer_mode": kwargs["answer_mode"],
"missing_fields": list(kwargs["fast_result"].get("missing_fields") or []),
}
async def _run_deterministic_query(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"deterministic query should be blocked: {kwargs}")
async def _build_internal_model_config_fast_answer(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"internal model config fast answer should be blocked: {kwargs}")
async def _try_fast_project_semantic_answer(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"provider semantic fast answer should be blocked: {kwargs}")
async def _build_retrieval_response(self, **kwargs): # pragma: no cover - should not be called
raise AssertionError(f"retrieval should be blocked: {kwargs}")
async def _maybe_return_snapshot_direct_response(self, **kwargs):
_ = kwargs
return None
def _build_snapshot_direct_answer(self, *args, **kwargs):
_ = (args, kwargs)
return None
service = _FakeService()
result = await service._execute_base_answer_mainline(
clean_q="帮我看看系统里面有没有开票系统。",
asked_by=1,
asked_via="pmflow_manual",
project_id=None,
source_chat_id=None,
session_id=11,
turn_index=3,
context_session_id=11,
conversation=[],
state_row=None,
effective_q="帮我看看系统里面有没有开票系统。",
rewrite_meta={},
query_type="explain",
query_semantics={
"source_policy": "internal",
"effective_source_policy": "internal",
"subject_focus": "project",
},
retrieval_domains=["db", "pmflow"],
scene_semantics={"scene_key": "ai_pmo", "snapshot_focus": "none", "deep_intent": "none"},
thinking_mode="normal",
active_thinking_mode="normal",
deep_thinking=False,
enforce_scene_prompt_only=False,
deep_retrieval_steps=2,
deep_vector_top_k=3,
started=0.0,
message_intent="question",
mixed_signal_part=None,
consultant_mode_preference=None,
route_decision={
"route_mode": "internal",
"effective_source_policy": "internal",
"reply_contract": {"head": "内部知识库查询:", "tail_hint": None},
},
)
assert result["processing_stage"] == "fast_path"
assert result["answer_mode"] == "clarify"
assert service.persist_kwargs["fast_result"]["reason_code"] == "missing_internal_query_plan_contract"
assert service.persist_kwargs["fast_result"]["missing_fields"] == ["answer_contract"]