강의 노트로 문제 만들기, 정답마다 근거 문장 붙이기
노트로 객관식 문제를 만들면 노트에 없는 내용이나 정답이 둘인 문제가 섞입니다. 정답마다 노트 원문 인용을 붙이게 하고, 스크립트로 인용을 대조합니다.
"{문제}만 만들어 줘" 라고 시키면 문제 5개와 정답표가 깔끔하게 나옵니다. 그런데 그 정답이 노트의 어느 문장에 근거하는지는 적혀 있지 않아서, 믿어도 되는지 확인하려면 노트를 처음부터 다시 읽어야 합니다. 시험 전날에 하기 싫은 일입니다.
[1] 노트를 파일로 둡니다. 교양 심리학 3주차를 가정한 가상의 노트이고, 개념 7개이고 마지막 틀 효과에는 일부러 「이 강의는 일상 소비 장면까지」 라는 단서를 넣었습니다. 아래는 일부만 옮겼습니다.
[교양 심리학 3주차 노트] 1. 앵커링. 처음 접한 숫자가 이후 판단의 기준점이 되어 최종 추정치가 그쪽으로 끌려가는 현상이다. 정가 10만 원짜리 옆에 있는 7만 원 상품이 싸 보이는 것이 예다. 기준점이 임의로 정해진 숫자여도 효과가 생긴다. 2. 손실 회피. 같은 크기라면 이득의 기쁨보다 손실의 고통을 더 크게 느낀다. 강의에서는 대략 2배 안팎이라고 소개했다. 그래서 "1만 원 할인"보다 "안 사면 1만 원 손해"라는 문구가 더 강하게 작동한다. … 7. 틀 효과. 같은 내용이라도 표현 방식에 따라 선택이 달라진다. "생존율 90%"와 "사망률 10%"는 같은 정보인데 앞의 표현이 더 긍정적으로 받아들여진다. 수술 같은 실제 결정에서도 나타난다고 했으나 이 강의에서 다루는 범위는 일상 소비 장면까지다.[2] 먼저 짧게 시켜 봅니다. 노트 앞에 "아래 강의 노트로 객관식 문제 5개 만들어 줘. 정답도 알려 줘." 한 줄만 붙였습니다. 문제 5개와 해설표가 나왔고 읽어서는 틀린 곳을 찾지 못했습니다. 다만 해설표에는 노트를 그대로 옮긴 문장과 풀어 쓴 문장이 섞여 있어서, 어느 해설이 노트의 어느 문장에서 왔는지는 직접 찾아야 합니다. 끝에는 7개 개념 중 둘을 뺐다는 말도 붙어 있었습니다.
[3] 프롬프트를 고칩니다. 문제마다 quote 칸을 두고 "노트에서 그대로 복사한 한 문장" 을 쓰게 하고, 못 찾으면 그 문제를 버리게 합니다. Anthropic 의 환각 줄이기 안내 에 있는 방식(주장마다 뒷받침 인용을 찾고, 못 찾으면 그 주장을 지운다)을 문제 만들기에 옮긴 것입니다. 출력은 5단계 스크립트가 읽도록 JSON 배열만 받습니다.
Write 5 multiple-choice practice questions in Korean from the lecture notes inside <notes>. Rules:- Ask only about content that is written in the notes. Do not use outside knowledge.- Each question has 4 choices (A-D) and exactly one correct answer. The wrong choices must be clearly wrong according to the notes, not just "less right".- For every question give a "quote": one sentence copied character for character from the notes that supports the correct answer. The quote must not also fit a wrong choice.- If you cannot find such a quote, drop the question. Fewer than 5 is fine.- Cover 5 different concepts.- Output only a JSON array, no other text. Each item: {"q": "...", "choices": {"A": "...", "B": "...", "C": "...", "D": "..."}, "answer": "A", "quote": "..."} <notes>{강의 노트 전체}</notes>[4] 실행합니다. 같은 프롬프트로 두 번 돌렸습니다.
$ (cat head.txt notes.ko.txt; echo "</notes>") > prompt.ko.txt$ claude -p --model claude-sonnet-5-5 --max-turns 1 --tools "" --setting-sources "" --strict-mcp-config < prompt.ko.txt > out.ko.1.txt첫 번째 결과에서 한 문제만 옮깁니다. 나머지 4개도 같은 형식입니다.
[ { "q": "손실 회피와 관련해 강의에서 소개한, 이득의 기쁨 대비 손실의 고통의 대략적인 크기는?", "choices": { "A": "절반 정도", "B": "대략 2배 안팎", "C": "대략 5배", "D": "대략 10배" }, "answer": "B", "quote": "강의에서는 대략 2배 안팎이라고 소개했다." }, …][5] 인용 대조 스크립트를 만듭니다. 노트의 공백·줄바꿈을 공백 하나로 합친 뒤 각 quote 가 노트에 몇 번 나오는지 세고, 정답 글자가 보기 4개 안에 있는지도 봅니다. 한 번이 아니면 종료 코드 1 입니다.
#!/usr/bin/env python3"""usage: check.py notes.txt quiz.json"""import json, sysnotes = " ".join(open(sys.argv[1], encoding="utf-8").read().split())bad = 0for i, it in enumerate(json.load(open(sys.argv[2], encoding="utf-8")), 1): n = notes.count(" ".join(it["quote"].split())) ok = n == 1 and it["answer"] in it["choices"] and len(it["choices"]) == 4 bad += not ok print("OK " if ok else "BAD ", f"Q{i}: quote found {n}x, answer {it['answer']}, choices {len(it['choices'])}")print(f"{i} questions, {bad} to review")sys.exit(1 if bad else 0)$ python3 -I check.py notes.ko.txt out.ko.1.txt; echo "exit $?"OK Q1: quote found 1x, answer B, choices 4OK Q2: quote found 1x, answer B, choices 4OK Q3: quote found 1x, answer C, choices 4OK Q4: quote found 1x, answer D, choices 4OK Q5: quote found 1x, answer A, choices 45 questions, 0 to reviewexit 0두 번째 결과도 5문제 모두 통과했습니다. 인용이 노트에 없으면 이렇게 걸립니다. 2번 문제의 인용을 손으로 「대략 3배 안팎」으로 바꾼 파일입니다(모델이 만든 오류가 아닙니다).
$ python3 -I check.py notes.ko.txt out-bad.json | grep -v '^OK'; echo "exit ${PIPESTATUS[0]}"BAD Q2: quote found 0x, answer B, choices 45 questions, 1 to reviewexit 1[6] 정답과 인용을 뺀 문제만 새 대화에 노트와 함께 주고 풀게 한 뒤 정답 키와 맞춰 봅니다. 두 결과 모두 5문제가 키와 일치했습니다. 풀이가 키와 다르면 정답이 둘일 수 있으니 그 문제를 사람이 읽습니다.
[7] 마지막은 사람 눈입니다. 스크립트는 인용이 노트에 있는지만 봅니다. 그 문장이 정답만 지지하는지는 문제와 인용을 나란히 놓고 읽어야 합니다.
빗나간 곳
- 정답 보기가 인용을 그대로 옮긴 것이다. 두 결과의 10문제 모두 정답 보기가 인용의 구절입니다(8개는 글자 그대로, 두 번의 3번은 어미만 다릅니다). 예를 들어 4번의 정답 「앞으로 들 비용과 얻을 이익」은 인용 「합리적 판단에서는 앞으로 들 비용과 얻을 이익만 비교한다.」 안에 그대로 있습니다. 노트를 읽지 않고도 인용과 같은 말이 든 보기를 고르면 맞힙니다. 스크립트는 통과시킵니다.
- 개념이 쏠린다. 두 번 모두 노트의 1~5번 개념(앵커링·손실 회피·현상 유지 편향·매몰 비용 오류·확증 편향)만 나왔고, 6번 가용성 휴리스틱과 7번 틀 효과는 한 번도 나오지 않았습니다. 7번 끝에 일부러 넣은 단서 문장도 문제가 되지 않았습니다. "5개 서로 다른 개념" 이라고 했어도 어느 개념인지는 지정하지 않았기 때문입니다. 빠진 개념은 직접 지정해서 한 번 더 시킵니다.
첫 번째 약점은 head.txt 에 규칙 한 줄을 더해 줄였습니다(단서 문장 문제를 막으려던 앞부분은 이번 결과에서는 필요가 없었습니다).
- Do not ask about a caveat or exception sentence, and do not use a quote that contains wording of a wrong choice. Choices must not copy the quote.이 줄을 넣고 두 번 다시 돌린 결과에서는 10문제 모두 정답 보기가 인용을 바꿔 쓴 문장이었습니다. 두 번째 결과는 JSON 을 ```json 코드 블록으로 감싸 보내 스크립트가 읽지 못했고, 코드 블록 줄을 지우자 5문제 모두 통과했습니다. 문제는 정의와 수치를 묻는 것이 대부분이었고, 6번 가용성 휴리스틱은 첫 번째에 한 번 나왔습니다.
이 방법은 노트 밖 내용을 걸러낼 뿐이라, 노트 자체가 틀렸으면 그 오류가 정답으로 나옵니다. 교재와 맞는지는 알 수 없으니 시험 범위와 정답은 교수·교재 기준으로 삼습니다. 시험 일정에 맞춰 공부 시간을 나누는 일은 시험일까지 공부 계획 짜기 에 따로 있습니다.