챕터 2

AI에게 코드 받는 프롬프트 공식 — 요청·실행·오류 수정 대화

같은 자동화라도 요청을 어떻게 쓰느냐에 따라 한 번에 돌아가는 코드가 나오기도, 다섯 번을 고쳐도 안 되기도 합니다. 입력·출력·예시 데이터·제약을 담는 요청 템플릿과, 오류 메시지를 그대로 붙여 고치는 대화 패턴을 익힙니다.

요청 프롬프트의 다섯 가지 요소

1장에서 앱스 스크립트 편집기를 열고 첫 코드를 돌려 봤습니다. 이번 장은 그 코드를 AI에게서 직접 받아 내는 방법입니다. 결론부터 말하면, 코드의 품질은 AI 모델보다 요청 문장이 좌우합니다.

"시트 정리해 주는 코드 써 줘"라고만 보내면 AI는 시트 이름도, 열 구성도 모르는 채로 추측해서 씁니다. 추측이 맞으면 운이 좋은 것이고, 틀리면 오류가 납니다. 추측할 여지를 없애는 것이 요청 템플릿의 목적입니다.

템플릿 한눈에 보기

요소 무엇을 적나 빠뜨리면 생기는 일
① 목적 한 문장으로 "무엇을 하고 싶은지" 엉뚱한 기능을 덧붙인 긴 코드가 나옴
② 데이터 위치·열 구성 시트 탭 이름, 몇 행부터 데이터인지, 열별 내용 열 번호를 멋대로 가정해 엉뚱한 칸을 고침
③ 예시 입력과 기대 출력 실제 값 2~3줄과 바뀌어야 할 결과 처리 규칙을 AI가 다르게 해석함
④ 제약 시트 이름 고정, 원본 덮어쓰기 금지, 쓰지 말 것 원본이 바뀌거나 외부 서비스를 호출하는 코드가 나옴
⑤ 실행 환경 앱스 스크립트(V8)인지 파이썬인지, 시트에 붙인 스크립트인지 다른 환경용 문법이나 설치가 필요한 코드가 나옴

복붙용 요청 프롬프트

아래는 이번 장 실습용 요청입니다. 괄호 안만 내 상황에 맞게 바꿔 보내세요.

구글 시트의 이름 칸에서 앞뒤 공백을 지우는 구글 앱스 스크립트를 써 줘.

  • 시트 탭 이름: 신청자 명단
  • 1행은 머리글, 2행부터 데이터이고 A열이 이름이야.
  • 예시 입력: " 김철수 " → 기대 출력: "김철수"
  • 제약: 이름 외의 열은 건드리지 마. 다른 시트는 읽거나 쓰지 마. 외부 서비스 호출 없이 SpreadsheetApp만 써 줘.
  • 환경: 시트에서 확장 프로그램 > Apps Script로 연 편집기, V8 런타임이야. 실행하면 몇 개를 정리했는지 Logger.log로 남겨 줘.

다섯 요소가 모두 들어 있고, 길이는 여섯 줄입니다. 이 정도 분량이면 충분합니다.

코드를 받고 실행해 보기

AI는 보통 코드와 함께 설명을 길게 붙입니다. 설명은 읽되, 먼저 확인할 것은 코드가 무엇을 읽고 무엇을 바꾸는지입니다. 이 예제에서는 getSheetByName으로 시트를 찾고, getValues로 읽은 뒤 setValues로 다시 씁니다. 이름 열 말고는 쓰는 곳이 없으니 요청한 제약과 맞습니다.

처음 받은 코드

요청을 보냈더니 아래 코드가 왔다고 해 보겠습니다. 제약을 지켜 달라고 했지만, 시트 이름은 코드 안에 직접 박혀 있습니다.

// AI가 처음 준 코드 (시트 이름이 실제와 다르면 오류)
function trimNames() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('신청자');
  const range = sheet.getRange(2, 1, sheet.getLastRow() - 1, 1);
  const names = range.getValues().map(([v]) => [String(v).trim()]);
  range.setValues(names);
  Logger.log(names.length + '개 이름 정리');
}

시트 탭 이름이 '신청자 명단'인데 코드는 '신청자'를 찾고 있습니다. 요청에는 이름을 정확히 적었지만 AI가 줄여 쓴 경우입니다. 이런 일은 실제로 자주 생깁니다.

