SONUB
KO English 한국어 日本語 中文 हिन्दी বাংলা اردو Español Português Français Deutsch Русский العربية Bahasa Indonesia Tiếng Việt ไทย Türkçe

알림을 켜는 방법

이 브라우저 또는 주소에서는 알림을 사용할 수 없습니다. 지원되는 브라우저로 보안 연결된 SONUB 사이트에 접속해 주세요.

알림이 차단되어 있으면 브라우저 설정에서 허용해 주세요.

  1. 주소 표시줄 옆의 사이트 설정 또는 브라우저의 사이트 설정을 열고, 이 사이트의 알림을 허용으로 바꾸세요.
  2. 기기 설정에서 브라우저 알림을 허용하고 방해 금지 또는 집중 모드를 확인하세요.
  3. SONUB으로 돌아와 페이지를 새로고침하세요. 알림이 켜지면 벨은 사라집니다.

iPhone 또는 iPad에서는 SONUB을 홈 화면에 추가하고 거기에서 연 뒤 알림을 허용하세요.

로그인 로그아웃 화면 테마 기본 테마 다크 테마 핑크 테마 채팅 1:1 채팅 그룹 채팅 게시판 공지사항 뉴스 게시판 건의 게시판 자기소개 게시판 메인 메뉴

자, 이제 여러분들만의 인공지능을 만들어 봅시다.

대화 을 직접 만들어 전체 흐름을 완성합니다. xchat.py 로 질문을 보내 내 와 직접 한 이 답하게 해 보세요.

단어 블록이 한 줄로 놓여 있고 끝에 빈칸이 있다. 빈칸 위에 높이가 다른 막대를 단 후보 블록 세 개가 있고, 그중 하나가 골라져 줄 끝에 붙은 뒤 화살표가 다시 처음으로 돌아가 다음 칸을 고른다.
9

XChat 만들기

은 대화 화면, 는 실행 서비스, 은 한 입니다. xchat.py는 질문을 읽어 학습 형식을 붙이고 요청을 보낸 뒤 결과를 보여 줍니다. 모델을 직접 불러오거나 답을 스스로 만들어 내지 않습니다.

첫 XChat은 안에서 실행합니다. 지금은 을 보내지 않아 질문마다 독립적입니다. 다음 도전은 작은 길이에 맞게 대화 기록을 붙이는 것입니다. 유창함보다 내가 만든 모델까지 요청이 실제로 왕복하는지가 완성 기준입니다.

요청이 지나가는 길 — XChat 에서 가중치까지

XChat 에 hi 를 치고 Enter 를 누르면 이런 일이 차례로 일어납니다.

  • xchat.py 가 질문을 학습 형식으로 감쌉니다. "Q: hi" 다음 줄에 "A: ".
  • {"": …, "": 24} 를 만들어 http://127.0.0.1:8765/generate 로 합니다.
  • Runner 의 do_POST 가 본문을 읽고 검사한 뒤 generate 를 부릅니다.
  • generate 가 로 번호를 만들고, 의 로 토큰을 하나씩 뽑고, 에서 멈춥니다.
  • Runner 가 {"text": …} 로 응답하고, xchat.py 가 XSLM> 뒤에 보여 줍니다.

이 길의 어느 한 곳이 끊기면 대화가 안 됩니다. 그래서 문제가 생기면 길을 따라 하나씩 확인합니다. Runner 가 켜져 있나( ), 생성이 되나(curl /generate), XChat 의 주소와 가 맞나.

XChat 클라이언트 — 입력 루프와 HTTP 요청

xchat.py 는 두 부분입니다.

  • ask(question): 요청 하나를 보내고 답을 돌려줍니다. Request 로 주소·본문·헤더를 담은 POST 요청을 만들고, 으로 보낸 뒤 json.load 로 응답 본문을 읽어 text 를 꺼냅니다. timeout=120 은 2분 안에 답이 없으면 포기한다는 뜻입니다. 느린 에서 긴 생성을 기다릴 수 있게 넉넉히 잡았습니다.
  • 입력 루프: while True 로 계속 You> 를 보여 주며 한 줄씩 읽습니다. /exit 이면 끝내고, 빈 줄은 건너뛰고, 나머지는 ask 에 넘겨 XSLM> 뒤에 답을 찍습니다.

