DEV Community

Cover image for Neuro-Symbolic Conversational Vehicle Advisor: Deterministic Constraint Solving, State Integrity, and Multi-Stage Recommendation
Udeogu Chekwube
Udeogu Chekwube

Posted on

Neuro-Symbolic Conversational Vehicle Advisor: Deterministic Constraint Solving, State Integrity, and Multi-Stage Recommendation

Abstract

Most conversational AI implementations in industry rely on naive Retrieval-Augmented Generation (RAG) or unconstrained agentic loops. While adequate for open-ended queries or low-stakes search, pure probabilistic Large Language Model (LLM) architectures fail catastrophically in high-consideration automotive e-commerce. In automotive discovery, hallucinating non-existent inventory, violating strict budget ceilings, misinterpreting physical vehicle capabilities, or dropping conversational constraints across multi-turn sessions directly destroys transactional trust and violates financial compliance boundaries.

This paper details the architecture, mathematical formulations, and engineering principles behind Vehicle Advisor—a production conversational discovery, recommendation, comparison, and financing decision-support platform engineered on NestJS, TypeScript, and PostgreSQL. By implementing a hybrid neuro-symbolic architecture, the system isolates non-deterministic natural language understanding (NLU) to slot extraction, intent classification, and conversational synthesis, while delegating inventory validation, constraint satisfaction, candidate scoring, and business ranking to deterministic, auditable software stages. Furthermore, this paper presents an evaluation harness (evals) that continuously verifies invariant safety, slot extraction recall, and zero-drift persistence across multi-turn multilingual conversational trajectories.

1. Domain Problem: Why Stochastic LLMs Fail in High-Consideration Retail

Automotive transactions are governed by an asymmetric balance of hard constraints (strict maximum purchase price, verified seating capacity, location proximity, financing eligibility) and soft preferences (fuel efficiency, cargo practicality, ground clearance, brand affinity).

When deploying conversational agents in automotive marketplaces, four systemic failure modes arise in pure LLM architectures:

1. Inventory Hallucination & Phantom Listings: Autoregressive models generate plausible-sounding vehicles (e.g., a "2021 Toyota RAV4 for ₦8,500,000") that do not exist in live inventory or have stale pricing.

2. Constraint Amnesia & Parameter Drift: Over a 4- to 8-turn negotiation, stochastic context windows experience catastrophic forgetting, dropping prior hard filters (such as budget ceilings or 7-seater requirements).

3. Zero Automotive Knowledge Translation: First-time buyers express needs in human lifestyle terms ("I have 3 toddlers and need to navigate flooded streets during the rainy season in Lekki"). Standard keyword search fails, while naive LLMs invent unverified vehicle specifications (e.g., claiming a sedan has high ground clearance).

4. Uncontrolled Business & Financing Policies: Commercial prioritisation (dealer tiers, inspection grades) and regulatory financing boundaries must never secretly override customer hard constraints or imply credit approval without underwriting.

To resolve these failure modes, we established a strict architectural boundary: The LLM never defines business truth, inventory state, or ranking outcomes.

2. System Architecture: The Neuro-Symbolic Pipeline

The system is architected as a Clean Architecture, Domain-Driven Design (DDD) backend built on NestJS and Fastify, decoupled from specific LLM providers through abstract orchestration adapters (supporting Google Gemini and OpenAI).

3. Engineering Pillars & Production Implementations

3.1 Pillar 1: Conversation State & Attribute Provenance
Conversation state belongs exclusively to the application database, never to the ephemeral context window of an LLM. In this architecture, user requirements are modelled via a strongly typed BuyerProfile aggregate containing granular attributes with explicit provenance and preference types:

// conversation.model.ts (Excerpt)
export enum AttributeCategory {
  BUDGET = 'BUDGET',
  BODY_TYPE = 'BODY_TYPE',
  SEATING = 'SEATING',
  MAKE = 'MAKE',
  USAGE = 'USAGE',
  LOCATION = 'LOCATION',
  FEATURE = 'FEATURE',
  FINANCING = 'FINANCING',
}
export enum PreferenceType {
  HARD_CONSTRAINT = 'HARD_CONSTRAINT', // Absolute invariant; zero violation tolerance
  SOFT_PREFERENCE = 'SOFT_PREFERENCE', // Used for scoring and affinity ranking
}
export enum AttributeProvenance {
  USER_EXPLICIT = 'USER_EXPLICIT',   // Stated directly by the user
  MODEL_INFERRED = 'MODEL_INFERRED', // Inferred from natural language context
  SYSTEM_DEFAULT = 'SYSTEM_DEFAULT', // Fallback policy
}
export interface BuyerProfileAttribute {
  category: AttributeCategory;
  key: string;
  value: BuyerAttributeValue;
  preferenceType: PreferenceType;
  provenance: AttributeProvenance;
  confidenceScore: number;
  isConfirmable: boolean;
}
Enter fullscreen mode Exit fullscreen mode

