You can build, connect, and deploy functional AI agents using visual no-code platforms — without writing a single line of code — by configuring…
Map the leading no-code agent platforms (Make, Zapier, Voiceflow, Botpress, Stack AI, and Relevance AI) against four criteria — complexity ceiling, native AI model support, integration library, and pricing — so you can commit to one before touching any settings. The running example throughout this lesson is a customer-support agent that triages inbound emails, drafts replies, and logs tickets.
A side-by-side comparison of six no-code agent platforms — Make, Zapier, Voiceflow, Botpress, Stack AI, and Relevance AI — on complexity ceiling, AI model support, integration depth, and pricing.
Why this matters: Choosing the wrong platform now means hitting a hard ceiling mid-build and migrating everything; this module lets you commit to one with confidence before touching any settings.
Decision this forces: Which no-code platform will you build on for this agent?
You're building a customer-support agent that triages emails, drafts replies, and logs tickets. One question comes first: which platform can carry that agent to production?
differ on four axes: complexity ceiling (loop and reason, or trigger→action only?), native AI model support (which LLMs are wired in?), library (how many services connect out of the box?), and pricing (task, seat, or usage-based?).
Six platforms span that range: Make, Zapier, Voiceflow, Botpress, Stack AI, and Relevance AI. Choosing wrong means hitting a ceiling mid-build and migrating everything.
Your customer-support agent receives an inbound email, classifies it as billing or technical, drafts a reply, and logs a ticket in Zendesk. Here's how platform choice changes what that loop looks like.
The Zapier version is live in 20 minutes but can't self-correct. The Relevance AI version takes longer to configure but handles ambiguous emails without human escalation.
# Naive: one LLM call, no loop, no fallback def handle_email(email_text): classification = llm_call( prompt=f"Classify this email: {email_text}", model="gpt-4o" ) log_ticket(classification) return classification
This mirrors what Zapier or a basic Make scenario does: one LLM call, one action, done. It works for clear-cut emails, but has a critical gap.
The agent returns whichever label the model guesses first (e.g. 'billing') with no confidence check. The ticket is logged with the wrong category. There is no error — the code runs cleanly — but the downstream team gets a miscategorised ticket silently. This is the core failure of trigger→action platforms for ambiguous inputs: no loop means no self-correction.
def handle_email(email_text, tools): result = agent_run( instructions="Triage the email, draft a reply, log a ticket.", tools=tools, # classify, fetch_context, draft_reply, log_ticket input=email_text, model="gpt-4o" ) return result.output
This is the pattern that Botpress and Relevance AI implement under the hood: the model runs in a loop, calling tools until the task is complete. The key shift is that tools replaces hard-coded action nodes — the agent decides which tool to call and when.
With context retrieved, the agent re-evaluates and calls 'draft_reply' with the enriched classification, then 'log_ticket'. The loop only exits when all three tasks are marked done. Stage 1 exits after one call regardless of confidence — Stage 2 self-corrects by looping. This is the complexity ceiling difference between Zapier and Relevance AI / Botpress.
| Option | Complexity ceiling | Native AI models | Integration library | When to choose | Cost | Complexity |
|---|---|---|---|---|---|---|
| Make (Integromat) | Scripted branching; no autonomous reasoning loop | OpenAI via HTTP module; no built-in LLM orchestration | 1,000+ app connectors | When you need complex multi-step workflows with branching logic and broad app coverage, but your agent's reasoning stays within scripted paths. | Free tier; paid from ~$9/mo (operations-based) | Low–Medium setup; visual scenario builder |
| Zapier | Trigger→action only; no reasoning loop | OpenAI actions via Zapier AI; single-turn only | 6,000+ app connectors — widest of all six | When you need the widest integration library and simple trigger→action automation; not for agents that must loop or self-correct. | Free tier; paid from ~$19.99/mo (task-based) | Lowest setup; table-driven Zap builder |
| Voiceflow | Multi-turn dialogue with conditional paths; limited autonomous looping | GPT-4o, Claude, Gemini built in; model-switchable per step | API connector + 50+ native integrations | When you're building a conversational agent (chat or voice) with structured dialogue flows and need built-in NLU and multi-turn memory. | Free tier; paid from $50/mo (seat-based) | Medium; canvas-based conversation designer |
| Botpress | Full autonomous reasoning loop with tool-calling | GPT-4o, Claude 3, Mistral, Llama 3 built in | Native CRM/helpdesk + webhook for the rest | When you need a fully autonomous reasoning agent with tool-calling, memory, and fallback handling — and you want open-source flexibility. | Free self-hosted; cloud from $0 (usage-based, pay-per-message) | Medium–High; node-based studio + JS hooks |
| Stack AI | Multi-step pipelines with RAG loops; limited autonomous branching | OpenAI, Anthropic, Cohere, Mistral — widest model menu | Google Drive, Notion, Slack, Zendesk + API connector | When your agent needs RAG over internal documents (knowledge bases, PDFs) and you want a drag-and-drop pipeline builder with enterprise data controls. | Free tier; paid from $199/mo (usage-based) | Medium; flow-based pipeline builder |
| Relevance AI | Full autonomous agent loop with long-term memory | GPT-4o, Claude 3, Gemini 1.5 built in | 50+ tools + webhook; narrower than Make/Zapier | When you want a fully autonomous multi-step agent with built-in tool library, long-term memory, and minimal code — closest to a true no-code agentic loop. | Free tier (100 credits/day); paid from $19/mo (credit-based) | Medium; agent + tool builder with visual steps |
Three failure patterns appear repeatedly when teams pick the wrong platform — and two of them produce no error message.
With a platform chosen, the next question is what goes inside the agent: instructions, memory scope, and response creativity.
Every no-code platform exposes three configuration layers under different names but with the same structure. Getting these wrong produces an agent that ignores its persona, forgets context, or gives inconsistent answers.
Walk through the three configuration layers every no-code agent exposes — system prompt / persona, memory scope (session vs. persistent), and model parameters (temperature, max tokens, fallback model) — using the customer-support agent as the worked example with pre-filled fields shown. You'll adjust one parameter at a time and observe the effect, building the habit of deliberate configuration over default-and-hope.
How to configure a no-code agent's system prompt, memory scope, and model parameters before it handles real users.
Why this matters: Getting these three layers right is what separates an agent that stays on-task from one that drifts, hallucinates, or forgets context it should keep.
Module 1 gave you a platform. This module gives that platform personality, memory, and guardrails.
Every exposes three layers: a (persona and scope), a (what it remembers across turns), and model parameters (how it generates replies).
Defaults ship agents that sound wrong, forget context, or hallucinate when they should stay conservative.
This module asks: what memory scope and model parameters does your support agent need? How do you write a system prompt that keeps it on-task?
The is the highest-authority text the model reads on every turn — it runs before the user's message and cannot be overridden by it.
A production system prompt answers three questions: who is this agent (persona), what is it allowed to do (scope), and how should it sound (tone). Omit any one and the model fills the gap with its own defaults — which may not match your product.
Keep invariant rules (things that must always be true) in the system layer. Put task-specific context in the user layer. Never mix them — the model treats system text as policy and user text as intent.
Here is the system prompt for the customer-support agent you'll build throughout this lesson, with all three layers filled in.
Notice what each line does: the first sentence sets persona, the second draws the scope boundary, and the third locks tone and hedging behavior.
controls what the agent retains after the current conversation ends. Two modes, different costs and risks.
(model's working memory per request) differs from persistent memory. Context resets each call; persistent memory is explicitly written and read by your workflow.
Two model parameters matter most: and max tokens.
Change one parameter at a time and test with the same prompt before moving next. Changing temperature and max tokens together hides which caused the shift.
# Stage 1 — bare defaults (what most no-code exports look like) agent_config = { "system_prompt": "", # blank — model uses its own defaults "memory": "session", "temperature": 1.0, # default: maximum randomness "max_tokens": 4096, # default: uncapped "fallback_model": None, # no fallback set } # Stage 2 — deliberate config for the customer-support agent agent_config = { "system_prompt": ( "You are Aria, a support agent for Acme SaaS. " "Help with billing, account access, and plan upgrades only. " "Reply in plain English, under 120 words. Never guess." ), "memory": "session", # tickets are self-contained "temperature": 0.3, # consistent, not robotic "max_tokens": 160, # ~120 words × 1.3 "fallback_model": "gpt-4o-mini", }
Stage 1 shows what a default export looks like — every field is either blank or at its maximum, which is the 'default-and-hope' trap this module is designed to break.
Stage 2 changes five fields deliberately: each change maps to one of the three configuration layers (prompt, memory, model params). Notice that memory stays 'session' — support tickets don't need cross-session recall.
The agent answers the Python question in full, possibly with enthusiasm and creative flair (temperature 1.0 adds variety). There is no scope boundary to stop it. In Stage 2, the same question gets: 'That's outside my area — please contact our team at support@acme.com.' The scope line in the system prompt is the only thing that changed the behavior.
# A scheduling assistant — fill in the TODO agent_config = { "system_prompt": ( "You are Cal, a scheduling assistant for a medical clinic. " "Book, reschedule, and cancel appointments only. " "Never discuss diagnoses or medications. Reply in under 80 words." ), "memory": TODO, # patients return across sessions — which scope? "temperature": 0.2, "max_tokens": 110, # ~80 words × 1.3 "fallback_model": "gpt-4o-mini", }
This is a variation of the worked example — same structure, new domain. The system prompt and model params are filled in; your job is to supply the one field that requires a judgment call about this agent's task requirements.
Hint 1: does a returning patient benefit from the agent remembering their last appointment? Hint 2: does that benefit outweigh the added complexity of a persistent store?
"memory": "persistent" — patients return across sessions and the agent should recall their appointment history, preferred times, or flagged accessibility needs. This is the key difference from the support-ticket agent (which used 'session'): continuity across contacts is a feature here, not a liability. Changed line: memory: "persistent". Everything else stays the same — the system prompt's scope boundary still prevents the agent from discussing diagnoses regardless of what it remembers.
feeds an AI classification branch that routes billing, technical, and general tickets to three separate reply drafts.
Build the customer-support agent's core workflow: an email-received trigger → AI classification branch (billing / technical / general) → three parallel reply-draft actions → a human-escalation fallback path. The module shows a near-complete workflow with one branch missing so you finish it, reinforcing the trigger→condition→action pattern before the solo build.
How to design a no-code agent workflow using a trigger → condition → action chain, with conditional branches and a human-escalation fallback.
Why this matters: This is the structural core of your customer-support agent — without a clear branching workflow, the agent can't route emails correctly or hand off to a human when it's out of its depth.
Answer: low temperature makes replies deterministic and consistent. That's essential when the agent must follow a fixed escalation policy.
Now you have a configured agent. What kicks it off, and how does it decide what to do?
actions that do the work.
webhook (HTTP callback from another service) is hit. The condition reads a value — usually the AI's input classification — and picks a branch. Each branch ends in actions: send a reply, log a row, ping Slack.
fallback branch for inputs the agent can't classify confidently.
Get this skeleton right and the rest is filling in action steps. The structure doesn't change as you add complexity.
A customer emails support@yourapp.com: "My invoice is wrong." Here's the trigger → condition → action chain end-to-end.
The three reply-draft actions (billing, technical, general) run in parallel branches. Only the matching one executes, but all three are defined so no input falls through.
# Stage 1 — wire the trigger and the AI classification step on_trigger("email_received") as email: subject = email["subject"] body = email["body"] label = ai_classify( input = f"{subject}\n{body}", classes = ["billing", "technical", "general", "unclear"], ) # label is now a string: one of the four classes above
This stage captures the email trigger and immediately classifies the input — the label it produces is the only value the condition branches need.
Notice "unclear" is a first-class class, not an afterthought — this is what feeds the fallback branch in stage 2.
label = "unclear" — the classifier can't map a vague message to billing, technical, or general with confidence, so it returns the fourth class. This is exactly the input that should trigger the human-escalation fallback, not a drafted reply.
# Stage 2 — add condition branches and the fallback (builds on Stage 1) if label == "billing": reply = draft_reply(template="billing", context=body) send_email(to=email["from"], body=reply) elif label == "technical": reply = draft_reply(template="technical", context=body) send_email(to=email["from"], body=reply) elif label == "general": reply = draft_reply(template="general", context=body) send_email(to=email["from"], body=reply) else: # "unclear" — human escalation fallback escalate_to_human(ticket={"email": email, "label": label})
Each branch calls the same draft_reply action with a different template — the pattern is identical, only the template name changes.
fallback: it fires for "unclear" and for any label the classifier returns that isn't one of the three expected values — a safety net for model drift.
Lines 3–5 execute: draft_reply(template="billing", context=body) runs and send_email fires. Lines 6–13 are all skipped. The escalate_to_human call never runs. Output: the customer receives a billing-specific reply; no human is notified.
# Mirror billing branch; template name must match label string exactly. if label == "billing": reply = draft_reply(template="billing", context=body) send_email(to=email["from"], body=reply) elif label == "technical": reply = draft_reply(template="technical", context=body) # ★ CHANGED send_email(to=email["from"], body=reply) # ★ CHANGED elif label == "general": reply = draft_reply(template="general", context=body) send_email(to=email["from"], body=reply) else: escalate_to_human(ticket={"email": email, "label": label})
The crux here is the technical branch — it must call draft_reply with the right template name and then send the reply, exactly as the billing branch does.
Getting the template name wrong (e.g. template="tech") means the action silently uses the wrong prompt — the reply goes out but reads like a generic response.
Changed lines (replace pass):
reply = draft_reply(template="technical", context=body)
send_email(to=email["from"], body=reply)
Why the template name matters: draft_reply uses the template string to select the system prompt for that reply type. If you write template="tech" or template="Technical", the lookup fails or falls back to a generic prompt — the customer gets an off-topic reply with no error raised.
label = label.lower().You now have a working trigger → condition → action skeleton with a fallback path. Right now it runs on dummy data. The email trigger is a placeholder, the ticket log doesn't exist, and the escalation action has nowhere to send alerts.
connectors so you write no authentication code yourself.
Connect the customer-support agent to Gmail (inbound trigger), a Google Sheet (ticket log), and a Slack channel (escalation alert) using built-in connectors — no API keys written by hand. The module also covers webhook-based custom integrations for services without a native connector, and revisits the system-prompt scope from Module 2 to show how integration data shapes the agent's context window.
How to connect a no-code agent to Gmail, Google Sheets, Slack, and custom webhooks — and map integration data into the agent's prompt context.
Why this matters: Every useful agent reads from or writes to external services; this module is where the customer-support agent becomes a live, connected system rather than a chatbot in isolation.
Decision this forces: Which services does your agent need to read from and write to, and does each have a native connector or require a webhook?
Your agent needs to read from some services and write to others. The connection method depends on whether the platform offers a .
A native (built-in) connector handles OAuth, field mapping, and pagination. You pick the service from a menu and authenticate with one click. A is an HTTP endpoint your platform generates. Any service that can POST JSON to a URL can trigger your without a dedicated connector.
Connectors are faster but limited to supported apps. Webhooks reach anything but require you to parse the raw payload and map fields yourself.
Here is how the customer-support agent connects its three services — no API keys typed by hand.
Add a Gmail connector and choose the "New email received" event as your . Authenticate with OAuth (one-click). The connector exposes fields: {{email.from}}, {{email.subject}}, {{email.body}}.
Add a Google Sheets — "Append row" — after the AI classification step. Map the output fields: {{email.from}} → Column A, {{ai.classification}} → Column B, {{workflow.timestamp}} → Column C.
On the human-escalation branch, add a Slack connector — "Send message" — targeting #support-escalations. Compose the message body using mapped fields: "Escalation: {{email.subject}} from {{email.from}} — classified as {{ai.classification}}".
The fields you map become variables injected into the or the user-message slot before the model sees them. The (the model's working memory) only holds what you explicitly pass — unmapped fields are invisible to the AI.
# Platform generates this URL; paste it into the third-party service WEBHOOK_URL = "https://your-platform.io/hooks/abc123" # Payload the third-party service POSTs to that URL incoming = { "event": "new_ticket", "customer_email": "user@example.com", "message": "My invoice is wrong.", "priority": "high" }
The platform auto-generates a webhook URL — you never write auth code. The third-party service POSTs a JSON payload to that URL; your job is to map its fields to the variables your agent expects.
Nothing. The {{incoming.priority}} field is in the payload but unmapped, so it never enters the context window. The agent cannot act on it unless you explicitly add it to the prompt template.
# After receiving the webhook payload, build the prompt context prompt_context = { "customer_email": incoming["customer_email"], "message": incoming["message"], "priority": incoming["priority"], # <-- newly mapped } system_prompt = """ You are a support agent. Customer: {customer_email}. Priority: {priority}. Message: {message}. """.format(**prompt_context)
Every field you want the AI to reason about must be explicitly placed in the prompt template. Adding priority to prompt_context is the delta from Stage 1 — the model can now act on urgency.
Add "account_tier": incoming["account_tier"] to prompt_context (mirrors line 5), then add 'Account tier: {account_tier}.' inside the system_prompt string. Those are the only two lines that change — the rest of the wiring is identical.
| Option | Auth & setup effort | Field visibility | Reliability signals | When to choose | Cost | Complexity |
|---|---|---|---|---|---|---|
| Native connector | One-click OAuth; no credentials to manage | Fields auto-listed in the UI; no JSON parsing | Platform surfaces errors in the execution log | The service appears in your platform's connector library and you want the fastest path to production. | Included in platform plan; some premium connectors cost extra | Low — OAuth in one click, fields auto-discovered |
| Webhook | Paste URL; optionally add a shared secret for verification | Raw JSON — you must map every field you need | No delivery receipt by default; sender may silently stop | The service has no native connector, or you need to receive events from a custom internal system. | No extra cost; engineering time to map and validate the payload | Medium — paste URL into the sender, parse and map fields manually |
Three failure patterns catch teams off-guard after a working demo.
429 Too Many Requests. The ticket is lost. Fix: enable the platform's built-in retry with exponential back-off, or batch rows.You now have a live agent: Gmail fires it, the Sheet logs every ticket, and Slack catches escalations. Real traffic immediately surfaces edge cases that a happy-path build never sees.
The next module puts the agent under deliberate stress. Five adversarial test cases include an empty email body, a non-English message, and a prompt-injection attempt. You can catch failures before real users do.
Run the customer-support agent through five adversarial test cases (ambiguous email, empty body, non-English input, malicious prompt injection, and a service-outage simulation) using the platform's built-in test runner. The module covers how to read execution logs, spot hallucinated outputs, verify that AI-generated draft replies are factually grounded, and apply the common-mistakes checklist from the SEO page's target section.
How to design a five-case adversarial test suite, read execution logs, and apply a verification checklist to catch failures before deployment.
Why this matters: Skipping structured testing is the most common reason a no-code agent fails in front of real users — this module gives you the exact checks to run before going live.
Answer: Gmail (inbound via built-in connector), Google Sheets (ticket log via app ), and Slack (escalation alert via built-in connector). No API keys written by hand.
Now those connections are live — but live connections can fail in ways your happy-path build never revealed. This module asks: how do you break your agent on purpose, before a real customer does it for you?
A robust test suite for a no-code covers three zones: happy path, edge cases, and adversarial inputs.
The happy path tests normal input with expected output.
Edge cases test empty or ambiguous input.
Adversarial inputs test guardrail breaks.
For the customer-support agent, five cases cover all three zones without overlap.
A sixth scenario tests service-outage simulation.
It tests what happens when a downstream (e.g., Google Sheets) is unreachable.
Run it by temporarily disabling the connector in your platform's settings.
Open your platform's built-in test runner (Make calls it "Scenario History"; Zapier calls it "Task History"; Relevance AI has a dedicated "Test" tab). Paste each test case as a manual trigger payload and run them one at a time.
For the outage simulation, disable the Google Sheets connector and re-run the happy-path case. The agent should log a connector error in the and send a Slack alert — not silently drop the ticket.
Every platform writes an per run: a timestamped list of steps, inputs, outputs, and status codes.
A failed step shows a red indicator and error payload.
A skipped branch shows as bypassed.
Three fields carry the most diagnostic signal:
When a appears in the output payload, the log tells you which model call produced it.
It also shows what context () was passed in.
You can then tighten the system prompt or add a retrieval step.
def verify_agent_output(reply: str, source_policy: str, original_email: str) -> dict: results = {} # Check 1: reply stays within policy scope results["grounded"] = any(phrase in reply for phrase in source_policy.split(".")) # Check 2: no system-prompt leakage results["no_leak"] = "SYSTEM:" not in reply and "ignore previous" not in reply.lower() # Check 3: reply language matches email language (naive heuristic) email_lang = detect_language(original_email) # your platform's lang-detect util results["lang_match"] = detect_language(reply) == email_lang return results
This function runs three targeted checks against every AI-generated draft reply before it leaves the workflow.
It checks factual grounding against the source policy text, scans for prompt-injection leakage strings, and verifies language consistency — the three failure modes most likely to reach a real customer undetected.
True. The check splits source_policy on '.' and tests whether any resulting phrase appears in the reply. The phrase 'Refunds take 5–7 days' is a substring match against the reply — so the condition passes and grounded is set to True.
INJECTION_SIGNALS = [
"ignore previous instructions",
"disregard your system prompt",
"you are now",
"act as",
]
def check_prompt_injection(email_body: str) -> bool:
lowered = email_body.lower()
# TODO: return True if ANY signal in INJECTION_SIGNALS appears in lowered
# Hint 1: iterate over INJECTION_SIGNALS
# Hint 2: use the `in` operator for substring matching
...This completion exercise extends the verification layer to catch in the inbound email before it ever reaches the AI step.
The function receives the raw email body and should return True if any known injection signal is present — blocking the run and routing to the human-escalation fallback instead.
return any(signal in lowered for signal in INJECTION_SIGNALS)
Changed lines vs. Stage 1: this is a NEW guard function that runs BEFORE the AI step, not after. The key change is the direction — Stage 1 checked the output for leakage; this checks the INPUT for injection attempts. Using any() with a generator keeps it readable and short-circuits on the first match.
Three failure patterns catch most teams off guard at this stage:
Before approving any AI-generated workflow step for production, run this four-point check:
Once all five cases pass and the checklist is clean, your agent is ready for production.
Next steps: publish it to a live channel, set rate limits, and wire up the monitoring dashboard.
Module 6 covers exactly this.
Publish the customer-support agent to a live channel, configure rate limits and access controls, and set up a monitoring dashboard that tracks response accuracy, escalation rate, and cost-per-run. The module closes by pointing to the next rung: adding a retrieval-augmented knowledge base so the agent answers from your own docs rather than model memory alone.
How to publish a no-code agent to a live channel with access controls, rate limits, and a monitoring dashboard tracking accuracy, escalation rate, and cost-per-run.
Why this matters: This is the final production step — without deployment controls and monitoring, the agent you've built has no safety net in front of real users.
Your agent passed its test suite. Why isn't it ready to ship? means exposing the agent to real users, volume, and adversarial inputs.
Three controls protect a live agent: access controls (who calls it), (how often), and (what happens). Skip any one and a passing test becomes a production incident.
Access controls gate the channel — API key, OAuth scope, or IP allowlist — so only your app invokes the agent. Rate limits cap requests per minute or per user, preventing runaway loops and cost spikes.
Monitoring closes the loop: it shows whether the agent works as designed, at what cost, and when it drifts.
In your no-code platform (Make, Voiceflow, Botpress, etc.), open the agent's Publish or Deploy panel and select the target channel — a webhook URL, a chat widget embed, or an email inbox connector.
Each channel type generates a unique endpoint. Copy it — you'll lock it down in the next step.
Attach an API key or OAuth token to the endpoint so only your application can call it. Set an IP allowlist if the agent is internal-only.
Enable filtering at the platform level — most no-code tools expose this as a toggle in the security settings.
Configure two limits: a per-user cap (e.g. 20 requests/minute) and a global cap (e.g. 500 requests/minute across all users). The global cap maps directly to your model API quota, so set it 20% below your hard quota to leave headroom.
Send three real requests through the production channel — not the test runner — and confirm the shows the correct → classify → reply chain.
Check that the path fires correctly by sending one deliberately ambiguous message.
Track exactly three metrics on your live dashboard; anything less leaves a blind spot, anything more creates noise.
Most no-code platforms expose these as built-in dashboard widgets; for custom stacks, tools like Langfuse or Helicone log token counts and latency per run automatically.
# After each agent run, extract and log the three health signals def log_run_metrics(run_result): accuracy_flag = run_result.get("human_approved") # bool from spot-check escalated = run_result.get("escalated", False) # bool token_cost = run_result["tokens_used"] * COST_PER_TOKEN metrics_store.append({ "accurate": accuracy_flag, "escalated": escalated, "cost": token_cost, }) return metrics_store
This fragment captures the three health signals from a single run result and appends them to a store your dashboard reads. Each key maps directly to one of the three metrics: accuracy flag, escalation boolean, and token cost.
Ten dicts — two with escalated: True, one with accurate: False (or None if no human review yet), and all ten with cost ≈ 0.004. The store is a flat list; aggregation (escalation rate = 2/10 = 20%, accuracy = 9/10 = 90%) happens at the dashboard layer, not here.
def check_health(metrics_store, window=50): recent = metrics_store[-window:] escalation_rate = sum(r["escalated"] for r in recent) / len(recent) avg_cost = sum(r["cost"] for r in recent) / len(recent) # TODO: compute accuracy_rate from recent and add its alert # Hint 1: accuracy_rate = share of runs where r["accurate"] is True # Hint 2: alert threshold for accuracy is < 0.80 if escalation_rate > 0.20: send_alert(f"Escalation rate {escalation_rate:.0%} — review new failure modes") if avg_cost > BASELINE_COST * 2: send_alert(f"Cost spike: ${avg_cost:.4f}/run — check context window")
This is a COMPLETION problem — the escalation and cost alerts are wired; your job is to add the accuracy alert. Stop and attempt the TODO before revealing the answer.
accuracy_rate = sum(1 for r in recent if r["accurate"]) / len(recent)
if accuracy_rate < 0.80:
send_alert(f"Accuracy {accuracy_rate:.0%} — prompt revision needed")
Changed lines vs. the worked stage: we filter on r["accurate"] being truthy (not a raw bool sum, because the value may be None for unreviewed runs — guard with 'if r["accurate"] is not None' in production). The threshold direction flips: escalation alerts on >, accuracy alerts on <.
Three failure patterns appear in the first production week — none show up in a test runner.
When escalation rate stabilises and accuracy holds above 90%, monitoring reveals the next bottleneck: the agent answers from model memory, not your actual docs. That's the signal to add (RAG).
RAG connects the agent to a searchable store of your documents — product pages, PDFs, support articles. It retrieves the relevant chunk before generating a reply. The agent stops guessing from training data and cites your source of truth.
The three metrics you wired — accuracy, escalation rate, cost-per-run — become your before/after benchmark when you add RAG. A well-tuned RAG layer typically cuts escalation rate by 30–50% on knowledge-heavy queries.
Before looking at the summary: reconstruct the six-step build path from memory — starting from platform selection and ending at live monitoring. For each step, name the one decision it forced and the biggest failure mode it introduced. Then check your sequence against the buildOrder below.
Apply what you learned to SEO/GEO page — the page title is the H1 and the exact search query. OPEN with a 40-60 word self-contained, quotable answer capsule that names the entity explicitly in sentence one (no "in this lesson…" preamble) — this is the sentence an LLM lifts. Name the entity by its full name every time (not pronoun-only). Structure each section as ONE sub-question (How it works · X vs Y · When to use it · Example · Common mistakes), each opening with its own 1-2 sentence direct answer then depth. End with a genuine 3-5 question FAQ phrased as real user questions ending in "?" (these become FAQPage schema + the knowledge check). Prefer quotable specifics — concrete numbers, defaults, version names, one short snippet — over vague prose. Self-contained for a reader who arrived cold from a search engine or an LLM. Intent = tutorial: numbered steps + one short runnable code snippet + a common-mistakes section. Target query: "no code ai agents"..
You need to build a no-code AI agent that runs a multi-step reasoning loop — it classifies incoming support tickets, looks up order data, drafts a reply, and escalates if confidence is low. Which platform criterion is the deciding factor here?
Multi-step reasoning loops require a platform with a high complexity ceiling (e.g., Relevance AI, Voiceflow, or Make with AI modules) — not just a linear trigger-action tool like Zapier's basic zaps. Integration depth matters too, but it is secondary: you can bridge gaps with webhooks. Model support and price are real concerns but do not determine whether the loop architecture is even possible on the platform.
A no-code agent answers customer questions about a software product. Its system prompt currently reads: 'You are a helpful assistant. Answer questions.' After launch, users get off-topic life-advice responses. Which rewrite best fixes this?
A well-constrained system prompt names the entity, defines the exact scope, and gives the agent a scripted fallback for out-of-scope inputs — all three elements are present only in option B. Option A adds a vague negation but gives no scope boundary or fallback. Option C addresses tone, not scope. Option D addresses confidence, not topic restriction — the agent can still wander into off-topic territory.
A webhook delivers this JSON payload to your no-code agent workflow:
{ "user_id": "u_882", "plan": "pro", "open_tickets": 3 }
You want the AI step to know the user's plan and ticket count. What must you do in the workflow editor before the AI step runs?
No-code platforms do not auto-inject upstream data into an AI step; you must explicitly map the fields you need into the step's prompt context or named variables. Option A confuses integration mapping with memory — persistent memory is for cross-session recall, not passing live payload data. Option C is an unnecessary workaround; native field mapping handles JSON directly. Option D is the most common mistake beginners make and leads to the AI receiving no external context at all.
During testing, your no-code agent passes the happy-path case but you have not yet tested adversarial inputs. Which of the following is the best adversarial test case for a customer-support agent?
Adversarial inputs are designed to break the agent's guardrails, and prompt injection — telling the agent to override its own instructions — is the canonical adversarial case for LLM-based agents. A blank message is an edge case (unexpected format), not adversarial. A typo is a robustness edge case. A standard in-scope question is the happy path. A five-case test suite should include at least one genuine adversarial attempt alongside happy path and edge cases.
Name the three key health metrics you should surface on a no-code agent's monitoring dashboard after deployment, and explain in one sentence why escalation rate specifically matters.
Accuracy tells you whether answers are correct; cost-per-run tells you whether the agent is economically viable; escalation rate is the early-warning signal — it rises before accuracy visibly collapses, giving you a chance to retrain or revise the prompt proactively. Monitoring only accuracy misses the leading indicator that something is drifting.