{"record":{"id":"1a4d7b9dc04fd41a","repo":"binary-husky/gpt_academic","slug":"i-1-1a4d7b","errorCode":null,"errorMessage":"未收到第 {i + 1} 个响应","messagePattern":"未收到第 (.+?) 个响应","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"crazy_functions/review_fns/query_analyzer.py","lineNumber":190,"sourceCode":"                sys_prompt_array=sys_prompts,\n                max_workers=5\n            )\n\n            # 从收集的响应中提取我们需要的内容\n            extracted_responses = []\n            for i in range(len(prompts)):\n                if (i * 2 + 1) < len(responses):\n                    response = responses[i * 2 + 1]\n                    if response is None:\n                        raise Exception(f\"Response {i} is None\")\n                    if not isinstance(response, str):\n                        try:\n                            response = str(response)\n                        except:\n                            raise Exception(f\"Cannot convert response {i} to string\")\n                    extracted_responses.append(response)\n                else:\n                    raise Exception(f\"未收到第 {i + 1} 个响应\")\n\n            # 解析基本信息\n            query_type = self._extract_tag(extracted_responses[self.BASIC_QUERY_INDEX], \"query_type\")\n            if not query_type:\n                print(\n                    f\"Debug - Failed to extract query_type. Response was: {extracted_responses[self.BASIC_QUERY_INDEX]}\")\n                raise Exception(\"无法提取query_type标签内容\")\n            query_type = query_type.lower()\n\n            main_topic = self._extract_tag(extracted_responses[self.BASIC_QUERY_INDEX], \"main_topic\")\n            if not main_topic:\n                print(f\"Debug - Failed to extract main_topic. Using query as fallback.\")\n                main_topic = query\n\n            query_type = self._normalize_query_type(query_type, query)\n\n            # 解析arXiv参数\n            try:","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/binary-husky/gpt_academic/blob/d6bde0fa54373309bd05823a49bda8da019d2c77/crazy_functions/review_fns/query_analyzer.py#L172-L208","documentation":"QueryAnalyzer expects responses to contain at least 2*len(prompts) entries (alternating user/assistant turns); when the collected list is shorter, index i*2+1 falls outside it and the code raises Exception('未收到第 {i+1} 个响应'). This means one or more of the fanned-out LLM requests never delivered its turn at all — stronger than error 90, where the slot exists but holds None.","triggerScenarios":"The multi-request bridge returns fewer turns than prompts sent: a worker crashed before appending its response, an exception aborted collection mid-way, or a silent short-circuit in the executor dropped one request entirely.","commonSituations":"Thread-pool exceptions swallowed inside the bridge so a turn is never appended; timeouts that terminate collection early; version drift between QueryAnalyzer's indexing assumption (i*2+1) and a bridge that changed its response layout (e.g. stopped interleaving user turns).","solutions":["Retry the analysis — partial collection is usually transient (worker crash/timeout).","Log len(responses) vs len(prompts): a systematic mismatch (e.g. exactly len(prompts) responses) means the bridge no longer interleaves turns and the i*2+1 indexing in query_analyzer.py:182 must be updated to i.","Check backend logs for a worker exception at the same timestamp.","Verify the bridge version/contract: if responses are assistant-only, read responses[i] instead."],"exampleFix":"# before\nresponse = responses[i * 2 + 1]\n\n# after (if the bridge returns one entry per prompt, no interleaving)\nresponse = responses[i] if len(responses) == len(prompts) else responses[i * 2 + 1]","handlingStrategy":"validation","validationCode":"def response_count_ok(responses: list, prompt_count: int) -> bool:\n    # bridge contract: interleaved user/assistant turns -> 2 per prompt\n    return len(responses) >= prompt_count * 2","typeGuard":null,"tryCatchPattern":"try:\n    result = analyzer.analyze(query)\nexcept Exception as e:\n    if '未收到' in str(e):\n        logger.warning('partial LLM fan-out, retrying once')\n        result = analyzer.analyze(query)\n    else:\n        raise","preventionTips":["Pin the bridge/analyzer versions together — the i*2+1 indexing is a cross-module contract.","If you modify the multi-request bridge, add a regression test asserting len(responses) == 2 * len(prompts).","Log len(responses) vs len(prompts) on failure to detect contract drift immediately."],"tags":["llm","parallel-requests","indexing","contract-mismatch","query-analyzer"],"backgroundTag":null,"analyzedSha":"d6bde0fa54373309bd05823a49bda8da019d2c77","analyzedAt":"2026-08-14T22:48:35.038Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}