-
Notifications
You must be signed in to change notification settings - Fork 0
Flow Control and Errors
The ReAct loop has 2 separate error mechanisms, mainly for errors that the LLM sees/deals with vs errors that the programmer needs to deal with.
This is the main method for communicating errors to the LLM. When an exception is thrown, the ReAct loop catches it, and presents it to the LLM. The LLM can then try something else in order to recover from the error.
For example this simple calculator tool only supports one operation at a time, and throws an exception if the inputs are not valid:
@tool
def calculator(expression:str) -> float:
"""
A simple calculator tool. Can perform basic arithmetic
...
"""
#ensure that only one operation is present
ops = [c for c in expression if c in '+-*/^%']
if len(ops) > 1:
raise ValueError(f"Invalid expression, too many operators. Expected exactly one of '+ - * / ^ %', found {', '.join(ops)}")
if len(ops) == 0:
raise ValueError(f"Invalid expression, no operation found. Expected one of '+ - * / ^ %'")
op = ops[0]
_a, _b = expression.split(op)
a = float(_a)
b = float(_b)
if op == '+':
return a+b
elif op == '-':
return a-b
...
The tool explicitly has code for throwing exceptions if multiple operators are encountered or if no known operators are found. Additionally, the call to float()
can throw an exception if the value is not a valid number, which also would be propagated back up to the agent.
In this way, the agent can recognize if it does something incorrect, e.g. using the tool with the wrong inputs, and then it has the opportunity to try again and correct the mistake.
(todo)
- using this dependency injected flow control which exits the whole loop by raising failed task
(todo)
- dependency injection for breaking out of the loop (on tool success)