datawhalechina/hello-agents · error · AgentException

工具 '{tool_name}' 不存在

Error message

工具 '{tool_name}' 不存在

What it means

BaseAgent.call_tool looks up tool_name in self.tools (populated via add_tool); an unknown name raises AgentException('工具 ... 不存在'). It is a registry lookup failure — the agent attempted to invoke a tool that was never registered on this instance.

Source

Thrown at Co-creation-projects/Shawnxyxy-HealthRecordAgent/backend/agents/base.py:168

            "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)
    
    async def call_tool(self, tool_name: str, tool_input: Any) -> Any:
        """调用工具"""
        if tool_name not in self.tools:
            raise AgentException(f"工具 '{tool_name}' 不存在")
        
        try:
            tool_func = self.tools[tool_name]["function"]
            if asyncio.iscoroutinefunction(tool_func):
                result = await asyncio.wait_for(
                    tool_func(tool_input), 
                    timeout=self.timeout
                )
            else:
                result = await asyncio.wait_for(
                    asyncio.to_thread(tool_func, tool_input),
                    timeout=self.timeout
                )
            
            self._add_to_history(f"Tool {tool_name} called with input: {tool_input}")
            self._add_to_history(f"Tool {tool_name} result: {result}")
            
            return result

View on GitHub (pinned to 606a07d341)

Solutions

  1. Register the tool before use: agent.add_tool('name', func, description).
  2. Constrain the model to the registered list — feed it get_tools_description() output verbatim.
  3. On AgentException with '不存在', re-prompt the model with the available tool list instead of crashing.

Example fix

# before
result = await agent.call_tool('search_drugs', q)  # never registered

# after
agent.add_tool('search_drugs', search_drugs, '查询药品信息')
result = await agent.call_tool('search_drugs', q)

# defensive: allowed = set(agent.tools)
Defensive patterns

Strategy: validation

Validate before calling

def tool_exists(agent, name):
    return name in agent.tools

if not tool_exists(agent, tool_name):
    raise KeyError(f'{tool_name} not registered; have: {sorted(agent.tools)}')

Try / catch

try:
    r = await agent.call_tool(name, tool_input)
except AgentException as e:
    if '不存在' in str(e):
        r = f'tool {name} not available; valid: {sorted(agent.tools)}'  # feed back to LLM

Prevention

When it happens

Trigger: LLM emitting a tool name that is not in get_tools_description(); calling agent.call_tool('search_drug', ...) when only 'drug_search' was registered via add_tool; instantiating a fresh agent and calling a tool its subclass never registers.

Common situations: Hallucinated or renamed tool names from the model; tools registered conditionally (only if an API key exists) so the name disappears in some environments; prompt tool lists drifting out of sync with registrations.

Related errors


AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14). Data as JSON: /api/errors/934ef38188f79b03. Report an issue: GitHub.