AI 출력 형식 JSON·CSV·마크다운 180회 비교: 파싱을 통과한 오답
코튼 파우치 C1이 CSV 응답에서는 cotton pouch C1로 나왔습니다.
파일은 문제없이 읽혔습니다. 열도 맞았고, 헤더도 맞았습니다.
같은 상품을 JSON으로 받았을 때는 한국어 이름이 그대로 남았습니다. 출력 형식을 바꿔 요청한 두 응답에서, 상품명까지 달라진 것입니다.
AI 출력을 스프레드시트나 자동 처리 프로그램에 넘기려면 어떤 형식을 골라야 할까요. 이번 기록에서 JSON과 CSV는 읽어 들이는 단계까지 안정적이었습니다. 세 형식 모두 값 검사가 필요했습니다. 마크다운 표는 그보다 앞선 구조 검사에서도 실패했습니다.
이름이 바뀌어도 CSV는 읽혔습니다
상품 속성 과제 P01의 입력에는 이렇게 적혀 있습니다.
코튼 파우치 C1, 색상 베이지, 크기 20x15cm, 면 소재, 현재 재고 있음.
상품명·색상·크기·재질·재고 여부를 각각 정해진 칸으로 나누는 작업입니다. JSON 응답의 상품명 부분은 다음과 같습니다.
"product": "코튼 파우치 C1",
CSV 응답의 데이터 행은 달랐습니다.
P01,cotton pouch C1,베이지,20x15cm,면,Y
색상부터 재고 여부까지는 같은 값이 남았습니다. 바뀐 건 상품명. 영어로 나왔습니다. 헤더와 데이터의 열 수는 맞아 CSV 파싱과 필드 검사를 모두 통과했습니다. 정답표와 값을 대조하는 단계에서 걸렸습니다.
사람이 읽으면 같은 물건을 가리킨다고 이해할 수 있습니다. 이번 과제에서는 입력에서 상품명을 추출해 지정된 값으로 남겨야 했습니다. 표기까지요. 상품명을 기준으로 다른 자료와 대조하는 작업이라면, 이런 표기 변경을 허용할지부터 정해야 합니다.
이 사례로 확인한 것은 같은 입력의 값이 형식별 응답에서 달라졌다는 사실입니다. 사례마다 각 형식으로 한 번씩 요청했고, 생성 온도와 seed를 요청에 따로 고정하지 않았습니다. 저장된 모델 설정의 온도는 1입니다.
JSON 안의 「상품문의」도 오답이었습니다
P01의 상품명은 JSON 응답에 그대로 남았습니다. 문의 분류 Q11에서는 JSON 안에 오답이 들어 있었습니다.
입력은 송장 번호를 묻는 문장이었습니다.
주문번호 A-104의 송장 번호를 확인하고 싶어요.
정답표의 분류는 「배송」입니다. JSON 응답에는 다음 값이 들어갔습니다.
"category": "상품문의"
JSON 문법은 맞았습니다. 필요한 키도 갖췄습니다. 「상품문의」도 프롬프트가 허용한 다섯 분류 중 하나였습니다.
분류 칸이 있는지, 그 칸에 허용된 문자열이 들어갔는지만 확인하면 이 응답은 그대로 지나갑니다. 값은 틀렸죠. 문의 내용에 맞는 분류인지까지 봐야 오답을 잡습니다.
상품명의 정확한 표기는 입력이나 상품 기준표와 대조할 수 있습니다. 문의 분류는 뜻을 판단해야 합니다. 검사도 따로. 빈칸이나 자료형을 확인한 뒤에는, 값이 입력 내용에 맞는지 각 작업에 맞춰 살펴야 합니다.
읽기 성공과 완전통과를 따로 셌습니다
이번 테스트는 2026년 9월 22일, 로컬 Ollama의 gemma3:4b Q4_K_M으로 실행했습니다. 문의 분류, 발주 정보 추출, 상품 속성 정규화에 서로 다른 사례를 20개씩 뒀습니다. 각 사례를 JSON·CSV·마크다운으로 한 번씩 요청해 모두 180회입니다.
파일럿 27회에서 진행 판정을 받은 뒤 나머지 153회를 이어 실행했습니다. 아래 집계에는 파일럿도 포함됩니다. 준비한 사례들을 형식별로 나눠 처리한 결과입니다.
채점기는 format_score.py입니다. 지정된 형식으로 읽히는지 확인하고 필드 구성을 검사합니다. 그다음은 값. 정답표와 대조해 구조와 값이 모두 맞은 응답을 완전통과로 셌습니다. 응답 전체를 감싼 코드펜스 하나는 허용했습니다.
| 출력 형식 | 파싱 성공 | 완전통과 | 실패 유형 |
|---|---|---|---|
| JSON | 60/60 | 40/60 | 값 오답 20건 |
| CSV | 60/60 | 38/60 | 값 오답 22건 |
| 마크다운 표 | 43/60 | 25/60 | 행 수 실패 17건 · 값 오답 18건 |
JSON과 CSV는 구조를 갖춘 채 잘못된 값을 전달했습니다. 읽기는 성공. 값은 오답. 두 형식의 실패는 파싱 뒤의 값 대조에서 드러납니다.
마크다운의 실패는 두 단계에 걸쳐 있습니다. 표를 읽는 단계에서 멈춘 응답도 있고, 표는 읽혔지만 값이 틀린 응답도 있습니다. 채점기는 구조가 깨지면 거기서 멈춥니다. 값은 미채점.
마크다운을 요구했는데 JSON 배열이 왔습니다
구조 계약의 첫 실패는 파일럿의 문의 Q03에서 나왔습니다. 요청에는 출력 형태를 구체적으로 적었습니다.
GFM 마크다운 표 하나로 출력하세요. 정확히 헤더·구분선·데이터 3행만 출력하세요.
첫 두 행의 모양까지 제시했습니다. 입력은 받은 셔츠가 작아서 큰 사이즈로 바꾸고 싶다는 내용이었습니다.
응답에서 분류가 적힌 부분을 발췌하면 이렇습니다.
"id": "Q03","category": "교환"
「교환」은 정답표와 맞습니다. 형식이 달랐죠. 전체 응답은 json 코드펜스로 감싼 JSON 배열이었습니다.
코드펜스를 걷어낸 배열 본문을 마크다운 파서에 넣었습니다. 행 수 오류. 마크다운 표에 필요한 행 수부터 맞지 않아 멈춘 판정이 화면에 남았습니다.
사람은 응답을 보고 교환 요청이라는 뜻을 읽을 수 있습니다. 뜻은 맞죠. 마크다운 표를 기다리는 프로그램이 이 응답까지 받으려면, 다른 형식을 감지해 변환하는 처리가 추가로 필요합니다. 이번 채점기는 형식 위반을 그대로 실패로 셌습니다.
값을 검사하기 전에 형식부터 다시 확인해야 하는 출력이었습니다. 자동화 파이프라인에 연결하려면 그 확인 단계를 먼저 둬야 합니다.
발주 추출에서 통하던 형식이 상품 속성에서는 버티지 못했습니다
전체 결과만 보면 형식 선택에 시선이 머뭅니다. 과제별로 나누면 맡기는 일의 차이가 더 크게 드러납니다.
아래 수치는 모두 구조와 값이 맞은 완전통과입니다.
| 과제 | JSON | CSV | 마크다운 |
|---|---|---|---|
| 문의 분류 · FMT-01 | 15/20 | 16/20 | 6/20 |
| 발주 정보 추출 · FMT-02 | 18/20 | 17/20 | 15/20 |
| 상품 속성 정규화 · FMT-03 | 7/20 | 5/20 | 4/20 |
발주 정보를 추출할 때는 세 형식 모두 비교적 잘 통과했습니다. 상품 속성으로 넘어가면 세 형식 모두 실패가 절반을 넘었습니다.
상품 속성 과제에서는 마크다운도 파싱과 필드 구성을 모두 통과했습니다. 남은 건 값. 여기서 발생한 실패는 모두 값에 있었습니다. 이 과제에 필요한 검사는 구조를 통과한 뒤에도 이어집니다.
이번 표에서는 발주 정보를 뽑느냐, 상품 속성을 정리하느냐의 차이가 각 과제 안에서 형식을 바꾼 차이보다 컸습니다. 일이 달라졌죠. 과제마다 필드 수와 정답표도 함께 달라집니다. 표는 그 두 차이를 나란히 보여줍니다. 「JSON으로 바꾸면 이 작업도 잘될 것」이라는 판단에는 맡길 과제의 결과까지 대조해야 합니다.
실행 기록상 인프라 오류는 0건이었습니다. 답은 왔습니다. 실패는 그 답의 구조와 값을 검사하는 단계에서 나왔습니다.
요청 시간은 중앙값 4.68초, 평균 4.7초, 합계 845.7초였습니다. 매 요청에 keep_alive=0을 적용했습니다. 모델 적재 시간이 포함될 수 있는 전체 요청 시간으로 읽어야 합니다.
JSON을 골라도 다음 단계로 넘길 조건은 따로 둡니다
저는 이번 기록을 근거로 자동 전달용 형식을 JSON이나 CSV에서 고르겠습니다. 두 형식 모두 파싱을 통과했고, 값 대조에서 오답이 나왔습니다.
조건을 둡니다. 값 검사까지 통과한 응답만 다음 작업에 넘기겠습니다. 지금 쓰는 출력 검사도 어디까지 확인하는지 살펴보시면 됩니다.
- 상품명·품번처럼 보존할 값은 입력이나 기준표와 대조합니다. 번역이나 약칭을 허용한다면 그 범위를 먼저 정합니다.
- 문의 분류처럼 판단할 값은 허용 목록에 속하는지 확인한 뒤, 문의 내용과 맞는지까지 봅니다. 정답을 붙인 사례로 분류 성능을 확인하고, 실제 처리에서 사람이 검토할 조건을 둡니다.
- 마크다운 표가 필요한 화면이라면 검증한 데이터를 표로 바꾸는 방식을 검토합니다. 모델이 작성한 표를 곧바로 다음 프로그램의 입력으로 쓰는 경로와 구분합니다.
이번 채점은 정답표를 가진 응답을 구조 검사와 값 대조로 나눠 살폈습니다. 구조는 통과. 값 대조에서 오답이 드러난 응답들이 있었습니다.
프롬프트에서 입력·할 일·출력 조건을 정리하는 방법은 프롬프트를 네 칸으로 나누는 방법에 이어서 볼 수 있습니다. 이번 마크다운 요청에도 형식은 상세히 적혀 있었습니다. 위반은 나왔죠. 지시문을 정리한 뒤에도 출력 검사는 남겨야 합니다.
코튼 파우치 C1을 떠올리면 오늘 확인할 곳이 분명해집니다. CSV 파일을 읽는 데 성공했다는 로그 옆에, 읽어 온 상품명이 원래 이름과 같은지 확인한 결과도 있는지 보시면 됩니다.
재현과 원자료
실행 파일은 run_format_bench.py입니다. 사례와 정답표는 format_bench_cases.json에 있고, 채점기는 format_score.py입니다. 파일럿은 --mode pilot으로 실행합니다. 진행 판정을 확인한 뒤 같은 실행 폴더에서 --mode full로 이어갑니다.
형식별·과제별 표는 같은 폴더의 aggregate.json에 있습니다. 회차와 시간은 results.csv, 인용한 응답과 요청은 raw/에 보관돼 있습니다. 본문에는 해당 실행의 실패 캡처 두 장과 마지막 집계 캡처를 실었습니다.
재현: cinevyze-bench의 run_format_bench.py·format_score.py·format_bench_cases.json(실행 프로그램 = 같은 조건으로 반복 실행하고 채점하는 스크립트).
이번 결과는 gemma3:4b Q4_K_M과 세 과제의 입력 사례 20개씩을 놓고 얻었습니다. 채점에는 사전에 정해둔 정답 일치 기준을 썼습니다. 형식 강제 기능은 프롬프트 지시문에만 의존했습니다.
JSON·CSV·마크다운 180회는 로컬 gemma3:4b로 실행한 결과입니다. 실행 프로그램과 글 작성에 AI 도구를 활용했고, 조건 승인과 발행 전 검수는 제가 합니다.
시네 · cinevyze 운영자 — AI 도구의 응답을 원출력과 검사 기준으로 대조합니다. 이번 측정은 RTX 4070 Ti SUPER가 있는 Linux 환경에서 Ollama의 gemma3:4b Q4_K_M으로 진행했습니다. 측정일은 2026년 9월 22일입니다. 운영자 소개
댓글
댓글 쓰기