{"record":{"id":"37f77f19a633f109","repo":"datawhalechina/hello-agents","slug":"tool-name-37f77f","errorCode":null,"errorMessage":"工具 '{tool_name}' 执行超时","messagePattern":"工具 '(.+?)' 执行超时","errorType":"exception","errorClass":"TimeoutException","httpStatus":null,"severity":"error","filePath":"Co-creation-projects/Shawnxyxy-HealthRecordAgent/backend/agents/base.py","lineNumber":189,"sourceCode":"            tool_func = self.tools[tool_name][\"function\"]\n            if asyncio.iscoroutinefunction(tool_func):\n                result = await asyncio.wait_for(\n                    tool_func(tool_input), \n                    timeout=self.timeout\n                )\n            else:\n                result = await asyncio.wait_for(\n                    asyncio.to_thread(tool_func, tool_input),\n                    timeout=self.timeout\n                )\n            \n            self._add_to_history(f\"Tool {tool_name} called with input: {tool_input}\")\n            self._add_to_history(f\"Tool {tool_name} result: {result}\")\n            \n            return result\n            \n        except asyncio.TimeoutError:\n            raise TimeoutException(f\"工具 '{tool_name}' 执行超时\")\n        except Exception as e:\n            raise AgentException(f\"工具 '{tool_name}' 执行失败: {str(e)}\")\n    # ========== 状态 & 历史 ==========\n    def _add_to_history(self, message: str):\n        \"\"\"添加到历史记录\"\"\"\n        timestamp = datetime.now().isoformat()\n        self.history.append(f\"[{timestamp}] {message}\")\n        \n        # 限制历史记录长度\n        if len(self.history) > 100:\n            self.history = self.history[-50:]\n    \n    def get_history(self, limit: int = 10) -> List[str]:\n        \"\"\"获取历史记录\"\"\"\n        return self.history[-limit:]\n    \n    def clear_history(self):\n        \"\"\"清空历史记录\"\"\"","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/Shawnxyxy-HealthRecordAgent/backend/agents/base.py#L171-L207","documentation":"call_tool runs the tool function (awaited directly if a coroutine, else via asyncio.to_thread) under asyncio.wait_for with self.timeout; asyncio.TimeoutError is re-raised as TimeoutException('工具 ... 执行超时'). The tool function itself is not cancelled cooperatively — the await gives up, but a blocked to_thread call may still occupy its worker thread.","triggerScenarios":"A tool doing slow synchronous I/O (HTTP request to a slow API, big DB query) inside asyncio.to_thread exceeding the timeout; a coroutine tool awaiting a hung network call; the shared timeout being too small for legitimately slow tools like file scans or external lookups.","commonSituations":"Third-party medical/API endpoints with high latency; per-tool timeouts being forced to share one agent-level timeout; thread pool starvation when several to_thread tools hang.","solutions":["Increase the agent timeout or make the tool faster (add internal timeouts to its HTTP/DB clients).","Put a deadline inside the tool (e.g. httpx timeout, cursor timeout) so it returns cleanly instead of being abandoned mid-thread.","Catch TimeoutException in the agent loop and either retry once or report a graceful 'tool unavailable' result to the LLM."],"exampleFix":"# before\ndef fetch_report(cid):\n    return requests.get(f'{API}/reports/{cid}', timeout=None).json()  # can hang\nagent.add_tool('fetch_report', fetch_report)\n\n# after\ndef fetch_report(cid):\n    return requests.get(f'{API}/reports/{cid}', timeout=10).json()  # bounded inside the tool too","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    r = await agent.call_tool(name, tool_input)\nexcept TimeoutException:\n    r = f'tool {name} timed out; try different arguments'  # graceful signal to the LLM","preventionTips":["Give every tool its own internal deadline (HTTP/DB client timeouts) shorter than the agent timeout.","Keep tool work chunked/idempotent so a timeout-then-retry does not duplicate side effects.","Track per-tool latency and raise the agent timeout only for genuinely slow tools."],"tags":["asyncio","timeout","tools","agent"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}