15. CRUD7-허깅페이스 연결하기 – Django가 대신 모델을 부르게 하기

1 – 토큰 발급받고 안전하게 두기

1.1 – 허깅페이스 토큰 발급받기

  1. 브라우저에서 https://huggingface.co/에 접속해 계정을 만들고 로그인합니다.
  2. https://huggingface.co/settings/tokens에 접속합니다.
  3. [Create new token] 버튼을 클릭합니다.
  4. Token type에서 [Fine-grained]를 고릅니다.
  5. Token name 칸에 chatbot-app을 입력합니다.
  6. 권한 목록에서 Make calls to Inference Providers 항목을 체크합니다.
  7. 맨 아래 [Create token]을 클릭합니다.
  8. 화면에 나타난 hf_로 시작하는 글자를 복사해 편집기에 임시로 붙여 둡니다.

토큰(token)은 내가 누구인지 알려 주는 긴 글자 열쇠입니다. 허깅페이스는 이 열쇠를 확인해 요청을 받아 주고, 쓴 만큼을 그 계정에 기록합니다. 열쇠가 남에게 넘어가면 남이 쓴 양까지 내 계정에 쌓입니다.

복사한 글자는 이 화면을 닫으면 다시 볼 수 없습니다. 잃어버리면 같은 자리에서 새로 만들어야 합니다.

Make calls to Inference Providers 권한을 체크하지 않으면 토큰이 만들어져도 요청이 거부됩니다. 뒤에서 401 또는 403 응답을 만나면 이 권한부터 확인합니다.

1.2 – 토큰을 코드 밖에 두기

  1. Django 쪽 터미널에서 값을 읽어 주는 도구를 설치합니다.
pip install python-dotenv requests
  1. 편집기에서 새 파일을 만들고 아래 두 줄을 적습니다. hf_ 뒤는 앞에서 복사한 값으로 바꿉니다.
HF_TOKEN=hf_여기에_복사한_토큰을_붙여_넣습니다
HF_MODEL=Qwen/Qwen2.5-7B-Instruct
  1. chatbot-app 폴더 안에 ".env"라는 이름으로 저장합니다.
  2. 편집기에서 새 파일을 만들고 아래 두 줄을 적습니다.
.env
__pycache__/
  1. 같은 폴더에 ".gitignore"라는 이름으로 저장합니다.
  2. 편집기로 config/settings.py 파일을 엽니다.
  3. 파일 맨 위 from pathlib import Path 줄 아래에 두 줄을 더합니다.
from dotenv import load_dotenv

load_dotenv()   # .env 파일의 값을 읽어 들입니다.
  1. 파일을 저장합니다.

토큰을 코드에 직접 적으면 그 파일을 남에게 보내거나 저장소에 올리는 순간 함께 새어 나갑니다. .env는 코드 밖에 값을 적어 두는 파일이고, load_dotenv()가 그 값을 읽어 들입니다.

.gitignore는 저장소에 올리지 않을 파일 목록입니다. 여기에 .env를 적어 두면 나중에 코드를 GitHub에 올릴 때 토큰이 든 파일이 빠집니다. 배포 단계에서 이 한 줄이 빠져 토큰이 공개 저장소에 올라가는 일이 자주 생깁니다.

모델 이름도 .env에 둔 이유는 바꿔 가며 시험하기 위해서입니다. 고른 모델이 응답하지 않으면 이 값만 다른 모델 이름으로 바꿔 다시 시도합니다.

실습 코칭 프롬프트

이 부분을 혼자 해 보다 막히면 아래 프롬프트를 대화형 AI(ChatGPT·Claude·Gemini)에 붙여 넣어 한 단계씩 도움받습니다.

실습에 쓰던 대화창이 아니라 새 대화창에 붙여 넣습니다. 실습 대화창에는 앞서 시킨 다른 지시가 남아 있어, 그 위에 얹으면 답이 뒤섞입니다.

아래는 토큰 발급받아 코드 밖에 두기 실습을 혼자 해 보다 막혀서 도움을 받으려는 요청입니다.

지금 하려는 것: 허깅페이스에서 토큰을 발급받아 .env 에 적고, .gitignore 로 그 파일을 저장소에서 빼는 것입니다.
지금까지 한 것: {지금까지 한 것}
막힌 지점: {막힌 지점}
화면에 나온 메시지: {에러 메시지}

