A customer service agent wired directly into Acumatica has access to real order status, invoice history, and case records — which is exactly what makes a wrong answer dangerous. The design goal is a system that answers from real data via tool calls, refuses gracefully when it doesn't have enough information, and escalates anything involving money or account changes rather than acting on its own.
Separate read tools from write tools, and gate the write side harder
An agent that can look up an order status is low risk. The same agent empowered to issue a refund, change a shipping address, or modify a payment method is a different risk category entirely. Split the tool set explicitly: read tools (look up order, check invoice, view case history) can run freely, while write tools (issue credit, update account, cancel order) require either a human approval step or are scoped to a tightly bounded, pre-approved action (e.g. only reschedule a delivery, nothing else) with hard limits enforced in the tool itself, not just described in the prompt.
def get_order_status(order_id: str, customer_id: str) -> dict:
"""Read-only. Verifies customer_id owns the order
before returning any data."""
...
def issue_refund(order_id: str, amount: float, reason: str) -> dict:
"""Write action. Hard-capped at REFUND_AUTO_LIMIT.
Anything above that returns 'pending_approval'
instead of executing."""
if amount > REFUND_AUTO_LIMIT:
return {"status": "pending_approval", "amount": amount}
return process_refund(order_id, amount, reason)
Answering only from data the agent actually retrieved this turn
The failure mode that erodes trust fastest is a confident, plausible-sounding answer about order status or policy that isn't actually grounded in a real lookup. Structure the system so the model is instructed — and, where possible, structurally required — to call the relevant lookup tool before answering any question about a specific account or order, rather than answering from what it recalls earlier in the conversation or from general knowledge about how such systems typically work.
Every read tool should verify the requesting customer actually owns the record being looked up. A customer service agent that returns another customer's order details because it wasn't told to check is a data breach, not a minor bug.
Graceful refusal beats a confident guess
When a lookup returns nothing, or a question falls outside what any available tool can answer (a policy question with no clear answer in your knowledge base, a request the agent isn't authorized to fulfill), the response should say so plainly and route to a human — not attempt an answer that sounds reasonable but isn't grounded in anything. This is a prompt instruction backed by a fallback path (a "create_support_ticket" tool that's always available), not something you can rely on the model to do reliably without an explicit route.
Too few refusals suggests the agent is guessing when it shouldn't. Too many suggests your tool coverage has gaps. Either extreme is worth investigating — refusal rate is a leading indicator most teams don't watch until something's already gone wrong.
Escalating with the conversation and tool-call history intact
When a case escalates to a human agent, hand off the full transcript including every tool call made and its result — not just a summary the model generates, which can drop or misstate details. The human picking up the case should be able to see exactly what data the agent already looked up, so they aren't repeating lookups or, worse, trusting a summary that smoothed over an inconsistency the raw data would have shown.
| Action type | Authorization |
|---|---|
| Order/invoice/case lookup | Automatic, identity-verified |
| Refund/credit under policy limit | Automatic, hard-capped in the tool |
| Refund/credit over limit | Human approval required |
| Account or payment changes | Human approval required, always |
Wrapping up
The agent that holds up in production is the one that never answers ungrounded and never writes without a check — verify identity, retrieve before answering, cap what it can do autonomously, and hand off cleanly with full context when it hits a wall. Speed matters less than customers trusting that what they're told is actually true.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.