Command Menu

Litestore
ShopCategoriesCollections
/Blog
/Adding AI to Commerce Modules: Confidence Ranking, Not Black Boxes

Adding AI to Commerce Modules: Confidence Ranking, Not Black Boxes

How we integrate AI into e-commerce without letting it take over. External intelligence as a multiplier, not a decision maker.

Jan 29, 2025•7 min read

Every commerce platform is adding AI. Most are doing it wrong.

They're building black boxes. "AI-powered recommendations" that operators can't explain, debug, or override. Magic ranking that works until it doesn't, and then nobody knows why.

We took a different approach: AI as a bounded multiplier, not a decision maker.

The Core Principle

AI should influence, not control. Here's the formula:

finalScore = baseScore × aiMultiplier

// Where:
// - baseScore comes from deterministic rules (engagement, recency, inventory)
// - aiMultiplier is bounded: 0.5 to 2.0 (can halve or double, but not more)

If AI breaks completely, the worst case is that products rank at half or double their expected position. The store still works. Operators can still explain why products appear where they do.

External Intelligence Architecture

We don't embed AI into core commerce logic. We treat it as an external signal source.

// lib/external-intelligence/types.ts
export type ExternalIntelligence = {
  source: "openai" | "anthropic" | "custom" | "manual";
  confidence: number; // 0.0 to 1.0
  signal: number; // -1.0 to 1.0 (negative = suppress, positive = boost)
  reasoning: string; // Human-readable explanation
  generatedAt: Date;
  expiresAt: Date; // Intelligence goes stale
};

Key design decisions:

  1. Confidence is explicit — AI must say how sure it is
  2. Signal is bounded — -1.0 to 1.0, no extreme values
  3. Reasoning is required — No opaque recommendations
  4. Expiration is mandatory — AI judgments have shelf life

Integrating with Product Ranking

The ranking engine treats AI as just another multiplier:

// lib/ranking.ts
export function computeProductScore(product: Product): ScoredProduct {
  const engagement = computeEngagementScore(product);
  const recency = computeRecencyMultiplier(product);
  const inventory = computeInventoryMultiplier(product);
  const boost = product.manualBoost ?? 1.0;

  // AI is optional — if not present, multiplier is 1.0 (neutral)
  const aiMultiplier = computeAIMultiplier(product.externalIntelligence);

  const finalScore =
    (1 + engagement) * recency * inventory * boost * aiMultiplier;

  return {
    ...product,
    score: finalScore,
    breakdown: {
      engagement,
      recency,
      inventory,
      boost,
      aiMultiplier,
    },
  };
}

The AI Multiplier Function

function computeAIMultiplier(
  intelligence: ExternalIntelligence | null,
): number {
  // No intelligence = neutral
  if (!intelligence) return 1.0;

  // Expired intelligence = neutral
  if (new Date() > intelligence.expiresAt) return 1.0;

  // Low confidence = dampened effect
  const effectiveSignal = intelligence.signal * intelligence.confidence;

  // Convert signal (-1 to 1) to multiplier (0.5 to 2.0)
  // signal = -1.0 → multiplier = 0.5 (halve the score)
  // signal = 0.0  → multiplier = 1.0 (no change)
  // signal = 1.0  → multiplier = 2.0 (double the score)
  const multiplier = 1.0 + effectiveSignal * 0.5;

  // Clamp to bounds (defense in depth)
  return Math.max(0.5, Math.min(2.0, multiplier));
}

Why This Bounds Matter

| Scenario | AI Signal | Confidence | Effective Multiplier | | --------------------- | --------- | ---------- | --------------------------- | | AI loves this product | +1.0 | 0.9 | 1.45 (45% boost) | | AI loves this product | +1.0 | 0.5 | 1.25 (25% boost) | | AI hates this product | -1.0 | 0.9 | 0.55 (45% suppression) | | AI is uncertain | +0.2 | 0.3 | 1.03 (3% boost, negligible) | | AI is missing | - | - | 1.0 (neutral) |

Low confidence AI has minimal effect. High confidence AI has bounded effect. The system degrades gracefully.

Adding AI to Any Module

The pattern is consistent across modules. Here's how to add AI to a new domain:

Step 1: Define the Intelligence Schema

// server/admin/curations/schema.ts
export const curationIntelligenceSchema = z.object({
  source: z.enum(["openai", "anthropic", "custom", "manual"]),
  confidence: z.number().min(0).max(1),
  signal: z.number().min(-1).max(1),
  reasoning: z.string().max(500),
  generatedAt: z.date(),
  expiresAt: z.date(),
  // Domain-specific fields
  suggestedProducts: z.array(z.string()).optional(),
  seasonalRelevance: z.number().min(0).max(1).optional(),
});

Step 2: Add the Field to the Model

model Collection {
  // ... existing fields
  externalIntelligence Json? @db.JsonB
}

