Bom tema. Acho que muita integração com LLM quebra exatamente nesse ponto: o sistema começa tratando a resposta como texto, mas depois precisa fingir que aquilo era uma interface estável.
Uma coisa que eu costumo separar é “formato válido” de “ação segura”. Mesmo quando o modelo devolve JSON perfeito, ainda falta validar se a função existe, se os parâmetros fazem sentido para aquele usuário e se a ação pode ser executada naquele estado do sistema. Senão a gente só troca regex frágil por JSON frágil.
Também acho útil tratar a resposta estruturada como uma sugestão de intenção, não como comando direto. O código determinístico ainda deveria decidir se executa, rejeita ou pede confirmação.
Você chegou a comparar JSON por prompt com function/tool calling nativo dos provedores?