다음 규칙을 지켜 주세요.
- 정답 코드를 통째로 주지 마세요. 다음 한 단계만 알려 주세요.
- 먼저 왜 막혔는지 짚어 주고, 제가 직접 해 보게 하세요.
- 제가 해 본 결과를 말하면 그때 확인 질문을 던지고 다음 단계로 넘어가세요.
- 제가 놓치기 쉬운 부분이 보이면 마지막에 한 줄로 짚어 주세요.
- 토큰에 Inference Providers 호출 권한을 줬는지, load_dotenv() 를 settings.py 에 넣었는지 먼저 확인해 주세요.
아래는 토큰 발급받아 코드 밖에 두기 실습을 혼자 해 보다 막혀서 도움을 받으려는 요청입니다.

지금 하려는 것: 허깅페이스에서 토큰을 발급받아 .env 에 적고, .gitignore 로 그 파일을 저장소에서 빼는 것입니다.
지금까지 한 것: 토큰을 발급받아 .env 에 HF_TOKEN 으로 적었습니다
막힌 지점: 코드에서 토큰을 읽으면 값이 비어 있습니다
화면에 나온 메시지: 서버에 토큰이 설정돼 있지 않습니다

다음 규칙을 지켜 주세요.
- 정답 코드를 통째로 주지 마세요. 다음 한 단계만 알려 주세요.
- 먼저 왜 막혔는지 짚어 주고, 제가 직접 해 보게 하세요.
- 제가 해 본 결과를 말하면 그때 확인 질문을 던지고 다음 단계로 넘어가세요.
- 제가 놓치기 쉬운 부분이 보이면 마지막에 한 줄로 짚어 주세요.
- 토큰에 Inference Providers 호출 권한을 줬는지, load_dotenv() 를 settings.py 에 넣었는지 먼저 확인해 주세요.
  1. {지금까지 한 것} — 어느 단계까지 마쳤는지 적습니다. 예: django-admin startproject config . 까지 실행했습니다
  2. {막힌 지점} — 무엇을 하려다 안 됐는지 적습니다. 예: python manage.py runserver 를 실행하면 서버가 바로 꺼집니다
  3. {에러 메시지} — 화면에 나온 글을 그대로 붙여 넣습니다. 없으면 없음이라고 적습니다.

AI가 고친 코드 전체를 한 번에 내놓으면 “코드 전체 말고 어느 줄을 왜 고쳐야 하는지 한 단계만 알려 주세요”라고 되물으십시오. 에러 메시지를 요약해 적으면 원인을 못 짚습니다. 화면에 나온 글을 그대로 붙여 넣습니다.

2 – Django가 대신 부르게 하기

2.1 – 모델을 부르는 함수 만들기

  1. 편집기에서 새 파일을 만듭니다.
  2. 아래 내용을 붙여 넣습니다.
import os

import requests

# OpenAI 규격과 같은 모양으로 받아 주는 허깅페이스 주소입니다.
API_URL = "https://router.huggingface.co/v1/chat/completions"

# 응답을 30초까지 기다립니다. 이 값을 두지 않으면 무한정 기다립니다.
TIMEOUT = 30

class ChatError(Exception):
    """모델 호출이 실패했을 때 쓰는 오류입니다."""

def ask_model(messages):
    """주고받은 글 목록을 보내고 답변 문장을 돌려받습니다."""

    token = os.environ.get("HF_TOKEN")
    model = os.environ.get("HF_MODEL")

    if not token:
        raise ChatError("서버에 토큰이 설정돼 있지 않습니다.")

    try:
        res = requests.post(
            API_URL,
            headers={"Authorization": f"Bearer {token}"},
            json={"model": model, "messages": messages, "max_tokens": 512},
            timeout=TIMEOUT,
        )
    except requests.Timeout:
        raise ChatError("모델이 30초 안에 답하지 않았습니다.")
    except requests.RequestException:
        raise ChatError("모델 서버에 연결하지 못했습니다.")

    if res.status_code == 401 or res.status_code == 403:
        raise ChatError("토큰이 올바르지 않거나 권한이 없습니다.")
    if res.status_code == 429:
        raise ChatError("사용 한도를 넘었습니다. 잠시 뒤 다시 시도합니다.")
    if res.status_code >= 400:
        raise ChatError(f"모델 서버가 {res.status_code} 를 돌려줬습니다.")

    data = res.json()
    # 답변 문장은 choices 목록의 첫 번째 안에 들어 있습니다.
    return data["choices"][0]["message"]["content"]
  1. chat 폴더 안에 "ai.py"라는 이름으로 저장합니다.