Step 3: Create the Intelligence Source

// lib/external-intelligence/curation-analyzer.ts
export async function analyzeCollection(
  curation: Collection,
): Promise<ExternalIntelligence> {
  const prompt = `
    Analyze this e-commerce curation:
    Name: ${curation.name}
    Description: ${curation.description}
    Product count: ${curation.productCount}
    Categories: ${curation.categories.join(", ")}

    Rate its current commercial potential from -1 (suppress) to +1 (boost).
    Consider: seasonality, trend alignment, inventory health, price competitiveness.
    Explain your reasoning in one sentence.
  `;

  const response = await anthropic.messages.create({
    model: "claude-3-5-sonnet-20241022",
    max_tokens: 200,
    messages: [{ role: "user", content: prompt }],
  });

  const parsed = parseAIResponse(response);

  return {
    source: "anthropic",
    confidence: parsed.confidence,
    signal: parsed.signal,
    reasoning: parsed.reasoning,
    generatedAt: new Date(),
    expiresAt: addHours(new Date(), 24), // Valid for 24 hours
  };
}

Step 4: Hook into the Refresh Cycle

// lib/cron/intelligence-refresh.ts
export async function refreshCollectionIntelligence() {
  const curations = await getCollectionsNeedingAnalysis();

  for (const curation of curations) {
    try {
      const intelligence = await analyzeCollection(curation);
      await updateCollectionIntelligence(curation.id, intelligence);
    } catch (error) {
      // AI failure doesn't break the system
      logger.warn("Collection analysis failed", {
        curationId: curation.id,
        error: error.message,
      });
      // Collection continues with existing/no intelligence
    }
  }
}

Step 5: Use in Queries (Optional)

// server/web/curations/queries.ts
export async function getFeaturedCollections() {
  const curations = await db.curation.findMany({
    where: { isFeatured: true },
    orderBy: { position: "asc" },
  });

  // Apply AI multiplier to curation ordering
  return curations
    .map((c) => ({
      ...c,
      effectiveScore: computeCollectionScore(c),
    }))
    .sort((a, b) => b.effectiveScore - a.effectiveScore);
}

Real-World Integration: Product Descriptions

Here's a complete example: AI-assisted product descriptions.

The Problem

Operators write product descriptions. Some are great. Some are SEO disasters. AI can help, but it shouldn't override human decisions.

The Solution

// lib/external-intelligence/description-analyzer.ts
export async function analyzeProductDescription(
  product: Product,
): Promise<DescriptionIntelligence> {
  const response = await anthropic.messages.create({
    model: "claude-3-5-sonnet-20241022",
    max_tokens: 500,
    messages: [
      {
        role: "user",
        content: `
        Analyze this product description for e-commerce effectiveness:

        Title: ${product.name}
        Description: ${product.description}
        Category: ${product.category}

        Evaluate:
        1. SEO quality (keywords, length, structure)
        2. Conversion potential (benefits, urgency, clarity)
        3. Sourcing voice consistency

        Return JSON:
        {
          "seoScore": 0-100,
          "conversionScore": 0-100,
          "suggestions": ["suggestion 1", "suggestion 2"],
          "rewriteSuggestion": "optional improved description"
        }
      `,
      },
    ],
  });

  const analysis = JSON.parse(response.content[0].text);

  return {
    source: "anthropic",
    confidence: 0.8, // Fixed confidence for this use case
    seoScore: analysis.seoScore,
    conversionScore: analysis.conversionScore,
    suggestions: analysis.suggestions,
    rewriteSuggestion: analysis.rewriteSuggestion,
    generatedAt: new Date(),
    expiresAt: addDays(new Date(), 7), // Valid until description changes
  };
}

Admin UI Integration

The admin shows AI analysis alongside the product form:

// app/admin/products/[id]/_components/description-intelligence.tsx
export function DescriptionIntelligence({ product }: Props) {
  const intelligence = product.descriptionIntelligence;

  if (!intelligence) {
    return <Button onClick={analyzeDescription}>Analyze with AI</Button>;
  }

  return (
    <Card>
      <CardHeader>
        <CardTitle>AI Analysis</CardTitle>
        <Badge variant={intelligence.confidence > 0.7 ? "success" : "warning"}>
          {Math.round(intelligence.confidence * 100)}% confident
        </Badge>
      </CardHeader>
      <CardContent>
        <div className="space-y-4">
          <ScoreBar label="SEO" value={intelligence.seoScore} />
          <ScoreBar label="Conversion" value={intelligence.conversionScore} />

          {intelligence.suggestions.length > 0 && (
            <div>
              <h4>Suggestions</h4>
              <ul>
                {intelligence.suggestions.map((s, i) => (
                  <li key={i}>{s}</li>
                ))}
              </ul>
            </div>
          )}

          {intelligence.rewriteSuggestion && (
            <div>
              <h4>Suggested Rewrite</h4>
              <p className="text-muted">{intelligence.rewriteSuggestion}</p>
              <Button
                variant="outline"
                onClick={() => applyRewrite(intelligence.rewriteSuggestion)}
              >
                Apply Suggestion
              </Button>
            </div>
          )}
        </div>
      </CardContent>
    </Card>
  );
}

