LLM으로 소프트웨어 개발하기: 프롬프트 엔지니어링과 대화형 코딩 나눠 쓰는 법

LLM 기반 개발에서 프롬프트 엔지니어링과 대화형 개발을 언제 나눠 쓰는지, 스펙 작성부터 검증까지의 워크플로우와 흔한 실수 패턴을 정리한다.

2026-08-12 · 최초 발행 2026-03-19

PyTorch KR을 비롯한 커뮤니티에서 반복적으로 나오는 질문이 있다. LLM을 도입했는데 왜 생산성이 기대만큼 오르지 않느냐는 것이다. 답은 대체로 도구가 아니라 사용 방법에 있다. LLM을 프롬프트 한 번으로 완성품을 뽑아내는 자판기처럼 쓰는 팀과, 스펙을 정리하고 단계별로 검증하며 쓰는 팀 사이의 결과 차이는 크다.

LLM 개발 도구, 지금 어디까지 왔나

2026년 3월 기준으로 시장에 나와 있는 도구를 성격별로 나누면 이렇다.

  • 코드 생성 LLM: GPT-4o, Claude 3.7 Sonnet, Gemini 2.0 Pro 등 멀티모달 지원 모델
  • IDE 통합 도구: GitHub Copilot, Cursor, Windsurf, JetBrains AI Assistant
  • 에이전트형 도구: Devin, SWE-agent, OpenHands 등 자율 코딩 에이전트가 성숙기에 접어들었다
  • 로컬 LLM: Ollama와 Qwen2.5-Coder, DeepSeek-Coder-V3 조합 등 온프레미스 옵션이 확장되는 중이다

LLM이 잘하는 일과 못하는 일

같은 LLM이라도 작업 성격에 따라 결과 편차가 크다.

영역 잘 함 한계 있음
단순 코드 생성 보일러플레이트, CRUD, 유틸함수 복잡한 도메인 로직
문서화 주석, README, API 문서 비즈니스 맥락 반영
테스트 생성 유닛 테스트 케이스 경계 조건 완전 커버
리팩토링 패턴 개선 제안 전체 아키텍처 재설계
디버깅 에러 메시지 분석, 원인 추론 멀티스레드·레이스 컨디션

이 표를 뒤집어 보면 개발 사이클 전체를 하나의 루프로 그릴 수 있다. 개발자 의도가 스펙 문서로 정리되고, LLM이 코드를 생성하면 인간이 검증하고, 통과하지 못하면 피드백이 다시 LLM으로 돌아간다. 배포 이후 이슈가 생기면 디버깅도 같은 루프를 탄다.

아니오아니오개발자 의도스펙 문서 작성LLM 코드 생성코드 리뷰 검증통과?통합 테스트피드백 제공배포모니터링이슈 발생?LLM 디버깅 지원완료

프롬프트 한 방 vs 대화로 풀어가기

단발성 프롬프트가 맞는 경우

상세한 요구사항을 한 프롬프트에 담아 완성된 결과물을 한 번에 얻으려는 접근이다. 독립적인 함수, 알고리즘 구현, 변환 로직처럼 경계가 뚜렷한 작업에 적합하다. 잘 쓰려면 입출력 예시를 few-shot으로 보여주고, 언어·라이브러리·성능 같은 제약 조건을 명시하고, 역할을 부여하고("당신은 Python 시니어 엔지니어입니다"), 필요하면 단계별 사고(Chain-of-Thought)를 유도한다.

좋은 프롬프트는 대략 이런 모양이다.

역할: Python 백엔드 개발자 (FastAPI, SQLAlchemy 사용)
작업: 사용자 인증 미들웨어 구현
요구사항:
- JWT Bearer 토큰 검증
- 토큰 만료 시 401 반환
- 사용자 ID를 request.state에 주입
- Redis 기반 토큰 블랙리스트 확인
제약: Python 3.12, pydantic v2, 외부 라이브러리 최소화
테스트 케이스: 유효 토큰, 만료 토큰, 블랙리스트 토큰 각각 포함

대화형 개발이 맞는 경우

초안을 뽑은 뒤 반복적인 피드백으로 다듬어가는 접근이다. 복잡한 비즈니스 로직, 아키텍처 설계, 레거시 코드 이해처럼 한 번에 정답이 나오기 어려운 작업에 맞는다. 세션 안에서 이전 코드를 계속 참조하도록 컨텍스트를 누적시키고, 요구사항을 단계적으로 추가하며, "이전 코드에서 X 부분만 수정" 식으로 범위를 좁혀 지시하고, 중간 결과물마다 구체적인 피드백을 준다.

