ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов Stage 3.7 ХВОСТЫ Убрана часть чат-дрифта и зафиксировал роутинг в deep \ Ослаблена шаблонность коротких блоков ответа (детерминированные вариативные формулировки вместо одной и той же фразы)

This commit is contained in:
2026-04-11 20:14:38 +03:00
parent 351993430f
commit 160ed18fe5
9 changed files with 594 additions and 86 deletions
@@ -1108,6 +1108,29 @@ function buildLimitedScopeLine(filters: AddressFilterSet): string | null {
return `Контекст запроса: ${scopeParts.join(", ")}.`;
}
function buildLimitedVariantSeedFingerprint(filters: AddressFilterSet): string {
const seedParts: string[] = [];
const keys: Array<keyof AddressFilterSet> = [
"organization",
"counterparty",
"contract",
"account",
"document_ref",
"as_of_date",
"period_from",
"period_to"
];
for (const key of keys) {
const raw = filters[key];
const value = typeof raw === "string" ? raw.trim() : "";
if (!value) {
continue;
}
seedParts.push(`${key}:${value.toLowerCase()}`);
}
return seedParts.length > 0 ? seedParts.join("|") : "no_filter_seed";
}
function buildLimitedOffers(input: {
category: AddressLimitedReasonCategory;
shape: AddressQueryShapeDetection;
@@ -1238,12 +1261,25 @@ function composeLimitedReply(input: {
missingRequiredFilters: string[];
}): string {
const reason = normalizeLimitedReason(input.reason);
const headingSeed = `${input.category}|${input.shape.shape}|${reason}`;
const filterSeed = buildLimitedVariantSeedFingerprint(input.filters);
const missingSeed = Array.from(new Set(input.missingRequiredFilters.map((item) => String(item ?? "").trim())))
.filter((item) => item.length > 0)
.sort()
.join(",");
const headingSeed = `${input.category}|${input.shape.shape}|${input.intent}|${reason}|${filterSeed}|${missingSeed}`;
const aggregateLimitedSignal = hasAggregateLimitedSignal({
shape: input.shape,
intent: input.intent,
reason: input.reason
});
const missingAnchorLabels = Array.from(
new Set(
(Array.isArray(input.missingRequiredFilters) ? input.missingRequiredFilters : [])
.map((item) => normalizeMissingAnchorLabel(String(item ?? "").trim()))
.filter((item) => item.length > 0)
)
);
const missingAnchorPhrase = missingAnchorLabels.length > 0 ? missingAnchorLabels.join(", ") : "контрагент, договор, счет или период";
const heading =
input.category === "empty_match"
? pickDeterministicVariant(headingSeed, [
@@ -1282,12 +1318,14 @@ function composeLimitedReply(input: {
])
: pickDeterministicVariant(reasonSeed, [
"Сценарий пока не закрыт текущими адресными маршрутами без потери точности.",
"Для этого запроса пока нет надежного ответа внутри текущего address-контура."
"Для этого запроса пока нет надежного ответа в текущем адресном режиме.",
"Надежный ответ здесь требует более широкого анализа, чем текущий адресный контур."
])
: input.category === "missing_anchor"
? pickDeterministicVariant(reasonSeed, [
"Нужно чуть точнее заякорить запрос: не хватает конкретного ориентира (контрагент, договор, счет или период).",
"Для точного ответа нужен хотя бы один явный якорь: контрагент, договор, счет или период."
`Нужно чуть точнее заякорить запрос: не хватает конкретного ориентира (${missingAnchorPhrase}).`,
`Для точного ответа нужен хотя бы один явный ориентир: ${missingAnchorPhrase}.`,
`Смысл запроса понятен, но без уточнения (${missingAnchorPhrase}) риск ошибки слишком высокий.`
])
: input.category === "recipe_visibility_gap"
? "Для уверенного ответа нужен более специализированный сценарий выборки."