Excel에서 추출한 상품 CSV를 데이터베이스나 다른 서비스로 옮기는 작업은 일주일에 한 번이라도 반복한다면 수작업으로는 감당할 수 없습니다. 가격을 소수점 손실 없이 정수로 만들고, 잘못된 행을 거부하며, 실패했을 때 이전의 products.json이나 원본 CSV를 훼손하지 않는 것이 중요합니다.
이러한 부분은 단순히 일회용 스크립트가 아니라 '저장해 두고 여러 번 실행할 것을 전제로 하는 작은 도구'로 작성되어야만 실제 환경에 적용하는 것이 두렵지 않습니다.
이번에는 GPT-5.6 Sol과 Claude Opus 4.8 양쪽 모델 모두에게 완전히 동일한 요구사항으로 동일한 CSV→JSON 변환 도구를 작성하도록 요청했습니다. 초기 버전은 두 모델 모두 입력과 출력에 같은 경로를 전달할 경우, 원본 CSV를 조용히 덮어쓰는 동일하게 위험한 동작을 보였습니다. 실패 케이스를 되돌려 수정시킨 2차 버전에서는 23가지 종류의 로컬 입력을 모두 예상대로 처리했습니다. 본문의 초점은 벤치마크 순위가 아니라, '어떤 공정을 맡길 수 있는지', 그리고 '무엇을 직접 검사해야 하는지'에 있습니다.
대상 데이터는 다음과 같은 한 행입니다. SKU, 상품명, 가격, 재고의 네 개 열이 있습니다. 가격은 12.30과 같은 두 자리 소수점이고, 재고는 비음의 정수인 0도 유효 값입니다.
sku,name,price,stock
A01,Mug,12.30,7
A02,Canvas Bag,0.29,0
출력되는 products.json은 가격을 정수 단위의 '센트(cent)'로 정규화한 배열입니다. 12.30은 1230이 되고, 0.29는 29가 됩니다. 재고 0은 누락된 값이 아니므로 그대로 stock: 0으로 출력해야 합니다.
[
{ "sku": "A01", "name": "Mug", "priceCents": 1230, "stock": 7 },
{ "sku": "A02", "name": "Canvas Bag", "priceCents": 29, "stock": 0 }
...
]
실제 업무용 CSV는 이 정도로는 부족합니다. `
이 조항을 무시했습니다. 입력과 출력을 같은 경로로 지정하는 순간, 두 모델의 초기 버전은 CSV 원본을 덮어쓰고, 저희가 준비한 '테스트용 쓰레기 CSV'를 손실하게 만들었습니다. 이 구체적인 실패 시나리오를 되돌리고, 파일의 실제 신분(inode에 상응하는 체크)을 요구사항에 추가하자, 두 모델의 수정 버전은 이 케이스를 거부하게 되었습니다. 초기 AI 코드를 검증 없이 프로덕션 환경에 적용하지 않는다는 원칙은 아무리 정교한 프롬프트를 작성해도 사라지지 않습니다.
생성된 코드는 import-products.cjs로, 같은 디렉터리에 있는 products.csv와 나란히 두고 Node.js가 설치된 환경에서 순조롭게 작동합니다.
node import-products.cjs products.csv products.json
자동화 파이프라인에 통합하려면, exit code 확인을 생략할 수 없습니다. $?가 0이 아닐 경우 후속 처리를 중단하는 다음과 같은 방식입니다.
node import-products.cjs products.csv products.json
if [ $? -ne 0 ]; then
echo "임포트 실패. 후속 처리를 중지합니다." >&2
...
성공적으로 생성된 products.json은 다른 스크립트에서 그대로 읽어 집계 등에 사용할 수 있습니다. 예를 들어 '재고가 0인 SKU를 추출'하는 것은 몇 줄로 충분합니다.
const fs = require('node:fs');
const products = JSON.parse(fs.readFileSync('products.json', 'utf8'));
const outOfStock = products.filter(product => product.stock === 0);
...
의도적으로 12.3 (소수점 두 자리가 아님)을 섞어 넣자, 수정 버전은 둘 다 stderr에 실패 이유를 출력하고 비-0 종료했으며 기존 JSON 파일은 건드리지 않았습니다. 여기서 중요한 것은 'products.json이 남아있다 = 이번 임포트가 성공했다'는 것이 아니라는 점입니다. 이전 성공 시의 JSON이 남아있을 뿐이라는 상태를 다음 공정에 넘기지 않도록, exit code를 반드시 읽는 설계로 해주십시오.
실무에서 의외로 유용한 것은 실패 메시지의 가독성입니다. 가격을 12.3으로 넣고 실행했을 때, Claude Opus 4.8의 수정 버전은 '가격은 소수점 두 자리로 지정해 주세요(예: 12.30)'와 같이 사양에 가까운 지적을 했습니다. 문자 코드는 Simplified Chinese (간체자)였으며, Qiita 독자를 대상으로 일본어 로케일까지 대응했다고는 할 수 없습니다. GPT-5.6 Sol의 수정 버전은 영어로, 오류가 발생한 논리 레코드 번호를 첨부했습니다. 긴 CSV에서 따옴표 닫기 누락을 찾을 때 이 번호가 검색의 출발점이 되어 도움이 됩니다.
또 하나, 작은 파싱 함수 단독 테스트를 3회 샘플링으로 진행했을 때, GPT-5.6 Sol은 세 건 모두 따옴표 내부 쉼표와 줄바꿈을 올바르게 해석했지만, Claude Opus 4.8은 세 건 중 한 건만 정답이었고 나머지 두 건은 빈 줄 혼입이나 충돌이 발생했습니다. 이 관찰은 parseCsv(input)과 같은 작은 부분에 국한된 것이므로, 'GPT가 코드 생성 면에서 종합적으로 우수하다'는 결론으로 확장할 수는 없습니다. 기존 코드베이스에 삽입할 하나의 함수를 의뢰하는 상황에서, 샘플 1회분의 판단 자료로 읽어주시기 바랍니다.
완성형 CLI 도구로 보면, GPT-5.6 Sol과 Claude Opus 4.8 모두 1라운드의 피드백 후 요구사항을 충족하는 구현을 반환했습니다. 헤더가 바뀌었음을 올바르게 해석하고, 비정상 데이터에서 중단하며, 출력 파일과 입력 파일을 보호합니다. 여기에는 큰 차이가 없습니다. 이미 익숙한 것을 사용하여 업무 규칙(SKU의 앞뒤 공백을 동일시할지, 가격의 01.00을 허용할지 등) 결정에 시간을 쓰는 것이 더 실리적입니다.
이번 요청은 2026년 11월 3일, Crazyrouter의 https://api.crazyrouter.com/v1/chat/completions에 대해 gpt-5.6-sol과 claude-opus-4-8을 사용했습니다.
특정 모델을 지정하여 보냈습니다. 초기 버전과 초기 버전의 문제점을 구체화한 1회의 수정판, 총 2회 왕복만을 진행했으며, 동일한 중국어 프롬프트를 사용했고 생성된 코드에는 수작업을 가하지 않았습니다. 실행 환경은 Node.js v24.21.0이며, 23종의 로컬 입력은 모두 '동일 도구에 대한 다른 입력'이었지, 23가지 문제에 대한 독립적인 모델 평가는 아닙니다. 장기적인 안정성이나 대규모 프로젝트에서의 동작은 이 실험 범위 밖에 있습니다.
직접 재현하고 싶다면, Crazyrouter의 코딩용 모델 목록에서 모델 번호를 확인한 후, OpenAI 호환 연결 문서에 따라 Base URL과 키를 설정하는 것이 가장 빠릅니다. 실제 데이터를 바로 적용하기보다는, '성공했을 때 무엇을 출력할지'와 '실패했을 때 절대 건드리지 말아야 할 것'을 본인만의 언어로 정의한 뒤 프롬프트를 전달해 주세요. 모델 선택보다도 이 조건의 명확함이 '반복적으로 구동할 수 있는 작은 도구'를 결정합니다.