AI Proposal Writer: A Two-Stage Prompt Engineering Guide A two-stage prompt engineering workflow that splits AI proposal writing into extraction and generation phases eliminates generic 'AI smell,' according to a developer who built a dedicated proposal tool using Next.js 14, Supabase, and GPT-4o. The first stage parses a job post into structured JSON fields, and the second stage uses those signals as constraints to generate tailored proposals under 200 words with strict negative rules. AI Proposal Writer: A Two-Stage Prompt Engineering Guide The secret to high-conversion AI writing isn't the model you use—it's the architecture. After building a dedicated proposal tool, I found that splitting the process into a two-stage workflow Extraction then Generation completely eliminates the "AI smell." The Architecture: Extraction vs. Generation The core issue with single-prompting is that the LLM tries to analyze the requirements and write the prose simultaneously, often defaulting to safe, boring templates. By decoupling these, you force the AI to understand the client's pain points before it even thinks about writing a sentence. Stage 1: Signal Extraction First, I use a prompt that acts as a data parser. It ignores the "writing" part entirely and just converts the messy job post into a structured JSON object. js const extractionPrompt = You are analyzing a freelance job posting. Extract ONLY these fields as JSON: { "client company": "string | null", "specific problem": "string - the exact pain point described", "desired outcome": "string - what success looks like", "tone": "formal | casual | urgent", "budget signal": "string | null - any rate mentioned" } Job Post: ${jobPost} ; Stage 2: Proposal Generation Now that we have the "signals," the second prompt uses that data as a constraint. I implement strict negative constraints the "NEVER" rules to kill the generic AI habits. js const proposalPrompt = Write an Upwork proposal using this EXACT structure: OPEN with: "${extracted.specific problem || 'Your project sounds interesting'}" Reference their SPECIFIC problem, not your skills Do NOT start with "Hi" or "I read your post" PROVE with one quantified result Example format: "I helped a client do X which resulted in Y " Keep it specific, not generic MATCH their tone: ${extracted.tone} END with a specific question about their current setup Example: "Are you currently using tool ?" Keep total word count under 200 NEVER start sentences with "I am," "I have," or "I am a" Client: ${extracted.client company || 'not mentioned'} ; Technical Implementation and Lessons For the build, I went with a standard modern stack: Next.js 14 App Router for the frontend, Supabase for the backend and edge functions, and GPT-4o. I found GPT-4o to be the most reliable for the extraction phase because it handles the JSON formatting without hallucinations. If you're planning a similar deployment, avoid these mistakes I made: Latency: Don't wait for the full response. Implement streaming immediately, or your users will think the app has crashed. Efficiency: Cache your extraction results. There's no reason to re-run the extraction prompt if the job post hasn't changed; hash the input and store the JSON. Iterative UI: Add a "regenerate" or "tweak" button from the start. Even with great prompts, users always want a slightly different version. This two-stage pattern is a massive lever for any AI workflow where you need tailored output from unstructured data. It moves the LLM from "guessing" what to write to "executing" based on extracted facts. Next Claude Code System Prompt: Why it Stops Asking Permission → /en/threads/4114/