ReAct: an agent that calls tools
ReAct loops: the model picks a tool and its arguments, DSPy runs it and adds the result to a trajectory, until the model picks finish and writes the answer.
ORDERS = {"A-1001": "shipped on 12 March", "A-1002": "waiting for stock"}
def lookup_order(order_id: str) -> str:
"""Look up the status of an order."""
return ORDERS.get(order_id, "no such order")agent = dspy.ReAct("ticket -> reply", tools=[lookup_order], max_iters=5)
result = agent(ticket="Where is my order A-1001?")
print(result.reply)
for key, value in result.trajectory.items():
print(f"{key:14} {value}")A tool is a plain function. DSPy reads its name, docstring and type hints to describe it. The trajectory shows the loop: in step 0 the model thought, chose lookup_order with {'order_id': 'A-1001'}, and DSPy put the function's return value in observation_0. In step 1 it chose finish. A last call then wrote reply from the whole trajectory.
What the model is asked
agent = dspy.ReAct("ticket -> reply", tools=[lookup_order], max_iters=5)
print(list(agent.react.signature.output_fields))
print(agent.react.signature.output_fields["next_tool_name"].annotation)
print(next(line.strip() for line in agent.react.signature.instructions.splitlines() if "(1)" in line))Each step is a Predict with three outputs: a thought, a tool name limited to the tools you gave plus finish, and the arguments as a dictionary. The instructions describe every tool with its arguments. The stand-in's rule for this, in shop_lm.py, is simple: call lookup_order when the ticket has an order id and no tool has run yet, otherwise finish.
agent = dspy.ReAct("ticket -> reply", tools=[lookup_order], max_iters=5)
result = agent(ticket="I was charged twice")
print(result.reply)
print(result.trajectory["tool_name_0"])No order id, so the model finished at once without a tool. max_iters caps the loop, so a model that never picks finish stops after that many tool calls.
- Add a
refund_order(order_id: str) -> strtool and print thenext_tool_nameannotation. - Ask about
A-9999. - Set
max_iters=1on the first ticket and print the trajectory.
Every expert started right here.