Whatever message this page gives is out now! Go check it out!

Configure AI providers with schema guardrails

Last update:
May 18, 2026
Use the ColdFusion AI framework to enforce structured JSON output from Anthropic, OpenAI, Azure OpenAI, Gemini, Mistral, and Ollama using the schema guardrail system.
Every provider uses the same ChatModel() + agent() pattern. Only the configuration struct changes. For a conceptual overview, see guardrails in the ColdFusion AI framework.
  1. Set up a provider
  2. Configure Anthropic (Claude).
    ADDITIONAL INFORMATION:
chatModel = ChatModel({
    PROVIDER:  "anthropic",
    APIKEY:    application.anthropicKey,
    MODELNAME: application.anthropicModelName
});
aiService = agent({ CHATMODEL: chatModel });
  1. Configure OpenAI.
    ADDITIONAL INFORMATION:
chatModel = ChatModel({
    PROVIDER:    application.provider,
    APIKEY:      application.openAikey,
    MODELNAME:   application.modelName,
    temperature: 0
});
aiService = agent({ CHATMODEL: chatModel });
  1. Tip: Set temperature: 0 for OpenAI, Azure OpenAI, and Mistral when using schema guardrails. Deterministic output is more reliable with structured schemas.
  2. Configure Azure OpenAI.
    ADDITIONAL INFORMATION:
