diff --git a/api/chat_routes.py b/api/chat_routes.py index 8dec5db..fb7a91b 100644 --- a/api/chat_routes.py +++ b/api/chat_routes.py @@ -534,6 +534,15 @@ def _rescue_bm25_divergence(contexts: List[Dict], search_result: dict, if chunk_id: existing_ids[chunk_id] = i + # 计算 contexts 中的多数 source(用于情况 B 注入校验) + # 防止跨文档注入无关切片(如 q013 场景:2.docx 的吸烟场所切片被注入到 1.docx 的查询中) + source_counter: Dict[str, int] = {} + for ctx in contexts: + src = ctx.get('meta', {}).get('source', '') + if src: + source_counter[src] = source_counter.get(src, 0) + 1 + majority_source = max(source_counter, key=source_counter.get) if source_counter else None + rescued_count = 0 for bm25_item in bm25_top3: @@ -560,8 +569,18 @@ def _rescue_bm25_divergence(contexts: List[Dict], search_result: dict, continue # 情况 B:切片不在 contexts 中(被 rerank 截断或已被过滤) - # 从 _bm25_top3 备份中注入 + # 从 _bm25_top3 备份中注入,但需校验 source 一致性 if bm25_doc and bm25_meta: + bm25_source = bm25_meta.get('source', '') + # source 一致性校验:只注入与 contexts 多数 source 一致的切片 + # 避免跨文档注入无关内容(如 2.docx 的吸烟场所切片混入 1.docx 的投放查询) + if majority_source and bm25_source and bm25_source != majority_source: + logger.debug( + f"BM25 分歧救援 (情况B-跳过): rank={rank}, " + f"source={bm25_source} != majority={majority_source}, " + f"section={bm25_meta.get('section', '')}" + ) + continue injected_ctx = { 'doc': bm25_doc, 'meta': bm25_meta, diff --git a/config.py b/config.py index 68329aa..0457fa1 100644 --- a/config.py +++ b/config.py @@ -101,7 +101,7 @@ LLM_MAX_TOKENS = 3000 # 最大输出 token 数 # ----- 意图分析(轻量、确定性高)----- # INTENT_MODEL 在顶部「一、API 密钥与模型」中统一配置 INTENT_TEMPERATURE = 0.1 -INTENT_MAX_TOKENS = 2048 # 推理模型需要额外 token 用于思维链 +INTENT_MAX_TOKENS = 4096 # 推理模型思维链消耗大量 token,2048 偶发截断导致意图分析失败 INTENT_HISTORY_WINDOW = 6 # 分析时取最近几条历史消息 # ==============================================================================