Urgent.News

What's breaking now, across thousands of outlets.

AI

Prompts as Contracts: How the SEO Master Agent Turns an LLM Into a Typed Function

SEO Master Agent runs five SEO workflows — on-page optimization, link-building outreach, Google Business Profile copy, content repurposing, geo SEO — through one multi-LLM gateway (OpenAI, Anthropic, Gemini, GLM, Ollama). FastAPI backend, Next.js frontend, async jobs. The design decision I want to talk about is in get_system_prompt() : every task type forces the LLM to return only a raw JSON…

The SEO Master Agent integrates five different SEO workflows - on-page optimization, link-building outreach, Google Business Profile copy, content repurposing, and geo SEO - into a single multi-LLM gateway. This gateway supports OpenAI, Anthropic, Gemini, GLM, and Ollama models. The architecture consists of a FastAPI backend, a Next.js frontend, and asynchronous jobs.

One key design decision in the system is the get_system_prompt() function, which mandates that every task type must force the LLM to return only a raw JSON object with fixed keys. There are no markdown fences in the output. The five task types (onpage, offpage, gmb, content, geo) are defined as:

TASK_TYPES = (

onpage,

offpage,

gmb,

content,

geo

)

REQUIRED_INPUTS = {

onpage : (url, keyword),

offpage : (niche,),

gmb : (business_name, services),

content : (blog_url,),

geo : (city, service),

}

If any input is missing, the system returns a 422 status code instead of making a guess. Each task's system prompt pinpoints the exact output shape. For example, the geo prompt requires four specific fields: geo_title, geo_meta_description, local_landmarks_to_mention, and localized_body_copy. Similarly, the on-page prompt demands optimized_title, optimized_meta_description, h1_suggestion, keyword_density_analysis, and content_recommendations.

The LLM stops behaving like a traditional chatbot and transforms into a function with a well-defined, typed return value. This allows downstream code and the frontend to render each workflow's output as real UI elements rather than a transcript dump. The multi-LLM routing system uses honest key handling through the resolve_llm_config() function.

Per-request headers have precedence, with environment variables serving as a fallback. Per-request LLM keys are used only in memory and never persisted. The routing is facilitated through prefix-based methods (gpt, claude, gemini, zhipu/GLM, ollama) with LiteLLM. The README explicitly mentions that POST /api/settings/keys stores keys in a local SQLite database for convenience, though it advises using environment variables for production environments.

The workflow lifecycle starts with a POST request to /api/execute, which validates the request, enqueues the task (returning a 202 status), and then a background worker fetches the site (for onpage and content tasks), builds the task prompt, and calls the LLM. The ExecutionLog updates the task status sequentially from pending to running, success, or error. Finally, GET /api/tasks/{task_id} returns the structured result.

Throughout this process, the system employs several security measures. An SSRF guard protects the fetcher, and X-API-Key authentication uses a fail-closed approach, meaning the server refuses to start without the SEO_API_KEY. Structured JSON errors and no stack traces are provided for better error handling. To ensure the system works as intended, a smoke test is included in the repository.

This test runs the server on port 18099 with inherited LLM keys stripped, waits for the /health endpoint to respond, and asserts the contract. A successful smoke test exits with a 0 status, indicating a pass, and does not require any manual setup.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in AI

More from Monday 12 October →