프록시(proxy)는 요청을 대신 받아 다른 곳에 넘겨 주는 중간 자리입니다. React가 허깅페이스를 직접 부르지 않고 Django를 거치게 하는 이유는 토큰 때문입니다.

React 코드는 브라우저로 내려가 실행됩니다. 코드 안에 적은 값은 개발자 도구에서 그대로 읽을 수 있으므로, 토큰을 React에 두면 화면을 연 사람 누구나 볼 수 있습니다. Django 코드는 서버 안에서만 돌기 때문에 브라우저로 내려가지 않습니다. 토큰을 서버에 두고 서버가 대신 부르면 밖으로 나가는 것은 답변 문장뿐입니다.

이 구조가 백엔드를 두는 이유를 가장 잘 보여 주는 자리입니다. 화면만으로 끝나는 일이라면 서버가 필요 없지만, 숨겨야 할 값이 있으면 숨길 자리가 있어야 합니다.

모델을 부르는 코드를 뷰에 바로 적지 않고 파일을 따로 만든 이유가 있습니다. 나중에 모델을 바꾸거나 다른 서비스로 옮길 때 이 파일 하나만 고치면 됩니다.

응답 번호마다 다른 문장을 돌려주는 이유가 있습니다. 오류를 한 문장으로 뭉뚱그리면 토큰이 잘못된 것인지 한도를 넘은 것인지 알 수 없어, 화면에서 무엇을 고쳐야 할지 판단하지 못합니다. 401403은 열쇠 문제, 429는 너무 자주 불렀다는 뜻입니다.

timeout을 반드시 적는 이유도 있습니다. 이 값이 없으면 상대 서버가 답하지 않을 때 Django도 함께 멈춰, 다른 사람의 요청까지 받지 못합니다.

무료 계정의 사용 한도는 넉넉하지 않습니다. 같은 토큰을 여러 사람이 나눠 쓰면 429가 빨리 나타나므로 각자 발급받은 토큰을 씁니다.

2.2 – 질문을 받아 답을 저장하는 자리 만들기

  1. 편집기로 chat/views.py 파일을 엽니다.
  2. 파일 맨 위 불러오기 부분에 두 줄을 더합니다.
from .ai import ChatError, ask_model
from .models import Conversation, Message
  1. ConversationViewSet 클래스 안, 앞서 만든 messages 함수 아래에 아래 내용을 이어 적습니다.
    @action(detail=True, methods=["post"])
    def ask(self, request, pk=None):
        conversation = self.get_object()

        text = (request.data.get("content") or "").strip()
        if not text:
            return Response(
                {"detail": "보낼 내용이 비어 있습니다."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        # 1) 사람이 쓴 글을 먼저 저장합니다.
        Message.objects.create(conversation=conversation, role="user", content=text)

        # 2) 이 방의 지난 대화를 모두 모아 모델에 넘길 모양으로 바꿉니다.
        #    지난 대화를 함께 보내야 모델이 앞 이야기를 이어 갑니다.
        history = [
            {"role": m.role, "content": m.content}
            for m in conversation.messages.all()
        ]

        try:
            answer = ask_model(history)
        except ChatError as err:
            # 모델 호출만 실패한 것이라 사람이 쓴 글은 지우지 않고 남겨 둡니다.
            return Response({"detail": str(err)}, status=status.HTTP_502_BAD_GATEWAY)

        # 3) 받은 답을 저장합니다.
        reply = Message.objects.create(
            conversation=conversation, role="assistant", content=answer
        )

        return Response(
            MessageSerializer(reply).data, status=status.HTTP_201_CREATED
        )
  1. 파일을 저장합니다.

이 자리는 세 가지 일을 이어서 합니다. 사람이 쓴 글을 저장하고, 모델에 물어보고, 받은 답을 다시 저장합니다.

지난 대화를 함께 보내는 이유가 있습니다. 모델은 요청마다 따로 처리하므로 앞에서 무슨 말을 주고받았는지 스스로 기억하지 못합니다. 이 방의 글을 모아 매번 함께 보내야 앞 이야기가 이어집니다.

응답 번호로 502를 쓴 것도 뜻이 있습니다. 우리 서버는 정상인데 중간에서 부른 다른 서버가 실패했다는 뜻이며, 화면에서 “다시 시도” 안내를 띄우기에 알맞습니다.

대화가 길어질수록 매번 보내는 글이 늘어 응답이 느려지고 한도도 빨리 찹니다. 대화가 길어지면 최근 몇 개만 보내거나 앞부분을 요약해 보내는 방법을 씁니다.

2.3 – 브라우저에서 답이 오는지 확인하기

  1. Django 서버를 다시 켭니다.
python manage.py runserver
  1. 브라우저에서 http://127.0.0.1:8000/api/conversations/1/ask/에 접속합니다. 숫자는 실제 대화방 id로 바꿉니다.
  2. 아래 [Raw data] 탭 입력란에 아래 내용을 붙여 넣고 [POST]를 클릭합니다.
{"content": "안녕하세요. 자기소개를 한 문장으로 해 주세요."}

약 3초에서 20초 뒤 HTTP 201 Created와 함께 모델이 만든 문장이 나타납니다. 화면을 고치기 전에 서버 쪽만 먼저 시험하면, 뒤에서 화면이 동작하지 않을 때 문제가 어느 쪽인지 가릅니다. 처음 부르는 모델은 준비하는 데 시간이 더 걸리므로 첫 응답이 가장 느립니다.

  1. http://127.0.0.1:8000/api/conversations/1/로 가서 messages 항목을 봅니다.

사람이 쓴 글과 모델이 쓴 글이 순서대로 들어 있습니다. role 값으로 둘을 가릅니다.

502와 함께 이유가 돌아오면 그 문장이 무엇을 고쳐야 하는지 알려 줍니다. 토큰 문제면 권한 체크를, 한도 문제면 잠시 뒤 재시도를, 연결 문제면 .env의 모델 이름이 실제로 있는 이름인지 확인합니다.

실습 코칭 프롬프트

이 부분을 혼자 해 보다 막히면 아래 프롬프트를 대화형 AI(ChatGPT·Claude·Gemini)에 붙여 넣어 한 단계씩 도움받습니다.

실습에 쓰던 대화창이 아니라 새 대화창에 붙여 넣습니다. 실습 대화창에는 앞서 시킨 다른 지시가 남아 있어, 그 위에 얹으면 답이 뒤섞입니다.

아래는 Django가 모델을 대신 부르게 하기 실습을 혼자 해 보다 막혀서 도움을 받으려는 요청입니다.

지금 하려는 것: ai.py 에 모델 호출 함수를 만들고, /api/conversations/1/ask/ 주소로 질문을 받아 답을 저장하는 것입니다.
지금까지 한 것: {지금까지 한 것}
막힌 지점: {막힌 지점}
화면에 나온 메시지: {에러 메시지}

다음 규칙을 지켜 주세요.
- 정답 코드를 통째로 주지 마세요. 다음 한 단계만 알려 주세요.
- 먼저 왜 막혔는지 짚어 주고, 제가 직접 해 보게 하세요.
- 제가 해 본 결과를 말하면 그때 확인 질문을 던지고 다음 단계로 넘어가세요.
- 제가 놓치기 쉬운 부분이 보이면 마지막에 한 줄로 짚어 주세요.
- 돌아온 응답 번호가 몇 번인지 먼저 확인하고, 그 번호가 뜻하는 원인부터 짚어 주세요.
아래는 Django가 모델을 대신 부르게 하기 실습을 혼자 해 보다 막혀서 도움을 받으려는 요청입니다.

지금 하려는 것: ai.py 에 모델 호출 함수를 만들고, /api/conversations/1/ask/ 주소로 질문을 받아 답을 저장하는 것입니다.
지금까지 한 것: ai.py 를 만들고 views.py 에 ask 함수를 붙였습니다
막힌 지점: 질문을 보내면 답이 안 오고 오류만 돌아옵니다
화면에 나온 메시지: {"detail": "토큰이 올바르지 않거나 권한이 없습니다."}

다음 규칙을 지켜 주세요.
- 정답 코드를 통째로 주지 마세요. 다음 한 단계만 알려 주세요.
- 먼저 왜 막혔는지 짚어 주고, 제가 직접 해 보게 하세요.
- 제가 해 본 결과를 말하면 그때 확인 질문을 던지고 다음 단계로 넘어가세요.
- 제가 놓치기 쉬운 부분이 보이면 마지막에 한 줄로 짚어 주세요.
- 돌아온 응답 번호가 몇 번인지 먼저 확인하고, 그 번호가 뜻하는 원인부터 짚어 주세요.
  1. {지금까지 한 것} — 어느 단계까지 마쳤는지 적습니다. 예: django-admin startproject config . 까지 실행했습니다
  2. {막힌 지점} — 무엇을 하려다 안 됐는지 적습니다. 예: python manage.py runserver 를 실행하면 서버가 바로 꺼집니다
  3. {에러 메시지} — 화면에 나온 글을 그대로 붙여 넣습니다. 없으면 없음이라고 적습니다.

AI가 고친 코드 전체를 한 번에 내놓으면 “코드 전체 말고 어느 줄을 왜 고쳐야 하는지 한 단계만 알려 주세요”라고 되물으십시오. 에러 메시지를 요약해 적으면 원인을 못 짚습니다. 화면에 나온 글을 그대로 붙여 넣습니다.

3 – 화면에 대화창 붙이기

3.1 – 대화방을 열어 글을 보여 주기

  1. 편집기로 frontend/src/App.jsx 파일을 엽니다.
  2. useState 줄 아래에 두 줄을 더합니다.
  // 지금 열어 둔 대화방. 고르지 않았으면 null 입니다.
  const [current, setCurrent] = useState(null);
  // 보내는 중인지 표시하는 자리.
  const [sending, setSending] = useState(false);
  1. renameRoom 함수 아래에 아래 함수를 이어 적습니다.
  // 대화방 하나를 열어 그 안의 글까지 받아 옵니다.
  async function openRoom(id) {
    const res = await fetch(`${API}/conversations/${id}/`);
    setCurrent(await res.json());
  }
  1. 목록 안 방 제목을 버튼으로 바꿉니다.
          <li key={room.id}>
            <button onClick={() => openRoom(room.id)}>{room.title}</button>
            <button onClick={() => renameRoom(room.id, room.title)}>이름 변경</button>
            <button onClick={() => removeRoom(room.id)}>삭제</button>
          </li>
  1. 목록을 감싼 </ul> 아래, </div> 위에 아래 내용을 넣습니다.
      {current && (
        <div>
          <h2>{current.title}</h2>
          {current.messages.map((m) => (
            <p key={m.id}>
              <b>{m.role === "user" ? "나" : "모델"}</b> {m.content}
            </p>
          ))}
        </div>
      )}
  1. 파일을 저장하고 목록에서 방 이름을 클릭합니다.

목록 아래에 그 방의 제목과 지금까지 주고받은 글이 나타납니다. current &&로 감싼 부분은 값이 있을 때만 그려집니다. 방을 고르지 않았을 때 current.title을 읽으려다 오류가 나는 것을 막습니다.

3.2 – 질문을 보내고 답을 받기

  1. openRoom 함수 아래에 아래 함수를 이어 적습니다.
  // 질문을 보내고 답이 오면 대화방을 다시 받아 옵니다.
  async function send(text) {
    if (!text.trim() || sending) return;
    setSending(true);

    try {
      const res = await fetch(`${API}/conversations/${current.id}/ask/`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ content: text }),
      });

      if (!res.ok) {
        const err = await res.json();
        window.alert(err.detail ?? "답을 받지 못했습니다.");
        return;
      }

      // 사람 글과 모델 글이 모두 저장된 상태를 다시 받아 옵니다.
      await openRoom(current.id);
    } finally {
      // 실패하든 성공하든 보내기 표시를 끕니다.
      setSending(false);
    }
  }
  1. 대화 내용을 그리는 부분 아래, 그 </div> 위에 입력란을 넣습니다.
          <input
            id="ask"
            placeholder="질문을 입력합니다"
            disabled={sending}
            onKeyDown={(e) => {
              if (e.key === "Enter") {
                send(e.target.value);
                e.target.value = "";
              }
            }}
          />
          {sending && <p>답을 기다리는 중입니다.</p>}
  1. 파일을 저장하고 입력란에 파이썬이 무엇인지 한 문장으로 설명해 주세요를 입력한 뒤 Enter를 누릅니다.