질문마다 settings.json 을 다시 읽습니다. 프롬프트 형식("Q: " … "A: ")은 가 붙입니다. 가 형식을 붙이도록 만들면 클라이언트는 형식을 몰라도 됩니다. 어느 쪽이든 형식은 한 곳에서만 정해야 어긋나지 않습니다.

오류 다루기 — 가짜 답을 만들지 않는다

xchat.py 는 오류를 이렇게 나눠 다룹니다.

  • EOFError·KeyboardInterrupt: (입력 끝)나 를 누른 것입니다. 루프를 끝내고 로 돌아갑니다.
  • URLError: Runner 에 연결하지 못했습니다( 등). Runner 가 꺼져 있거나 포트가 다릅니다.
  • HTTPError: 연결은 됐지만 Runner 가 400 같은 오류 코드로 답했습니다. URLError 의 한 종류라 같은 줄에서 잡힙니다.
  • TimeoutError: 정한 시간 안에 답이 오지 않았습니다.

어느 경우든 "Runner: 오류 내용" 을 보여 주고 다음 질문을 기다립니다. 연결이 안 될 때 미리 정해 둔 문장을 대신 보여 주는 식으로 감추지 않습니다. 그래야 무엇이 고장 났는지 바로 압니다. Runner 를 끄고 질문해 보고(오류가 나야 정상), 다시 켜서 대화가 돌아오는지 확인하세요.

대화 기록 붙이기 — 문맥 길이의 한계

지금 XChat 은 질문마다 독립적입니다. 앞에서 한 말을 모델이 모릅니다. 실제 이 앞 대화를 기억하는 것처럼 보이는 까닭은, 매번 지난 대화 전체를 프롬프트 앞에 붙여 보내기 때문입니다. 모델 자체에는 기억이 없습니다.

XSLM 으로 해 보면 곧 벽에 부딪힙니다. 아래 실험은 대화 한 번(Q: hi / A: hi friend.) 뒤에 새 질문 cat 을 붙입니다. 프롬프트는 21토큰인데 모델은 마지막 12토큰만 보므로, 실제로 보는 글은 "iend." 부터입니다. 앞 대화는 잘려 나갑니다.

그래서 대화 기록을 붙이려면 이런 일을 함께 합니다.

  • 오래된 대화부터 버려 문맥 길이 안에 맞춥니다.
  • context 를 키운 모델을 새로 학습합니다(위치 표가 커지고 계산이 느려집니다).
  • 에도 여러 차례 이어진 대화를 넣어야 모델이 그 모양을 배웁니다.

다음 도전: xchat.py 에 history 목록을 두고 지난 질문·답을 붙여 보내 보세요. 토큰 수를 세어 12를 넘으면 앞부분을 버리게 만듭니다.

직접 확인하기 lab/context.py
import json
from pathlib import Path
from tokenizer import BPE

tok = BPE(**json.loads(Path('data/tokenizer.json').read_text()))
size = json.loads(Path('settings.json').read_text())['context']
history = 'Q: hi\nA: hi friend.\nQ: cat\nA: '
ids = tok.encode(history)
print(len(ids), 'tokens; the model sees the last', size)
print(repr(tok.decode(ids[-size:])))
cd ~/xslm
mkdir -p lab
micro lab/context.py
python3 -m lab.context

실행 결과

21 tokens; the model sees the last 12
'iend.\nQ: cat\nA: '

실제 대화 모델은 어떻게 만드나 — 사전 학습 다음 단계

