datawhalechina/hello-agents · error · AgentException
LLM思考失败: {str(e)}
Error message
LLM思考失败: {str(e)} What it means
The generic except in BaseAgent.think: any exception from the LLM call that is not asyncio.TimeoutError is re-wrapped as AgentException('LLM思考失败: <original message>'). The original cause is only in the string, so the real failure (auth error, connection refused, malformed response, missing attribute on the response object) must be read out of the message.
Source
Thrown at Co-creation-projects/Shawnxyxy-HealthRecordAgent/backend/agents/base.py:145
{
"duration_sec": duration,
"prompt_tokens": len(full_prompt),
}
)
response_text = response.content if hasattr(response, 'content') else str(response)
self.trace("LLM RESPONSE", response_text)
self._add_to_history(f"LLM prompt: {prompt}")
self._add_to_history(f"LLM response: {response_text}")
return response_text
except asyncio.TimeoutError:
raise TimeoutException(f"LLM思考超时")
except Exception as e:
raise AgentException(f"LLM思考失败: {str(e)}")
# ========== Tool 机制 ==========
def add_tool(self, tool_name: str, tool_func: Callable, description: str = ""):
"""添加工具"""
self.tools[tool_name] = {
"function": tool_func,
"description": description
}
def get_tools_description(self) -> str:
"""获取工具描述"""
if not self.tools:
return "暂无可用工具"
descriptions = []
for name, tool_info in self.tools.items():
descriptions.append(f"- {name}: {tool_info['description']}")
return "\n".join(descriptions)View on GitHub (pinned to 606a07d341)
Solutions
- Read the embedded original message after 'LLM思考失败:' — it usually names the HTTP status or library error.
- Fix the root cause: verify API key, base URL, and model id by making one direct client call outside the agent.
- If the message mentions response shape issues, normalize the response before think() processes it.
- Distinguish from error 133: no '超时' in the message means it is this generic path, not a timeout.
Example fix
# before
try:
out = await agent.think(prompt)
except AgentException as e:
abort() # loses cause
# after
try:
out = await agent.think(prompt)
except AgentException as e:
cause = str(e).removeprefix('LLM思考失败: ')
if '401' in cause or 'api key' in cause.lower():
refresh_credentials()
raise Defensive patterns
Strategy: try-catch
Validate before calling
async def llm_reachable(llm):
try:
await asyncio.wait_for(llm.ainvoke('ping'), timeout=10)
return True
except Exception:
return False Try / catch
try:
out = await agent.think(prompt)
except AgentException as e:
msg = str(e)
if '401' in msg or 'Unauthorized' in msg:
rotate_api_key()
elif 'Connection' in msg:
check_base_url_and_network()
else:
raise Prevention
- Verify credentials and endpoint with a direct minimal LLM call during agent startup.
- Log the embedded cause string — the wrapper preserves no exception chain for programmatic use.
- Keep the LLM client's response shape stable (wrap clients so .content always exists).
When it happens
Trigger: Invalid/expired API key (401), unreachable base URL, model name not found, the LLM client returning an object without .content (falls into str() then downstream errors), or serialization issues in the prompt — anything except a wait_for timeout.
Common situations: Rotated API keys after the agent was deployed; pointing the client at a wrong/self-hosted endpoint; swapping LLM libraries whose response objects differ; empty responses from rate limiting.
Related errors
- 工具 '{tool_name}' 执行失败: {str(e)}
- 工具 '{tool_name}' 不存在
- 工具未定义: {tool_name}.
- LLM思考超时
- PlannerAgent 执行失败: {str(e)}
AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14).
Data as JSON: /api/errors/fb3ff67831e2d1d3.
Report an issue: GitHub.