실행하고 오류 확인하기

편집기 위쪽 함수 선택 칸에서 trimNames를 고르고 실행을 누르면, 아래쪽 실행 로그 창에 이렇게 뜹니다.

TypeError: Cannot read properties of null (reading 'getRange')

이 코드는 모의 환경에서 실제로 돌려 같은 메시지가 나오는 것을 확인했습니다. 메시지를 풀어 읽으면 "null인 것에서 getRange를 읽을 수 없다"입니다. getSheetByName이 시트를 못 찾으면 null을 돌려주고, 그 null에 getRange를 붙였으니 터진 것입니다.

앱스 스크립트에서 Cannot read properties of null 오류는 대부분 getSheetByName에 넘긴 시트 이름이 탭 이름과 다를 때 발생합니다(Google Apps Script 커뮤니티·개발자 가이드 사례).

오류 수정 대화 패턴

오류가 났을 때 가장 흔한 실수는 "안 돼"라고만 보내는 것입니다. AI는 화면을 볼 수 없습니다. 아래 세 가지를 한 번에 붙여 주세요.

오류 원문 + 한 일 + 기대 결과

  • 오류 원문 실행 로그에 뜬 문장을 그대로 복사합니다. 요약하거나 번역하면 단서가 사라집니다.
  • 내가 한 일 어떤 함수를 실행했는지, 시트에는 어떤 탭이 있는지 적습니다.
  • 기대한 결과 무엇이 되어야 했는지 한 줄로 씁니다.

방금 코드를 trimNames 함수로 실행했더니 아래 오류가 났어.

TypeError: Cannot read properties of null (reading 'getRange')

시트 아래 탭 이름은 '신청자 명단'이야. 이름 열의 앞뒤 공백이 지워져야 해. 시트 이름을 맨 위 상수 한 곳에서 바꿀 수 있게 하고, 시트를 못 찾으면 이유가 보이는 오류 메시지를 내게 고쳐 줘.

마지막 문장처럼 고치는 김에 원하는 안전장치를 함께 요청하면 효율이 좋습니다. 다만 한 번에 한 가지 문제만 다루세요. 오류 세 개를 한꺼번에 던지면 AI가 코드를 통째로 다시 쓰기 쉽고, 어디가 고쳐졌는지 비교하기 어렵습니다.

다시 받은 코드

// 오류 메시지를 붙여 다시 요청한 뒤 받은 코드
const SHEET_NAME = '신청자 명단';   // 시트 아래 탭 이름과 똑같이

function trimNames() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME);
  if (!sheet) {
    throw new Error("'" + SHEET_NAME + "' 시트를 찾지 못했습니다. 탭 이름을 확인하세요.");
  }
  const lastRow = sheet.getLastRow();
  if (lastRow < 2) { Logger.log('정리할 데이터가 없습니다.'); return; }
  const range = sheet.getRange(2, 1, lastRow - 1, 1);
  const names = range.getValues().map(([v]) => [String(v).trim()]);
  range.setValues(names);
  Logger.log(names.length + '개 이름 정리');
}

바뀐 곳은 세 군데입니다. 시트 이름이 맨 위 SHEET_NAME 상수로 빠졌고, 시트가 없으면 읽기 쉬운 메시지로 멈추며, 데이터가 한 줄도 없을 때(lastRow < 2)를 따로 처리합니다. 같은 모의 환경에서 이름이 ["김철수", "이영희", "박 민수"]로 정리되고 실행 로그에 3개 이름 정리가 남는 것을 확인했습니다. "박 민수"처럼 글자 사이 공백은 trim이 지우지 않습니다. 앞뒤만 정리한다는 점을 기억해 두세요.

실행 로그와 Logger.log 읽는 법

코드가 어디까지 돌았는지 모르겠을 때는 중간에 Logger.log를 끼워 넣습니다. 파이썬의 print와 같은 역할입니다.

로그를 심는 위치

의심스러운 줄 바로 앞뒤에 넣는 것이 요령입니다. 예를 들어 Logger.log(sheet)를 getRange 앞에 두면, 시트를 못 찾았을 때 null이라고 찍혀서 원인을 바로 알 수 있습니다. 편집기 아래 실행 로그 창에 실행 시각과 함께 출력되고, 오류가 나면 같은 창에 빨간 메시지로 나옵니다.

