Skip to content

Conversation

@mylux
Copy link
Contributor

@mylux mylux commented Oct 18, 2025

The real purpose behind #431 and object of discussion in #434

@evalstate
Copy link
Owner

OK, I think this has the correct behaviour now:

async def test_error_handling_e2e(fast_agent, model_name):
"""Call a faulty tool and make sure the loop does as we expect."""
fast = fast_agent
# Define the agent
@fast.agent(
"agent",
instruction="SYSTEM PROMPT",
model=model_name,
servers=["test_server"],
)
async def agent_function():
async with fast.run() as agent:
await agent.agent.generate("fail please")
assert 4 == len(agent.agent.message_history)
# this makes sure that the user message has the tool result with the error
assert next(iter(agent.agent.message_history[-2].tool_results.values())).isError is True
await agent_function()

In the case of a standard Tool Call error, we reflect it back to the LLM to self-correct (hence the 4 messages in the test). If you want to capture that it happened, you can check the tool results isError flag (will usually be on the message_history[-2]).

The FAST_AGENT_ERROR_CHANNEL should really be used for otherwise unrecoverable exceptions; in this case the failure is "soft" - e.g. the LLM messed up some parameters or the MCP Server wanted to flag something going wrong, but not fatally.

LMK if this works for you, I'm very keen to get this merged now.

@mylux mylux marked this pull request as ready for review October 29, 2025 02:27
@mylux
Copy link
Contributor Author

mylux commented Oct 29, 2025

OK, just got the time to look at this. If I understand well your approach into this, you are providing the feedback to the LLM in tool_agent level. In this case, the component will simply pass the error message back to the LLM and make it trying again. As per my experience using local LLMs, this might not always help. My initial idea was to make this to the surface outside the tool call loop, because sometimes the error message is too generic, like:

name_of_the_tool is not available

And this is ambiguous:

  • Is the tool called correctly but not working? In this case I should just try again
  • Is the tool name wrong? In this case I should try to guess the correct name...But how?
  • Is the tool actually inexistent? Did I hallucinate? I should maybe try to work this around trying to use another tool or give up

What happened with me sometimes was the llm insisting in calling the tool the very same way again and again, because the message was not clear that the issue was with the name or the toolset instructions may have been lost in the context and needs to be refreshed.

By surfacing these messages to the user out of the tool call loop, they will be able to define more specific messages given a specific kind of error. This is actually better than having to wait until the max iterations be reached (and this value can be quite high depending on the settings) to improve instructions to the LLM. It's the "fail fast" thing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants