{"record":{"id":"88b5c11defed6626","repo":"binary-husky/gpt_academic","slug":"error-88b5c1","errorCode":null,"errorMessage":"程序终止。","messagePattern":"程序终止。","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"warning","filePath":"request_llms/local_llm_class.py","lineNumber":262,"sourceCode":"                    what_gpt_answer = {}\n                    what_gpt_answer[\"role\"] = \"assistant\"\n                    what_gpt_answer[\"content\"] = history[index+1]\n                    if what_i_have_asked[\"content\"] != \"\":\n                        if what_gpt_answer[\"content\"] == \"\":\n                            continue\n                        history_feedin.append(what_i_have_asked)\n                        history_feedin.append(what_gpt_answer)\n                    else:\n                        history_feedin[-1]['content'] = what_gpt_answer['content']\n\n        watch_dog_patience = 5  # 看门狗 (watchdog) 的耐心, 设置5秒即可\n        response = \"\"\n        for response in _llm_handle.stream_chat(query=inputs, history=history_feedin, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']):\n            if len(observe_window) >= 1:\n                observe_window[0] = response\n            if len(observe_window) >= 2:\n                if (time.time()-observe_window[1]) > watch_dog_patience:\n                    raise RuntimeError(\"程序终止。\")\n        return response\n\n    def 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            refer to request_llms/bridge_all.py\n        \"\"\"\n        chatbot.append((inputs, \"\"))\n\n        _llm_handle = GetSingletonHandle().get_llm_model_instance(LLMSingletonClass)\n        chatbot[-1] = (inputs, load_message + \"\\n\\n\" + _llm_handle.get_state())\n        yield from update_ui(chatbot=chatbot, history=[])\n        if not _llm_handle.running:\n            raise RuntimeError(_llm_handle.get_state())\n\n        if additional_fn is not None:\n            from core_functional import handle_core_functionality\n            inputs, history = handle_core_functionality(","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/binary-husky/gpt_academic/blob/d6bde0fa54373309bd05823a49bda8da019d2c77/request_llms/local_llm_class.py#L244-L280","documentation":"Watchdog in predict_no_ui_long_connection for local models: observe_window[1] holds the last 'feed' timestamp; if the caller (UI) stops refreshing it for more than watch_dog_patience (5 s), the generator assumes the user cancelled and raises RuntimeError('程序终止。'). This is cooperative cancellation, not a crash — the model thread simply stops streaming.","triggerScenarios":"Streaming from a local model while the front end stops updating observe_window[1] = time.time() for over 5 seconds: user pressed stop, the UI tab was closed/refreshed, or the calling plugin never maintains the second observe_window slot.","commonSituations":"User clicks 'Stop' during a slow local-model generation; gradio page closed mid-generation; a custom caller passes observe_window of length >= 2 but never refreshes index 1.","solutions":["If cancellation was intended, no fix is needed — this is by design.","If generation aborts unexpectedly, ensure the caller/UI keeps setting observe_window[1] = time.time() at least every few seconds while the response is still wanted.","Pass an observe_window list of length 1 (observation only, no watchdog) when programmatic long calls don't need cancellation.","For very slow models, understand the watchdog measures caller liveness, not model progress — do not 'fix' by ignoring it."],"exampleFix":"# caller: keep the watchdog fed while consuming the stream\n# before\nfor response in predict_no_ui_long_connection(inputs, llm_kwargs, observe_window=obs):\n    ...\n\n# after\nobs[1] = time.time()\nfor response in predict_no_ui_long_connection(inputs, llm_kwargs, observe_window=obs):\n    obs[1] = time.time()  # feed the watchdog each iteration\n    ...","handlingStrategy":"validation","validationCode":"# pass a one-element window to run without the watchdog\nobserve_window = ['']           # no index 1 -> cancellation check disabled\n# or keep feeding it:\nobserve_window = ['', time.time()]","typeGuard":null,"tryCatchPattern":"try:\n    for r in predict_no_ui_long_connection(q, kw, observe_window=obs):\n        obs[1] = time.time()\nexcept RuntimeError as e:\n    if str(e) == '程序终止。':\n        handle_user_cancel()  # expected, not an error\n    else:\n        raise","preventionTips":["Refresh observe_window[1] on every iteration while consuming the stream.","Treat this exception as cancellation, never as a model failure.","Use a 1-element window for headless/programmatic calls."],"tags":["watchdog","cancellation","local-llm","streaming","timeout"],"backgroundTag":null,"analyzedSha":"d6bde0fa54373309bd05823a49bda8da019d2c77","analyzedAt":"2026-08-14T22:48:35.038Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}