프롬프트 엔지니어링과 대화형 개발을 섞어 쓰는 법

실무에서는 어느 한쪽만 쓰기보다 단계별로 조합하는 편이 낫다. 설계 단계는 대화형으로 아키텍처를 탐색해 구조를 합의하고, 구현 단계는 프롬프트 엔지니어링으로 개별 컴포넌트를 뽑아내고, 통합 단계는 다시 대화형으로 연결 로직과 오류를 처리한다.

스펙부터 쓰고 시작한다

LLM 기반 개발에서 가장 중요한 단계는 코딩이 아니라 스펙 작성이다. 명확한 스펙 없이 시작하면 LLM은 십중팔구 엉뚱한 방향으로 코드를 만들어낸다. 효과적인 스펙 문서는 다섯 가지를 담는다.

  • 기능 요약: 1~2문장으로 핵심 목적을 기술
  • 입출력 명세: 타입, 형식, 예외 케이스 포함
  • 비기능 요구사항: 성능, 보안, 확장성 기준
  • 의존성: 사용 라이브러리, 외부 시스템
  • 제외 범위: 명시적으로 구현하지 않을 것들

구현 단계는 순서를 지키는 게 도움이 된다. 함수 시그니처와 클래스 인터페이스를 먼저 LLM과 합의하고(인터페이스 먼저), TDD 방식으로 테스트 케이스를 LLM이 먼저 생성하게 하고(테스트 먼저), 그 테스트를 통과하는 구현 코드를 생성한 다음, 생성된 코드를 LLM에게 다시 리뷰 요청한다. 컨텍스트는 파일 단위로 분리해 토큰 한계에 대응하고, 핵심 인터페이스 정의는 항상 컨텍스트에 포함하며, 이전 세션의 결정사항은 요약 문서로 남겨둔다.

검증 단계에서는 LLM이 생성한 코드에 대해 LLM이 테스트도 생성하는 상호 검증을 활용하고, "보안 취약점", "성능 병목", "엣지 케이스" 관점을 나눠 코드 리뷰를 요청하고, mypy·ruff·eslint 같은 정적 분석 결과를 LLM에 피드백해 자동 수정을 유도한다. 다만 비즈니스 로직의 정확성만큼은 반드시 인간이 최종 확인해야 한다.

디버깅과 리팩토링, LLM을 어떻게 부릴까

에러 분석을 요청할 때는 에러 메시지 전문, 관련 코드, 실행 환경, 재현 조건을 빠짐없이 넘기는 게 핵심이다.

다음 에러와 코드를 분석하여 원인과 수정 방법을 알려주세요.

에러 메시지:
[에러 전문 붙여넣기]

관련 코드:
[문제 발생 코드 스니펫]

실행 환경:
- Python 3.12 / Node.js 22
- 관련 라이브러리 버전

재현 조건:
[에러가 발생하는 구체적 조건]

에러 메시지를 자르지 말고 전문을 전달해야 LLM이 스택 트레이스를 제대로 분석한다. "왜 이런 에러가 발생하는지" 설명을 먼저 요청하고 그다음 수정 코드를 요청하면 이해 없이 땜질하는 것을 피할 수 있다. 수정 후에도 같은 에러가 나면 "이전 수정이 효과 없었다"고 명시적으로 알려야 LLM이 같은 답을 반복하지 않는다.

리팩토링은 목적별로 지시를 구체화한다. 가독성 개선은 "기능은 동일하게, 더 읽기 쉽게", 성능 최적화는 "O(n²) 복잡도를 줄이는 방향으로", 패턴 적용은 "이 코드에 Strategy 패턴 적용 방법 제안", 레거시 현대화는 "Python 2 스타일을 Python 3.12 방식으로 변환" 식이다. 리팩토링 후에는 기존 테스트가 모두 통과하는지, 성능 프로파일링 결과가 나빠지지 않았는지, API 호환성이 유지되는지, 코드 커버리지가 유지되거나 향상됐는지를 체크리스트로 확인한다.

프로젝트 규모별로 도구를 다르게 골라야 하는 이유

소규모 프로젝트(개인·스타트업 초기)는 Cursor + Claude 3.7 Sonnet 조합이 무난하다. 단일 파일이나 소수 파일 컨텍스트로 전체 프로젝트를 파악할 수 있고, API 직접 호출보다 구독형 플랜이 비용 면에서 유리하다. 다만 LLM 의존도가 과해지면 정작 개발자 본인의 코드 이해도가 떨어질 수 있으니 주의가 필요하다.

