Skip to content
Learn Agentic AI9 min read0 views

Building a Pricing Agent: Dynamic Pricing and Quote Generation with AI

Implement an AI pricing agent that applies dynamic pricing rules, generates professional quotes, performs competitor price analysis, and handles discount approval workflows.

The Complexity of B2B Pricing

B2B pricing is rarely as simple as a price tag. Deals involve volume discounts, contract length tiers, bundle pricing, competitive matching, and approval chains. Sales reps spend hours assembling quotes manually, and inconsistent pricing erodes margins. An AI pricing agent codifies your pricing rules, generates professional quotes instantly, and enforces approval workflows for discounts that exceed predefined thresholds.

Pricing Rule Engine

The foundation is a rule engine that encodes your pricing logic. Rules are composable — each rule can modify the base price, and they apply in order.

from dataclasses import dataclass, field
from typing import Optional
from enum import Enum


class DiscountType(Enum):
    PERCENTAGE = "percentage"
    FIXED = "fixed"


@dataclass
class PricingRule:
    name: str
    discount_type: DiscountType
    value: float
    condition: str  # e.g., "quantity >= 100"
    max_discount_pct: float = 30.0  # ceiling to protect margins
    requires_approval: bool = False


@dataclass
class LineItem:
    product_id: str
    product_name: str
    base_price: float
    quantity: int
    applied_rules: list[str] = field(default_factory=list)
    final_unit_price: float = 0.0

    @property
    def line_total(self) -> float:
        return self.final_unit_price * self.quantity


@dataclass
class Quote:
    quote_id: str
    customer_name: str
    items: list[LineItem]
    valid_until: str
    notes: str = ""
    requires_approval: bool = False
    approval_reason: Optional[str] = None

    @property
    def total(self) -> float:
        return sum(item.line_total for item in self.items)


def evaluate_condition(condition: str, context: dict) -> bool:
    """Safely evaluate a pricing condition against context."""
    allowed_names = {
        "quantity": context.get("quantity", 0),
        "contract_months": context.get("contract_months", 1),
        "total_value": context.get("total_value", 0),
        "is_new_customer": context.get("is_new_customer", False),
        "customer_tier": context.get("customer_tier", "standard"),
    }
    try:
        return bool(eval(condition, {"__builtins__": {}}, allowed_names))
    except Exception:
        return False

Applying Pricing Rules

The pricing engine iterates through rules, applies matching discounts, and tracks which rules were used for audit purposes.

PRICING_RULES = [
    PricingRule(
        name="Volume 50+",
        discount_type=DiscountType.PERCENTAGE,
        value=10.0,
        condition="quantity >= 50",
    ),
    PricingRule(
        name="Volume 200+",
        discount_type=DiscountType.PERCENTAGE,
        value=20.0,
        condition="quantity >= 200",
    ),
    PricingRule(
        name="Annual contract",
        discount_type=DiscountType.PERCENTAGE,
        value=15.0,
        condition="contract_months >= 12",
    ),
    PricingRule(
        name="Enterprise deep discount",
        discount_type=DiscountType.PERCENTAGE,
        value=35.0,
        condition="quantity >= 500 and contract_months >= 24",
        requires_approval=True,
    ),
]


def calculate_price(
    base_price: float,
    quantity: int,
    context: dict,
    rules: list[PricingRule] = PRICING_RULES,
) -> tuple[float, list[str], bool]:
    """Apply pricing rules and return final unit price, applied rules, approval flag."""
    ctx = {**context, "quantity": quantity}
    total_discount_pct = 0.0
    applied = []
    needs_approval = False

    for rule in rules:
        if not evaluate_condition(rule.condition, ctx):
            continue
        if rule.discount_type == DiscountType.PERCENTAGE:
            total_discount_pct += rule.value
        if rule.requires_approval:
            needs_approval = True
        applied.append(rule.name)

    # Cap total discount
    max_cap = max((r.max_discount_pct for r in rules), default=30.0)
    total_discount_pct = min(total_discount_pct, max_cap)

    final_price = base_price * (1 - total_discount_pct / 100)
    return round(final_price, 2), applied, needs_approval

Competitor Price Analysis

When a prospect mentions a competitor's price, the agent should be able to assess the competitive position and recommend a response.

from openai import AsyncOpenAI
import json

client = AsyncOpenAI()

COMPETITOR_ANALYSIS_PROMPT = """A prospect mentioned a competitor's pricing.

Our product: {our_product} at ${our_price}/unit
Competitor: {competitor} at ${competitor_price}/unit
Deal size: {quantity} units, {contract_months}-month contract
Customer tier: {customer_tier}

Our differentiation points:
{differentiators}

Return JSON with:
- "price_gap_pct": percentage difference
- "recommendation": "match", "hold", or "counter"
- "suggested_price": our recommended price per unit
- "talk_track": 2-3 sentences the sales rep can use
- "max_discount_pct": maximum discount percentage to recommend
"""


