datawhalechina/hello-agents · error · AgentException

工具 '{tool_name}' 不存在

Error message

工具 '{tool_name}' 不存在

What it means

Raised by BaseAgent.call_tool in InnocoreAI when the requested tool_name is not a key in self.tools, the registry populated at agent construction. It is a lookup precondition failure: the LLM (or caller) hallucinated a tool name, or the agent was built without registering the tool. Note the f-string in the source means the message interpolates the actual name (e.g. "工具 'search_papers' 不存在").

Source

Thrown at Co-creation-projects/Apricity-InnocoreAI/agents/base.py:61

            "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. Log/print self.tools.keys() next to the failing name to spot exact spelling/case mismatch.
  2. Make the system prompt's tool list generated from the same registry (get_tools_description already does this) instead of hardcoded names.
  3. Register the missing tool in the agent's __init__ (self.register_tool(name, {'function':..., 'description':...})).
  4. Normalize LLM output (strip, lower, alias map) before call_tool.
  5. Optionally return a corrective message instead of raising so the LLM loop can retry with the valid tool list.

Example fix

# before
async def call_tool(self, tool_name, tool_input):
    if tool_name not in self.tools:
        raise AgentException(f"工具 '{tool_name}' 不存在")

# after — fuzzy-correct before failing
async def call_tool(self, tool_name, tool_input):
    name = tool_name.strip()
    if name not in self.tools:
        candidates = [k for k in self.tools if k.lower().replace('_','') == name.lower().replace('_','')]
        if not candidates:
            raise AgentException(
                f"工具 '{tool_name}' 不存在; 可用工具: {sorted(self.tools)}"
            )
        name = candidates[0]
    ...
Defensive patterns

Strategy: validation

Validate before calling

# Pre-check before dispatching an LLM tool call
if tool_name not in agent.tools:
    valid = sorted(agent.tools)
    # return corrective feedback to the model instead of crashing the loop
    return f"Unknown tool '{tool_name}'. Available tools: {valid}"

Type guard

def is_registered_tool(agent, name: str) -> bool:
    return isinstance(name, str) and name in agent.tools

Try / catch

try:
    result = await agent.call_tool(name, tool_input)
except AgentException as e:
    if "不存在" in str(e):
        log.warning(str(e)); reply_correction_to_model(e)  # let LLM retry
    else:
        raise

Prevention

When it happens

Trigger: An LLM tool-calling loop emitting a function name that differs from the registered key (snake_case vs camelCase, suffix drift like 'search_arxiv' vs 'arxiv_search'); constructing an agent subclass whose __init__ never registers tools; JSON-parsing a tool call where the name field picks up whitespace/quotes; removing a tool from the registry while prompts still advertise it.

Common situations: Prompt template lists tool names that no longer match the registry after refactoring; model outputs localized tool names; registration happens in a subclass the DI container skips; typos in tool names inside hand-written orchestration code.

Related errors


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