중규모 프로젝트(팀 단위, 10~50명)는 GitHub Copilot Enterprise와 사내 LLM 가이드라인을 함께 두는 편이 낫다. PR 리뷰 자동화와 코드 리뷰 보조가 워크플로우의 중심이 되고, 프롬프트 템플릿 라이브러리를 팀 표준으로 공유하며, 인증·결제 같은 민감 코드는 LLM 전송을 제한하는 보안 정책이 필요하다.

대규모 프로젝트(엔터프라이즈, 50명 이상)는 Azure OpenAI나 AWS Bedrock 같은 사내 구축 LLM 서버와 IDE 플러그인 조합으로 간다. CI/CD 파이프라인에 LLM 코드 리뷰를 통합하고, LLM 사용 감사 로그와 지식재산권 정책 같은 거버넌스를 갖추고, 사내 코드베이스 기반 RAG로 컨텍스트 정확도를 높인다.

1~5명10~50명50명 이상프로젝트 규모 판단 규모Cursor / Claude API 직접활용GitHub Copilot Enterprise사내 LLM 인프라 구축개인 생산성 극대화 워크플로우 표준화보안 거버넌스 중심빠른 프로토타이핑코드 리뷰 자동화RAG 기반 사내 지식 통합

도구별로 비용과 특성을 비교하면 다음과 같다(2026년 3월 기준).

도구 강점 약점 월 비용
GitHub Copilot IDE 통합, 팀 관리 컨텍스트 창 제한 $19~39/인
Cursor 멀티파일 컨텍스트 개인용 최적화 $20~40/인
Windsurf 에이전트형 작업 상대적으로 신생 $15~35/인
Claude API 직접 유연성, 비용 통제 직접 통합 필요 사용량 기반
로컬 LLM (Ollama) 보안, 무료 성능 제한 서버 비용만

LLM 개발에서 흔히 저지르는 실수

LLM 맹신(Blind Trust) — 생성된 코드를 검토 없이 바로 커밋하면 보안 취약점, 미묘한 로직 버그, 존재하지 않는 라이브러리 사용으로 이어진다. 모든 LLM 생성 코드에 최소 1회 인간 리뷰를 의무화하는 게 대응이다.

컨텍스트 오염(Context Pollution) — 한 세션에서 너무 많은 주제를 다루면 LLM이 이전 코드와 혼용해 불일치 코드를 만든다. 기능 단위로 새 세션을 시작하고 핵심 컨텍스트만 요약해서 전달한다.

과도한 추상화 요청 — "확장 가능하고 유연한 범용 프레임워크 만들어줘" 같은 요청은 필요 이상으로 복잡한 코드와 과도한 보일러플레이트를 낳는다. YAGNI 원칙을 적용해 현재 요구사항만 구현하도록 명시한다.

디버깅 루프(Debug Loop) — 같은 에러를 LLM에게 계속 물어보며 해결하지 못하는 상태는 시간 낭비와 품질 저하로 이어진다. 3회 시도 후에는 다른 접근법을 쓰거나 인간 동료에게 넘긴다.

할루시네이션 API 사용 — LLM이 존재하지 않는 함수나 라이브러리를 자신 있게 제안하는 경우가 있다. 런타임 에러와 의존성 문제로 이어지므로 공식 문서 확인은 필수이고, "공식 문서 URL도 알려줘"라고 요청해 검증 경로를 남기는 게 좋다.

안전하게 쓰려면 몇 가지 습관을 지킨다. LLM이 생성한 코드도 작성자가 완전히 이해하고 있어야 하고(코드 소유권 유지), 대규모 생성 코드를 한 번에 들이지 않으며(점진적 통합), 커밋 메시지로 LLM 생성 이력을 명시적으로 추적하고(버전 관리), 구현 전에 테스트 케이스부터 만들게 해 명세 역할을 시키고(테스트 선행), 인증·암호화·결제 관련 코드는 LLM 보조를 최소화한다(보안 민감 코드 분리).

결국 남는 건 사고 능력이다

LLM은 코드를 대신 써주는 도구가 아니라 개발자의 의도를 코드로 빠르게 변환해주는 협업 파트너에 가깝다. 명확한 스펙, 단계적 검증, 인간의 최종 판단이 결합될 때 비로소 생산성이 오른다. 문제를 정확히 정의하고 검증하는 능력은 여전히 개발자 몫이고, LLM은 그 능력을 증폭시키는 도구일 뿐이다.

Sources

LLM 개발프롬프트 엔지니어링대화형 개발코드 리뷰AI 페어프로그래밍