async def analyze_competitor_price(
    our_product: str,
    our_price: float,
    competitor: str,
    competitor_price: float,
    quantity: int,
    contract_months: int,
    customer_tier: str,
    differentiators: str,
) -> dict:
    response = await client.chat.completions.create(
        model="gpt-4o",
        response_format={"type": "json_object"},
        messages=[
            {"role": "system", "content": "Return valid JSON only."},
            {
                "role": "user",
                "content": COMPETITOR_ANALYSIS_PROMPT.format(
                    our_product=our_product,
                    our_price=our_price,
                    competitor=competitor,
                    competitor_price=competitor_price,
                    quantity=quantity,
                    contract_months=contract_months,
                    customer_tier=customer_tier,
                    differentiators=differentiators,
                ),
            },
        ],
    )
    return json.loads(response.choices[0].message.content)

Quote Generation

The agent assembles all pricing decisions into a professional quote document.

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

import uuid
from datetime import datetime, timedelta


async def generate_quote(
    customer_name: str,
    items: list[dict],
    context: dict,
) -> Quote:
    """Generate a complete quote with pricing rules applied."""
    line_items = []
    needs_approval = False

    for item in items:
        final_price, applied_rules, approval = calculate_price(
            base_price=item["base_price"],
            quantity=item["quantity"],
            context=context,
        )
        if approval:
            needs_approval = True

        line_items.append(LineItem(
            product_id=item["product_id"],
            product_name=item["product_name"],
            base_price=item["base_price"],
            quantity=item["quantity"],
            applied_rules=applied_rules,
            final_unit_price=final_price,
        ))

    valid_until = (datetime.utcnow() + timedelta(days=30)).strftime("%Y-%m-%d")

    quote = Quote(
        quote_id=f"Q-{uuid.uuid4().hex[:8].upper()}",
        customer_name=customer_name,
        items=line_items,
        valid_until=valid_until,
        requires_approval=needs_approval,
        approval_reason="Deep discount rules triggered" if needs_approval else None,
    )
    return quote


def format_quote_text(quote: Quote) -> str:
    lines = [
        f"QUOTE: {quote.quote_id}",
        f"Customer: {quote.customer_name}",
        f"Valid until: {quote.valid_until}",
        "",
        "Line Items:",
    ]
    for item in quote.items:
        savings = (item.base_price - item.final_unit_price) * item.quantity
        lines.append(
            f"  {item.product_name}: {item.quantity} x "
            f"${item.final_unit_price:.2f} = ${item.line_total:.2f}"
            f" (saves ${savings:.2f})"
        )
        if item.applied_rules:
            lines.append(f"    Discounts: {', '.join(item.applied_rules)}")
    lines.append(f"\nTOTAL: ${quote.total:.2f}")
    if quote.requires_approval:
        lines.append(f"\n** REQUIRES APPROVAL: {quote.approval_reason} **")
    return "\n".join(lines)

Discount Approval Workflow

Discounts that exceed thresholds need manager approval before the quote can be sent. The agent routes these through an approval queue.

async def submit_for_approval(quote: Quote, db_pool, notifier):
    async with db_pool.acquire() as conn:
        await conn.execute(
            """INSERT INTO quote_approvals
               (quote_id, customer, total, reason, status, requested_at)
               VALUES ($1, $2, $3, $4, 'pending', NOW())""",
            quote.quote_id, quote.customer_name,
            quote.total, quote.approval_reason,
        )
    await notifier.send(
        channel="#pricing-approvals",
        message=(
            f"Quote {quote.quote_id} for {quote.customer_name} "
            f"(${quote.total:.2f}) needs approval.\n"
            f"Reason: {quote.approval_reason}"
        ),
    )

FAQ

How do I prevent the pricing agent from offering discounts that are too deep?

Implement hard caps at the rule engine level using the max_discount_pct field. Even if multiple rules stack, the total discount cannot exceed the cap. Additionally, any discount above a configurable threshold (e.g., 25 percent) should automatically flag the quote for manager approval rather than applying it directly.

How do I handle pricing for custom or non-standard configurations?

Define a fallback rule that routes non-standard requests to a human pricing specialist. The agent collects the requirements in a structured format — quantities, contract terms, special needs — and creates an approval ticket with all the context the pricing team needs to respond quickly.

Should I let the LLM set prices directly?

Never. The LLM should recommend pricing strategies and generate talk tracks, but actual price calculations must come from your deterministic rule engine. LLMs are not reliable for precise arithmetic, and pricing errors have direct financial consequences. Use the LLM for analysis and presentation, not for the math.


#DynamicPricing #QuoteGeneration #PricingStrategy #SalesAI #Python #AgenticAI #LearnAI #AIEngineering

Share this article
C

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.