XSLM 은 Q/A 형식의 글로 처음부터 학습했습니다. · 같은 대화 모델은 보통 여러 단계를 거칩니다.

  • (pre-training): 아주 많은 글로 다음 토큰 맞히기를 합니다. XSLM 의 train.py 가 하는 일과 같고 규모만 다릅니다.
  • (SFT, instruction tuning): 질문과 좋은 답의 쌍으로 더 학습해 지시를 따르는 습관을 들입니다. 사용자·도우미 차례를 나누는 대화 형식()도 이때 익힙니다.
  • 선호 학습( 등): 사람이 더 낫다고 고른 답 쪽으로 기울도록 다듬습니다.

최신 정보가 필요하면 다시 학습하는 대신 를 씁니다. 질문으로 문서를 검색해 찾아 프롬프트에 함께 넣고, 모델은 그 문서를 보며 답합니다. 자료 형식에 [DOC] 같은 문서 칸을 두고 문서를 참고해 답하는 모양을 미리 학습해 두면, 나중에 검색 결과를 그 칸에 넣어 쓸 수 있습니다.

다음 도전 — XSLM 을 키우는 방법

완성한 XSLM 으로 해 볼 수 있는 실험입니다. 하나씩 바꾸고 과 답을 기록하세요.

  • 자료 늘리기: 질문을 여러 표현으로, 답을 같은 형식으로 수십~수백 줄 씁니다.
  • 학습 늘리기: ·학습 횟수를 바꾸며 학습·을 비교합니다.
  • 모델 키우기: width 를 16으로, context 를 24로 바꿉니다. 수와 걸음마다의 시간이 어떻게 변하는지 잽니다.
  • 쌓기: model.py 의 + 를 로 묶고 를 블록마다 따로 만들어 두 번 지나가게 합니다.
  • 나누기: 폭 8을 4칸씩 두 헤드로 나눠 따로 어텐션한 뒤 이어 붙입니다.
  • 더하기: generate 에 로 후보를 자르는 옵션을 만듭니다.
  • ·대화 기록: Runner 와 XChat 에 붙여 봅니다.

여기까지 할 수 있게 되면 에서 로 같은 구조를 다시 써 보세요. 로 계산하면 수천 배 빠르게, 수천만 파라미터를 학습할 수 있습니다. 의 ·build-nanogpt 도 좋은 다음 교재입니다.

직접 타이핑하며 실습하기

Runner를 켜 둔 채 xchat.py를 작성하고 실행하세요. You>에서 hi를 치고 Enter를 누릅니다. /exit로 bash로 나온 다음에만 마지막 으로 Runner를 끝냅니다. 완성한 프로젝트를 내보내세요.

cd ~/xslm
micro xchat.py
python3 xchat.py
hi
/exit
kill "$(cat runner.pid)"
터미널에서 실습하기
xchat.py직접 작성할 전체 소스

input은 한 줄을 읽고, Request는 JSON POST를 만들고, urlopen은 실제 응답을 읽습니다. 연결이 실패하면 가짜 답을 넣지 않고 오류를 알려 줍니다.

import json
from pathlib import Path
from urllib.request import Request, urlopen
from urllib.error import URLError


def ask(question):
    cfg = json.loads(Path('settings.json').read_text())
    body = {'prompt': 'Q: ' + question + '\nA: ', 'tokens': cfg['tokens']}
    request = Request('http://127.0.0.1:' + str(cfg['port']) + '/generate',
                      data=json.dumps(body).encode(),
                      headers={'Content-Type': 'application/json'})
    with urlopen(request, timeout=120) as response:
        return json.load(response)['text']


if __name__ == '__main__':
    print('XChat -> Runner -> XSLM | /exit')
    while True:
        try:
            question = input('You> ').strip()
            if question == '/exit':
                break
            if question:
                print('XSLM>', ask(question))
        except (EOFError, KeyboardInterrupt):
            break
        except (URLError, TimeoutError) as error:
            print('Runner:', error)

코드 한 줄씩 뜯어보기

xchat.py ask — 질문 하나 보내기

