1부 · 컴퓨터는 어떻게 일하는가
코드를 짜기 전에, 코드가 어디서 어떻게 도는지에 대한 큰 그림이 필요합니다. 이 그림이 없으면 나중에 "Python이 없다는데요?", "그 파일을 못 찾는대요" 같은 오류가 그냥 마법처럼 느껴집니다. 큰 그림이 있으면 오류가 "아, 이 조각이 빠졌구나"로 바뀝니다.
이 챕터는 외울 게 아니라 감을 잡는 챕터입니다. 용어 몇 개와 그 관계만 머리에 들어오면 됩니다.
1.1 네 개의 층
컴퓨터에서 무언가가 실행될 때는 보통 네 개의 층이 위아래로 쌓여 일합니다.
flowchart TB
A["① 하드웨어<br/>CPU·메모리·디스크"] --> B["② 운영체제 (OS)<br/>Windows·macOS·Linux"]
B --> C["③ 프로그램·앱<br/>크롬·터미널·Python"]
C --> D["④ 내가 만든 코드<br/>app.py 같은 파일"]
classDef hw fill:#E6D6FF,stroke:#7C4DBC,color:#000
classDef os fill:#E6D6FF,stroke:#7C4DBC,color:#000
classDef app fill:#C8F0E8,stroke:#2BA88E,color:#000
classDef mine fill:#CDE7FF,stroke:#3B82C4,color:#000
class A hw
class B os
class C app
class D mine
하나씩 풀어보겠습니다.
① 하드웨어는 물리적인 부품입니다. 계산을 하는 CPU(중앙처리장치), 지금 작업 중인 내용을 잠깐 올려두는 메모리(RAM), 끄고 켜도 내용이 남는 저장 공간인 디스크(SSD/HDD)가 핵심입니다. 메모리와 디스크의 차이는 뒤에서 다시 짚습니다 — 입문자가 가장 자주 헷갈리는 지점입니다.
② 운영체제(OS, operating system)는 하드웨어를 직접 다루는 대장 프로그램입니다. Windows, macOS, Linux가 대표적입니다. 우리가 "파일을 저장한다", "프로그램을 실행한다"고 할 때 실제로 디스크와 CPU에 명령을 내리는 건 OS입니다. 우리는 OS에게 부탁하고, OS가 하드웨어를 부립니다.
③ 프로그램·앱은 OS 위에서 도는 소프트웨어입니다. 웹 브라우저, 메모장, 그리고 우리가 곧 만날 터미널과 Python도 전부 프로그램입니다. 중요한 통찰 하나: Python은 "언어"이기도 하지만, 동시에 설치해야 쓸 수 있는 하나의 프로그램이기도 합니다. 이 점이 5부에서 "Python을 설치한다"는 말의 의미로 이어집니다.
④ 내가 만든 코드는 app.py 같은 텍스트 파일입니다. 그 자체로는 그냥 글자 뭉치입니다. 이걸 ③의 프로그램(Python)이 읽어서 실행해 줍니다. 코드는 요리 레시피, Python은 그 레시피를 보고 실제로 요리하는 요리사라고 생각하면 됩니다.
콜아웃 · 왜 이 층 구분이 중요한가
나중에 "command not found: python" 같은 오류를 만나면, 이건 ③층(프로그램)이 빠졌다는 뜻입니다. "No such file or directory"는 ④층 파일을 OS가 못 찾는다는 뜻이고요. 오류를 층으로 번역하는 습관이 디버깅의 절반입니다.
1.2 메모리 vs 디스크 — 가장 흔한 혼동
입문자가 거의 항상 헷갈리는 두 가지가 메모리(RAM)와 디스크입니다. 이름은 둘 다 "저장"처럼 들리지만 역할이 완전히 다릅니다.
| 메모리 (RAM) | 디스크 (SSD/HDD) | |
|---|---|---|
| 비유 | 작업용 책상 | 책장·서랍 |
| 속도 | 매우 빠름 | 상대적으로 느림 |
| 크기 | 작음 (예: 16GB) | 큼 (예: 512GB~) |
| 전원을 끄면 | 사라짐 | 남음 |
| 쓰임 | 지금 실행 중인 프로그램·데이터 | 파일·프로그램을 보관 |
요점은 "전원을 끄면 메모리는 비고, 디스크는 남는다"입니다. 그래서 작업한 파일을 저장(save)하지 않고 컴퓨터를 끄면 날아갑니다 — 책상(메모리) 위에만 있던 내용을 책장(디스크)에 옮겨 적지 않았기 때문입니다. "저장"이란 곧 메모리 → 디스크로 옮겨 적는 행위입니다.
이 비유는 단순화입니다. 실제로는 캐시·가상메모리 등 층이 더 있지만, 입문 단계에서는 "책상 vs 책장"으로 충분합니다.
콜아웃 · RAG에서 이 구분이 실제로 문제가 되는 순간
나중에 RAG에서 문서 수천 개를 임베딩해 메모리에 올리면, "책상"(RAM)이 가득 차서 프로그램이 느려지거나 멈출 수 있습니다. 반대로 한 번 만든 임베딩을 디스크(또는 벡터 DB)에 저장해두지 않으면, 프로그램을 끌 때마다 비싼 계산을 처음부터 다시 해야 합니다. "무엇을 메모리에 두고, 무엇을 디스크에 저장할까"는 RAG 설계의 단골 고민입니다. 지금은 이 둘이 다르다는 감각만 챙기면 됩니다.
1.3 컴퓨터 안에서는 모든 것이 숫자다
이건 나중에 RAG의 핵심(임베딩)을 이해하는 데 결정적인 감각이라 미리 짚습니다. 컴퓨터는 글자도, 그림도, 소리도 직접 다루지 못합니다. 컴퓨터가 아는 건 0과 1뿐입니다. 이 0 또는 1 하나를 비트(bit), 비트 8개 묶음을 바이트(byte)라고 합니다.
그래서 우리가 보는 모든 것은 일단 숫자로 번역되어 저장됩니다. 글자도 예외가 아닙니다. 예를 들어 영어 대문자 A는 약속에 따라 숫자 65로, 한글 가도 정해진 숫자로 저장됩니다. 이 "글자 ↔ 숫자" 약속표가 2.8에서 만날 인코딩입니다.
flowchart LR
A["글자 'A'"] --> B["약속표(인코딩)로<br/>번역"] --> C["숫자 65"] --> D["0과 1<br/>01000001"]
classDef text fill:#FFF3B0,stroke:#C9A227,color:#000
classDef step fill:#CDE7FF,stroke:#3B82C4,color:#000
classDef num fill:#C8F0E8,stroke:#2BA88E,color:#000
class A text
class B step
class C,D num
여기서 한 걸음 더. 글자 하나가 숫자 하나라면, 문장이나 문서 전체도 숫자들의 묶음으로 바꿀 수 있지 않을까요? RAG의 심장인 임베딩(embedding)이 바로 이 발상입니다 — "고양이"라는 단어나 한 문단을, 그 의미를 담은 숫자들의 줄(벡터)로 바꾸는 것이죠. 위의 A=65는 단순한 글자-번호 약속이고, 임베딩은 훨씬 정교하게 "뜻이 비슷하면 숫자도 가깝게" 만든다는 차이가 있지만, "결국 다 숫자로 바뀐다"는 큰 그림은 같습니다. 지금은 이 직관 하나면 충분합니다. (임베딩의 진짜 원리는 RAG 안내서에서 자세히 다룹니다.)
파일 크기 단위도 바이트에서 옵니다. 1킬로바이트(KB)≈1,000바이트, 1메가바이트(MB)≈100만 바이트, 1기가바이트(GB)≈10억 바이트. 텍스트 문서는 보통 수십 KB, 이미지는 수 MB, 영상은 수백 MB~GB입니다. RAG에서 "이 PDF가 2MB"라면 대략 200만 글자분의 정보량이라고 어림할 수 있습니다.
1.4 CPU는 결국 "한 줄씩" 처리한다
CPU가 하는 일은 생각보다 단순합니다. 아주 작은 명령(숫자 더하기, 값 비교하기, 메모리에서 값 가져오기 같은 것)을 엄청나게 빠른 속도로 한 줄씩 처리하는 것입니다. 우리가 보기엔 영상이 재생되고 웹페이지가 뜨고 RAG가 답을 내놓지만, 그 밑은 전부 이런 단순 명령 수십억 개의 연속입니다.
그래서 코드를 짠다는 건 결국 "CPU가 차례로 따라갈 명령의 순서를 글로 적는 일"입니다. 우리가 Python으로 "파일을 읽고 → 한 줄씩 잘라 → API에 보내라"라고 쓰면, 그게 더 잘게 쪼개진 명령들로 번역되어 CPU가 위에서 아래로 밟아갑니다. 이 "위에서 아래로, 한 줄씩"이라는 감각은 4부에서 코드 실행을 이해할 때 그대로 쓰입니다.
한 가지 직관: 컴퓨터는 "똑똑해서" 일을 하는 게 아니라, "엄청 빠르고 시키는 대로 정확히" 일을 합니다. 그래서 우리가 명령을 조금만 틀리게 적어도(오타·순서 실수) 그대로 틀리게 실행됩니다. 6부에서 다룰 오류 대부분이 여기서 옵니다.
1.5 네트워크 — 다른 컴퓨터에 부탁하기
지금까지는 내 컴퓨터 한 대 이야기였습니다. 그런데 RAG를 포함한 거의 모든 현대 프로그램은 다른 컴퓨터와 대화합니다. 임베딩을 만들어 주는 서버, 답을 생성하는 LLM, 웹페이지를 주는 서버 — 전부 인터넷 너머의 다른 컴퓨터입니다.
이 "다른 컴퓨터에 부탁하고 결과를 받는" 일을 네트워크 요청(request)이라고 합니다. 부탁을 받는 쪽을 서버(server), 부탁하는 쪽(내 프로그램)을 클라이언트(client)라고 부릅니다.
flowchart LR
A["내 프로그램<br/>(클라이언트)"] -->|"① 요청<br/>이 문장 임베딩해줘"| B["인터넷 너머<br/>서버 (API)"]
B -->|"② 응답<br/>벡터 [0.1, -0.3, ...]"| A
classDef client fill:#C8F0E8,stroke:#2BA88E,color:#000
classDef server fill:#CDE7FF,stroke:#3B82C4,color:#000
class A client
class B server
여기서 두 가지를 미리 알아두면 좋습니다. 첫째, 네트워크 요청은 내 컴퓨터 안의 계산보다 훨씬 느리고(수백 밀리초~수 초), 가끔 실패합니다(인터넷 끊김, 서버 혼잡). 그래서 RAG 코드에는 "느릴 수 있다", "실패하면 어떻게 한다"는 처리가 종종 들어갑니다. 둘째, 남의 서버(API)를 쓰려면 보통 인증 키(API key)가 필요하고, 이 키는 코드에 직접 박지 않고 환경변수로 다룹니다 — 이건 4부에서 자세히 봅니다.
API라는 말: API(application programming interface)는 "프로그램끼리 약속된 방식으로 부탁을 주고받는 창구"입니다. 식당의 메뉴판에 비유하면, 우리는 메뉴판에 적힌 방식대로 주문(요청)하고 음식(응답)을 받습니다. 주방이 어떻게 돌아가는지는 몰라도 됩니다. RAG에서 임베딩 API, LLM API를 쓴다는 건 이런 창구로 부탁한다는 뜻입니다.
1.6 프로그램이 "돈다"는 게 무슨 뜻인가
디스크에 가만히 놓인 프로그램 파일은 아직 아무 일도 하지 않습니다. 더블클릭하거나 터미널에서 이름을 입력해 실행(run)하면, OS가 그 파일을 디스크에서 읽어 메모리로 올리고 CPU가 그 명령들을 한 줄씩 처리하기 시작합니다. 이렇게 메모리 위에서 살아 움직이는 프로그램의 한 인스턴스를 프로세스(process)라고 부릅니다.
flowchart LR
A["디스크 위의<br/>프로그램 파일<br/>(잠든 상태)"] -->|실행| B["메모리로 로드"]
B --> C["CPU가 한 줄씩 처리<br/>= 프로세스 (살아 움직임)"]
C -->|끝나거나 종료| D["프로세스 사라짐<br/>메모리 반환"]
classDef file fill:#E6D6FF,stroke:#7C4DBC,color:#000
classDef run fill:#C8F0E8,stroke:#2BA88E,color:#000
classDef done fill:#D7F2C8,stroke:#5BA63B,color:#000
class A file
class B,C run
class D done
같은 프로그램을 여러 번 실행하면 프로세스도 여러 개 생깁니다(크롬 창을 여러 개 켠 것처럼). 프로그램이 멈추거나 우리가 종료하면 그 프로세스는 사라지고 쓰던 메모리를 OS에 돌려줍니다.
1.7 우리가 코드로 시키는 일의 종류
개발에서 코드가 하는 일은 결국 몇 가지 기본 동작의 조합입니다. 지금 외울 필요는 없지만, 이런 게 있다는 것만 알아두면 좋습니다.
| 동작 | 무슨 뜻 | RAG에서의 예 |
|---|---|---|
| 읽기/쓰기 | 디스크의 파일을 읽거나 새로 쓴다 | PDF·문서를 읽어들임, 임베딩을 파일로 저장 |
| 네트워크 | 다른 컴퓨터(서버)에 부탁하고 받는다 | 임베딩 API·LLM API 호출 |
| 계산·변형 | 받은 데이터를 자르고·비교하고·바꾼다 | 문서를 청크로 자름, 벡터 유사도 계산 |
| 출력 | 결과를 화면이나 파일로 내보낸다 | 생성된 답과 출처를 보여줌 |
RAG 시스템도 결국 이 네 가지의 조합입니다 — 문서를 읽고(읽기), 임베딩 API에 보내고(네트워크), 벡터를 비교하고(계산), 답을 출력하는(출력) 흐름이죠. 앞으로 어떤 복잡한 코드를 보더라도 "이 줄은 이 네 가지 중 뭘 하고 있나?"로 분해해 보면 한결 읽기 쉬워집니다.
직접 해보기
설치나 터미널 없이, 지금 컴퓨터로 1.1~1.2의 감을 확인해 봅니다.
- 작업 관리자를 열어 프로세스를 봅니다.
Windows에서 Ctrl + Shift + Esc를 누르세요. (macOS는 "활성 상태 보기"/Activity Monitor 앱, Linux는 시스템 모니터 또는 터미널의 top.)
"프로세스" 탭에 지금 메모리 위에서 살아 움직이는 프로그램들(1.6의 프로세스)이 보입니다. 크롬을 여러 창 켜두었다면 크롬이 여러 줄로 나올 수 있습니다.
- 메모리 사용량을 봅니다.
같은 창에서 "성능" 탭 → "메모리"를 보세요. 지금 책상(RAM) 위에 얼마나 올라와 있는지 숫자로 보입니다.
- 메모리 vs 디스크를 직접 느껴봅니다.
메모장(또는 아무 메모 앱)을 열고 아무 글자나 칩니다. 아직 저장하지 않은 이 글자는 메모리에만 있습니다. 저장(Ctrl + S)하는 순간 디스크로 옮겨 적힙니다. 저장 안 하고 닫으면 "변경 내용을 저장할까요?"가 뜨는 이유가 바로 이것입니다.
- 네트워크 요청을 눈으로 봅니다.
웹 브라우저에서 아무 사이트나 연 뒤 F12(개발자 도구)를 누르고 "네트워크(Network)" 탭을 열어 페이지를 새로고침해 보세요. 한 페이지를 띄우려고 브라우저가 서버에 수많은 요청을 보내고 응답을 받는 게 줄줄이 보입니다. 1.5의 "클라이언트 ↔ 서버"가 실제로 일어나는 모습입니다. 각 줄의 시간(ms)을 보면 네트워크가 왜 "느리다"고 했는지도 느껴집니다.
이 챕터 한 줄 정리
하드웨어 위에 OS가, OS 위에 프로그램이, 프로그램이 내 코드를 실행한다. 메모리는 끄면 비는 책상, 디스크는 남는 책장이고, CPU는 명령을 한 줄씩 빠르게 밟아가며, 네트워크로는 인터넷 너머 다른 컴퓨터(서버)에 부탁한다.
다음 챕터에서는 그 "책장"의 구조, 즉 파일·폴더·경로를 다룹니다. 경로를 이해하는 것이 개발 입문의 첫 번째 큰 산입니다.