From 5475ea6dfc25374c334f5c44e0b6265ff1cb0842 Mon Sep 17 00:00:00 2001 From: chengke <404835780@qq.com> Date: Wed, 13 May 2026 22:41:50 +0800 Subject: [PATCH] feat: add per-request use_agentic toggle and slim retrieval API contract - Add use_agentic (bool|null) request parameter: true=force agentic, false=force legacy, null=server default (RETRIEVAL_AGENTIC_ENABLED). - Remove deprecated enable_decomposition parameter (was ignored). - Strip debug-only response fields (plan, steps, wallet_snapshot, planner_snapshot, final_strategy_used, evidence_text). - Keep core response: namespace, query, router_used, answer_text, referenced_chunks, results. --- apps/api/app/api/v1/routes/retrieval.py | 26 +++---------------- .../shared/services/retrieval/app_service.py | 9 ++++--- 2 files changed, 8 insertions(+), 27 deletions(-) diff --git a/apps/api/app/api/v1/routes/retrieval.py b/apps/api/app/api/v1/routes/retrieval.py index aaee0b7bc..1ef332e4b 100644 --- a/apps/api/app/api/v1/routes/retrieval.py +++ b/apps/api/app/api/v1/routes/retrieval.py @@ -52,10 +52,9 @@ class RetrievalQueryRequest(BaseModel): internal_recall_k: int | None = Field( None, ge=1, description="Override per-channel recall count" ) - enable_decomposition: bool | None = Field( + use_agentic: bool | None = Field( None, - description="Deprecated: agentic mode now always uses workflow decomposition. This field is ignored.", - deprecated=True, + description="Per-request agentic mode toggle. true=force agentic, false=force legacy, null=use server default.", ) @field_validator("channels") @@ -68,20 +67,6 @@ def validate_channels(cls, v: list[str]) -> list[str]: return v -class WorkflowStepResponse(BaseModel): - step_id: str - sub_query: str - step_kind: Literal["retrieve", "synthesize"] - depends_on: list[str] - output_role: str - status: Literal["done", "skipped", "error", "budget_stop"] - answer_text: str - evidence_text: str | None = None - referenced_chunks: list[dict] = Field(default_factory=list) - budget_snapshot: dict | None = None - child_run_id: str | None = None - - class RetrievalQueryResponse(BaseModel): namespace: str query: str @@ -89,11 +74,6 @@ class RetrievalQueryResponse(BaseModel): answer_text: str | None = None referenced_chunks: list[dict] = Field(default_factory=list) results: list[dict] = Field(default_factory=list) - plan: dict | None = None - steps: list[WorkflowStepResponse] | None = None - final_strategy_used: str | None = None - wallet_snapshot: dict | None = None - planner_snapshot: dict | None = None @router.post("/query", response_model=RetrievalQueryResponse) @@ -118,5 +98,5 @@ async def query_retrieval( rerank=payload.rerank, threshold=payload.threshold, internal_recall_k=payload.internal_recall_k, - enable_decomposition=payload.enable_decomposition, + use_agentic=payload.use_agentic, ) diff --git a/packages/shared-python/shared/services/retrieval/app_service.py b/packages/shared-python/shared/services/retrieval/app_service.py index 42166ea28..96c125e49 100644 --- a/packages/shared-python/shared/services/retrieval/app_service.py +++ b/packages/shared-python/shared/services/retrieval/app_service.py @@ -432,8 +432,6 @@ async def _to_public_response(response: dict[str, Any]) -> dict[str, Any]: } # Forward agentic evidence fields when present - if response.get('evidence_text') is not None: - public_response['evidence_text'] = response['evidence_text'] if response.get('answer_text') is not None: public_response['answer_text'] = response['answer_text'] if response.get('referenced_chunks') is not None: @@ -982,7 +980,7 @@ async def run_retrieval_query( rerank: bool = False, threshold: float = 0.0, internal_recall_k: int | None = None, - enable_decomposition: bool | None = None, # deprecated: now always uses workflow + use_agentic: bool | None = None, ) -> dict[str, Any]: """Checkerboard retrieval: 3 independent channels -> RRF -> agent/graph union -> assembly.""" t_start = time.monotonic() @@ -1100,7 +1098,10 @@ async def run_retrieval_query( return await _to_public_response(response) # ══ Route: agentic (unified workflow) vs legacy ══ - _agentic_enabled = os.environ.get('RETRIEVAL_AGENTIC_ENABLED', 'true') == 'true' + if use_agentic is not None: + _agentic_enabled = use_agentic + else: + _agentic_enabled = os.environ.get('RETRIEVAL_AGENTIC_ENABLED', 'true') == 'true' if _agentic_enabled: # ── Unified agentic path via WorkflowOrchestrator ── # Simple queries: planner returns a single-step plan (no decomposition).