chatModel = ChatModel({
    PROVIDER:    "azureopenAi",
    APIKEY:      application.azureopenaikey,
    BASEURL:     application.azureopenaiEndpoint,
    MODELNAME:   application.azureModelName,
    temperature: 0
});
aiService = agent({ CHATMODEL: chatModel });
  1. Important: Azure requires the BASEURL of your deployed endpoint (for example, https://my-resource.openai.azure.com/). Without it the call will fail regardless of schema validity.
  2. Configure Google Gemini.
    ADDITIONAL INFORMATION:
chatModel = ChatModel({
    PROVIDER:  "gemini",
    APIKEY:    application.geminiKey,
    MODELNAME: application.geminiModelName
});
aiService = agent({ CHATMODEL: chatModel });
  1. Configure Mistral.
    ADDITIONAL INFORMATION:
chatModel = ChatModel({
    PROVIDER:       "mistral",
    APIKEY:         application.mistralkey,
    MODELNAME:      application.mistralModelName,
    temperature:    0,
    MAXTOKENS:      2048,
    LOGRESPONSES:   false,
    ResponseFormat: "JSON"
});
aiService = agent({ CHATMODEL: chatModel });
  1. Important: ResponseFormat: "JSON" is the Mistral-specific flag that enables JSON mode. Without it, Mistral may include markdown fences or prose around the JSON.
  2. Configure Ollama for local models.
    ADDITIONAL INFORMATION:
chatModel = ChatModel({
    PROVIDER:       "ollama",
    BASEURL:        application.ollamaurl,
    MODELNAME:      application.ollamaModelName,
    responseFormat: "json"
});
aiService = agent({ CHATMODEL: chatModel });
  1. Note: Ollama runs locally. The BASEURL points to the Ollama server. Local models vary in their JSON output reliability. Set responseFormat: "json" to improve consistency.
  2. Define a schema
  3. Pass a SCHEMA key in the aiService.chat() call with a plain ColdFusion struct.
    ADDITIONAL INFORMATION:
response = aiService.chat({
    USERMESSAGE: { MESSAGE: "Return person Alice who is 30 years old and active." },
    SCHEMA: { "name": "String", "age": "Number", "active": "Boolean" }
});
  1. For the full list of supported types, invalid types, and array syntax, see the supported schema types.
  2. To reuse schemas across requests, define them in a SchemaFactory CFC.
    ADDITIONAL INFORMATION:
component displayname="SchemaFactory" {

    public struct function getPersonSchema() {
        return {
            "firstName": "String",
            "lastName":  "String",
            "age":       "Number",
            "active":    "Boolean?"
        };
    }
}

factory = new SchemaFactory();
response = aiService.chat({
    USERMESSAGE: { MESSAGE: "Return person Jane Doe age 32 active true." },
    SCHEMA: factory.getPersonSchema()
});
  1. Tip: Store schemas in a SchemaFactory CFC or in application scope. Do not repeat schema definitions across CFMs — one change should update everywhere.
  2. To share schemas across all CFMs, register them in application scope during startup.
    ADDITIONAL INFORMATION:
// Application.cfc — onApplicationStart()
application.aiSchemas = {
    person: {
        "firstName": "String",
        "lastName":  "String",
        "age":       "Number",
        "email":     "String?",
        "active":    "Boolean"
    },
    order: {
        "orderId":  "String",
        "customer": "String",
        "total":    "Number",
        "items":    [{ "product": "String", "quantity": "Number", "price": "Number" }]
    }
};

// Any CFM
response = aiService.chat({
    USERMESSAGE: { MESSAGE: "..." },
    SCHEMA: application.aiSchemas.person
});
  1. Add a system message
  2. Call aiService.systemMessage() before aiService.chat() to set behavioral constraints on the model.
    ADDITIONAL INFORMATION:
aiService.systemMessage(
    "You are a nutrition expert. You MUST provide accurate nutritional data including " &
    "calories, protein, and serving information. Always respond with precise numbers."
);

response = aiService.chat({
    USERMESSAGE: { MESSAGE: "Give info for Caesar Salad, 4 servings, 350 calories, 15g protein." },
    SCHEMA: {
        "recipe":   "String",
        "servings": "Number",
        "nutrition": {
            "calories": "Number",
            "protein":  "String"
        }
    }
});
  1. Validate input schemas
  2. Wrap every aiService.chat() call in try/catch.
    ADDITIONAL INFORMATION:
try {
    response = aiService.chat({
        USERMESSAGE: { MESSAGE: "Return data." },
        SCHEMA: { "created": "Date" }
    });
} catch (any e) {
    errType = e.type;
    errMsg  = e.message;
}

if (len(errMsg)) {
    writeLog(file="ai_errors", type="error", text="Schema error: #errMsg#");
}
  1. For schemas used repeatedly, pre-validate them at application startup.
    ADDITIONAL INFORMATION:
public function onApplicationStart() {
    try {
        application.schemas = {
            person:  { "firstName": "String", "lastName": "String", "age": "Number" },
            order:   { "orderId": "String", "total": "Number", "items": [{ "product": "String", "price": "Number" }] },
            company: { "name": "String", "founded": "Number", "active": "Boolean?" }
        };
        writeLog(file="application", type="info", text="AI schemas initialized.");
    } catch (any e) {
        writeLog(file="application", type="error", text="Invalid schema at startup: #e.message#");
        rethrow;
    }
    return true;
}
  1. Validate responses
  2. Check isJSON() before calling deserializeJSON().
    ADDITIONAL INFORMATION:
response = aiService.chat({ USERMESSAGE: { MESSAGE: "..." }, SCHEMA: { "name": "String" } });
text   = response.message ?: "";
parsed = isJSON(text) ? deserializeJSON(text) : {};

if (structIsEmpty(parsed)) {
    writeLog(file="ai_errors", type="warning", text="Non-JSON response: #text#");
}
  1. Use structKeyExists() to check field presence before accessing any field.
    ADDITIONAL INFORMATION:
hasName = structKeyExists(parsed, "name") && len(trim(parsed.name)) > 0;
hasAge  = structKeyExists(parsed, "age")  && isNumeric(parsed.age);

if (!hasName || !hasAge) {
    throw(type="AIResponseError", message="Required fields missing from AI response");
}
  1. For array fields, validate both the array and the shape of each item.
    ADDITIONAL INFORMATION:
hasItems = structKeyExists(parsed, "items") &&
           isArray(parsed.items) &&
           arrayLen(parsed.items) >= 1;

if (hasItems) {
    for (var item in parsed.items) {
        if (!isStruct(item) || !structKeyExists(item, "product") || !structKeyExists(item, "price")) {
            hasItems = false;
            break;
        }
    }
}
  1. Advanced patterns
  2. To implement multi-provider fallback with the same schema guardrail, use a chatWithFallback function.
    ADDITIONAL INFORMATION:
function chatWithFallback(required struct chatRequest, required array providers) {
    var lastError = "";
    for (var providerConfig in arguments.providers) {
        try {
            var model   = ChatModel(providerConfig);
            var service = agent({ CHATMODEL: model });
            return service.chat(arguments.chatRequest);
        } catch (any e) {
            lastError = e.message;
            writeLog(file="ai_fallback", type="warning",
                     text="Provider #providerConfig.PROVIDER# failed: #e.message#");
        }
    }
    throw(type="AIUnavailable", message="All providers failed. Last error: #lastError#");
}

providers = [
    { PROVIDER: "anthropic", APIKEY: application.anthropicKey, MODELNAME: "claude-3-5-sonnet-20241022" },
    { PROVIDER: "openai",    APIKEY: application.openAikey,    MODELNAME: "gpt-4o", temperature: 0 },
    { PROVIDER: "mistral",   APIKEY: application.mistralkey,   MODELNAME: application.mistralModelName, temperature: 0 }
];
  1. To compose schemas dynamically based on user role or feature flags, use a composeSchema function.
    ADDITIONAL INFORMATION:
function composeSchema(required struct base, struct extension = {}) {
    var result = duplicate(arguments.base);
    if (!structIsEmpty(arguments.extension)) {
        structAppend(result, arguments.extension, true);
    }
    return result;
}

basePersonSchema = { "firstName": "String", "lastName": "String", "age": "Number" };
adminExtension   = { "internalId": "Number", "accessLevel": "String", "lastLogin": "String?" };

schema = isAdminUser ? composeSchema(basePersonSchema, adminExtension) : basePersonSchema;

response = aiService.chat({
    USERMESSAGE: { MESSAGE: extractionPrompt },
    SCHEMA: schema
});
Result
After completing setup, every call to aiService.chat() with a SCHEMA key will return structured JSON that conforms to the defined contract, with schema validation errors thrown before any API quota is consumed.
AFTER COMPLETING THE TASK
For a full list of supported types, error messages, and provider features, see the ColdFusion AI framework schema reference.

Share this page

Was this page helpful?
We're glad. Tell us how this page helped.
We're sorry. Can you tell us what didn't work for you?
Thank you for your feedback. Your response will help improve this page.

On this page