Skip to content
Nasir Nasir-Ameen
Notes

Voice-Driven CRM Assistant

Tool arguments arrive as strings, not trusted objects

Why function-calling workflows still require parsing, schema checks and explicit dispatch boundaries.
5 min read

Function calling lets a model choose from a fixed set of actions. In my voice-driven CRM assistant, a spoken instruction becomes a call such as "log this lead" with a set of arguments. It is tempting to treat that call as safe because the model can only pick from the list. It is not.

The string that looks like an object

With OpenAI's function calling, the arguments come back as a JSON-encoded string, not as an object. It has to be parsed before use. Other providers return it already parsed, so code written against one breaks quietly against another.

That is the easy half. Parsing tells you the arguments are well formed. It does not tell you they are right.

A valid call can still be the wrong action

In a voice workflow, the text the model sees has already been through speech recognition. A name can be misheard, an email address mangled, a number changed. Recognition can also produce text when nobody said anything meaningful, and I filter for those known patterns before the model sees them.

So the path is: parse the arguments, validate them against the expected shape, normalise the fields, and only then run the database action. Anything that fails takes a controlled failure branch and the user is told, instead of a half-right record being written.

Two smaller traps

A model can return ordinary text and a tool call in the same response. The workflow has to handle both parts, not assume it gets one or the other.

And the first time a new user speaks to the assistant, a lookup for their history returns nothing. In n8n, a database node that returns zero rows stops the workflow by default, which broke the assistant for exactly the people meeting it for the first time. I set the node to always produce output and filtered the empty placeholder further down.

Memory is bounded on purpose

The assistant keeps a short window of the conversation so that "him" or "that account" can be resolved. The window is deliberately small. Old context costs money and makes the current request harder to read.

Function calling narrows what a model can ask for. Deciding whether the request is good enough to carry out is still the application's job.