Enterprise Sales AI: Separating Deal Strategy from Proposal Drafting
The proposal engine separates internal deal strategy from client-facing drafting. Messy sales notes become a structured strategy object first, then a streamed proposal document, with cleanup, validation, post-processing, and an internal logic view.
The first version of the proposal engine had a simple risk.
If the model wrote the proposal in one pass, it could also invent the deal.
That is a bad place to put AI.
A local sales team wanted to see if they could use AI to speed up proposal work. The need was practical. They were not trying to build a full enterprise CPQ system on day one. They had repeatable service packages, client notes, sales constraints, and commercial language that kept getting rewritten by hand.
The workflow still depended on someone taking old proposals, replacing names, cleaning up scope, editing commercial language, and trying to make the whole document sound coherent.
That work adds up.
The obvious AI version is weak:
client notes
+ service list
+ constraints
→ LLM
→ proposal
That produces a document quickly, but it gives the model too much control. It can choose the positioning, change the structure, invent urgency, reshape pricing language, and hide weak assumptions inside polished prose.
For sales teams, polished prose can be dangerous when it makes the offer look more certain than the actual deal logic.
So I split the workflow into two phases.
Phase 1: build the deal strategy
Phase 2: draft the proposal
That was the main architecture decision.
The workflow starts with sales inputs
The frontend starts with three practical inputs:
client intelligence
service catalog
deal constraints
Client intelligence can be pasted from notes, emails, or a short profile. The service catalog is a plain list of offerings and prices. Deal constraints cover things like timeline, compliance language, required support, or how the offer should be framed.
The request flow looks like this:
proposal form
→ FastAPI proposal endpoint
→ AI gateway
→ Phase 1 strategy JSON
→ strategy cleanup and validation
→ Phase 2 drafting stream
→ proposal document view
→ internal logic view
The system builds internal deal strategy before drafting the client-facing proposal.
Phase 1 creates the internal deal brief
The first model call does not write the proposal.
It returns a structured strategy object:
gap_analysis
selected_modules
total_investment_estimate
timeline_estimate
roi_thesis
why_now_urgency
implementation_risk
winning_angle
agent_reasoning_summary
That object becomes the internal deal brief.
The backend cleans the model output before trusting it. If the model wraps JSON in markdown, the service strips the wrapper. If it returns extra prose around the JSON, the service extracts the first JSON object. If fields are missing, the backend fills safe defaults.
There is also a small validation layer around the strategy object. The timeline is forced back to a sane value if the model returns a broken string or weird list structure. Selected modules are normalized into a list. Missing ROI and urgency fields get defaulted so the UI does not collapse.
The backend treats deal strategy JSON as untrusted model output and normalizes it before the UI or drafting phase uses it.
That is not a full pricing engine yet.
The current prototype still lets the strategy model estimate commercial structure from the service catalog. That is fine for an early proposal workflow demo, but it is not enough for production quoting.
I would not let this version control final pricing for a serious sales team.
The useful part is the boundary.
The system already separates deal logic from proposal language. That gives the next version a clear place to insert deterministic pricing:
service catalog
→ normalized module IDs
→ pricebook lookup
→ discount rules
→ margin floor
→ immutable pricing summary
→ proposal drafting with locked numbers
→ numeric validation before render
That is the direction the architecture should go.
The current app proves the first half of that pattern: the proposal is not drafted from loose notes directly. It is drafted from a structured strategy object.
Phase 2 drafts the client-facing document
The second model call handles the client-facing document.
It receives:
strategy blueprint
client context
required proposal sections
voice rules
commercial terms
Then it streams the proposal back through the FastAPI endpoint.
The proposal writer is allowed to produce the document, but the prompt keeps it inside a fixed structure:
- Executive Summary
- Strategic Value Proposition
- Solution Architecture
- Investment Schedule
- Implementation Roadmap
- Commercial Terms & Validity
The backend also post-processes the draft.
That cleanup layer handles a few common model problems:
- Removes conversational filler
- Guards against repeated year loops
- Fixes compressed markdown tables
- Removes unwanted generated signatures
- Removes duplicated footer language
The signature block is owned by the frontend component, not the model.
That matters because proposals need consistent closing language. The model should not invent authorization language, signer names, or document footer text. The app can render that deterministically.
The UI separates client document from internal logic
The frontend separates the output into two views.
DOC
LOGIC
The DOC view is the client-facing proposal. It renders the streamed markdown into a clean, print-ready document.
The LOGIC view shows the strategy object: gap analysis, winning angle, ROI thesis, urgency, commercial structure, timeline, and selected modules.
The client sees the proposal. The internal team can inspect the strategy that shaped it.
That separation is useful for a sales workflow.
The client should only see the proposal. The internal team should be able to inspect why the proposal was shaped that way. If the positioning is weak, they can adjust the client notes or constraints and regenerate. If the selected modules are wrong, they can fix the catalog or refine the input.
A single chat output does not give that control surface.
Streaming turns generation into a workflow
The streaming path also improves the feel of the system.
The frontend reads SSE chunks from /api/proposal/stream, parses data: messages, switches from loading state to streaming state when the strategy object is ready, and appends proposal tokens as they arrive.
The stop button uses AbortController, so the user can cancel generation if the inputs are wrong.
loading
→ strategy complete
→ streaming proposal
→ final document ready
That made the app feel more like a workflow tool and less like a waiting room.
The frontend treats strategy generation and proposal drafting as distinct streaming states instead of one opaque waiting period.
The AI gateway owns provider and budget control
The AI gateway sits behind the endpoint.
The frontend never calls the model provider directly. The backend gateway owns:
- API key handling
- Model routing
- Budget cap
- Redis spend tracking
- Redis rate limiting
- Provider retries
- Exponential backoff
- Token usage tracking
That is important for a sales team prototype because proposal generation can get expensive fast if users keep testing variations.
The gateway also gives the app room to change models without rewriting the UI. In this version, the proposal workflow uses one model path for deal strategy and another for drafting. The exact provider can change later. The boundary stays the same.
The gateway keeps provider calls, retries, budget limits, rate limits, and token accounting outside the frontend.
The proposal engine should not be one big prompt
This was the real lesson from the prototype.
AI proposal generation should not be one big prompt.
A better pattern is:
structured inputs
→ strategy object
→ validation
→ drafting pass
→ post-processing
→ print-ready document
→ internal logic view
That still leaves work to do.
The production version needs a deterministic pricebook layer. The service catalog should become normalized data, not a freeform text box. Each module should have an ID, base price, cost floor, margin rule, optional discount rule, and approval threshold. The proposal writer should never be allowed to invent the final numbers.
The safer production flow would be:
client notes
→ requirement extraction
→ module matching
→ pricebook calculation
→ locked pricing summary
→ proposal drafting
→ number validation
→ sales approval
→ PDF export
That is where this becomes a stronger sales operations system instead of just a proposal assistant.
For now, the prototype establishes the right first boundary. It keeps the model from jumping straight from messy notes to client-facing prose. It forces an intermediate deal strategy object, exposes that object to the internal team, then drafts the proposal from a clearer structure.
That is already useful.
A local sales team does not need AI to hallucinate a better offer. They need a faster way to turn the offer they actually mean to sell into a clean proposal.
The model can help with strategy language and drafting. The pricing, margin rules, approvals, and final commercial truth need to move into code.
Onto the next one. Let’s keep sharpening that edge!
First written on August 21, 2025.
Want to implement this architecture in your business?
Discuss Your Project