레브잇
경력근거: LLM을 활용해 상품의 모든 속성(제품 속성 및 체감 속성 등)을 추출하고 체계화하는 새로운 시스템
※ 실제 산출물이 아닌 AI 예측 시안입니다.
공고가 주요 업무에 '차세대 커머스 카탈로그 시스템을 만듭니다' 를 적고, 그 안에서 'LLM을 활용해 상품의 모든 속성(제품 속성 및 체감 속성 등)을 추출하고 체계화하는 새로운 시스템을 구축합니다' 라고 밝혔습니다. 뽑는 것과 체계화하는 것 사이에 실을 수 있는지를 가르는 자리가 있고, 이 포트폴리오는 그 자리를 규격표와 규칙으로 만듭니다. 공고가 제품 속성과 체감 속성을 나눠 적은 것도 규격이 있는 속성과 없는 속성을 갈라 두는 이 설계와 맞습니다. 이 포트폴리오가 보여주는 것은 속성 규격을 데이터로 두고 추출 결과와 맞춰 실림 여부를 가르는 기술이며, 대규모 카탈로그 운영 경험이나 패션·뷰티 도메인 전문성은 주장하지 않습니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
'차세대 커머스 카탈로그 시스템을 만듭니다'. 뽑은 속성을 실을 수 있는 형태로 만드는 일이 그 앞단입니다.
'LLM을 활용해 상품의 모든 속성(제품 속성 및 체감 속성 등)을 추출하고 체계화하는 새로운 시스템'. 체감 속성은 규격이 없어 따로 갈라야 합니다.
'기술적 완성도뿐 아니라 실제 고객과 비즈니스에 미치는 영향을 비판적으로 사고할 수 있어야 합니다'. 못 실을 속성을 걸러내는 일이 그 판단입니다.
뽑은 상품 속성이 카탈로그에 실릴 수 있는지 가릅니다. 카테고리별 속성 규격표에 자료형과 허용 단위, 값 범위를 두고 추출 결과와 맞춰, 단위와 범위를 지키면 환산해 싣고 그렇지 않으면 단위 없음·범위 밖·자료형 불일치 중 어느 쪽인지 사유로 남깁니다. 페이지의 어느 대목에서 나왔는지가 없으면 싣지 않고, 규격표에 없는 속성은 체감 속성으로 남겨 규격을 먼저 정하게 합니다. 추출 결과는 실 서비스 데이터 대신 지원자가 공개 상품 페이지에서 직접 뽑아 만든 것을 가정합니다.
쇼핑 AI 가 쓸 상품 카탈로그를 만드는 자리에 앉는 프로덕트 엔지니어입니다. LLM 이 뽑아 준 속성이 단위도 범위도 제각각이라, 무엇을 그대로 싣고 무엇을 버릴지를 매번 눈으로 훑어 정하던 사람입니다.
카테고리마다 속성의 자료형과 허용 단위, 값 범위를 규격표로 두고 추출 결과와 맞추면, 실을 속성과 못 실을 속성이 규칙으로 갈리고 못 싣는 이유가 근거로 남는다는 가정입니다. 규격표에 없는 속성은 체감 속성으로 빠지므로 아직 규격이 없는 자리가 그대로 드러납니다.
추출 결과와 속성 규격표를 받아 속성마다 실림·못 실림을 판정하고, 못 실으면 단위 없음·범위 밖·자료형 불일치·근거 없음 중 어느 쪽인지 붙여 카테고리별로 묶은 판정 리포트를 터미널과 Markdown 파일로 내는 CLI 가 도는 완결품입니다.
공개 상품 페이지에서 뽑은 속성 400건에 손으로 붙인 정답 판정과 대조해 일치율을 내고, 미등록이 몰리는 속성을 모아 규격이 없는 자리를 목록으로 냅니다.
환산까지 끝난 속성만 모아 같은 카테고리 안에서 상품끼리 견줄 수 있는 표로 조립하고, 못 실은 속성은 다시 뽑을 목록으로 갈라 내는 단계입니다.
추출 결과와 속성 규격표를 넣으면 속성마다 실림 여부와 못 실은 사유가 카테고리별로 묶여 나오는 과정을 시연합니다.
공개 상품 페이지에서 뽑은 속성 400건과 손으로 붙인 정답 판정을 대조해 일치율을 냅니다. 단, 정답과 추출 결과를 모두 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건 동작입니다.
단위가 빠졌거나 속성 이름 표기가 흔들리거나 규격표에 없는 속성이 섞인 입력 30종을 넣어도 출력 형식이 안 깨지고 사유별로 빠지는 비율을 보여줍니다.
규격표의 단위와 범위를 바꿨을 때 옛 판정이 어떻게 뒤집히는지 회귀로 확인합니다.
진짜 성능 검증은 여기서 멈춥니다. 위 수치는 작성자가 뽑은 속성의 자가채점이며, 실제 카탈로그 품질은 레브잇의 실 상품 데이터와 실 규격이 있어야 측정됩니다. 이 포트폴리오는 그 검증을 바로 돌릴 수 있는 상태까지 만듭니다.
수치는 합성 데이터 자가채점이라 성능 증명이 아니므로, 면접에서는 데모 동작과 실검증 준비 상태로 솔직히 설명합니다.
정답을 작성자가 붙였으니 잘 맞는 게 당연하므로, 단위 결측과 범위 밖 값, 규격표에 없는 속성을 일부러 섞어 쉬운 속성만 푸는 함정을 피합니다.
이 포트폴리오가 보여주는 것은 속성 규격을 데이터로 두고 추출 결과와 맞춰 실림 여부를 가르는 기술이며, 대규모 카탈로그 운영 경험이나 패션·뷰티 도메인 전문성은 주장하지 않습니다. 판정은 단위 환산과 범위 비교가 하고 LLM 은 속성 후보를 뽑는 앞단만 맡습니다.
범위 밖 값이 늘 오추출은 아니어서 실제로 큰 값인 상품도 있으므로, 판정에 근거 대목을 함께 실어 담당자가 한 번 더 읽게 둡니다.
실제 도입 때는 카테고리마다 속성과 단위가 다르므로, 규격표를 새로 채우는 일을 도입 단계 과제로 둡니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
LLM 이 상품 페이지에서 뽑은 속성 결과입니다. 속성 번호와 상품 키, 카테고리 표기, 속성 이름 표기, 값, 근거 대목, 뽑은 날짜, 몰 이름을 한 행에 둡니다. 속성 이름은 페이지마다 달라 '용량'과 '용 량'처럼 흔들립니다. 단위가 빠진 값, 근거 대목이 없는 행, 몰 이름이 비어 있는 행, 규격표에 없는 체감 속성을 일부러 섞어 두어 사유가 갈리게 둡니다.
| attr_no | product_key | category_raw | attr_raw | value_raw | source_span | extracted_at | mall_name |
|---|---|---|---|---|---|---|---|
| AT-1001 | PD-3301 | 건강식품 | 용량 | 500ml | 제품 정보: 500ml | 2026-08-18 | 쇼포트 |
| AT-1002 | PD-3301 | 건강식품 | 유통기한 | 제조일로부터 24개월 | 유통기한 제조일로부터 24개월 | 2026-08-18 | 쇼포트 |
| AT-1003 | PD-3302 | 가전 | 소비전력 | 1200 | 소비전력 1200 | 2026-08-18 | 쇼포트 |
| AT-1004 | PD-3302 | 가전 | 소음도 | 48dB | 소음 48dB | 2026-08-18 | 쇼포트 |
| AT-1005 | PD-3303 | 뷰티 | 용 량 | 50ml | 용량 50ml | 2026-08-19 | 쇼포트 |
아래 JSON Schema 를 그대로 만족하는 추출 결과 행을 400개 더 만들어 주세요. 카테고리를 다섯 종으로 섞고 속성 이름은 몇 행에서 '용 량'처럼 띄어 적어 흔들리게 둡니다. 2할은 단위를 빼거나 근거 대목을 비우고, 몇 행은 범위를 크게 벗어난 값을 넣으며, 몇 행은 규격표에 없는 체감 속성을 씁니다. 실림 여부나 환산 결과는 넣지 마세요.
{"type": "object", "properties": {"attr_no": {"type": "string"}, "product_key": {"type": "string"}, "category_raw": {"type": "string"}, "attr_raw": {"type": "string"}, "value_raw": {"type": ["string", "null"]}, "source_span": {"type": ["string", "null"]}, "extracted_at": {"type": "string"}, "mall_name": {"type": ["string", "null"]}}, "required": ["attr_no", "product_key", "category_raw", "attr_raw", "value_raw", "extracted_at"]}{"type": "object", "properties": {"attr_no": {"type": "string"}, "product_key": {"type": "string"}, "category_raw": {"type": "string"}, "attr_raw": {"type": "string"}, "value_raw": {"type": ["string", "null"]}, "source_span": {"type": ["string", "null"]}, "extracted_at": {"type": "string"}, "mall_name": {"type": ["string", "null"]}}, "required": ["attr_no", "product_key", "category_raw", "attr_raw", "value_raw", "extracted_at"]}카테고리별 속성 규격표입니다. 속성 이름과 카테고리, 자료형, 허용 단위, 최소·최대, 필수 여부, 담당을 한 행에 둡니다. 같은 속성도 카테고리마다 허용 범위가 달라 상한이 갈립니다. 추출 결과에 나오는 속성 중 체감 속성은 일부러 넣지 않아 미등록이 도출되게 둡니다.
| rule_no | attr_raw | category_raw | value_type | allowed_unit | min_value | max_value | required_flag | owner_name |
|---|---|---|---|---|---|---|---|---|
| AS-1001 | 용량 | 건강식품 | number | ml | 10 | 5,000 | true | 카탈로그 |
| AS-1002 | 유통기한 | 건강식품 | text | — | — | — | true | 카탈로그 |
| AS-1003 | 원산지 | 건강식품 | enum | — | — | — | false | 카탈로그 |
| AS-1004 | 소비전력 | 가전 | number | W | 1 | 5,000 | true | 카탈로그 |
| AS-1005 | 소음도 | 가전 | number | dB | 10 | 90 | false | 카탈로그 |
아래 JSON Schema 를 그대로 만족하는 속성 규격 행을 40개 더 만들어 주세요. 카테고리마다 속성을 서넛씩 붙이고 자료형을 세 값으로 고루 씁니다. 같은 속성이라도 카테고리에 따라 허용 단위와 범위를 다르게 두세요. 추출 결과에 나오는 체감 속성은 일부러 넣지 마세요 — 미등록이 있어야 규격표의 구멍이 드러납니다. 판정 결과는 넣지 마세요.
{"type": "object", "properties": {"rule_no": {"type": "string"}, "attr_raw": {"type": "string"}, "category_raw": {"type": "string"}, "value_type": {"type": "string", "enum": ["number", "enum", "text"]}, "allowed_unit": {"type": ["string", "null"]}, "min_value": {"type": ["number", "null"]}, "max_value": {"type": ["number", "null"]}, "required_flag": {"type": "boolean"}, "owner_name": {"type": "string"}}, "required": ["rule_no", "attr_raw", "category_raw", "value_type", "required_flag", "owner_name"]}{"type": "object", "properties": {"rule_no": {"type": "string"}, "attr_raw": {"type": "string"}, "category_raw": {"type": "string"}, "value_type": {"type": "string", "enum": ["number", "enum", "text"]}, "allowed_unit": {"type": ["string", "null"]}, "min_value": {"type": ["number", "null"]}, "max_value": {"type": ["number", "null"]}, "required_flag": {"type": "boolean"}, "owner_name": {"type": "string"}}, "required": ["rule_no", "attr_raw", "category_raw", "value_type", "required_flag", "owner_name"]}| Python | 추출 결과와 규격표를 맞춰 단위를 환산하고 범위를 견주는 판정기를 맡습니다. |
| LLM | 상품 페이지에서 속성 후보를 뽑는 앞단에 씁니다. 실을지 말지는 규격이 정합니다. |
| Markdown | 카테고리별로 묶은 판정 리포트와 다시 뽑을 목록을 파일로 냅니다. |
✗ fail → 미등록이 절반을 넘으면 규격표를 먼저 채웁니다.
✓ pass → 2주차 정답 대조로 넘어갑니다.
✗ fail → 어긋난 유형을 모아 단위와 범위 정의를 다시 봅니다.
✓ pass → 3주차 비교표 조립으로 넘어갑니다.
뽑힌 속성 하나와 규격 한 행이 만나는 자리마다 카탈로그에 실을 수 있는지 정합니다. 실을 수 있으면 허용 단위로 환산한 수치를 싣고, 못 실으면 단위 없음·범위 밖·자료형 불일치·근거 없음 중 어느 쪽인지 싣습니다. 화면과 리포트는 이 사유 코드로 묶습니다.
{"type": "object", "properties": {"verdict_no": {"type": "string"}, "attr_no": {"type": "string"}, "product_key": {"type": "string"}, "attr_raw": {"type": "string"}, "rule_no": {"type": ["string", "null"]}, "attr_code": {"type": "string", "enum": ["accepted", "unit_missing", "out_of_range", "type_mismatch", "span_missing", "attr_unmapped"]}, "normalized_value": {"type": ["number", "null"], "description": "허용 단위로 환산한 수치입니다. value_type 이 number 이고 accepted 일 때만 채웁니다."}, "allowed_unit": {"type": ["string", "null"]}, "owner_name": {"type": ["string", "null"]}, "evidence": {"type": "array", "items": {"type": "object", "properties": {"field": {"type": "string"}, "agg": {"type": ["string", "null"]}, "value": {}}, "required": ["field", "value"]}}, "summary": {"type": "string"}, "hedge": {"type": ["string", "null"]}}, "required": ["verdict_no", "attr_no", "product_key", "attr_raw", "attr_code", "evidence", "summary"]}[
{
"verdict_no": "AV-001",
"attr_no": "AT-1001",
"product_key": "PD-3301",
"attr_raw": "용량",
"rule_no": "AS-1001",
"attr_code": "accepted",
"normalized_value": 500,
"allowed_unit": "ml",
"owner_name": "카탈로그",
"evidence": [
{
"field": "value_raw",
"agg": null,
"value": "500ml"
},
{
"field": "allowed_unit",
"agg": null,
"value": "ml"
}
],
"summary": "허용 단위 ml 로 적혀 있고 범위 안이라 500 으로 실을 수 있습니다.",
"hedge": null
},
{
"verdict_no": "AV-002",
"attr_no": "AT-1005",
"product_key": "PD-3303",
"attr_raw": "용 량",
"rule_no": "AS-1006",
"attr_code": "accepted",
"normalized_value": 50,
"allowed_unit": "ml",
"owner_name": "카탈로그",
"evidence": [
{
"field": "attr_raw",
"agg": null,
"value": "용 량"
},
{
"field": "value_raw",
"agg": null,
"value": "50ml"
}
],
"summary": "속성 이름이 띄어 적혔으나 표기를 접으면 규격표의 용량과 같아 그대로 실습니다.",
"hedge": null
},
{
"verdict_no": "AV-003",
"attr_no": "AT-1003",
"product_key": "PD-3302",
"attr_raw": "소비전력",
"rule_no": "AS-1004",
"attr_code": "unit_missing",
"normalized_value": null,
"allowed_unit": "W",
"owner_name": "카탈로그",
"evidence": [
{
"field": "value_raw",
"agg": null,
"value": "1200"
},
{
"field": "allowed_unit",
"agg": null,
"value": "W"
}
],
"summary": "수치는 있는데 단위가 없어 W 인지 kW 인지 정해지지 않습니다.",
"hedge": "페이지 문맥상 W 로 보이나 규칙만으로는 못 정합니다."
},
{
"verdict_no": "AV-004",
"attr_no": "AT-1008",
"product_key": "PD-3304",
"attr_raw": "하중",
"rule_no": "AS-1008",
"attr_code": "out_of_range",
"normalized_value": null,
"allowed_unit": "kg",
"owner_name": "카탈로그",
"evidence": [
{
"field": "value_raw",
"agg": null,
"value": "9000kg"
},
{
"field": "max_value",
"agg": null,
"value": 500
}
],
"summary": "9000kg 은 가구 하중 상한 500kg 을 크게 넘어 뽑기가 틀렸을 가능성이 큽니다.",
"hedge": null
},
{
"verdict_no": "AV-005",
"attr_no": "AT-1010",
"product_key": "PD-3305",
"attr_raw": "핏감",
"rule_no": null,
"attr_code": "attr_unmapped",
"normalized_value": null,
"allowed_unit": null,
"owner_name": null,
"evidence": [
{
"field": "attr_raw",
"agg": null,
"value": "핏감"
},
{
"field": "rule_no",
"agg": "count",
"value": 12
}
],
"summary": "규격표 열두 행에 핏감이 없어 체감 속성으로 남기고 규격을 먼저 정합니다.",
"hedge": null
},
{
"verdict_no": "AV-006",
"attr_no": "AT-1006",
"product_key": "PD-3303",
"attr_raw": "피부타입",
"rule_no": null,
"attr_code": "span_missing",
"normalized_value": null,
"allowed_unit": null,
"owner_name": null,
"evidence": [
{
"field": "source_span",
"agg": null,
"value": null
},
{
"field": "value_raw",
"agg": null,
"value": "복합성"
}
],
"summary": "값은 있는데 페이지의 어느 대목에서 나왔는지가 없어 그대로 싣지 않습니다.",
"hedge": null
},
{
"verdict_no": "AV-007",
"attr_no": "AT-1002",
"product_key": "PD-3301",
"attr_raw": "유통기한",
"rule_no": "AS-1002",
"attr_code": "accepted",
"normalized_value": null,
"allowed_unit": null,
"owner_name": "카탈로그",
"evidence": [
{
"field": "value_raw",
"agg": null,
"value": "제조일로부터 24개월"
},
{
"field": "value_type",
"agg": null,
"value": "text"
}
],
"summary": "글 속성이라 환산 없이 원문을 그대로 실을 수 있습니다.",
"hedge": null
}
][자동 검증 · 코드가 판정합니다] 1. attr_code 가 enum 여섯 값 중 하나인지 확인합니다. 2. verdict_no·attr_no·product_key·attr_raw·attr_code·evidence·summary 가 모두 채워졌는지 확인합니다. 3. attr_no 가 추출 결과에 실재하는 번호인지 대조합니다. 4. rule_no 가 있으면 규격표에 실재하는 행 번호인지 대조합니다. 5. rule_no 가 있으면 allowed_unit·owner_name 이 그 규격 행의 값과 같은지 대조합니다. 6. attr_raw 를 공백을 지워 접은 뒤 그 카테고리의 규격 속성과 맞고, 맞는 행이 없으면 attr_code 가 attr_unmapped 인지 확인합니다. 7. attr_code 가 accepted 이고 자료형이 number 이면 normalized_value 를 값에서 다시 뽑아 허용 단위로 환산해 같은지 확인합니다. 8. attr_code 가 accepted 이면 환산값이 min_value 이상 max_value 이하인지 다시 확인합니다. 9. attr_code 가 unit_missing 이면 값에 수치는 있고 단위가 없는지 다시 확인합니다. 10. attr_code 가 out_of_range 이면 환산값이 선언 범위를 벗어나는지 다시 계산합니다. 11. attr_code 가 type_mismatch 이면 값이 자료형과 맞지 않는지 확인합니다. 12. source_span 이 비어 있으면 attr_code 가 span_missing 인지 확인합니다. 13. evidence 의 field 이름이 추출 결과와 규격표에 실재하는 컬럼인지 대조합니다. 14. agg 가 없는 evidence 의 value 가 그 컬럼에 수록된 행 값과 같은지 확인합니다. 15. summary 가 존댓말로 끝나는지 확인합니다. [평가 러너 · 2주차] 공개 상품 페이지에서 뽑은 속성 400건에 손으로 붙인 정답 판정과 대조해 일치율과 사유 코드별 분포를 내고, 미등록이 몰리는 속성을 모아 규격이 없는 자리를 목록으로 냅니다. [수동 검증 · 사람이 봅니다] 1. 체감 속성에 규격을 붙일지 카탈로그 담당이 정합니다. 2. 범위를 벗어난 값이 오추출인지 실제로 큰 값인지 담당자가 근거 대목을 읽어 정합니다.