The Provenance Rule
If a customer explicitly specifies "Budget max 15 million naira", it is stored as USER_EXPLICIT + HARD_CONSTRAINT. If a customer mentions "I have a family", the system infers a SOFT_PREFERENCE for spacious body types (SUV, MINIVAN, MPV). Crucially, the recommendation pipeline enforces that model-inferred attributes cannot create artificial hard filters that would prematurely collapse viable inventory.

3.2 Pillar 2: Domain Intelligence & Goal Decomposition
Raw inventory records contain low-level attributes (make, model, year, price, mileage). However, users express lifestyle goals. To bridge this gap, we engineered SoftVehicleClassAffinityService to deterministically translate high-level customer intents into canonical body-class affinities without LLM hallucinations:

// soft-vehicle-class-affinity.service.ts (Excerpt)
@Injectable()
export class SoftVehicleClassAffinityService {
  private readonly goalClassAffinityCatalog: Record<CustomerGoalKey, string[] | null> = {
    [CustomerGoalKey.SPACIOUSNESS]: ['SUV', 'MINIVAN', 'MPV', 'CROSSOVER', 'STATION_WAGON'],
    [CustomerGoalKey.FAMILY_PRACTICALITY]: ['SUV', 'MINIVAN', 'MPV', 'CROSSOVER', 'STATION_WAGON'],
    [CustomerGoalKey.CARGO_PRACTICALITY]: ['STATION_WAGON', 'SUV', 'MINIVAN', 'MPV'],
    [CustomerGoalKey.LOW_MILEAGE_FOCUS]: null, // Directional metric, not body-class affinity
    [CustomerGoalKey.PURCHASE_AFFORDABILITY]: null, // Handled via max_budget hard filter
    [CustomerGoalKey.FINANCING_AFFORDABILITY]: null, // Handled via financing gate
  };
  public resolveCargoClasses(context: CargoUsageContext): string[] {
    switch (context) {
      case CargoUsageContext.EQUIPMENT_BULKY_GOODS:
        return ['CARGO_VAN', 'PICKUP', 'STATION_WAGON', 'MINIVAN'];
      case CargoUsageContext.COMMERCIAL_CARGO:
        return ['CARGO_VAN', 'PICKUP'];
      case CargoUsageContext.FAMILY_LUGGAGE:
      case CargoUsageContext.GENERAL_LUGGAGE:
      default:
        return ['STATION_WAGON', 'SUV', 'MINIVAN', 'MPV'];
    }
  }
}

Enter fullscreen mode Exit fullscreen mode

3.3 Pillar 3: Deterministic Multi-Stage Recommendation Pipeline
The recommendation pipeline evaluates candidates through a sequential filter-and-rank flow:

Active Inventory ➔ [Hard Filter] ➔ Viable Candidates ➔ [Finance Gate] ➔ Eligible Candidates ➔ [Fit Scorer] ➔ Scored Candidates ➔ [Business Ranker] ➔ Ranked Candidates ➔ [Diversity] ➔ Final Recommendations

Dynamic Signal Availability & Weight Renormalisation
In emerging markets, marketplace listings often suffer from missing attributes (e.g., unconfirmed mileage or missing inspection sheets). Naive weighted sums penalise vehicles with missing data.

To solve this, we formulated and implemented a Dynamic Weight Renormaliser that redistributes weight among active, available dimensions:

Weight Renormalisation Formula:

For each active dimension with an available signal: RenormalizedWeight = ConfiguredWeight / Sum(ConfiguredWeights of all available dimensions)

For unavailable or missing signals: RenormalizedWeight = 0 (and omitted reason is recorded for audit-ability)

Candidate Total Fit Score:

TotalScore(candidate) = Sum(RenormalizedWeight_i * RawScore_i(candidate)) across all available dimensions

// weight-renormalizer.util.ts
export function renormalizeWeights(
  dimensions: ScoringDimensionResult[],
): ScoringDimensionResult[] {
  const activeDimensions = dimensions.filter(
    (d) => d.capabilityState === 'AVAILABLE' && d.rawScore !== undefined,
  );
  const activeSum = activeDimensions.reduce(
    (sum, d) => sum + (d.configuredWeight || 0),
    0,
  );
  return dimensions.map((d) => {
    if (d.capabilityState !== 'AVAILABLE' || d.rawScore === undefined) {
      return {
        ...d,
        renormalizedWeight: 0,
        weightedScore: 0,
        omittedReason: d.omittedReason || `Capability state is ${d.capabilityState} (signal unavailable)`,
      };
    }
    const renormalizedWeight = activeSum > 0 ? d.configuredWeight / activeSum : 0;
    const weightedScore = d.rawScore * renormalizedWeight;
    return {
      ...d,
      renormalizedWeight,
      weightedScore,
    };
  });
}
Enter fullscreen mode Exit fullscreen mode

3.4 Pillar 4: Grounded Explanation & Zero-Hallucination Delivery
When candidates reach the final turn generation, the LLM is provided with the structured scoring lineage (dimensions, explanationFactors, omittedReason).

