AI는 똑같은데 결과가 다른 이유, 하네스: 초보자가 내 업무에 바로 붙이는 7단계
이 글과 연결된 글 보기
드래그로 이동 · 휠/두 손가락으로 확대 · 방향키로 글 선택 · 0으로 맞춤. 실선: 본문 링크, 점선: 시리즈·주제의 대표 연결.표시된 글 24편 목록
요즘 AI 이야기에 '하네스(harness)'라는 말이 자주 나옵니다. 한 줄로 줄이면 AI 모델 바깥에 있는 나머지 전부입니다. 이 글은 제가 AI에게 식물vs좀비와 프로스트펑크를 혼자 맡기면서 하네스를 직접 만들어 본 경험을 바탕으로, 초보자가 가장 궁금해하는 질문인 "그래서 이걸 내 일에는 어떻게 쓰나요?"에 답합니다. 끝까지 따라 하면 주간 보고서 같은 반복 업무에 붙일 수 있는 작은 하네스가 하나 생깁니다.
2026년 10월 28일에 정리했습니다. 실습은 Codex CLI 0.160.0(ChatGPT 구독)으로 직접 돌렸고, 데이터는 실습용으로 만든 가상 카페 주문 197줄입니다. 글에 나오는 줄 수, 토큰 수, 실패 출력은 전부 그 실행에서 나온 값입니다. Claude Code에서는 같은 규칙서를 CLAUDE.md라는 이름으로 두면 됩니다. 게임 실험 숫자는 AI 게임 리그 EP.1 식물vs좀비 글의 실행 로그에서 가져왔습니다.

이 글은 이런 분께 필요합니다
- ChatGPT나 Claude를 매주 같은 일(보고서, 정리, 답장 초안)에 쓰는데 결과 형식이 매번 달라서 다시 고치는 분
- AI가 "다 했습니다"라고 했는데 열어 보니 숫자가 틀려 있던 적이 있는 분
- '하네스', '하네스 엔지니어링'이라는 말을 들었는데 개발자 이야기 같아서 나와 상관없다고 느낀 분
준비물
- 쓰고 있는 AI 하나. 웹 채팅(ChatGPT, Claude)만 써도 Step 1~3, 6은 그대로 적용됩니다.
- 실습까지 따라 하려면 Codex나 Claude Code 같은 에이전트 도구, 그리고 Python 3
- 실습 파일 받기(harness-practice.zip): 규칙서, 계산기, 검사기, 가상 주문 데이터
하네스를 처음부터: 모델이 아닌 건 전부 하네스입니다
AI 서비스는 크게 두 부분으로 나눠 볼 수 있습니다.
- 모델: 실제로 생각하는 부분입니다. Claude Opus, GPT 같은 이름이 붙은 것입니다.
- 하네스: 그 모델에게 무엇을 보여 주고, 무엇을 할 수 있게 하고, 결과를 어떻게 확인할지 정하는 나머지 전부입니다. 지시문, 규칙 문서, 붙여 주는 데이터, 쓸 수 있는 도구, 검사, 기록이 다 여기에 들어갑니다.
LangChain은 이걸 "Agent = Model + Harness", 모델이 아니면 하네스라고 정리했고, Anthropic도 Claude Code를 '에이전트 하네스'라고 부릅니다. 그러니 ChatGPT 프로젝트에 지침을 적어 두고 쓰고 있다면, 이미 아주 작은 하네스를 쓰고 있는 셈입니다.
초보자에게 이 구분이 중요한 이유는 하나입니다. 결과가 나쁠 때 고칠 수 있는 쪽은 대부분 모델이 아니라 하네스이기 때문입니다. 모델은 내가 바꿀 수 없지만, 무엇을 보여 주고 무엇을 확인할지는 오늘 바로 바꿀 수 있습니다.
같은 모델, 하네스만 고쳤더니 결과가 바뀐 장면
제가 AI에게 게임을 혼자 맡긴 실험에서 이 차이를 여러 번 봤습니다. 두 경우 모두 모델은 그대로였습니다.
- 식물vs좀비, 컨베이어 레벨: Claude Opus 5.5가 심기 48번 중 14번을 실패했습니다. 카드가 계속 밀려가는데 몇 초 전에 읽은 위치를 눌렀기 때문입니다. 하네스가 "클릭 직전에 다시 읽기"를 하도록 고치자 다음 판에 바로 깼습니다.
- 프로스트펑크, 1일차 밤: 매뉴얼과 공략에 "밤에는 발전기를 켜라"가 분명히 있었는데, AI는 석탄을 아끼겠다며 발전기를 끈 채 밤을 넘기다 한파를 맞았고 80명 중 21명이 얼어 죽었습니다. 아는 것과 제때 하는 것은 달랐습니다. 그래서 "밤에 발전기가 꺼져 있고 석탄이 있으면 하네스가 1단계로 켜고 AI에게 알린다"는 장치를 넣었고, 그 뒤 3일차 밤까지 사망자는 없었습니다.