답을 기다리는 중입니다.라는 줄이 나타났다가, 몇 초 뒤 모델이 쓴 문장이 대화 내용에 붙습니다.

답이 올 때까지 몇 초가 걸리므로 그동안 화면에 표시를 띄웁니다. sending 값을 두는 이유가 있습니다. 답을 기다리는 동안 입력란을 잠그지 않으면 학습자가 여러 번 눌러 같은 질문이 여러 번 저장됩니다. 한도도 그만큼 빨리 찹니다.

finally 블록에 표시를 끄는 코드를 둔 것도 이유가 있습니다. 실패했을 때 표시를 끄지 않으면 입력란이 잠긴 채로 남아 다시 시도할 수 없습니다.

글자가 한 자씩 나타나는 방식은 여기서 다루지 않았습니다. 그 방식은 응답을 조각으로 나눠 받아야 해서 서버와 화면 양쪽 코드가 함께 바뀝니다. 지금 구조가 도는 것을 확인한 뒤에 붙이는 편이 낫습니다.

실습 코칭 프롬프트

이 부분을 혼자 해 보다 막히면 아래 프롬프트를 대화형 AI(ChatGPT·Claude·Gemini)에 붙여 넣어 한 단계씩 도움받습니다.

실습에 쓰던 대화창이 아니라 새 대화창에 붙여 넣습니다. 실습 대화창에는 앞서 시킨 다른 지시가 남아 있어, 그 위에 얹으면 답이 뒤섞입니다.

