DSPyDSPy 3.3 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
24 small wins to finish your pathNext lesson

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.

Example
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")
Example
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

Example
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.

Example
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.

Tools run your code
The model chooses the arguments. A tool that refunds money or deletes data must check them itself, because a model can be talked into calling anything it is given.
Try it yourself
  • Add a refund_order(order_id: str) -> str tool and print the next_tool_name annotation.
  • Ask about A-9999.
  • Set max_iters=1 on the first ticket and print the trajectory.

Every expert started right here.