The operator sees:

  • AI's confidence level
  • Specific scores for SEO and conversion
  • Actionable suggestions
  • An optional rewrite they can apply with one click

But the operator decides. AI doesn't auto-update descriptions. It provides analysis. Humans approve changes.

AI for Spot Copy

The same pattern works for promotional content:

// lib/external-intelligence/banner-copy-generator.ts
export async function generateSpotCopy(
  banner: Spot,
  curation: Collection,
): Promise<SpotCopyIntelligence> {
  const response = await anthropic.messages.create({
    model: "claude-3-5-sonnet-20241022",
    max_tokens: 300,
    messages: [
      {
        role: "user",
        content: `
        Generate promotional copy for this e-commerce banner:

        Spot type: ${banner.spotType}
        Placement: ${banner.placement}
        Collection: ${curation.name}
        Products: ${curation.productCount} items
        Price range: $${curation.minPrice} - $${curation.maxPrice}

        Generate 3 variants of:
        - Headline (max 60 chars)
        - Subheadline (max 120 chars)
        - CTA text (max 20 chars)

        Match the tone: ${banner.spotType === "promotional" ? "urgent, deal-focused" : "aspirational, lifestyle"}
      `,
      },
    ],
  });

  return {
    source: "anthropic",
    confidence: 0.75,
    variants: parseVariants(response),
    generatedAt: new Date(),
    expiresAt: addHours(new Date(), 48),
  };
}

Operators see three copy variants. They pick one, edit it, or ignore all of them. AI suggests. Humans decide.

Guardrails and Limits

1. Bounded Values

Every AI output is clamped:

const signal = Math.max(-1, Math.min(1, rawSignal));
const confidence = Math.max(0, Math.min(1, rawConfidence));

2. Expiration Enforcement

Stale intelligence is ignored:

if (new Date() > intelligence.expiresAt) {
  return 1.0; // Neutral multiplier
}

3. Graceful Degradation

AI failures don't break commerce:

try {
  const intelligence = await analyzeProduct(product);
  await updateIntelligence(product.id, intelligence);
} catch (error) {
  logger.error("AI analysis failed", { productId: product.id, error });
  // Product continues with neutral AI multiplier
  // No user-facing error
}

4. Audit Trail

Every AI decision is logged:

await db.intelligenceLog.create({
  data: {
    entityType: "product",
    entityId: product.id,
    source: intelligence.source,
    signal: intelligence.signal,
    confidence: intelligence.confidence,
    reasoning: intelligence.reasoning,
    appliedAt: new Date(),
  },
});

Operators can see: "On Jan 15, Claude recommended boosting this product by 40% because 'seasonal trend alignment with Valentine's Day sample searches'."

5. Kill Switch

Global AI influence can be disabled:

// config/features.ts
export const FEATURES = {
  aiRankingEnabled: process.env.AI_SCORING_ENABLED !== "false",
  aiCopyGenerationEnabled: process.env.AI_COPY_ENABLED !== "false",
};

// In ranking.ts
const aiMultiplier = FEATURES.aiRankingEnabled
  ? computeAIMultiplier(product.externalIntelligence)
  : 1.0;

If AI goes haywire, one environment variable disables it system-wide.

What AI Should NOT Do

  1. Make final decisions — AI suggests, humans approve
  2. Modify data without audit — Every change is logged
  3. Have unbounded influence — Multipliers are clamped
  4. Be required — System works without AI
  5. Be opaque — Reasoning is always required

What's Next

The external intelligence system is live. What we're building:

  1. Competitive pricing intelligence — AI monitors competitor prices, suggests adjustments
  2. Trend detection — Identify rising search terms, suggest curation updates
  3. Review sentiment analysis — Surface negative reviews early
  4. Inventory forecasting — Predict stockouts before they happen

All following the same pattern: bounded influence, required reasoning, human approval, graceful degradation.

AI makes commerce smarter. It doesn't make commerce automatic.

Share:
Written by
Fabian Likam's profile

Fabian Likam

@fabianlikam
Shop
All ProductsNew ArrivalsNewBest SellersSale
Help
Contact UsFAQShippingReturns
Company
About UsBlogCareersPress
Connect
InstagramTwitterTiktokYoutube
Privacy PolicyTerms of Service
  • Visa
  • Mastercard
  • American Express
  • PayPal
  • Apple Pay
  • Google Pay
Secure Checkout

© 2026 Litestore. All rights reserved.

HomeCartWishlistAccount