{"record":{"id":"b6480234709c1214","repo":"binary-husky/gpt_academic","slug":"json-delta","errorCode":null,"errorMessage":"意外Json结构：{delta}","messagePattern":"意外Json结构：(.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"request_llms/bridge_openrouter.py","lineNumber":200,"sourceCode":"        if ('data: [DONE]' in chunk_decoded): break # api2d 正常完成\n        # 提前读取一些信息 （用于判断异常）\n        json_data = chunkjson['choices'][0]\n        delta = json_data[\"delta\"]\n        if len(delta) == 0: break\n        if (not has_content) and has_role: continue\n        if (not has_content) and (not has_role): continue # raise RuntimeError(\"发现不标准的第三方接口：\"+delta)\n        if has_content: # has_role = True/False\n            result += delta[\"content\"]\n            if not console_silence: print(delta[\"content\"], end='')\n            if observe_window is not None:\n                # 观测窗，把已经获取的数据显示出去\n                if len(observe_window) >= 1:\n                    observe_window[0] += delta[\"content\"]\n                # 看门狗，如果超过期限没有喂狗，则终止\n                if len(observe_window) >= 2:\n                    if (time.time()-observe_window[1]) > watch_dog_patience:\n                        raise RuntimeError(\"用户取消了程序。\")\n        else: raise RuntimeError(\"意外Json结构：\"+delta)\n    if json_data and json_data['finish_reason'] == 'content_filter':\n        raise RuntimeError(\"由于提问含不合规内容被Azure过滤。\")\n    if json_data and json_data['finish_reason'] == 'length':\n        raise ConnectionAbortedError(\"正常结束，但显示Token不足，导致输出不完整，请削减单次输入的文本量。\")\n    return result\n\n\ndef predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies,\n            history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None):\n    \"\"\"\n    发送至chatGPT，流式获取输出。\n    用于基础的对话功能。\n    inputs 是本次问询的输入\n    top_p, temperature是chatGPT的内部调优参数\n    history 是之前的对话列表（注意无论是inputs还是history，内容太长了都会触发token数量溢出的错误）\n    chatbot 为WebUI中显示的对话列表，修改它，然后yield出去，可以直接修改对话界面内容\n    additional_fn代表点击的哪个按钮，按钮见functional.py\n    \"\"\"","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/binary-husky/gpt_academic/blob/d6bde0fa54373309bd05823a49bda8da019d2c77/request_llms/bridge_openrouter.py#L182-L218","documentation":"RuntimeError('意外Json结构：'+delta) raised when a stream delta from bridge_openrouter is neither the has_content nor the has_role shape - i.e. decode_chunk found a valid choices[0].delta dict, but it contains unexpected keys only (no 'content', no 'role'). This is the bridge's guard against non-standard OpenAI-compatible providers that inject extra fields or change the delta schema.","triggerScenarios":"Provider sends delta with only fields like {'reasoning_content': ...} or {'tool_calls': ...}; third-party relay inserting custom metadata keys; new API surface (function calling, reasoning models) not handled by this older bridge.","commonSituations":"Routing OpenRouter to reasoning models (e.g. deepseek-r1 style) whose deltas carry reasoning fields; providers with bespoke SSE extensions; model versions adding new delta fields.","solutions":["Inspect the delta printed in the exception to see which unexpected field the provider sends","Switch to a model/provider whose deltas only carry role/content, or extend decode_chunk to whitelist the extra field (e.g. map reasoning_content into content)","Update the bridge to a version that tolerates extra delta keys instead of raising","Disable function-calling / tool parameters if the provider echoes them into deltas"],"exampleFix":"# before\nelse: raise RuntimeError(\"意外Json结构：\"+delta)\n\n# after\nelif 'reasoning_content' in delta:\n    result += delta['reasoning_content']\nelse:\n    raise RuntimeError(\"意外Json结构：\" + str(delta))","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"def delta_is_supported(delta: dict) -> bool:\n    \"\"\"True when the bridge can consume this delta shape.\"\"\"\n    return isinstance(delta, dict) and ('content' in delta or 'role' in delta)","tryCatchPattern":"try:\n    result = predict_no_ui_long_connection(...)\nexcept RuntimeError as e:\n    if '意外Json结构' in str(e):\n        unsupported = e.args[0].split('意外Json结构：')[-1]\n        logging.warning('provider sent unsupported delta keys: %s', unsupported)\n        switch_to_standard_provider()\n    raise","preventionTips":["Pin providers whose deltas only carry role/content when using this bridge","Whitelist known extra fields (reasoning_content, tool_calls) in decode_chunk instead of crashing","Log the offending delta once and degrade gracefully for the rest of the stream"],"tags":["openrouter","json","delta","schema","compatibility"],"backgroundTag":null,"analyzedSha":"d6bde0fa54373309bd05823a49bda8da019d2c77","analyzedAt":"2026-08-14T22:48:35.038Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}