하네스의 다섯 부품
게임이든 업무든 하네스는 결국 다섯 가지로 나뉩니다. 이 표가 이 글 전체의 지도입니다.
| 부품 | 하는 일 | 게임 실험에서 | 매출 보고서 실습에서 | 웹 채팅만 쓴다면 |
|---|---|---|---|---|
| ① 규칙서 | AI가 추측하면 안 되는 것을 적어 둠 | 게임 매뉴얼, 게임 오버 조건 | AGENTS.md | 프로젝트 지침, 맞춤 지침 |
| ② 입력 | AI가 정확히 읽을 수 있는 형태로 줌 | 화면 대신 메모리에서 읽은 숫자 | sales.csv | 스크린샷 대신 표나 CSV를 붙여 넣기 |
| ③ 손 | 계산과 반복은 프로그램이 함 | 클릭 대행, 햇빛 자동 줍기 | calc.py | 엑셀 피벗으로 먼저 합계를 내고 AI에게는 문장만 |
| ④ 검사기 | AI의 말 대신 결과를 확인함 | 건물 미리보기 색 확인, 화면 감시 | check.py | 매번 확인할 체크리스트 |
| ⑤ 기록 | 실패를 다음 규칙으로 바꿈 | 판마다 복기, 바뀐 규칙 목록 | 실패 노트 | 틀린 점을 지침 끝에 한 줄씩 추가 |
스타크래프트로 보면 한 번에 이해됩니다
하네스가 아직 막연하다면 스타크래프트 프로게이머를 떠올려 보세요. 모델은 선수의 머리, 하네스는 그 선수의 손과 키보드, 그리고 리그 규정입니다. 머리가 아무리 좋아도 화면을 잘못 보거나 손이 느리면 지고, 반대로 손이 머리 대신 판단하기 시작하면 그건 더 이상 선수의 실력이 아닙니다.
| 하네스 부품 | 스타크래프트로 치면 | 게임 실험에서 실제로 있었던 일 |
|---|---|---|
| 모델 | 선수의 판단력과 전략 | Claude Opus와 GPT가 무엇을 어디에 심을지 정함 |
| ① 규칙서 | 맵 이해, 종족 상성, 리그 규정 | 게임 오버 조건과 매뉴얼을 미리 줌 |
| ② 입력 | 미니맵, 자원 수치, 정찰 | 화면 대신 메모리에서 햇빛·좀비 위치를 정확히 읽음 |
| ③ 손 | 단축키, 부대 지정, 일꾼 자동 채취 | AI는 "2줄 3칸에 완두슈터"만 말하고 클릭은 프로그램이, 햇빛은 자동으로 주움 |
| ③ 손 (계획 실행) | 빌드오더를 짜고 타이밍대로 찍는 매크로 | AI가 배치표를 쓰고 프로그램이 0.3초마다 그대로 실행 |
| ④ 검사기 | 경기 중 랙이 나면 심판이 멈춤 | 15분 동안 아무 진행이 없으면 경고하고 다시 시작 |
| ⑤ 기록 | 리플레이 복기 | 진 판마다 AI가 원인을 적고 다음 판 계획을 고침 |
이 비유는 "어디까지가 공정한가"를 설명할 때 더 쓸모가 있습니다. 하네스를 너무 세게 만들면 AI가 잘한 게 아니라 장치가 잘한 게 되기 때문입니다.
| 스타크래프트의 반칙 | 하네스로 치면 |
|---|---|
| 맵핵: 안 보이는 곳까지 다 봄 | 입력이 사람이 볼 수 없는 정보까지 AI에게 넘김 |
| 매크로 프로그램: 빌드와 컨트롤을 프로그램이 대신 | 손이 판단까지 대신함(위험한 줄을 먼저 막는 자동 규칙 등) |
| 코치 귓속말: 경기 중에 전략을 알려줌 | 사람이 중간에 공략을 넣어 줌 |
| 한쪽만 좋은 PC와 낮은 핑 | 두 모델의 접속 방식과 사용량 제한이 다름 |
실제로 딥마인드도 스타크래프트 2 AI 알파스타를 프로 수준으로 평가할 때 사람과 비슷한 화면(카메라) 시야와 행동 횟수 제한을 걸었고, 그 조건을 프로게이머가 승인했습니다. 제 식물vs좀비 실험에서 한쪽 AI에만 중간부터 계획 실행기와 사람의 지시가 붙자 "누가 더 잘했나"가 아니라 "누가 더 도움을 받았나"를 비교하게 된 것도 같은 이유입니다.
업무에 옮기면 기준은 간단합니다. 눈과 손(입력, 계산, 확인, 기록)은 최대한 튼튼하게, 판단은 AI에게. 판단까지 프로그램에 넘기고 싶다면 그건 그것대로 좋은 자동화지만, "AI가 해냈다"고 말할 범위는 줄어든다는 점만 알고 쓰면 됩니다.
이제 이 다섯 부품을 내 업무에 하나씩 붙여 보겠습니다. 예제는 "가상의 카페 사장님께 매주 보내는 매출 보고서"입니다.
Step 1. AI에게 매주 맡기는 일 하나와, 망쳤던 장면 3개를 적습니다
처음부터 거창한 자동화를 설계할 필요는 없습니다. 매주 반복하는 일 하나만 고르고, AI가 그 일을 망쳤던 장면을 세 개 적습니다. 하네스는 이상적인 설계도가 아니라 실제로 겪은 실패에서 출발할 때 잘 맞습니다.
매출 보고서라면 이런 목록이 나옵니다.
- 보고서 형식이 매주 달라서 사장님이 매번 어디를 봐야 할지 헤맨다.
- 우리 가게만의 기준(머그컵은 굿즈로 따로 본다)이 빠진다.
- 숫자가 맞는지 내가 다시 계산해 봐야 한다.
게임 실험도 똑같았습니다. 식물vs좀비에서는 게임 PC의 모니터 신호가 끊겨 AI가 1시간 50분 동안 검은 화면을 보며 490번 호출(약 $9)을 했고, 다른 날에는 이긴 판의 보상 열쇠를 누를 주체가 없어 5시간 동안 멈춰 있었습니다. 감시 장치는 전부 이런 사고가 난 뒤에 생겼습니다.
Step 2. 판단, 계산, 확인을 나눠 표로 적습니다
다음으로 그 일을 쪼개서 누가 맡을지 정합니다. 기준은 간단합니다.
- AI: 문장 쓰기, 요약, 질문 만들기처럼 판단이 필요한 일
- 프로그램(또는 엑셀): 합계, 중복 제거, 환불 빼기처럼 매번 똑같이 해야 하는 일
- 나: 규칙 정하기, 최종 발송
| 할 일 | 맡는 쪽 |
|---|---|
| 같은 주문번호 중복 제거, 환불 제외, 채널별 합계 | 프로그램(calc.py) |
| 3줄 요약 문장, 사장님께 물어볼 질문 | AI |
| 숫자가 계산 결과와 같은지, 형식이 맞는지 확인 | 프로그램(check.py) |
| "머그컵은 굿즈" 같은 가게 규칙, 최종 발송 | 나 |
식물vs좀비에서 가장 크게 남은 교훈도 이것이었습니다. AI에게 "(412, 233)을 클릭해"라고 시키지 않고, AI는 "완두슈터를 2줄 3칸에"까지만 정하고 실제 클릭은 하네스가 했습니다. 판단은 AI, 정확해야 하는 반복은 프로그램입니다.
Step 3. 규칙서를 파일 하나로 만듭니다
AI가 추측하면 안 되는 것을 한 파일에 적습니다. 핵심은 AI가 데이터만 봐서는 절대 알 수 없는 것을 적는 것입니다. Codex는 작업 폴더의 AGENTS.md를, Claude Code는 CLAUDE.md를 읽습니다. 웹 채팅이라면 프로젝트 지침 칸에 같은 내용을 붙여 넣으면 됩니다.
실습에서 쓴 규칙서입니다.
# 주간 매출 보고서 규칙서
이 폴더에서 하는 일은 하나입니다. `sales.csv`(지난주 주문 내역)로 사장님께 보낼 `report.md`를 씁니다.
## 우리 가게 규칙 (AI가 추측하지 말 것)
1. 매출은 환불(refunded=Y)을 뺀 금액입니다. 같은 order_id가 여러 줄이면 한 번만 셉니다.
2. 머그컵은 굿즈입니다. '커피 매출'과 '굿즈 매출'을 나눠서 보고합니다.
3. 사장님은 휴대폰으로 읽습니다. 맨 위에 3줄 요약, 전체 25줄 이내.
4. 왜 늘었는지, 왜 줄었는지 같은 원인은 추측하지 않습니다. 원인이 궁금한 점은 '확인 필요'에 적습니다.
## 작업 순서
1. `python3 calc.py`를 실행합니다. 숫자는 직접 계산하지 말고 `summary.json`에 있는 숫자만 씁니다.
2. 아래 형식으로 `report.md`를 씁니다.
3. `python3 check.py`를 실행합니다. '통과'가 나올 때까지 report.md를 고칩니다. check.py와 calc.py는 고치지 않습니다.
## report.md 형식
- `# 주간 매출 보고 (기간)`
- `## 3줄 요약`
- `## 채널별` (표)
- `## 커피 vs 굿즈` (표)
- `## 확인 필요`
## 실패 노트 (틀린 적이 있으면 여기에 한 줄씩 추가)
- (아직 없음)
규칙서에는 세 종류가 들어갑니다. 가게 규칙(데이터로는 알 수 없는 정의), 작업 순서(무엇을 실행하고 언제 끝났다고 볼지), 형식(매주 같은 목차)입니다. 맨 아래 실패 노트는 Step 6에서 채웁니다.
Step 4. 계산은 프로그램에 맡깁니다
숫자는 AI가 머릿속으로 더하게 두지 않고, 매번 똑같이 계산하는 작은 프로그램에 맡깁니다. 코드를 못 쓰셔도 괜찮습니다. 이 정도 계산기는 AI에게 "이 규칙대로 합계를 내는 파이썬 파일을 만들어 줘"라고 한 번 시키고, 첫 결과만 엑셀 합계와 한 번 대조하면 됩니다. 그다음부터는 매주 같은 계산기를 다시 씁니다.
import csv, json
rows = list(csv.DictReader(open("sales.csv", encoding="utf-8")))
seen, orders = set(), []
for r in rows: # 같은 주문번호는 한 번만
if r["order_id"] in seen:
continue
seen.add(r["order_id"]); orders.append(r)
dup = len(rows) - len(orders)
refunds = [r for r in orders if r["refunded"] == "Y"]
net = [r for r in orders if r["refunded"] == "N"]
amt = lambda r: int(r["qty"]) * int(r["unit_price"])
def total(rs): return sum(amt(r) for r in rs)
by = lambda key: {k: total([r for r in net if key(r) == k]) for k in sorted({key(r) for r in net})}
s = {
"기간": f'{min(r["date"] for r in rows)} ~ {max(r["date"] for r in rows)}',
"주문수": len(net), "중복제거_줄수": dup, "환불_건수": len(refunds), "환불_금액": total(refunds),
"매출": total(net),
"채널별": by(lambda r: r["channel"]),
"커피_vs_굿즈": by(lambda r: "굿즈" if r["product"] == "머그컵" else "커피"),
"일별": by(lambda r: r["date"]),
"채널별_환불건수": {k: sum(1 for r in refunds if r["channel"] == k) for k in sorted({r["channel"] for r in refunds})},
}
json.dump(s, open("summary.json", "w", encoding="utf-8"), ensure_ascii=False, indent=2)
print("summary.json 저장:", s["매출"], "원")
실행하면 이렇게 나옵니다.
$ python3 calc.py
summary.json 저장: 3199400 원
이 데이터에는 일부러 함정을 넣었습니다. 같은 주문이 두 번 내려받아진 줄이 9개, 환불 주문이 13건입니다. 중복을 안 빼면 매출이 3,387,400원, 환불을 안 빼면 3,448,700원, 둘 다 빼야 정답인 3,199,400원이 나옵니다.
Step 5. 검사기를 붙입니다
검사기는 AI가 "다 했습니다"라고 말해도 믿지 않고, 결과물을 직접 열어 확인하는 프로그램입니다. 실습의 검사기는 네 가지를 봅니다. 정해 둔 섹션이 다 있는지, 보고서에 나온 금액과 건수가 전부 summary.json에 있는 숫자인지, 총매출이 들어 있는지, 25줄을 넘지 않는지입니다.
import json, re, sys
s = json.load(open("summary.json", encoding="utf-8"))
rep = open("report.md", encoding="utf-8").read()
def nums(o): # summary.json 안의 모든 숫자
if isinstance(o, dict): return [n for v in o.values() for n in nums(v)]
return [o] if isinstance(o, int) else []
allowed = set(nums(s))
problems = []
for sec in ["## 3줄 요약", "## 채널별", "## 커피 vs 굿즈", "## 확인 필요"]:
if sec not in rep: problems.append(f"섹션 없음: {sec}")
for n in re.findall(r"\d{1,3}(?:,\d{3})+(?=\s*원)", rep): # '1,234원' 꼴 금액
if int(n.replace(",", "")) not in allowed:
problems.append(f"summary.json에 없는 금액: {n}원")
for n in re.findall(r"(\d+)\s*건", rep): # '7건' 꼴 건수
if int(n) not in allowed:
problems.append(f"summary.json에 없는 건수: {n}건")
if f'{s["매출"]:,}원' not in rep: problems.append("총매출이 보고서에 없음")
if len(rep.strip().splitlines()) > 25: problems.append("25줄 초과")
print("통과" if not problems else "실패\n- " + "\n- ".join(problems))
sys.exit(1 if problems else 0)
검사기를 믿기 전에 일부러 틀린 보고서를 넣어서 정말 잡아내는지부터 확인했습니다. 중복을 안 뺀 매출(3,387,400원)을 쓰고 섹션 하나를 뺀 보고서입니다.
$ python3 check.py
실패
- 섹션 없음: ## 커피 vs 굿즈
- summary.json에 없는 금액: 3,387,400원
- 총매출이 보고서에 없음
하네스가 있을 때와 없을 때, 직접 돌려 본 결과
이제 같은 요청을 두 폴더에서 각각 두 번씩 돌렸습니다. 한 폴더에는 sales.csv만, 다른 폴더에는 규칙서, 계산기, 검사기까지 넣었습니다. 요청은 짧게 했습니다.
# 하네스 없는 폴더 (sales.csv만 있음)
codex exec --skip-git-repo-check -s danger-full-access \
"sales.csv는 우리 카페 온라인·오프라인 지난주 주문 내역이야. 사장님께 보낼 주간 매출 보고서를 report.md로 써줘."
# 하네스 있는 폴더 (압축을 푼 harness-practice 폴더)
codex exec --skip-git-repo-check -s danger-full-access "지난주 주간 매출 보고서 써줘."
--skip-git-repo-check는 git 저장소가 아닌 폴더에서도 실행하게 해 줍니다. -s danger-full-access는 AI에게 폴더 밖까지 파일 권한을 열어 주는 옵션입니다. 제 실험 환경에서는 더 좁은 옵션(-s workspace-write)이 파일을 읽지 못해서 이렇게 돌렸습니다. 같은 옵션을 쓸 때는 실습 폴더처럼 중요한 파일이 없는 곳에서만 쓰세요.

