Action

Building the Per-Field Components

I built the following components to generate and recommend values for each required field, one at a time.

Product Name

sequenceDiagram
    autonumber
    participant Client as Client<br/>(listing screen)
    participant API as AI Registration API
    participant LLM as LLM API

    Client->>API: Thumbnail image
    API->>LLM: Image + prompt
    LLM-->>API: Generated product name
    API-->>Client: Product name (shown as AI suggestion)
          

If the latency between uploading an image and generating a product name is too long, we judged users wouldn't wait for it — so we only use the first uploaded image, the one shown as the thumbnail. The name generated from the thumbnail doesn't auto-fill the field; instead, it appears as an AI-suggestion badge above the keyboard. Tapping the badge accepts the suggestion, and ignoring it lets the user keep typing — designed this way so it doesn't disrupt the existing listing experience.

Category

sequenceDiagram
    autonumber
    participant Client as Client<br/>(listing screen)
    participant Category as Category Recommendation API

    Client->>Category: Product name
    Category-->>Client: List of category IDs<br/>(shown as recommended-category carousel)
            

Category classification is a narrow, well-structured domain, so there was no need for an LLM. Our team already had a lightweight text encoder pretrained on Bungaejangter text that we were using in another component, so I fine-tuned it on (product name, category ID) pairs collected from the product DB to build a classifier that predicts category ID from product name. Since the recommended-category carousel shows 4 buttons by design, I trained against HitRatio@4 as the target metric, and built a separate API that takes a product name and returns 4 category IDs, called directly by the client.

Product Options

sequenceDiagram
    autonumber
    participant Client as Client<br/>(listing screen)
    participant API as AI Registration API
    participant Bunjang as Option Schema API
    participant LLM as LLM API

    Client->>API: Product name, category ID
    API->>Bunjang: Category ID
    Bunjang-->>API: Option list for the category (nullable)

    opt Option list exists
        API->>LLM: Product name, option list + prompt
        LLM-->>API: Option name extracted from product name (nullable)
    end

    API-->>Client: Option info ID (nullable)
          

The option-recommendation feature was meant to prevent drop-off in categories with a large number of choices. Shoes, for example, list Korean, US, and European sizes together, and we judged that making users scan through all of them to find the right option could be tiring. So, in the same spirit as category recommendation, we decided to build a feature that proactively suggests the option a user is looking for.

We could have implemented this as a self-built classification model too, the same way we did for category recommendation. But product options have a different schema per category, which would have meant managing separate training data and model artifacts per category — and every schema change (adding or removing an option) would require a fresh round of data updates and retraining, a heavy management burden. An LLM, by contrast, can adapt to schema changes immediately just by injecting the current option list into the prompt. Weighing that management burden against the benefit, we chose the LLM-extraction approach: look up the schema from the option schema API using the category ID, and only call the LLM to extract an option name when a schema actually exists.

Product Description

sequenceDiagram
    autonumber
    participant Client as Client<br/>(listing screen)
    participant API as AI Registration API
    participant LLM as LLM API

    Client->>API: Thumbnail image, product name, category
    API->>LLM: Image, product name, category + prompt
    LLM-->>API: Generated description
    API-->>Client: Description (shown as AI suggestion)
          

The product description is generated by combining three inputs: image, product name, and category. To keep an overly long generated description from overwhelming the listing screen's layout, we needed to constrain the text length to fit the UI area. So I specified a format in the prompt: the first sentence reads like a title, the next two describe features visible in the image, and the last sentence closes with a line that encourages a purchase.

After launch, I monitored ROUGE-L scores comparing the generated text against what users actually kept in the listing, broken down by category. This gave me a rough sense of whether the generated text was actually being adopted, and if so, how closely it matched the original.

Product Price

sequenceDiagram
    autonumber
    participant Client as Client<br/>(listing screen)
    participant API as AI Registration API
    participant LLM as LLM API
    participant Search as Product Search Engine
    participant Pricer as Price Recommendation API

    Client->>API: Product name, category
    API->>LLM: Product name, category + prompt
    LLM-->>API: A search query this product might be found under
    API->>Search: Search query
    Search-->>API: Matching product listings (active)

    alt Enough listings in the same category
        API->>Pricer: Product name, matching listings
        Pricer-->>API: Recommended price range (min, max)
    else Not enough listings
        Note over API: No price recommendation
    end

    API-->>Client: Recommended price range or empty result
          

Since a price suggestion needs to reflect the current market rate for the item being listed, first I had the LLM generate "a search query that would surface a product with this category and name," and fed that into Bungaejangter's product search engine. I then estimate a representative price from the price distribution of same-category listings among the search results — but if too few listings come back, the variance of that estimate gets too high to trust. So I only recommend a price when the search results from the LLM-generated query are sufficient. When they are, I rerank the matching listings by combining text similarity to the product name with whether they've already sold, then compute the recommended price range from the median price of the top-ranked listings.