Structured Score Payload:
- Make Fit: 1.0 (Exact Match: Toyota)
- Seating Fit: 1.0 (7 seats matches stated family requirement)
- Inspection Grade: 4.5/5 (Authoritative Autochek Inspected)
- Omitted Signal: Mileage Fit (Missing from listing, weight renormalized)
Enter fullscreen mode Exit fullscreen mode

The LLM is strictly constrained via system prompts and output validators:

It cannot introduce vehicles not returned by the deterministic pipeline.

It cannot quote financial terms (down payment, monthly payment) not produced by the authoritative financing calculator.

It explains why the vehicle was chosen based directly on the scoring dimensions.

4. Multilingual Adaptability: English and Nigerian Pidgin (PCM)

A critical challenge in emerging digital markets is conversational accessibility. In Nigeria, users alternate fluidly between standard English and Nigerian Pidgin (PCM).

Rather than relying on generic translation layers that distort technical constraints, the intent extractor natively handles Pidgin idioms while maintaining strict type boundaries:

// Pidgin Input Sample:
// "I get 8m naira, and I want clean SUV for my pikin to go school for Ikeja, road get pot-hole well well"
// Parsed Canonical State:
{
  budgetMax: 8000000,
  currency: 'NGN',
  bodyTypes: ['SUV'],
  location: { state: 'Lagos', city: 'Ikeja' },
  usageContext: 'FAMILY_COMMUTE',
  roughRoadPracticality: true
}
Enter fullscreen mode Exit fullscreen mode

The system generates responses natively in Nigerian Pidgin while maintaining complete mathematical grounding in the underlying inventory facts.

5. Evaluation Harness & Continuous Invariant Verification

To guarantee that prompt edits or model upgrades never introduce behavioural regression, we designed an automated continuous evaluation suite (evals/) executed via npm run test:eval.

// evals/dataset/scenarios.data.ts (Excerpt)
export const SCENARIO_DATASET: ScenarioDefinition[] = [
  {
    scenarioId: 'SCEN-01',
    description: 'Budget ₦15M, urban family commute, 5 seats',
    language: 'EN',
    customerInput: 'I need a family car in Lagos for my daily commute under 15 million naira.',
    inventoryCondition: '10 matching candidates in Lagos under 15M',
    primaryInvariants: ['Hard budget filter', 'Location filter'],
    applicableCriteria: ['q1', 'q2', 'q3', 'q4'],
    expectedResult: { status: 'QUALIFIED', shortlistCount: 3 },
  },
  {
    scenarioId: 'SCEN-02',
    description: 'PCM locale compliance: "I get 8m naira, want car for my pikin"',
    language: 'PCM',
    customerInput: 'I get 8m naira, want car for my pikin to go school for Ikeja',
    inventoryCondition: '5 candidates matching Lagos under 8M',
    primaryInvariants: ['PCM locale text generation'],
    applicableCriteria: ['q1', 'q2', 'q4'],
    expectedResult: { status: 'QUALIFIED' },
  },
  {
    scenarioId: 'SCEN-03',
    description: 'Budget ₦5M, financing requested, all inventory > ₦10M',
    language: 'EN',
    customerInput: 'I have a strict max budget of 5 million naira for a financed vehicle.',
    inventoryCondition: 'All inventory prices > 10M',
    primaryInvariants: ['Hard budget filter'],
    applicableCriteria: ['q1', 'q3', 'q4'],
    expectedResult: { status: 'ZERO_CANDIDATES', shortlistCount: 0 },
  }
];
Enter fullscreen mode Exit fullscreen mode

Measured Invariants & Verification Results

6. Architectural Insights

The design of the Vehicle Advisor platform provides three key insights of high-stakes conversational systems:

Separation of Concerns via Neuro-Symbolic Boundaries: Probabilistic LLMs should be treated as interpreters and synthesizers, never as databases or decision engines. Decoupling extraction from deterministic ranking eliminates hallucinations and ensures regulatory compliance.

Dynamic Signal Availability: Recommendation scoring models in real-world marketplaces must gracefully degrade when data is sparse. Dynamic weight renormalisation prevents bias against vehicles with missing attributes.

Automated Regression Invariants: Continuous evaluation frameworks (evals) that assert domain invariants (such as a strict 0.00% budget violation rate) are essential prerequisites for shipping conversational agents to production.

Tech Stack & System Specifications

Runtime & Framework: Node.js, NestJS, Fastify, TypeScript

State & Persistence: PostgreSQL, TypeORM, CQRS (@nestjs/cqrs)

AI Orchestration: Provider-Agnostic Adapter Pattern (Google Gemini @google/genai, OpenAI openai)

Observability & Telemetry: OpenTelemetry SDK, Langfuse (AI Traces), PostHog (Analytics)

Testing & Evaluation: Jest, Custom Multi-Turn Scenario Test Runner (evals/)

Top comments (0)