| 항목 | 하네스 없음 1회 | 하네스 없음 2회 | 하네스 1회 | 하네스 2회 |
|---|---|---|---|---|
| 매출 숫자(정답 3,199,400원) | 맞음 | 맞음 | 맞음 | 맞음 |
| 보고서 길이 | 74줄 | 51줄 | 18줄 | 19줄 |
| 목차 | 7개 섹션 | 5개 섹션(구성이 바뀜) | 정해 둔 4개 섹션 | 정해 둔 4개 섹션 |
| 머그컵을 굿즈로 따로 | 없음 | 없음 | 있음 | 있음 |
| 검사기 | - | - | 통과 | 통과 |
| 쓴 토큰 | 53,196 | 51,276 | 14,177 | 26,871 |
솔직히 예상과 다른 점이 하나 있었습니다. 하네스가 없어도 Codex는 매출 숫자를 맞혔습니다. 중복 9줄과 환불 13건을 알아서 찾아 뺐습니다. Codex 자체가 코드를 실행할 수 있는 하네스이기 때문입니다. 요즘 에이전트 도구는 이 정도 계산은 스스로 합니다.
그래서 내 하네스가 더해 준 것은 계산 실력이 아니었습니다.
- 우리 가게 규칙: "머그컵은 굿즈"는 데이터 어디에도 없으니 AI가 알 방법이 없습니다. 하네스 없는 두 번 모두 빠졌습니다.
- 매주 같은 형식: 하네스가 없으면 같은 요청에도 7개 섹션 74줄, 5개 섹션 51줄로 달라졌습니다. 사장님은 매주 다른 보고서를 받게 됩니다.
- 확인된 숫자: 하네스 쪽은 검사기를 통과한 보고서만 나옵니다. 내가 다시 계산할 필요가 없습니다.
토큰도 이번에는 하네스 쪽이 적었습니다(실행마다 달라서 늘 그렇다고 단정하지는 않겠습니다). 할 일과 끝나는 조건이 정해져 있으니 AI가 데이터를 이리저리 탐색하는 시간이 줄어든 것으로 보입니다.
Step 6. 틀릴 때마다 실패 노트에 한 줄 추가합니다
하네스는 한 번에 완성되지 않습니다. 결과를 보고 틀린 곳이 나오면 규칙서의 실패 노트에 무엇이 틀렸고, 앞으로 어떻게 하라를 한 줄씩 적습니다. 실습에서도 두 번 이렇게 고쳤습니다.
첫 번째: 쓸모없는 '확인 필요'. 하네스 첫 실행의 '확인 필요' 칸에는 "매출 증감 원인: 확인 필요" 한 줄만 있었습니다. 규칙은 지켰지만 사장님께는 쓸모가 없습니다. 실패 노트에 이렇게 적었습니다.
- 10/28: '확인 필요'에 "매출 증감 원인: 확인 필요"처럼 빈 문장만 씀 → '확인 필요'에는
사장님이 직접 확인할 수 있는 질문을 숫자와 함께 2개 이상 씁니다.
다시 돌리자 질문이 구체적으로 바뀌었습니다. 그런데 여기서 진짜 실수가 나왔습니다.
## 확인 필요
- 스마트스토어 환불이 7건으로 가장 많은데, 해당 주문들의 주요 환불 사유는 무엇인가요?
두 번째: 검사기가 안 보는 곳에서 틀렸습니다. 실제 스마트스토어 환불은 6건입니다. 실행 기록을 열어 보니 AI가 채널별 환불 건수가 필요해지자 calc.py를 쓰지 않고 sales.csv를 직접 세면서 중복 줄까지 셌습니다. 그런데도 검사기는 '통과'였습니다. 그때의 검사기는 '원'이 붙은 금액만 확인하고 '건'은 보지 않았기 때문입니다. 규칙서에 "숫자는 직접 계산하지 말 것"이라고 적어 둬도, 검사하지 않는 곳에서는 이렇게 어깁니다.
그래서 세 군데를 고쳤습니다.
calc.py에채널별_환불건수를 추가했습니다(위 Step 4 코드에 이미 반영).check.py가 '건'이 붙은 숫자도 확인하게 했습니다(위 Step 5 코드에 이미 반영).- 실패 노트에 한 줄을 더 적었습니다.
- 10/28: 환불 건수를 sales.csv에서 직접 세다가 중복 줄까지 세서 스마트스토어 환불을 7건(실제 6건)으로 씀
→ summary.json에 없는 숫자는 직접 계산하지 않습니다. 필요하면 '확인 필요'에 "calc.py에 추가 필요"라고 적습니다.
고친 검사기에 7건이 들어간 예전 보고서를 다시 넣으면 이제 바로 걸립니다.
$ python3 check.py
실패
- summary.json에 없는 건수: 7건
그리고 다시 돌린 결과는 검사기를 통과했고, 숫자도 실제와 같았습니다.
## 확인 필요
- 스마트스토어 환불 6건의 사유 중 가장 많은 것은 무엇인가요?
- 쿠팡 환불 4건과 오프라인 환불 3건의 사유는 각각 무엇인가요?
게임 실험의 규칙 대부분도 이렇게 생겼습니다. 식물vs좀비에서 "왜 좀비가 나오는 줄에 공격 식물을 먼저 안 심지?"라는 질문이 "공격 식물이 없는 줄에 좀비가 들어오면 그 줄부터 심는다"는 규칙이 됐고, 프로스트펑크에서 게임이 자동 저장을 덮어써 엉뚱한 날로 돌아간 뒤에는 "자동 저장은 쓰지 않고 이름 붙인 저장만 쓴다"는 규칙이 생겼습니다.
실제로 틀린 것만 적고, 한 줄에 "무엇이 틀렸나 → 앞으로 어떻게"를 같이 씁니다. 같은 실수가 두 번 나오면 그때는 규칙서 본문이나 검사기로 올립니다. 이번 실습의 7건 실수처럼, 말로 적은 규칙보다 검사기가 훨씬 확실합니다.
Step 7. 사람이 안 볼 때 돌린다면, 멈춤 장치를 먼저 겁니다
매번 내가 결과를 열어 보는 동안은 Step 6까지로 충분합니다. 하지만 밤사이나 정해진 시간에 혼자 돌게 만들 생각이라면, 실행 전에 세 가지를 먼저 정합니다.
- 실패하면 멈추기: 검사기가 실패하면 결과를 내보내지 않습니다. 저는 매일 올라가는 쇼츠 채널들에서 사실 확인, 품질 검사, 대표 프레임 확인, 게시 계정 확인을 통과한 것만 올라가게 해 두었습니다.
- 아무 일도 안 일어나면 깨우기: 식물vs좀비에서 5시간 멈췄던 밤 이후로, 15분 동안 행동도 결과도 화면 변화도 없으면 알림을 보내게 했습니다. 실패보다 무서운 건 조용히 멈춰 있는 상태입니다.
- 비용 상한 걸기: "조건이 될 때까지 5분마다 AI에게 확인시키기"는 하면 안 됩니다. 실제로 그렇게 돌린 확인 작업 하나가 하루 만에 크레딧을 크게 써 버렸습니다. 지금은 확인 작업은 AI 없는 일반 스크립트로 돌리고, AI 작업은 최소 60분 간격과 하루 횟수 상한을 둡니다.
계정을 여러 개 쓰는 일이라면 하나 더 있습니다. 같은 브라우저에서 계정을 바꿔 가며 올리다가 업로드가 다른 계정에 올라간 적이 있어서, 지금은 올리기 직전에 계정 이름을 다시 확인하는 단계가 하네스에 들어 있습니다.
내 업무에는 이렇게 시작해 보세요
직군별로 첫 하네스를 짠다면 이런 모양이 됩니다. 아래는 아이디어 예시이고, 직접 돌려 본 것은 위의 매출 보고서 실습입니다.
| 반복 업무 | 규칙서 첫 줄 | 프로그램에 맡길 것 | 검사 항목 |
|---|---|---|---|
| 주간 광고 성과 보고(마케터) | "전환은 구매 완료만, 장바구니는 빼고 센다" | 매체별 비용·전환 합계 | 보고서 숫자가 내보낸 파일 합계와 같은가 |
| 고객 문의 답장 초안(운영·CS) | "환불 기한은 7일, 예외는 약속하지 않는다" | 주문 번호로 주문 상태 조회 | 답장에 약속한 날짜·금액이 정책 안에 있는가 |
| 제안서 초안(영업) | "고객이 쓴 표현을 첫 문단에 그대로 쓴다" | 지난 제안서에서 비슷한 사례 찾기 | 고객사 이름·금액·일정이 요청서와 같은가 |
| 회의록 정리(누구나) | "결정, 할 일, 담당자, 기한 4칸으로" | 녹음 파일을 글로 바꾸기 | 할 일마다 담당자와 기한이 있는가 |
시작 순서는 이 글의 Step 그대로입니다. 일 하나를 고르고, 망쳤던 장면 셋을 적고, 규칙서를 만들고, 계산은 엑셀이나 작은 프로그램에 넘기고, 확인할 것을 체크리스트로 적고, 틀릴 때마다 한 줄씩 늘립니다. 웹 채팅만 쓰신다면 규칙서는 프로젝트 지침에, 검사기는 내 체크리스트로 대신하면 됩니다.
자주 막히는 곳
| 증상 | 원인 | 해결 |
|---|---|---|
| AI가 규칙서를 안 읽는 것 같음 | 파일 이름이나 위치가 다름 | Codex는 작업 폴더의 AGENTS.md, Claude Code는 CLAUDE.md. 웹 채팅은 그 프로젝트 안에서 대화를 시작했는지 확인 |
| 규칙은 적었는데 AI가 직접 계산함 | 말로 적은 규칙은 어길 수 있음 | 그 숫자를 검사기가 확인하게 함(실습의 '건' 검사) |
| 검사기는 통과했는데 결과가 틀림 | 검사기가 그 부분을 안 봄 | 틀린 부분을 검사 항목에 추가하고, 예전 틀린 결과로 검사기가 잡는지 먼저 확인 |
| 규칙서가 길어져 오히려 결과가 흐려짐 | 상상으로 만든 규칙까지 넣음 | 실제로 틀린 것만 실패 노트에, 두 번 반복된 것만 본문으로 |
| 매번 결과가 너무 길거나 짧음 | 형식과 길이 기준이 없음 | 목차와 최대 줄 수를 규칙서에 고정 |
| 하네스 없이도 결과가 맞아서 필요성을 못 느낌 | 요즘 에이전트 도구는 계산을 스스로 잘함 | 하네스의 몫은 내 규칙, 같은 형식, 확인된 결과. 이 셋이 필요한 일부터 적용 |
정리
하네스는 개발자만의 말이 아닙니다. AI에게 무엇을 보여 주고, 무엇을 프로그램에 맡기고, 결과를 어떻게 확인할지 정하는 일입니다. 하네스 한 줄을 고치자 같은 모델이 막혔던 판을 깼고, 감시 장치가 없던 밤에는 몇 시간씩 멈춰 있었습니다. 오늘 할 일은 세 가지면 충분합니다. 매주 하는 일 하나를 고르고, 그 일의 규칙서를 한 파일로 쓰고, 다음에 틀리면 그 자리를 검사 항목으로 바꾸세요.