def ask(question):
    cfg = json.loads(Path('settings.json').read_text())
    body = {'prompt': 'Q: ' + question + '\nA: ', 'tokens': cfg['tokens']}
    request = Request('http://127.0.0.1:' + str(cfg['port']) + '/generate',
                      data=json.dumps(body).encode(),
                      headers={'Content-Type': 'application/json'})
    with urlopen(request, timeout=120) as response:
        return json.load(response)['text']

질문마다 settings.json 을 읽어 토큰 수와 포트를 얻습니다. 질문을 "Q: " + 질문 + 줄바꿈 + "A: " 로 감싸 학습 형식을 맞춥니다. Request 에 를 주면 POST 가 되고, 본문은 JSON , 헤더는 입니다. with urlopen(…) 은 응답을 다 읽은 뒤 연결을 닫아 줍니다. json.load 가 응답을 사전으로 읽고, ask 는 text 만 돌려줍니다.

xchat.py 대화 루프

if __name__ == '__main__':
    print('XChat -> Runner -> XSLM | /exit')
    while True:
        try:
            question = input('You> ').strip()
            if question == '/exit':
                break
            if question:
                print('XSLM>', ask(question))
        except (EOFError, KeyboardInterrupt):
            break
        except (URLError, TimeoutError) as error:
            print('Runner:', error)

시작 안내를 찍고 while True 로 질문을 받습니다. input 은 You> 를 보여 주고 Enter 까지 한 줄을 읽으며, strip 으로 앞뒤 공백을 지웁니다. /exit 면 break 로 끝내고, 빈 질문은 건너뜁니다. Ctrl+D 는 EOFError, Ctrl+C 는 KeyboardInterrupt 로 들어와 역시 끝냅니다. Runner 연결 오류와 시간 초과는 알려 주고 다음 질문을 기다립니다.

여기까지 이해했나요?

XChat → HTTP Runner → 저장한 가중치 → 생성한 글의 흐름을 보여 주세요. Runner를 끄고 대화하면 연결 오류가 나야 합니다. 다시 켜면 대화가 돌아오나요? 각 파일이 맡은 일을 다른 사람에게 설명해 보세요.

막혔을 때 확인하기

XChat 안에서 kill을 입력하면 명령이 아니라 질문으로 보내집니다. 먼저 /exit로 나가세요. 내용이 어설퍼도 실제 모델의 응답이 돌아오면 연결은 완성입니다. 다음에는 자료와 학습을 개선해 보세요.

자주 묻는 질문

XChat 에서 kill 을 쳤는데 Runner 가 안 꺼져요.

You> 에 친 글은 명령이 아니라 질문으로 Runner 에 보내집니다. 먼저 /exit 나 Ctrl+D 로 XChat 을 끝내 bash 프롬프트($)로 돌아온 뒤 kill 명령을 칩니다.

Runner: <urlopen error [Errno 111] Connection refused> 가 나와요.

Runner 가 꺼져 있거나 아직 켜지는 중입니다. cat runner.log 로 시작 문구(XSLM Runner: …)를 확인하고, curl -s http://127.0.0.1:8765/health 가 답하는지 본 뒤 다시 질문하세요. 새로 고침을 했다면 Runner 를 다시 켜야 합니다.

답이 질문과 상관없어요. 연결이 잘못된 건가요?

XSLM> 뒤에 무엇이든 생성된 글이 나왔다면 연결은 맞습니다. 내용은 모델의 실력입니다. 같은 질문을 generate.py --prompt 로 직접 실행해 보세요. 설정과 가 같으면 Runner 를 거친 답과 똑같이 나옵니다.

가이드라인

인공지능

에이전트 툴

바이브코딩

AI 활용

AI 자격증

화상 수업

IT 기초

채팅

게시판

만들기

소통

더보기

용어 사전

모르는 말을 골라 보세요. 쉬운 설명과 관련 용어를 볼 수 있어요.

찾는 용어가 아직 없어요.

용어를 고르면 설명이 보여요.