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을 홈 화면에 추가하고 거기에서 연 뒤 알림을 허용하세요.

XSML · 첫 코드부터 나만의 대화까지

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

이 브라우저에서 직접 타이핑하며 언어 모델을 만듭니다. 데이터를 준비하고 작은 GPT를 학습한 뒤, 내가 만든 Runner와 XChat으로 대화합니다. 미리 학습된 가중치나 외부 AI API는 쓰지 않습니다.

8

Runner·API

학습한 모델을 실제 HTTP API로 실행하는 서버를 만듭니다.

Runner는 체크포인트를 한 번 읽고 JSON 요청을 받아 generate를 호출합니다. HTTPServer는 요청을 하나씩 처리합니다. GET /health는 실행 상태를, POST /generate는 생성 문장을 돌려줍니다. 공개 서비스용이 아닌 수업용 서버입니다.

127.0.0.1은 가상 리눅스 자신의 주소입니다. 아래 은 반드시 이 터미널에서 실행합니다. 브라우저 주소창의 는 다른 컴퓨터를 가리킵니다. nohup과 &로 뒤에서 실행할 수 있지만 이 탭이 살아 있는 동안뿐입니다. 새로 고침하거나 닫으면 종료됩니다. 여기서는 systemd가 필요 없습니다.

직접 타이핑하며 실습하기

runner.py를 작성하고 명령대로 시작하세요. 바로 다음 줄에서 프로세스 번호를 저장합니다. runner.log를 확인한 뒤 /health와 /generate를 요청합니다. 첫 확인이 너무 빠르면 시작 문구가 나올 때까지 기다렸다 다시 요청하세요.

cd ~/xsml
nano runner.py
nohup python3 -u runner.py > runner.log 2>&1 &
echo $! > runner.pid
cat runner.log
curl -s http://127.0.0.1:8765/health
curl -s http://127.0.0.1:8765/generate -H 'Content-Type: application/json' -d '{"prompt":"Q: hi\nA:","tokens":8,"temperature":0.8}'
runner.py직접 작성할 전체 소스

요청마다 모델을 새로 만들지 않습니다. 본문을 검사하고 문장을 생성한 뒤 UTF-8 JSON으로 응답합니다. 가상 리눅스의 loopback에 연결하여 이 리눅스 세션 안에서만 씁니다.

import json
from http.server import BaseHTTPRequestHandler, HTTPServer
from generate import load, generate


def main():
    model, tokenizer, cfg = load()

    class Handler(BaseHTTPRequestHandler):
        def reply(self, status, body):
            data = json.dumps(body, ensure_ascii=False).encode('utf-8')
            self.send_response(status)
            self.send_header('Content-Type', 'application/json; charset=utf-8')
            self.send_header('Content-Length', str(len(data)))
            self.end_headers()
            self.wfile.write(data)

        def do_GET(self):
            if self.path == '/health':
                self.reply(200, {'status': 'ok', 'model': 'XSML'})
            else:
                self.reply(404, {'error': 'not found'})

        def do_POST(self):
            if self.path != '/generate':
                return self.reply(404, {'error': 'not found'})
            try:
                length = int(self.headers.get('Content-Length', '0'))
                if not 0 < length <= 4096:
                    raise ValueError('request size')
                data = json.loads(self.rfile.read(length))
                prompt = data['prompt']
                tokens = data.get('tokens', cfg['tokens'])
                temperature = data.get('temperature', 0.8)
                top_k = data.get('top_k', 8)
                seed = data.get('seed', cfg['seed'])
                if not isinstance(prompt, str) or not 0 < len(prompt) <= 512:
                    raise ValueError('prompt')
                if type(tokens) is not int or not 1 <= tokens <= cfg['max_tokens']:
                    raise ValueError('tokens')
                if type(top_k) is not int or top_k < 0 or type(seed) is not int:
                    raise ValueError('top_k/seed')
                if type(temperature) not in (int, float):
                    raise ValueError('temperature')
                result = generate(model, tokenizer, prompt, tokens, temperature, top_k, seed)
                self.reply(200, {'text': result, 'model': 'XSML'})
            except (ValueError, KeyError, TypeError):
                self.reply(400, {'error': 'invalid request'})

    address = ('127.0.0.1', cfg['port'])
    print('XSML Runner:', address, flush=True)
    HTTPServer(address, Handler).serve_forever()


if __name__ == '__main__':
    main()

여기까지 이해했나요?

상태 확인은 status ok, 생성 요청은 text가 들어 있는 JSON이어야 합니다. 빈 JSON을 보내면 서버가 죽지 않고 400을 반환하나요? 응답은 정해 놓은 문장이 아니라 내 체크포인트에서 나와야 합니다.

막혔을 때 확인하기

Connection refused라면 runner.log와 체크포인트 파일을 확인하세요. Address already in use라면 기존 Runner를 쓰거나 저장한 PID로 종료한 뒤 다시 시작합니다. 새로 학습했다면 Runner를 다시 시작해야 바뀐 가중치를 읽습니다.