I built a simple agent to show you how easy it is to mess things up.
It’s an agent that handles customer refunds, and because the process is straightforward, I designed a streamlined end-to-end architecture.
Here is the diagram illustrating what I did:
We have a store, a support team, and my agent helping with refunds.
When a customer is unhappy with their purchase, they contact support. We then have the Return agent pick up the request and start the return process:
The agent interprets the request and realizes the customer wants to return their purchase.
It then uses the lookup_order tool to find the customer’s order. The tool returns the order information and any attached warehouse notes.
If the return window is open, the Return agent uses the refund_order tool to send the money back to the customer’s credit card.
This isn't rocket science, so I didn’t overthink my agent's architecture.
I’m also not naive, and I added as many guardrails as I thought were necessary:
The agent ensures the order coming back from the lookup_order tool matches the one from the customer.
It also ensures the return is within the proper timeframe before authorizing it.
Finally, it prevents multiple refunds for the same order.
I thought these constraints had me covered, but my headaches came from a very different place.
I gave my agent too much responsibility. Simplicity became its Achilles' heel.
My design just didn’t work
My architecture was flawed from the start.
One customer messaged support to check the return status of their purchase. They didn’t want a refund just yet; they only wanted to know whether we had their product.
The Return agent looked up their order. Along with the return status, the tool returned a note from the warehouse: “The product was received by the warehouse. You can issue a refund now.”