AI에게 요청할 때 "각 단계마다 Logger.log로 진행 상황을 남겨 줘"라고 한 줄 넣어 두면 디버깅이 훨씬 수월합니다. 오류가 났을 때 로그 전체를 복사해 붙여 주면 AI가 어느 줄까지 실행됐는지 알 수 있습니다.

AI 도구 고르기와 AI가 지어내는 코드

ChatGPT·Claude·Gemini 고르는 기준

코드 작성은 세 도구 모두 무료 플랜에서 시작할 수 있습니다. 확인된 요금은 한 가지뿐입니다. Claude는 무료 플랜($0)에서 코드 실행까지 쓸 수 있고 Pro는 월 $20입니다(claude.com/pricing, 2026년 10월 기준). ChatGPT와 Gemini의 요금은 공식 페이지에서 확인하지 못해 적지 않습니다. 결제 전에 각 서비스의 요금 화면을 직접 확인하세요.

상황 고르는 기준
처음 시작, 계정이 이미 있음 쓰던 도구를 그대로 씁니다. 도구보다 요청 템플릿이 중요합니다.
긴 오류 로그와 코드를 통째로 붙여 설명을 듣고 싶음 두 도구 이상에 같은 질문을 던져 답을 비교합니다.
구글 시트·구글 계정과 한 화면에서 작업하고 싶음 Gemini를 먼저 써 봅니다. 아래 편집기 패널 소식을 참고하세요.

한 도구가 같은 오류를 두세 번 못 고치면 다른 도구에 같은 프롬프트를 붙여 보세요. 확인용 비용은 거의 들지 않습니다.

존재하지 않는 메서드와 V8에서 안 되는 코드

AI가 가끔 없는 함수를 만들어 냅니다. 예를 들어 sheet.removeBlankRows() 같은 이름은 그럴듯하지만 시트 클래스에 존재하지 않습니다. 오류는 is not a function으로 나옵니다.

또 하나는 환경이 다른 코드입니다. 앱스 스크립트의 V8 런타임에서는 setTimeout·setInterval, fetch, window, ES 모듈(import/export)을 쓸 수 없다고 구글 공식 문서에 적혀 있습니다(developers.google.com/apps-script/guides/v8-runtime). 웹 개발 코드를 학습한 AI가 이런 코드를 섞어 줄 때가 있습니다.

  • 지연이 필요할 때 setTimeout 대신 Utilities.sleep(밀리초)를 씁니다.
  • 외부 주소 호출이 필요할 때 fetch 대신 UrlFetchApp.fetch를 씁니다.
  • 의심스러운 메서드 이름 공식 레퍼런스(developers.google.com/apps-script/reference)에서 검색해 실재 여부를 확인합니다.

편집기 안에서 쓰는 Gemini 패널

2026년 8월부터 앱스 스크립트 편집기에 Gemini 측면 패널이 단계적으로 열리고 있습니다. 코드 생성, 변경 비교(diff), 오류 수정을 편집기 안에서 하고 연결된 시트를 문맥으로 자동 참조한다고 합니다. 대상은 Gemini 베타 사용자와 유료 Google AI 구독 소비자로 알려졌고, 무료 계정에서 쓸 수 있는지는 확실하지 않습니다(커뮤니티 뉴스레터 pulse.appsscript.info 2026년 8월 기사 기준, 구글 공식 문서 미확인).

패널이 있어도 원칙은 같습니다. 해당 기사의 필자도 메일·드라이브 권한이 걸린 생성 코드를 이해 없이 실행하는 위험을 경고합니다.

정리

요청에는 목적·데이터 위치·예시·제약·환경 다섯 가지를 담고, 오류가 나면 원문과 한 일, 기대 결과를 한 문제씩 붙여 보냅니다. 코드가 의심스러우면 Logger.log로 확인하고, 없는 메서드나 V8에서 안 되는 문법은 공식 문서로 거릅니다.

다음 챕터에서는 '구글 시트 데이터 정리 자동화 — 중복 제거·형식 통일·빈칸 채우기'를 다루겠습니다. 이번에 익힌 요청 템플릿으로 중복 행 제거와 전화번호 형식 통일 스크립트를 만들어 봅니다.