648 lines
27 KiB
Python
648 lines
27 KiB
Python
"""Adaptive RAG answer mainline orchestration helpers."""
|
|
from __future__ import annotations
|
|
|
|
from .shared import *
|
|
|
|
|
|
class AdaptiveRAGAnswerMainlineMixin:
|
|
_EXTERNAL_FACT_FRESHNESS_MARKERS = (
|
|
"最新",
|
|
"目前",
|
|
"当前",
|
|
"截至现在",
|
|
"截至当前",
|
|
"截止当前",
|
|
"今天",
|
|
"现在",
|
|
"最近",
|
|
"出到什么",
|
|
"发布了吗",
|
|
"发布到",
|
|
"版本",
|
|
"最高模型",
|
|
)
|
|
_MODEL_ENTITY_MARKERS = (
|
|
"codex",
|
|
"gpt",
|
|
"chatgpt",
|
|
"claude",
|
|
"deepseek",
|
|
"qwen",
|
|
"gemini",
|
|
"copilot",
|
|
"grok",
|
|
"kimi",
|
|
"llama",
|
|
"openai",
|
|
"anthropic",
|
|
)
|
|
_INTERNAL_MODEL_CONFIG_MARKERS = (
|
|
"ai-config",
|
|
"/ai-config",
|
|
"模型配置",
|
|
"配置项",
|
|
"配置值",
|
|
"路由规则",
|
|
"初始化参数",
|
|
"llm服务",
|
|
"llm 服务",
|
|
"运行时",
|
|
"当前系统",
|
|
"我们系统",
|
|
"pmflow",
|
|
"本系统",
|
|
"接入的模型",
|
|
"接的是",
|
|
"用的是哪个模型配置",
|
|
)
|
|
_PROJECT_CONTEXT_POSITIVE_MARKERS = (
|
|
"这个项目",
|
|
"当前项目",
|
|
"本项目",
|
|
"我们项目",
|
|
"项目所在行业",
|
|
"对项目的影响",
|
|
"对这个项目的影响",
|
|
"对当前项目的影响",
|
|
"对我们项目的影响",
|
|
"结合项目",
|
|
"结合当前项目",
|
|
"落到项目",
|
|
)
|
|
_PROJECT_CONTEXT_NEGATIVE_MARKERS = (
|
|
"不要提项目",
|
|
"别提项目",
|
|
"不要结合项目",
|
|
"不用结合项目",
|
|
"不需要结合项目",
|
|
"先别结合项目",
|
|
"不要绑定项目",
|
|
"别绑定项目",
|
|
)
|
|
|
|
@classmethod
|
|
def _extract_prompt_variant_from_policy_version(cls, policy_version: Optional[str]) -> Optional[str]:
|
|
raw = str(policy_version or "").strip()
|
|
if not raw:
|
|
return None
|
|
for part in raw.split("|"):
|
|
normalized = str(part or "").strip()
|
|
if not normalized.startswith("prompt:"):
|
|
continue
|
|
value = normalized.split(":", 1)[1].strip().lower()
|
|
return value or None
|
|
return None
|
|
|
|
@classmethod
|
|
def _question_explicitly_requests_project_context(
|
|
cls,
|
|
*,
|
|
question: str,
|
|
project_id: Optional[int],
|
|
) -> bool:
|
|
if project_id is None:
|
|
return False
|
|
normalized = re.sub(r"\s+", "", str(question or "")).strip().lower()
|
|
if not normalized:
|
|
return False
|
|
if any(marker in normalized for marker in cls._PROJECT_CONTEXT_NEGATIVE_MARKERS):
|
|
return False
|
|
return any(marker in normalized for marker in cls._PROJECT_CONTEXT_POSITIVE_MARKERS)
|
|
|
|
@classmethod
|
|
def _looks_like_external_freshness_question(cls, question: str) -> bool:
|
|
normalized = re.sub(r"\s+", "", str(question or "")).strip().lower()
|
|
if not normalized:
|
|
return False
|
|
return any(marker in normalized for marker in cls._EXTERNAL_FACT_FRESHNESS_MARKERS)
|
|
|
|
@classmethod
|
|
def _looks_like_internal_model_config_question(cls, question: str) -> bool:
|
|
normalized = re.sub(r"\s+", "", str(question or "")).strip().lower()
|
|
if not normalized:
|
|
return False
|
|
return any(marker in normalized for marker in cls._INTERNAL_MODEL_CONFIG_MARKERS)
|
|
|
|
@classmethod
|
|
def _looks_like_model_fact_question(cls, question: str) -> bool:
|
|
normalized = re.sub(r"\s+", "", str(question or "")).strip().lower()
|
|
if not normalized:
|
|
return False
|
|
has_entity = any(marker in normalized for marker in cls._MODEL_ENTITY_MARKERS)
|
|
if not has_entity:
|
|
return False
|
|
return "模型" in normalized or cls._looks_like_external_freshness_question(question)
|
|
|
|
async def _resolve_anchor_prompt_variant(
|
|
self,
|
|
*,
|
|
anchor_resolution: Optional[FollowupAnchorResolution],
|
|
conversation_scope_key: Optional[str],
|
|
) -> Optional[str]:
|
|
resolver = getattr(self, "_resolve_anchor_qa_record", None)
|
|
if not callable(resolver):
|
|
return None
|
|
try:
|
|
anchor_row = await resolver(
|
|
anchor_resolution=anchor_resolution,
|
|
conversation_scope_key=conversation_scope_key,
|
|
)
|
|
except Exception:
|
|
return None
|
|
if anchor_row is None:
|
|
return None
|
|
return self._extract_prompt_variant_from_policy_version(getattr(anchor_row, "policy_version", None))
|
|
|
|
def _apply_chat_external_fact_scene_policy(
|
|
self,
|
|
*,
|
|
question: str,
|
|
project_id: Optional[int],
|
|
scene_semantics: Optional[dict[str, Any]],
|
|
anchor_prompt_variant: Optional[str] = None,
|
|
) -> dict[str, Any]:
|
|
normalized = dict(scene_semantics or {})
|
|
scene_key = str(normalized.get("scene_key") or "default").strip().lower() or "default"
|
|
anchor_variant = str(anchor_prompt_variant or "").strip().lower()
|
|
explicit_project_context = self._question_explicitly_requests_project_context(
|
|
question=question,
|
|
project_id=project_id,
|
|
)
|
|
requires_freshness = self._looks_like_external_freshness_question(question)
|
|
internal_model_config_question = self._looks_like_internal_model_config_question(question)
|
|
model_fact_question = self._looks_like_model_fact_question(question)
|
|
anchored_trend_followup = anchor_variant in {"external_trend", "industry_trend"}
|
|
|
|
if scene_key == "ai_pmo" and model_fact_question and requires_freshness and not internal_model_config_question:
|
|
scene_key = "external_trend" if explicit_project_context else "industry_trend"
|
|
normalized["snapshot_focus"] = "none"
|
|
normalized["deep_intent"] = "none"
|
|
normalized["external_fact_chat"] = True
|
|
normalized["requires_freshness"] = True
|
|
|
|
if scene_key == "ai_pmo_correction" and anchored_trend_followup:
|
|
scene_key = "external_trend" if explicit_project_context else "industry_trend"
|
|
normalized["snapshot_focus"] = "none"
|
|
normalized["deep_intent"] = "none"
|
|
normalized["external_fact_chat"] = True
|
|
|
|
if scene_key == "external_trend" and not explicit_project_context:
|
|
scene_key = "industry_trend"
|
|
|
|
if scene_key in {"external_trend", "industry_trend"}:
|
|
normalized["external_fact_chat"] = True
|
|
normalized["requires_freshness"] = bool(requires_freshness)
|
|
if requires_freshness:
|
|
normalized["deep_intent"] = "none"
|
|
|
|
normalized["scene_key"] = scene_key
|
|
return normalized
|
|
|
|
def _plan_query_runtime(
|
|
self,
|
|
*,
|
|
question: str,
|
|
effective_question: str,
|
|
query_type: str,
|
|
scene_semantics: Optional[dict[str, Any]] = None,
|
|
requested_thinking_mode: str,
|
|
enforce_scene_prompt_only: bool,
|
|
consultant_mode_preference: Optional[str] = None,
|
|
) -> QueryPlannerDecision:
|
|
normalize_thinking_mode = getattr(
|
|
self,
|
|
"_normalize_thinking_mode",
|
|
lambda value: THINKING_MODE_DEEP if str(value or "").strip().lower() == THINKING_MODE_DEEP else THINKING_MODE_NORMAL,
|
|
)
|
|
normalized_thinking_mode = normalize_thinking_mode(requested_thinking_mode)
|
|
normalized_query_type = str(query_type or QUERY_TYPE_UNKNOWN).strip().lower()
|
|
normalized_consultant_mode = str(consultant_mode_preference or "").strip().lower()
|
|
fast_path_candidate = normalized_query_type in {QUERY_TYPE_COUNT, QUERY_TYPE_LIST, QUERY_TYPE_STATUS}
|
|
normalized_question = str(question or "").strip()
|
|
normalized_effective = str(effective_question or "").strip()
|
|
|
|
normalized_scene_semantics = scene_semantics if isinstance(scene_semantics, dict) else {}
|
|
deep_intent = str(normalized_scene_semantics.get("deep_intent") or "none").strip().lower()
|
|
force_deep_by_semantics = deep_intent in {
|
|
"correction_turn",
|
|
"correction_escalation",
|
|
"engine_process_query",
|
|
"runtime_state_query",
|
|
}
|
|
if enforce_scene_prompt_only:
|
|
retrieval_mode = ANSWER_MODE_RETRIEVAL_DEEP if normalized_thinking_mode == THINKING_MODE_DEEP else ANSWER_MODE_RETRIEVAL_NORMAL
|
|
return QueryPlannerDecision(
|
|
answer_mode=retrieval_mode,
|
|
thinking_mode=THINKING_MODE_DEEP if retrieval_mode == ANSWER_MODE_RETRIEVAL_DEEP else THINKING_MODE_NORMAL,
|
|
allow_fast_path=False,
|
|
retrieval_answer_mode=retrieval_mode,
|
|
budget=RetrievalBudget(
|
|
max_steps=DEEP_RETRIEVAL_STEPS if retrieval_mode == ANSWER_MODE_RETRIEVAL_DEEP else AGENT_MAX_RETRIEVAL_STEPS,
|
|
vector_top_k=DEEP_VECTOR_TOP_K if retrieval_mode == ANSWER_MODE_RETRIEVAL_DEEP else DEFAULT_TOP_K,
|
|
),
|
|
reason="scene_prompt_only",
|
|
)
|
|
|
|
if fast_path_candidate and not force_deep_by_semantics:
|
|
if normalized_consultant_mode:
|
|
return QueryPlannerDecision(
|
|
answer_mode=ANSWER_MODE_RETRIEVAL_NORMAL,
|
|
thinking_mode=THINKING_MODE_NORMAL,
|
|
allow_fast_path=False,
|
|
retrieval_answer_mode=ANSWER_MODE_RETRIEVAL_NORMAL,
|
|
budget=RetrievalBudget(max_steps=AGENT_MAX_RETRIEVAL_STEPS, vector_top_k=DEFAULT_TOP_K),
|
|
reason=f"consultant_mode:{normalized_consultant_mode}",
|
|
)
|
|
return QueryPlannerDecision(
|
|
answer_mode=ANSWER_MODE_FAST_PATH,
|
|
thinking_mode=THINKING_MODE_NORMAL,
|
|
allow_fast_path=True,
|
|
retrieval_answer_mode=ANSWER_MODE_RETRIEVAL_NORMAL,
|
|
budget=RetrievalBudget(max_steps=AGENT_MAX_RETRIEVAL_STEPS, vector_top_k=DEFAULT_TOP_K),
|
|
reason="deterministic_query_type",
|
|
)
|
|
|
|
retrieval_mode = ANSWER_MODE_RETRIEVAL_DEEP if (normalized_thinking_mode == THINKING_MODE_DEEP or force_deep_by_semantics) else ANSWER_MODE_RETRIEVAL_NORMAL
|
|
return QueryPlannerDecision(
|
|
answer_mode=retrieval_mode,
|
|
thinking_mode=THINKING_MODE_DEEP if retrieval_mode == ANSWER_MODE_RETRIEVAL_DEEP else THINKING_MODE_NORMAL,
|
|
allow_fast_path=False,
|
|
retrieval_answer_mode=retrieval_mode,
|
|
budget=RetrievalBudget(
|
|
max_steps=DEEP_RETRIEVAL_STEPS if retrieval_mode == ANSWER_MODE_RETRIEVAL_DEEP else AGENT_MAX_RETRIEVAL_STEPS,
|
|
vector_top_k=DEEP_VECTOR_TOP_K if retrieval_mode == ANSWER_MODE_RETRIEVAL_DEEP else DEFAULT_TOP_K,
|
|
),
|
|
reason="requested_thinking_mode" if retrieval_mode == ANSWER_MODE_RETRIEVAL_DEEP else "default_retrieval",
|
|
)
|
|
|
|
async def _prepare_answer_runtime(
|
|
self,
|
|
*,
|
|
clean_q: str,
|
|
asked_by: Optional[int],
|
|
asked_via: str,
|
|
project_id: Optional[int],
|
|
source_chat_id: Optional[str],
|
|
session_id: Optional[int],
|
|
conversation_key: Optional[str],
|
|
force_new_session: bool,
|
|
action_mode: str,
|
|
source_message_id: Optional[str] = None,
|
|
source_sender_open_id: Optional[str] = None,
|
|
thread_context: Optional[dict[str, Any]] = None,
|
|
) -> dict[str, Any]:
|
|
external_conversation_key = self._build_external_conversation_key(
|
|
asked_via=asked_via,
|
|
source_chat_id=source_chat_id,
|
|
conversation_key=conversation_key,
|
|
source_sender_open_id=source_sender_open_id,
|
|
sender=None,
|
|
thread_context=thread_context,
|
|
)
|
|
self._set_active_external_qa_context(
|
|
source_chat_id=source_chat_id,
|
|
source_message_id=source_message_id,
|
|
source_sender_open_id=source_sender_open_id,
|
|
conversation_scope_key=external_conversation_key,
|
|
thread_context=thread_context,
|
|
)
|
|
session_id, turn_index = await self._touch_session_for_new_record(
|
|
asked_by=asked_by,
|
|
asked_via=asked_via,
|
|
project_id=project_id,
|
|
question=clean_q,
|
|
preferred_session_id=session_id,
|
|
force_new_session=bool(force_new_session),
|
|
external_conversation_key=external_conversation_key,
|
|
)
|
|
context_session_id: Optional[int]
|
|
if session_id is not None:
|
|
context_session_id = int(session_id)
|
|
elif asked_by is None:
|
|
context_session_id = self._external_session_id_from_key(external_conversation_key)
|
|
else:
|
|
context_session_id = None
|
|
conversation = await self._load_recent_conversation(
|
|
asked_by=asked_by,
|
|
asked_via=asked_via,
|
|
project_id=project_id,
|
|
session_id=session_id,
|
|
external_session_id=context_session_id,
|
|
limit=10,
|
|
)
|
|
state_session_id = int(session_id) if session_id is not None else (
|
|
int(context_session_id) if context_session_id is not None else None
|
|
)
|
|
state_row = await self._ensure_session_state(session_id=state_session_id)
|
|
pending_selection = self._consume_pending_clarification_selection(
|
|
question=clean_q,
|
|
session_state=state_row,
|
|
)
|
|
resolved_question = str(pending_selection.get("effective_question") or clean_q).strip() if isinstance(
|
|
pending_selection, dict
|
|
) else clean_q
|
|
anchor_resolution = await self._resolve_followup_anchor(
|
|
question=resolved_question,
|
|
session_id=state_session_id,
|
|
context_session_id=context_session_id,
|
|
session_state=state_row,
|
|
conversation_scope_key=external_conversation_key,
|
|
source_chat_id=source_chat_id,
|
|
source_sender_open_id=source_sender_open_id,
|
|
source_message_id=source_message_id,
|
|
thread_context=thread_context,
|
|
)
|
|
effective_q, rewrite_meta = self._rewrite_question_with_state(
|
|
question=resolved_question,
|
|
conversation=conversation,
|
|
session_state=state_row,
|
|
anchor_resolution=anchor_resolution,
|
|
)
|
|
query_semantics = await self._resolve_query_semantics(
|
|
message=effective_q,
|
|
source_system=asked_via,
|
|
metadata={
|
|
"project_id": project_id,
|
|
"source_chat_id": source_chat_id,
|
|
"source_message_id": source_message_id,
|
|
"conversation_scope_key": external_conversation_key,
|
|
"reply_to_message_id": str((thread_context or {}).get("reply_to_message_id") or "").strip() or None,
|
|
"root_message_id": str((thread_context or {}).get("root_message_id") or "").strip() or None,
|
|
},
|
|
)
|
|
query_semantics = dict(query_semantics) if isinstance(query_semantics, dict) else {}
|
|
query_type = str(query_semantics.get("query_type") or QUERY_TYPE_UNKNOWN).strip().lower() or QUERY_TYPE_UNKNOWN
|
|
conversation_text = "\n".join(
|
|
[
|
|
f"Q: {str(row.get('question') or '').strip()}\nA: {str(row.get('answer') or '').strip()}"
|
|
for row in conversation[-4:]
|
|
if isinstance(row, dict)
|
|
]
|
|
) or "无"
|
|
scene_semantics = await self._resolve_answer_scene_semantics(
|
|
question=clean_q,
|
|
effective_question=effective_q,
|
|
asked_via=asked_via,
|
|
message_intent=str(query_semantics.get("message_intent") or query_semantics.get("intent") or "").strip().lower() or None,
|
|
query_type=query_type,
|
|
conversation_text=conversation_text,
|
|
)
|
|
anchor_prompt_variant = await self._resolve_anchor_prompt_variant(
|
|
anchor_resolution=anchor_resolution,
|
|
conversation_scope_key=external_conversation_key,
|
|
)
|
|
scene_semantics = self._apply_chat_external_fact_scene_policy(
|
|
question=resolved_question,
|
|
project_id=project_id,
|
|
scene_semantics=scene_semantics,
|
|
anchor_prompt_variant=anchor_prompt_variant,
|
|
)
|
|
if bool(scene_semantics.get("requires_freshness")):
|
|
query_semantics["external_freshness_only"] = True
|
|
query_semantics["retrieval_domains"] = ["url"]
|
|
requested_action_mode = self._normalize_action_mode(action_mode)
|
|
effective_action_mode = await self._resolve_action_mode_async(
|
|
requested_mode=requested_action_mode,
|
|
question=resolved_question,
|
|
effective_question=effective_q,
|
|
asked_via=asked_via,
|
|
)
|
|
return {
|
|
"session_id": session_id,
|
|
"turn_index": turn_index,
|
|
"context_session_id": context_session_id,
|
|
"conversation": conversation,
|
|
"state_row": state_row,
|
|
"resolved_question": resolved_question,
|
|
"effective_q": effective_q,
|
|
"rewrite_meta": rewrite_meta,
|
|
"query_type": query_type,
|
|
"query_semantics": query_semantics,
|
|
"retrieval_domains": list(query_semantics.get("retrieval_domains") or []),
|
|
"message_intent": str(query_semantics.get("message_intent") or query_semantics.get("intent") or "").strip().lower() or None,
|
|
"scene_semantics": scene_semantics if isinstance(scene_semantics, dict) else {},
|
|
"effective_action_mode": effective_action_mode,
|
|
"anchor_resolution": anchor_resolution,
|
|
}
|
|
|
|
async def _execute_base_answer_mainline(
|
|
self,
|
|
*,
|
|
clean_q: str,
|
|
asked_by: Optional[int],
|
|
asked_via: str,
|
|
project_id: Optional[int],
|
|
source_chat_id: Optional[str],
|
|
session_id: Optional[int],
|
|
turn_index: int,
|
|
context_session_id: Optional[int],
|
|
conversation: list[dict[str, str]],
|
|
state_row: Optional[QASessionState],
|
|
effective_q: str,
|
|
rewrite_meta: dict[str, Any],
|
|
query_type: str,
|
|
query_semantics: dict[str, Any],
|
|
retrieval_domains: list[str],
|
|
scene_semantics: dict[str, Any],
|
|
thinking_mode: str,
|
|
active_thinking_mode: str,
|
|
deep_thinking: bool,
|
|
enforce_scene_prompt_only: bool,
|
|
deep_retrieval_steps: int,
|
|
deep_vector_top_k: int,
|
|
started: float,
|
|
message_intent: Optional[str],
|
|
mixed_signal_part: Optional[str],
|
|
anchor_resolution: Optional[FollowupAnchorResolution] = None,
|
|
consultant_mode_preference: Optional[str] = None,
|
|
) -> dict[str, Any]:
|
|
planner = self._plan_query_runtime(
|
|
question=clean_q,
|
|
effective_question=effective_q,
|
|
query_type=query_type,
|
|
scene_semantics=scene_semantics,
|
|
requested_thinking_mode=active_thinking_mode,
|
|
enforce_scene_prompt_only=enforce_scene_prompt_only,
|
|
consultant_mode_preference=consultant_mode_preference,
|
|
)
|
|
active_thinking_mode = planner.thinking_mode
|
|
deep_thinking = planner.retrieval_answer_mode == ANSWER_MODE_RETRIEVAL_DEEP
|
|
deep_retrieval_steps = int(planner.budget.max_steps or deep_retrieval_steps)
|
|
deep_vector_top_k = int(planner.budget.vector_top_k or deep_vector_top_k)
|
|
|
|
forced_deep_reason = ""
|
|
if not deep_thinking and not planner.allow_fast_path:
|
|
deep_intent = str((scene_semantics or {}).get("deep_intent") or "none").strip().lower()
|
|
if deep_intent != "none":
|
|
forced_deep_reason = deep_intent
|
|
deep_thinking = True
|
|
active_thinking_mode = THINKING_MODE_DEEP
|
|
|
|
clarification_payload = self._build_followup_clarification_payload(
|
|
question=clean_q,
|
|
anchor_resolution=anchor_resolution,
|
|
session_state=state_row,
|
|
)
|
|
meta_followup_payload = await self._build_meta_followup_payload(
|
|
question=clean_q,
|
|
anchor_resolution=anchor_resolution,
|
|
conversation_scope_key=self._get_active_external_qa_context().get("conversation_scope_key"),
|
|
)
|
|
meta_followup_result = await self._maybe_return_meta_followup_response(
|
|
meta_followup_payload=meta_followup_payload,
|
|
started=started,
|
|
clean_q=clean_q,
|
|
effective_q=effective_q,
|
|
query_type=query_type,
|
|
asked_by=asked_by,
|
|
asked_via=asked_via,
|
|
project_id=project_id,
|
|
session_id=session_id,
|
|
turn_index=turn_index,
|
|
state_row=state_row,
|
|
rewrite_meta=rewrite_meta,
|
|
context_session_id=context_session_id,
|
|
active_thinking_mode=active_thinking_mode,
|
|
)
|
|
if meta_followup_result is not None:
|
|
return meta_followup_result
|
|
clarification_result = await self._maybe_return_clarification_response(
|
|
clarification_payload=clarification_payload,
|
|
started=started,
|
|
clean_q=clean_q,
|
|
effective_q=effective_q,
|
|
query_type=query_type,
|
|
asked_by=asked_by,
|
|
asked_via=asked_via,
|
|
project_id=project_id,
|
|
session_id=session_id,
|
|
turn_index=turn_index,
|
|
state_row=state_row,
|
|
rewrite_meta=rewrite_meta,
|
|
context_session_id=context_session_id,
|
|
active_thinking_mode=active_thinking_mode,
|
|
)
|
|
if clarification_result is not None:
|
|
return clarification_result
|
|
|
|
system_snapshot = await self.context_cache.get_system_snapshot(
|
|
db=self.db,
|
|
tenant_id=self.tenant_id,
|
|
)
|
|
user_snapshot = await self.context_cache.get_user_snapshot(
|
|
db=self.db,
|
|
tenant_id=self.tenant_id,
|
|
user_id=asked_by,
|
|
)
|
|
|
|
if planner.allow_fast_path:
|
|
deterministic_result = await self._run_deterministic_query(
|
|
question=effective_q,
|
|
project_id=project_id,
|
|
query_type=query_type,
|
|
query_semantics=query_semantics,
|
|
)
|
|
if deterministic_result is not None:
|
|
return await self._persist_fast_answer(
|
|
question=clean_q,
|
|
asked_by=asked_by,
|
|
asked_via=asked_via,
|
|
project_id=project_id,
|
|
fast_result=deterministic_result,
|
|
session_id=session_id,
|
|
external_session_id=context_session_id,
|
|
turn_index=turn_index,
|
|
query_type=str(deterministic_result.get("query_type") or query_type),
|
|
missing_fields=list(deterministic_result.get("missing_fields") or []),
|
|
state_row=state_row,
|
|
effective_question=effective_q,
|
|
rewrite_meta=rewrite_meta,
|
|
thinking_mode=active_thinking_mode,
|
|
answer_mode=ANSWER_MODE_FAST_PATH,
|
|
)
|
|
|
|
direct_answer = None
|
|
if planner.allow_fast_path:
|
|
direct_answer = self._build_snapshot_direct_answer(
|
|
effective_q,
|
|
system_snapshot=system_snapshot,
|
|
user_snapshot=user_snapshot,
|
|
snapshot_focus=str((scene_semantics or {}).get("snapshot_focus") or "none"),
|
|
)
|
|
direct_result = await self._maybe_return_snapshot_direct_response(
|
|
direct_answer=direct_answer,
|
|
started=started,
|
|
clean_q=clean_q,
|
|
effective_q=effective_q,
|
|
asked_by=asked_by,
|
|
asked_via=asked_via,
|
|
project_id=project_id,
|
|
session_id=session_id,
|
|
turn_index=turn_index,
|
|
state_row=state_row,
|
|
rewrite_meta=rewrite_meta,
|
|
context_session_id=context_session_id,
|
|
active_thinking_mode=active_thinking_mode,
|
|
user_snapshot=user_snapshot,
|
|
)
|
|
if direct_result is not None:
|
|
return direct_result
|
|
|
|
is_snapshot_direct_question = str((scene_semantics or {}).get("snapshot_focus") or "none").strip().lower() != "none"
|
|
if planner.allow_fast_path and not is_snapshot_direct_question:
|
|
glm_semantic_result = await self._try_glm_project_semantic_answer(
|
|
clean_q=effective_q,
|
|
project_id=project_id,
|
|
query_semantics=query_semantics,
|
|
)
|
|
if glm_semantic_result is not None:
|
|
return await self._persist_fast_answer(
|
|
question=clean_q,
|
|
asked_by=asked_by,
|
|
asked_via=asked_via,
|
|
project_id=project_id,
|
|
fast_result=glm_semantic_result,
|
|
session_id=session_id,
|
|
external_session_id=context_session_id,
|
|
turn_index=turn_index,
|
|
query_type=query_type if query_type != QUERY_TYPE_UNKNOWN else QUERY_TYPE_EXPLAIN,
|
|
missing_fields=[],
|
|
state_row=state_row,
|
|
effective_question=effective_q,
|
|
rewrite_meta=rewrite_meta,
|
|
thinking_mode=active_thinking_mode,
|
|
answer_mode=ANSWER_MODE_FAST_PATH,
|
|
)
|
|
|
|
return await self._build_retrieval_response(
|
|
clean_q=clean_q,
|
|
effective_q=effective_q,
|
|
asked_by=asked_by,
|
|
asked_via=asked_via,
|
|
project_id=project_id,
|
|
source_chat_id=source_chat_id,
|
|
session_id=session_id,
|
|
turn_index=turn_index,
|
|
context_session_id=context_session_id,
|
|
conversation=conversation,
|
|
state_row=state_row,
|
|
rewrite_meta=rewrite_meta,
|
|
query_type=query_type,
|
|
query_semantics=query_semantics,
|
|
retrieval_domains=retrieval_domains,
|
|
scene_semantics=scene_semantics,
|
|
thinking_mode=thinking_mode,
|
|
active_thinking_mode=active_thinking_mode,
|
|
deep_thinking=deep_thinking,
|
|
forced_deep_reason=forced_deep_reason or str(planner.reason or ""),
|
|
deep_retrieval_steps=deep_retrieval_steps,
|
|
deep_vector_top_k=deep_vector_top_k,
|
|
system_snapshot=system_snapshot,
|
|
user_snapshot=user_snapshot,
|
|
started=started,
|
|
message_intent=message_intent,
|
|
mixed_signal_part=mixed_signal_part,
|
|
answer_mode=planner.retrieval_answer_mode,
|
|
consultant_mode_preference=consultant_mode_preference,
|
|
)
|