아래는 화면에 대화창 붙이기 실습을 혼자 해 보다 막혀서 도움을 받으려는 요청입니다.

지금 하려는 것: 대화방을 열어 지난 글을 보여 주고, 입력란에서 질문을 보내 답을 화면에 붙이는 것입니다.
지금까지 한 것: {지금까지 한 것}
막힌 지점: {막힌 지점}
화면에 나온 메시지: {에러 메시지}

다음 규칙을 지켜 주세요.
- 정답 코드를 통째로 주지 마세요. 다음 한 단계만 알려 주세요.
- 먼저 왜 막혔는지 짚어 주고, 제가 직접 해 보게 하세요.
- 제가 해 본 결과를 말하면 그때 확인 질문을 던지고 다음 단계로 넘어가세요.
- 제가 놓치기 쉬운 부분이 보이면 마지막에 한 줄로 짚어 주세요.
- 답을 기다리는 동안 입력란을 잠갔는지, 답이 온 뒤 대화방을 다시 받아 오는지 먼저 확인해 주세요.
아래는 화면에 대화창 붙이기 실습을 혼자 해 보다 막혀서 도움을 받으려는 요청입니다.

지금 하려는 것: 대화방을 열어 지난 글을 보여 주고, 입력란에서 질문을 보내 답을 화면에 붙이는 것입니다.
지금까지 한 것: 대화방을 열어 지난 글을 보여 주는 데까지 됐습니다
막힌 지점: 질문을 보내면 화면이 안 바뀝니다
화면에 나온 메시지: 없음

다음 규칙을 지켜 주세요.
- 정답 코드를 통째로 주지 마세요. 다음 한 단계만 알려 주세요.
- 먼저 왜 막혔는지 짚어 주고, 제가 직접 해 보게 하세요.
- 제가 해 본 결과를 말하면 그때 확인 질문을 던지고 다음 단계로 넘어가세요.
- 제가 놓치기 쉬운 부분이 보이면 마지막에 한 줄로 짚어 주세요.
- 답을 기다리는 동안 입력란을 잠갔는지, 답이 온 뒤 대화방을 다시 받아 오는지 먼저 확인해 주세요.
  1. {지금까지 한 것} — 어느 단계까지 마쳤는지 적습니다. 예: django-admin startproject config . 까지 실행했습니다
  2. {막힌 지점} — 무엇을 하려다 안 됐는지 적습니다. 예: python manage.py runserver 를 실행하면 서버가 바로 꺼집니다
  3. {에러 메시지} — 화면에 나온 글을 그대로 붙여 넣습니다. 없으면 없음이라고 적습니다.

AI가 고친 코드 전체를 한 번에 내놓으면 “코드 전체 말고 어느 줄을 왜 고쳐야 하는지 한 단계만 알려 주세요”라고 되물으십시오. 에러 메시지를 요약해 적으면 원인을 못 짚습니다. 화면에 나온 글을 그대로 붙여 넣습니다.

댓글 남기기