From c2fa360eb9833cc18f9693c4757eae13efaa12ac Mon Sep 17 00:00:00 2001 From: dctouch Date: Sat, 11 Apr 2026 17:04:50 +0300 Subject: [PATCH] =?UTF-8?q?=D0=93=D0=9B=D0=9E=D0=91=D0=90=D0=9B=D0=AC?= =?UTF-8?q?=D0=9D=D0=AB=D0=99=20=D0=A0=D0=95=D0=A4=D0=90=D0=9A=D0=A2=D0=9E?= =?UTF-8?q?=D0=A0=D0=98=D0=9D=D0=93=20=D0=90=D0=A0=D0=A5=D0=98=D0=A2=D0=95?= =?UTF-8?q?=D0=9A=D0=A2=D0=A3=D0=A0=D0=AB=20-=20=D0=A0=D0=B5=D1=84=D0=B0?= =?UTF-8?q?=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D1=8D=D1=82=D0=B0?= =?UTF-8?q?=D0=BF=D0=BE=D0=B2=20Stage=203.2=20=D0=92=20=D0=BE=D1=80=D0=BA?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE=20=D1=81=D0=B5=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD=D1=82=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8=D0=B9=20?= =?UTF-8?q?=D0=B0=D1=80=D0=B1=D0=B8=D1=82=D1=80=D0=B0=D0=B6=20fallback?= =?UTF-8?q?=D0=BE=D0=B2=20(=D1=83=D1=87=D0=B5=D1=82=20guard=5Fhints=20?= =?UTF-8?q?=D0=B8=20extraction)=20=D0=B8=20followup-override=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20aggregate/unsupported=20=D0=BA=D0=B5=D0=B9=D1=81?= =?UTF-8?q?=D0=BE=D0=B2.=20\=20=D0=A3=D0=B1=D1=80=D0=B0=D0=BD=D0=BE=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=BB=D0=B8=D0=BF=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B2?= =?UTF-8?q?=20address=5Flane=20=D0=BF=D1=80=D0=B8=20carryover-=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=82=D0=B5=D0=BA=D1=81=D1=82=D0=B5=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20=D0=BA=D0=B5=D0=B9=D1=81=D0=B0=20=D1=82=D0=B8=D0=BF=D0=B0=20?= =?UTF-8?q?=D0=BA=D0=B0=D0=BA=D0=B8=D0=B5=20=D0=BE=D0=B1=D0=BE=D1=80=D0=BE?= =?UTF-8?q?=D1=82=D1=8B=20...=20=D0=B7=D0=B0=202020,=20=D0=BD=D0=BE=20?= =?UTF-8?q?=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D0=B8=D0=BB=20=D0=B7=D0=B0?= =?UTF-8?q?=D1=89=D0=B8=D1=82=D1=83=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B6=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D0=B8=D0=BD=D1=82=D0=B5?= =?UTF-8?q?=D0=BD=D1=82=D0=BE=D0=B2=20(list=5Fopen=5Fcontracts=20=D0=B8=20?= =?UTF-8?q?=D1=82.=D0=BF.),=20=D0=BA=D1=80=D0=BE=D0=BC=D0=B5=20strict=20de?= =?UTF-8?q?ep-=D0=B4=D0=B8=D0=B0=D0=B3=D0=BD=D0=BE=D1=81=D1=82=D0=B8=D0=BA?= =?UTF-8?q?=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/TECH/1CLLMARCH-FACT.md | 16 ++ .../backend/dist/services/assistantService.js | 49 ++++- .../backend/src/services/assistantService.ts | 49 ++++- .../tests/assistantLivingRouter.test.ts | 44 ++++ ...istant_autogen_runtime_job-O0P9xlQ61X.json | 190 ++++++++++++++++++ 5 files changed, 332 insertions(+), 16 deletions(-) create mode 100644 llm_normalizer/data/eval_cases/assistant_autogen_runtime_job-O0P9xlQ61X.json diff --git a/docs/TECH/1CLLMARCH-FACT.md b/docs/TECH/1CLLMARCH-FACT.md index 00aa8e4..794b61e 100644 --- a/docs/TECH/1CLLMARCH-FACT.md +++ b/docs/TECH/1CLLMARCH-FACT.md @@ -2366,6 +2366,22 @@ Implemented in current pass (Stage 3.1 kick-off): - `assistantSemanticExtractionContract.test.ts` (new) - Existing router/chat regressions revalidated (`assistantLivingRouter.test.ts`, `assistantLivingChatMode.test.ts`). +Implemented in current pass (Stage 3.2 semantic route arbitration): +1. Extended orchestration fallback arbitration with semantic hints: + - `resolveAssistantOrchestrationDecision(...)` now evaluates semantic extraction hints (`guard_hints`, `extraction`) in addition to lexical flags. + - Added followup-aware override path so unsupported aggregate carryover queries can still be redirected to deep-analysis lane. +2. Reduced false route stickiness in followup turns: + - Aggregate/unsupported questions with stale followup context no longer remain in address lane by default. + - Supported intents (for example `list_open_contracts`) remain protected from accidental deep fallback unless strict deep-investigation cue is detected. +3. Extended orchestration debug contract: + - Added `semantic_route_arbitration` block (`supported_address_intent_detected`, `semantic_deep_investigation_hint_detected`, `semantic_aggregate_shape_detected`, `followup_semantic_override_to_deep_allowed`). +4. Added/updated regression coverage for real failures: + - `assistantLivingRouter.test.ts` now includes followup-carryover aggregate scenario (`какие обороты ... за 2020 год`) and validates deep fallback. + - Existing list-open-contracts guard scenario remains green (`Покажи незакрытые договоры ...` stays in address lane). +5. Validation snapshot: + - Stage 3 focused suite: `10` files / `76` tests passed. + - Type build: `npm --prefix llm_normalizer/backend run build` passed. + Acceptance (Stage 3): 1. LLM outputs strictly validated schema for extraction/decomposition (no free-form). 2. Deterministic guards can block or downgrade answers when evidence insufficient. diff --git a/llm_normalizer/backend/dist/services/assistantService.js b/llm_normalizer/backend/dist/services/assistantService.js index e784626..eff08c9 100644 --- a/llm_normalizer/backend/dist/services/assistantService.js +++ b/llm_normalizer/backend/dist/services/assistantService.js @@ -3429,13 +3429,35 @@ function resolveAssistantOrchestrationDecision(input) { hasAddressFollowupContextSignal(effectiveAddressUserMessage) || hasAddressFollowupContextSignal(repairedRawUserMessage) || hasAddressFollowupContextSignal(repairedEffectiveAddressUserMessage)); - const unsupportedIntentOrMode = modeDetection.mode !== "address_query" && - (intentResolution.intent === "unknown" || llmContractMode === "unsupported"); - const unsupportedAddressIntentFallbackToDeep = Boolean(!followupContext && - baseToolGate?.runAddressLane && + const supportedAddressIntentDetected = !strictDeepInvestigationCueDetected && + Boolean((intentResolution.intent && ADDRESS_INTENTS_KEEP_ADDRESS_LANE.has(intentResolution.intent)) || + (llmContractIntent && ADDRESS_INTENTS_KEEP_ADDRESS_LANE.has(llmContractIntent))); + const semanticGuardHints = semanticExtractionContract?.guard_hints && + typeof semanticExtractionContract.guard_hints === "object" + ? semanticExtractionContract.guard_hints + : null; + const semanticExtraction = semanticExtractionContract?.extraction && + typeof semanticExtractionContract.extraction === "object" + ? semanticExtractionContract.extraction + : null; + const semanticDeepInvestigationHintDetected = semanticGuardHints?.deep_investigation_signal_detected === true; + const semanticAggregateShapeDetected = semanticExtraction?.query_shape === "AGGREGATE_LOOKUP" || + semanticExtraction?.aggregation_profile === "management_profile"; + const followupSemanticOverrideToDeepAllowed = Boolean(followupContext && + !supportedAddressIntentDetected && + (llmContractMode === "unsupported" || + semanticAggregateShapeDetected || + semanticDeepInvestigationHintDetected || + !semanticApplyCanonicalRecommended)); + const unsupportedIntentOrMode = (modeDetection.mode !== "address_query" && intentResolution.intent === "unknown") || + llmContractMode === "unsupported"; + const unsupportedAddressIntentFallbackToDeep = Boolean(baseToolGate?.runAddressLane && unsupportedIntentOrMode && strongDataSignal && - !preserveAddressLaneSignal); + !preserveAddressLaneSignal && + !keepAddressLaneByIntent && + !supportedAddressIntentDetected && + (!followupContext || followupSemanticOverrideToDeepAllowed)); const deepAnalysisPreferenceDetected = Boolean(hasDeepAnalysisPreferenceSignal(rawUserMessage) || hasDeepAnalysisPreferenceSignal(repairedRawUserMessage) || hasDeepAnalysisPreferenceSignal(effectiveAddressUserMessage) || @@ -3448,14 +3470,19 @@ function resolveAssistantOrchestrationDecision(input) { toNonEmptyString(followupContext.previous_intent) === "vat_payable_forecast" && /(?:\u043f\u043e\u0447\u0435\u043c\u0443|why).*(?:\u043f\u0440\u043e\u0433\u043d\u043e\u0437|forecast).*(?:\u0443\u043f\u043b\u0430\u0442|payable|\b0\b)/iu.test(compactWhitespace(`${repairedRawUserMessage} ${repairedEffectiveAddressUserMessage}`))); const deepAnalysisSignalFallbackToDeep = Boolean(baseToolGate?.runAddressLane && - deepAnalysisPreferenceDetected && + (deepAnalysisPreferenceDetected || semanticDeepInvestigationHintDetected) && !keepAddressLaneByIntent && + !supportedAddressIntentDetected && !vatExplainFollowupSignal && - (!followupContext || !dataRetrievalSignal)); + (!followupContext || !dataRetrievalSignal || followupSemanticOverrideToDeepAllowed)); const aggregateAnalyticsFallbackToDeep = Boolean(baseToolGate?.runAddressLane && aggregateBusinessAnalyticsSignal && !keepAddressLaneByIntent && - !followupContext); + !supportedAddressIntentDetected && + (!followupContext || + llmContractMode === "unsupported" || + semanticAggregateShapeDetected || + !semanticApplyCanonicalRecommended)); const deepSessionContinuationFallbackToDeep = Boolean(!followupContext && baseToolGate?.runAddressLane && hasDeepSessionContinuationSignal({ @@ -3541,6 +3568,12 @@ function resolveAssistantOrchestrationDecision(input) { semantic_contract_valid: semanticContractValid, semantic_apply_canonical_recommended: semanticApplyCanonicalRecommended, semantic_reason_codes: semanticReasonCodes, + semantic_route_arbitration: { + supported_address_intent_detected: supportedAddressIntentDetected, + semantic_deep_investigation_hint_detected: semanticDeepInvestigationHintDetected, + semantic_aggregate_shape_detected: semanticAggregateShapeDetected, + followup_semantic_override_to_deep_allowed: followupSemanticOverrideToDeepAllowed + }, followup_context_detected: Boolean(followupContext), unsupported_address_intent_fallback_to_deep: unsupportedAddressIntentFallbackToDeep, deep_analysis_signal_fallback_to_deep: deepAnalysisSignalFallbackToDeep, diff --git a/llm_normalizer/backend/src/services/assistantService.ts b/llm_normalizer/backend/src/services/assistantService.ts index fc7935d..0d0c897 100644 --- a/llm_normalizer/backend/src/services/assistantService.ts +++ b/llm_normalizer/backend/src/services/assistantService.ts @@ -3385,13 +3385,35 @@ export function resolveAssistantOrchestrationDecision(input) { hasAddressFollowupContextSignal(effectiveAddressUserMessage) || hasAddressFollowupContextSignal(repairedRawUserMessage) || hasAddressFollowupContextSignal(repairedEffectiveAddressUserMessage)); - const unsupportedIntentOrMode = modeDetection.mode !== "address_query" && - (intentResolution.intent === "unknown" || llmContractMode === "unsupported"); - const unsupportedAddressIntentFallbackToDeep = Boolean(!followupContext && - baseToolGate?.runAddressLane && + const supportedAddressIntentDetected = !strictDeepInvestigationCueDetected && + Boolean((intentResolution.intent && ADDRESS_INTENTS_KEEP_ADDRESS_LANE.has(intentResolution.intent)) || + (llmContractIntent && ADDRESS_INTENTS_KEEP_ADDRESS_LANE.has(llmContractIntent))); + const semanticGuardHints = semanticExtractionContract?.guard_hints && + typeof semanticExtractionContract.guard_hints === "object" + ? semanticExtractionContract.guard_hints + : null; + const semanticExtraction = semanticExtractionContract?.extraction && + typeof semanticExtractionContract.extraction === "object" + ? semanticExtractionContract.extraction + : null; + const semanticDeepInvestigationHintDetected = semanticGuardHints?.deep_investigation_signal_detected === true; + const semanticAggregateShapeDetected = semanticExtraction?.query_shape === "AGGREGATE_LOOKUP" || + semanticExtraction?.aggregation_profile === "management_profile"; + const followupSemanticOverrideToDeepAllowed = Boolean(followupContext && + !supportedAddressIntentDetected && + (llmContractMode === "unsupported" || + semanticAggregateShapeDetected || + semanticDeepInvestigationHintDetected || + !semanticApplyCanonicalRecommended)); + const unsupportedIntentOrMode = (modeDetection.mode !== "address_query" && intentResolution.intent === "unknown") || + llmContractMode === "unsupported"; + const unsupportedAddressIntentFallbackToDeep = Boolean(baseToolGate?.runAddressLane && unsupportedIntentOrMode && strongDataSignal && - !preserveAddressLaneSignal); + !preserveAddressLaneSignal && + !keepAddressLaneByIntent && + !supportedAddressIntentDetected && + (!followupContext || followupSemanticOverrideToDeepAllowed)); const deepAnalysisPreferenceDetected = Boolean(hasDeepAnalysisPreferenceSignal(rawUserMessage) || hasDeepAnalysisPreferenceSignal(repairedRawUserMessage) || hasDeepAnalysisPreferenceSignal(effectiveAddressUserMessage) || @@ -3404,14 +3426,19 @@ export function resolveAssistantOrchestrationDecision(input) { toNonEmptyString(followupContext.previous_intent) === "vat_payable_forecast" && /(?:\u043f\u043e\u0447\u0435\u043c\u0443|why).*(?:\u043f\u0440\u043e\u0433\u043d\u043e\u0437|forecast).*(?:\u0443\u043f\u043b\u0430\u0442|payable|\b0\b)/iu.test(compactWhitespace(`${repairedRawUserMessage} ${repairedEffectiveAddressUserMessage}`))); const deepAnalysisSignalFallbackToDeep = Boolean(baseToolGate?.runAddressLane && - deepAnalysisPreferenceDetected && + (deepAnalysisPreferenceDetected || semanticDeepInvestigationHintDetected) && !keepAddressLaneByIntent && + !supportedAddressIntentDetected && !vatExplainFollowupSignal && - (!followupContext || !dataRetrievalSignal)); + (!followupContext || !dataRetrievalSignal || followupSemanticOverrideToDeepAllowed)); const aggregateAnalyticsFallbackToDeep = Boolean(baseToolGate?.runAddressLane && aggregateBusinessAnalyticsSignal && !keepAddressLaneByIntent && - !followupContext); + !supportedAddressIntentDetected && + (!followupContext || + llmContractMode === "unsupported" || + semanticAggregateShapeDetected || + !semanticApplyCanonicalRecommended)); const deepSessionContinuationFallbackToDeep = Boolean(!followupContext && baseToolGate?.runAddressLane && hasDeepSessionContinuationSignal({ @@ -3497,6 +3524,12 @@ export function resolveAssistantOrchestrationDecision(input) { semantic_contract_valid: semanticContractValid, semantic_apply_canonical_recommended: semanticApplyCanonicalRecommended, semantic_reason_codes: semanticReasonCodes, + semantic_route_arbitration: { + supported_address_intent_detected: supportedAddressIntentDetected, + semantic_deep_investigation_hint_detected: semanticDeepInvestigationHintDetected, + semantic_aggregate_shape_detected: semanticAggregateShapeDetected, + followup_semantic_override_to_deep_allowed: followupSemanticOverrideToDeepAllowed + }, followup_context_detected: Boolean(followupContext), unsupported_address_intent_fallback_to_deep: unsupportedAddressIntentFallbackToDeep, deep_analysis_signal_fallback_to_deep: deepAnalysisSignalFallbackToDeep, diff --git a/llm_normalizer/backend/tests/assistantLivingRouter.test.ts b/llm_normalizer/backend/tests/assistantLivingRouter.test.ts index 3e0c7ee..6c0b823 100644 --- a/llm_normalizer/backend/tests/assistantLivingRouter.test.ts +++ b/llm_normalizer/backend/tests/assistantLivingRouter.test.ts @@ -228,6 +228,50 @@ describe("assistant orchestration contract", () => { ]).toContain(String(decision.livingReason)); }); + it("routes unsupported turnover query to deep even with followup context carryover", () => { + const decision = resolveAssistantOrchestrationDecision({ + rawUserMessage: "\u043a\u0430\u043a\u0438\u0435 \u043e\u0431\u043e\u0440\u043e\u0442\u044b \u043f\u043e \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0435 \u0437\u0430 2020 \u0433\u043e\u0434", + effectiveAddressUserMessage: "\u041e\u0431\u043e\u0440\u043e\u0442\u044b \u043f\u043e \u0441\u0447\u0435\u0442\u0443 '\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430' \u0437\u0430 2020 \u0433\u043e\u0434.", + followupContext: { + previous_intent: "list_documents_by_contract", + previous_filters: { + organization: "\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441" + } + }, + llmPreDecomposeMeta: { + applied: true, + llmCanonicalCandidateDetected: true, + predecomposeContract: { + mode: "unsupported", + mode_confidence: "low", + intent: "account_balance_snapshot", + intent_confidence: "high" + }, + semanticExtractionContract: { + extraction: { + query_shape: "AGGREGATE_LOOKUP", + aggregation_profile: "management_profile" + }, + guard_hints: { + deep_investigation_signal_detected: false + } + } + } as any, + useMock: false + }); + + expect(decision.runAddressLane).toBe(false); + expect(decision.toolGateDecision).toBe("skip_address_lane"); + expect(decision.livingMode).toBe("deep_analysis"); + expect([ + "address_signal_unsupported_intent_fallback_to_deep", + "aggregate_analytics_signal_fallback_to_deep" + ]).toContain(String(decision.toolGateReason)); + expect( + decision.orchestrationContract?.semantic_route_arbitration?.followup_semantic_override_to_deep_allowed + ).toBe(true); + }); + it("routes profitability ranking query to deep analysis instead of address lane", () => { const decision = resolveAssistantOrchestrationDecision({ rawUserMessage: "\u043a\u0430\u043a\u043e\u0439 \u0441\u0430\u043c\u044b\u0439 \u0434\u043e\u0445\u043e\u0434\u043d\u044b\u0439 \u0433\u043e\u0434?", diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_runtime_job-O0P9xlQ61X.json b/llm_normalizer/data/eval_cases/assistant_autogen_runtime_job-O0P9xlQ61X.json new file mode 100644 index 0000000..49ce842 --- /dev/null +++ b/llm_normalizer/data/eval_cases/assistant_autogen_runtime_job-O0P9xlQ61X.json @@ -0,0 +1,190 @@ +{ + "suite_id": "assistant_autogen_runtime_job-O0P9xlQ61X", + "suite_version": "0.1.0", + "schema_version": "assistant_autogen_runtime_v0_1", + "scenario_count": 15, + "case_ids": [ + "AUTO-001", + "AUTO-002", + "AUTO-003", + "AUTO-004", + "AUTO-005", + "AUTO-006", + "AUTO-007", + "AUTO-008", + "AUTO-009", + "AUTO-010", + "AUTO-011", + "AUTO-012", + "AUTO-013", + "AUTO-014", + "AUTO-015" + ], + "cases": [ + { + "case_id": "AUTO-001", + "scenario_tag": "autogen_runtime", + "question_type": "direct", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Кому из контрагентов мы уже месяц отдаем товары, но на счетах все еще красуется минусовое сальдо - это реально зеленый свет для ручного вмешательства?" + } + ] + }, + { + "case_id": "AUTO-002", + "scenario_tag": "autogen_runtime", + "question_type": "direct", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Где у нас накопились авансы к отгрузкам, которые уже давно пора закрыть или хотя бы перепроверить, чтобы не подозревать худшее?" + } + ] + }, + { + "case_id": "AUTO-003", + "scenario_tag": "autogen_runtime", + "question_type": "direct", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Покажи контрагентов, по которым сальдо у нас выглядит так, будто оно врет - ну точно не совпадает с тем, что они нам прислали. Это уже критично для сверки." + } + ] + }, + { + "case_id": "AUTO-004", + "scenario_tag": "autogen_runtime", + "question_type": "direct", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Сколько заказчиков у нас на этот момент могут считаться долгожителями по своим задолженностям?" + } + ] + }, + { + "case_id": "AUTO-005", + "scenario_tag": "autogen_runtime", + "question_type": "direct", + "broadness_level": "medium", + "turns": [ + { + "user_message": "В каких случаях мы видим ситуацию, когда документы есть, а денег - нет и пока не предвидится?" + } + ] + }, + { + "case_id": "AUTO-006", + "scenario_tag": "autogen_runtime", + "question_type": "direct", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Какие контрагенты висят с закрытыми отгрузками, но с открытыми документами оплаты, что явно выглядит как кейс для ручной проверки?" + } + ] + }, + { + "case_id": "AUTO-007", + "scenario_tag": "autogen_runtime", + "question_type": "direct", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Покажи контрагентов, у которых есть неоплаченные задолженности по договорам на конец месяца - это уже красный свет для бухгалтера." + } + ] + }, + { + "case_id": "AUTO-008", + "scenario_tag": "autogen_runtime", + "question_type": "direct", + "broadness_level": "medium", + "turns": [ + { + "user_message": "По каким заказчикам мы можем выделить непростую картину: сальдо нулевое, а история платежей явно говорит о том, что все не так просто?" + } + ] + }, + { + "case_id": "AUTO-009", + "scenario_tag": "autogen_runtime", + "question_type": "direct", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Какие контрагенты у нас на этом моменте могут быть причислены к тем, кто вообще не платит уже несколько месяцев?" + } + ] + }, + { + "case_id": "AUTO-010", + "scenario_tag": "autogen_runtime", + "question_type": "direct", + "broadness_level": "medium", + "turns": [ + { + "user_message": "В каких случаях мы видим зависшие отгрузки, которые уже давно пора закрыть - это грозит проблемами в отчетности." + } + ] + }, + { + "case_id": "AUTO-011", + "scenario_tag": "autogen_runtime", + "question_type": "direct", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Покажи контрагентов, по которым на конец месяца сальдо выглядит так, будто документы собраны криво и их нужно перепроверить." + } + ] + }, + { + "case_id": "AUTO-012", + "scenario_tag": "autogen_runtime", + "question_type": "direct", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Какие у нас зависшие авансы или предоплаты уже давно пора либо закрыть, либо хотя бы проверить - это уже не просто вопрос времени?" + } + ] + }, + { + "case_id": "AUTO-013", + "scenario_tag": "autogen_runtime", + "question_type": "direct", + "broadness_level": "medium", + "turns": [ + { + "user_message": "По каким контрагентам мы можем заметить такую картину: оплачено меньше, чем отгружено, и это явно требует вмешательства бухгалтера." + } + ] + }, + { + "case_id": "AUTO-014", + "scenario_tag": "autogen_runtime", + "question_type": "direct", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Какие незакрытые документы по договорам у нас уже давно пора проверить - это грозит серьезными проблемами?" + } + ] + }, + { + "case_id": "AUTO-015", + "scenario_tag": "autogen_runtime", + "question_type": "direct", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Покажи контрагентов, чьи заказы на отгрузку еще не оплачены, но сальдо уже отрицательное - это явный признак того, что нужно вмешаться." + } + ] + } + ] +} \ No newline at end of file