生成即合规:Agentic AIGC 驱动的广告素材修复实践|QCon上海
InfoQ - 促进软件开发领域知识与创新的传播
点击查看原文>
Балл: 54.57Уверенность: 54%
ПодробнееЗагружаем каталог…
НАВИГАТОР ПО ВОЗМОЖНОСТЯМ ИИ
Найдите свой ИИ-инструмент. Бесплатный доступ, пробные периоды и кредиты — в одном месте.
InfoQ - 促进软件开发领域知识与创新的传播
点击查看原文>
Балл: 54.57Уверенность: 54%
Подробнееvelog
The Bahrain vs Kuwait, 11th Match, ICC Men’s T20 World Cup Sub Regional Asia Qualifier A 2026 is set to bring together two competitive Asian sides in an important early-stage fixture. Both teams will look to make a strong start to their qualifying campaign, with disciplined batting, effective bowling, and sharp fielding likely to play key roles. Bahrain will aim to build momentum through a balanced team performance, while Kuwait will look to challenge their opponents with an energetic approach. The match should provide an interesting contest as both sides target a positive result in the race for progression. Bahrain vs Kuwait, Match Details: Location: Bangi, Selangor, Malaysia Venue: UKM-YSD Oval Date & Time: 9th Sep/06:15 AM PST LOCAL Time Streaming: JioHotstar Establish: 2010 Capacity: 5000 Owner: Universiti Kebangsaan Malaysia Home Team: – End Name: – Flood Light: Yes Bahrain vs Kuwait, ODI Head-to-Head Records: Total Match: 10 Bahrain: 3 Kuwait: 7 No Result: 0 Tie: 0 Team Form (Last Five Matches, Most Recent First) Bahrain: W W L L W Kuwait: W W L W L Bahrain vs Kuwait Last Five Head-to-Head Records: Teams: Bahrain vs Kuwait | Winner: Bahrain | Date: 14 Dec 2024 Teams: Kuwait vs Bahrain | Winner: Kuwait | Date: 15 Apr 2024 Teams: Bahrain vs Kuwait | Winner: Bahrain | Date: 5 Mar 2024 Teams: Kuwait vs Bahrain | Winner: Kuwait | Date: 2 Nov 2023 Teams: Kuwait vs Bahrain | Winner: Kuwait | Date: 16 Sep 2023 Bahrain vs Kuwait, Weather Report: Temperature: 33° Humidity: 70% Wind Speed: 10km/hr Cloud Cover: 45% Bahrain vs Kuwait, Pitch Report: Bahrain vs Kuwait UKM-YSD Cricket Oval in Bangi generally offers a balanced surface where both batters and bowlers can find opportunities. The pitch may provide some assistance to pace bowlers with the new ball, while spinners can become more effective as the game progresses and the surface slows down. Batters who settle early can score freely, but shot selection becomes increasingly important during the middle and later overs. Teams winning the toss may consider batting first to make the most of the fresher conditions before the pitch potentially becomes slower. Match Performance: Total Matches Played: 30 1st Batting Team Won: 17 2nd Batting Team Won: 13 No Result: 0 Average Batting Score: 113 Highest Score: 227/4 Lowest Score: 10/10 Pitch Report: Batting Pitch Bahrain vs Kuwait, Playing 11: Bahrain: Abdulla Pervaiz (WK), Ali Dawood, Abdul Majid, Ahmer Bin Nasir, Fiaz Ahmed, Imran Anwar, Junaid Aziz, Prashant Kurup, Rizwan Butt, Sohail Ahmed, Shujaat Rasool Kuwait: Mohammed Aslam (C), Meet Bhavsar (WK), Ravija Sandaruwan, Ali Zaheer, Muhammad Umar, Adnan Idrees, Bilal Tahir, Sandaruwan Chinthaka, Mohamed Shafeeq, Yasin Patel, Shahrukh Quddus Injury And Availability News: We will add any updates here. Bahrain vs Kuwait, Betting Tips: Who Will Win The Toss: Bahrain Match Winner: Kuwait Total Boundaries: 30+ Player Of The Match: Mohammed Aslam 1st Innings Total: 240+ Most Wicket Taker: Ali Zaheer My prediction Kuwait will win this match.
Балл: 54.4Уверенность: 49%
Подробнееvelog
들어가며 1편 에서 지식그래프와 온톨로지의 차이, 구축 절차를 정리했다. 이번 글은 그 절차대로 대전의 실제 하천·수위관측소 데이터로 지식그래프를 만들어 본 기록이다. 처음에는 가상의 도시를 하나 만들어서 가짜 하천·관측소 데이터로 연습했다. 그걸로는 잘 돌아갔는데, 실제 데이터로 바꾸자마자 문제가 줄줄이 나왔다. 원본에 값이 빠져 있기도 하고, 출처마다 값이 달랐고, 관측소마다 수위 기준이 다른 경우도 있었다. 구축 과정과 함께 이런 문제를 어떻게 처리했는지도 같이 적었다. 작업 환경은 Windows 11이고, Docker(Rancher Desktop)로 Neo4j 5.26 Community를 띄웠다. 데이터 수집은 Python 3.11 표준 라이브러리만으로 했다. 1) 이번 글에서 다룰 내용 답할 질문 정하기와 그래프 모델 설계 (노드 3종, 관계 4종) WAMIS API로 대전 관측소 19곳 수집 ( fetch_wamis.py ) Docker로 Neo4j 띄우고 LOAD CSV + MERGE 로 적재 가변 길이 경로 질의로 "금강까지 몇 단계?" 같은 질문에 답하기 트러블슈팅 — 경로 변환, BOM, 콘솔 인코딩, 원천 결측, 집계 중복, 수위 기준 2) 배경 / 설계 2-1. 답할 질문 1편에서 정리한 대로 질문부터 적었다. 하천이 어디로 흘러가는지, 넘치면 어디를 봐야 하는지처럼 연결을 따라가야 답이 나오는 질문 위주로 골랐다. # 질문 필요한 노드·관계 Q1 금강으로 흘러드는 대전 하천은 모두 무엇인가? (몇 단계든) 하천, 지류이다 Q2 유등천이 넘치면 어느 구, 어느 관측소를 봐야 하나? (상류 포함) 하천, 관측소, 행정구역 Q3 하천마다 합류 직전의 관측소는 어디인가? 관측소의 합류점거리 Q4 구별로 관측소가 몇 곳이고 어떤 하천을 보나? 관측소, 위치한다 Q5 어떤 하천과도 연결되지 않은 관측소가 있나? (품질 점검) 관측한다 2-2. 데이터 출처 관측소 정보는 처음에 웹 검색으로 모으려고 했다. 검색 결과에 관측소 이름이랑 주의보 수위 같은 값이 요약돼서 나오길래 금방 될 줄 알았는데, 근거 페이지를 열어 보니 404였다. 원문으로 확인이 안 되는 숫자를 실제 데이터라고 넣을 수는 없어서 API로 방향을 바꿨다. API도 처음엔 HRFCO 시리즈 때 쓰던 홍수통제소 API를 다시 쓰려고 했다. 그런데 인증키를 다시 꺼내서 설정하는 게 귀찮아서 키 없이 되는 게 있나 찾아봤고, WAMIS(국가수자원관리종합정보시스템)에서 관측소 제원이랑 시자료를 키 없이 준다는 걸 알게 됐다. 게다가 제원에 하천명까지 들어 있어서 오히려 이쪽이 더 편했다. 데이터 출처 비고 관측소 19곳 제원·최신 수위 WAMIS Open API ( wl_dubwlobs , wl_obsinfo , wl_hrdata ) 인증키 불필요, 스크립트로 수집 국가하천 4개 연장·합류점 대전시 하천관리사업소 하천현황 금강·갑천·유등천·대전천 갑천 지천 대전시 3대하천현황 진잠천·유성천·관평천·매노천 등 대동천→대전천, 반석천→유성천 위키백과 대전시 자료에 없는 2건 보완 출처를 확인 못 한 값은 넣지 않고 비워 두기로 했다. 이 원칙 때문에 뒤에서 몇 번 손해를 보긴 했는데, 그래도 틀린 값이 섞이는 것보다는 낫다고 봤다. 2-3. 그래프 모델 (관측소)-[:관측한다]->(하천) (관측소)-[:위치한다]->(행정구역) (하천)-[:흐른다]->(행정구역) ← 관측소 주소(양쪽 강변)에서 도출 (하천)-[:지류이다]->(하천) ← 몇 단계든 따라갈 수 있는 고리 라벨과 관계 타입은 한글로 지었다. Cypher가 유니코드 식별자를 허용해서 백틱 없이 (:하천) , [:지류이다] 로 쓸 수 있다. 업무 담당자랑 같이 질의를 볼 일이 있으면 한글 쪽이 훨씬 읽기 편하다. 2-4. 전체 흐름과 프로젝트 구조 knowledge-graph-lab/ ├── scripts/fetch_wamis.py # WAMIS → stations.csv, station_regions.csv ├── data/ │ ├── stations.csv # 관측소 19 (스크립트 생성) │ ├── station_regions.csv # 관측소-구 26 (스크립트 생성) │ ├── rivers.csv # 하천 10 (출처 컬럼 포함) │ ├── river_tributary.csv # 합류 9 (출처 컬럼 포함) │ └── regions.csv # 자치구 5 ├── neo4j/docker-compose.yml ├── cypher/ │ ├── 01_schema.cypher # 유일성 제약조건 │ ├── 02_load.cypher # CSV → 노드·관계 │ └── 03_queries.cypher # Q1~Q5 └── SOURCES.md # 항목별 출처와 알려진 한계 3) 목표 상태 항목 값 노드 34 (관측소 19 · 하천 10 · 행정구역 5) 관계 60 (관측한다 18 · 위치한다 19 · 지류이다 9 · 흐른다 14) 검증 원천 CSV 행 수와 노드·관계 수 일치 질의 Q1~Q5 결과가 원천 자료로 손 검산한 값과 일치 4) 데이터 분석 — WAMIS 응답 살펴보기 4-1. 관측소 목록 → 대전만 고르기 wl_dubwlobs 를 호출하면 전국 관측소 목록 1,363건이 온다. 관측소명이 대전시(원촌교) 형식이라 대전시( 로 시작하는 것만 골랐더니 19곳이었다. http://www.wamis.go.kr:8080/wamis/openapi/wkw/wl_dubwlobs?output=json 4-2. 관측소 제원 — 하천명이 들어 있다 wl_obsinfo 에 관측소 코드를 넣으면 제원이 나온다. 여기서 제일 반가웠던 게 rivnm (하천명) 필드다. 관측소 → 하천 관계를 다른 자료 없이 바로 만들 수 있었다. 그래프에 쓴 필드는 이 정도다. 필드 예 (원촌교) 처리 wlobscd 3009680 관측소 노드 식별자 rivnm 갑천 관측한다 관계 addr 대전광역시 대덕구 대화동 원촌교 (대전광역시시 유성구 원촌동) 괄호 밖 = 본주소 구, 괄호 안 = 맞은편 강변 구 lat / lon 36-22-42 / 127-24-36 도-분-초 문자열 → 십진수, point() 로 저장 bsnara 609.4 유역면적(km2) rvmjctdis 10.32 합류점까지 거리(km) — Q3에 사용 주소를 보다가 괄호 안에 다리 건너편 주소가 들어 있다는 걸 알았다. 하천은 구 경계를 따라 흐르는 경우가 많아서, 괄호 안 구까지 모으면 "이 하천이 지나는 구"를 어느 정도 만들 수 있다. 원본에는 대전광역시시 같은 오타나 lat 끝에 붙은 공백도 있어서, 공백 기준으로 잘라서 구 이름만 고르고 strip() 을 했다. 4-3. 시자료 수위 wl_hrdata 는 관측소별 시간 단위 수위를 준다. 최근 이틀 치를 받아서 값이 있는 마지막 행을 최신 수위로 썼다. .../wl_hrdata?obscd=3009680&startdt=20261006&enddt=20261007&output=json → [{"ymdh": "2026100601", "wl": ".45"}, ..., {"ymdh": "2026100709", "wl": ".40"}] 수위가 ".45" 처럼 앞의 0이 빠진 문자열로 와서 float() 로 바꿨다. 5) 해결 (구현) 5-1. 수집 스크립트 — fetch_wamis.py 표준 라이브러리만 썼다. 관측소 CSV와 관측소-구 CSV 두 개를 만든다. """WAMIS(국가수자원관리종합정보시스템) Open API 에서 대전 수위관측소 데이터를 받아 CSV 로 만든다. 인증키가 필요 없다. 실행: python scripts/fetch_wamis.py 결과: data/stations.csv, data/station_regions.csv """ import csv import json import re import urllib.request from datetime import datetime, timedelta from pathlib import Path BASE = "http://www.wamis.go.kr:8080/wamis/openapi/wkw" DATA = Path(__file__).resolve().parent.parent / "data" DISTRICTS = ["동구", "중구", "서구", "유성구", "대덕구"] def get(endpoint, **params): query = "&".join(f"{k}={v}" for k, v in {**params, "output": "json"}.items()) with urllib.request.urlopen(f"{BASE}/{endpoint}?{query}", timeout=30) as res: return json.load(res) def dms_to_decimal(dms): """'127-24-36' → 127.41""" d, m, s = (float(x) for x in dms.strip().split("-")) return round(d + m / 60 + s / 3600, 6) def districts_in(addr): """주소에서 대전 자치구를 순서대로 뽑는다. 괄호 안은 맞은편 강변 주소다.""" main, _, opposite = addr.partition("(") pick = lambda text: [t for t in re.split(r"\s+", text) if t in DISTRICTS] return pick(main), pick(opposite) def latest_level(obscd): """최근 이틀 시자료 중 마지막 값. 자료가 없으면 (None, None).""" today = datetime.now() rows = get("wl_hrdata", obscd=obscd, startdt=(today - timedelta(days=1)).strftime("%Y%m%d"), enddt=today.strftime("%Y%m%d")).get("list", []) rows = [r for r in rows if r.get("wl") not in (None, "", "-")] if not rows: return None, None last = rows[-1] return float(last["wl"]), last["ymdh"] def main(): stations = [s for s in get("wl_dubwlobs")["list"] if s["obsnm"].startswith("대전시(")] station_rows, region_rows = [], [] for s in stations: info = get("wl_obsinfo", obscd=s["obscd"])["list"][0] level, observed_at = latest_level(s["obscd"]) station_rows.append({ "id": info["wlobscd"], "name": info["obsnm"], "river": info["rivnm"] or "", # 원천 결측은 빈 값으로 둔다 — 추정하지 않는다 "agency": info["mggvcd"], "opened": info["obsopndt"], "basin_area_km2": info["bsnara"], "dist_to_confluence_km": info["rvmjctdis"], "lat": dms_to_decimal(info["lat"]), "lon": dms_to_decimal(info["lon"]), "address": info["addr"].strip(), "latest_level_m": "" if level is None else level, "observed_at": observed_at or "", }) main_side, opposite_side = districts_in(info["addr"]) for d in main_side: region_rows.append({"station_id": info["wlobscd"], "district": d, "side": "본주소"}) for d in opposite_side: region_rows.append({"station_id": info["wlobscd"], "district": d, "side": "맞은편"}) for name, rows in [("stations.csv", station_rows), ("station_regions.csv", region_rows)]: # utf-8-sig: BOM 을 붙여야 엑셀(한국어 Windows)이 한글을 깨뜨리지 않고 연다 with open(DATA / name, "w", newline="", encoding="utf-8-sig") as f: writer = csv.DictWriter(f, fieldnames=rows[0].keys()) writer.writeheader() writer.writerows(rows) print(f"{name}: {len(rows)}행") if __name__ == "__main__": main() > python scripts/fetch_wamis.py stations.csv: 19행 station_regions.csv: 26행 5-2. 정리 CSV — 출처 컬럼을 남긴다 하천과 합류 관계는 공식 자료를 보고 직접 옮겨 적었다. 손으로 만든 데이터라 행마다 source 컬럼을 두고, 그래프 관계 속성에도 그대로 넣었다. 나중에 "이 연결은 어디서 온 거지?" 싶을 때 질의로 바로 확인할 수 있다. child,parent,source 갑천,금강,대전시 하천관리사업소 하천현황 유등천,갑천,대전시 하천관리사업소 하천현황 대전천,유등천,대전시 하천관리사업소 하천현황 진잠천,갑천,대전시 3대하천현황 (갑천 지천) 유성천,갑천,대전시 3대하천현황 (갑천 지천) 관평천,갑천,대전시 3대하천현황 (갑천 지천) 매노천,갑천,대전시 3대하천현황 (갑천 지천) 대동천,대전천,위키백과 대동천(대전) 반석천,유성천,위키백과 반석천 rivers.csv 의 등급(국가하천/지방하천)도 출처가 있는 것만 채웠다. 대전시 자료에 국가하천으로 나온 4개와 위키백과에 지방하천으로 나온 2개만 값이 있고, 나머지 4개는 비어 있다. 5-3. Neo4j 실행 — docker-compose.yml # 지식그래프 실습용 Neo4j (로컬 데모 전용 — 비밀번호를 운영 환경에 그대로 쓰지 말 것) services: neo4j: image: neo4j:5-community container_name: kg-neo4j ports: - "7474:7474" # 브라우저 UI http://localhost:7474 - "7687:7687" # Bolt (드라이버·cypher-shell) environment: NEO4J_AUTH: neo4j/kgdemo1234 volumes: - ../data:/import:ro # LOAD CSV 가 읽는 위치 - ../cypher:/cypher:ro # 스크립트 실행용 /import 는 Neo4j가 LOAD CSV ... FROM 'file:///...' 로 읽는 기본 경로라서 CSV 폴더를 여기에 읽기 전용으로 붙였다. 5-4. 스키마 — 유일성 제약조건 // 같은 식별자를 가진 노드가 두 번 만들어지지 않도록 막는다 (ERD의 PK 역할). CREATE CONSTRAINT 행정구역_이름 IF NOT EXISTS FOR (n:행정구역) REQUIRE n.이름 IS UNIQUE; CREATE CONSTRAINT 하천_이름 IF NOT EXISTS FOR (n:하천) REQUIRE n.이름 IS UNIQUE; CREATE CONSTRAINT 관측소_코드 IF NOT EXISTS FOR (n:관측소) REQUIRE n.코드 IS UNIQUE; 제약조건을 걸면 인덱스도 같이 생겨서, 뒤에서 MERGE / MATCH 로 노드를 찾을 때도 빠르다. 5-5. 적재 — LOAD CSV + MERGE MERGE 는 없으면 만들고 있으면 그대로 둔다. 스크립트를 몇 번 다시 돌려도 결과가 같아서 테스트하면서 마음 편하게 재실행할 수 있었다. // --- 노드 --- LOAD CSV WITH HEADERS FROM 'file:///stations.csv' AS row MERGE (s:관측소 {코드: row.id}) SET s.이름 = row.name, s.운영기관 = row.agency, s.관측개시일 = date(row.opened), s.유역면적_km2 = toFloat(row.basin_area_km2), s.합류점거리_km = toFloat(row.dist_to_confluence_km), s.위치 = point({latitude: toFloat(row.lat), longitude: toFloat(row.lon)}), s.주소 = row.address, s.최신수위_m = toFloat(row.latest_level_m), s.관측시각 = row.observed_at; // (행정구역·하천 노드도 같은 방식 — 생략) // --- 관계 --- LOAD CSV WITH HEADERS FROM 'file:///river_tributary.csv' AS row MATCH (child:하천 {이름: row.child}), (parent:하천 {이름: row.parent}) MERGE (child)-[r:지류이다]->(parent) SET r.출처 = row.source; // 하천명이 비어 있는 관측소(원천 결측)는 관계를 만들지 않는다. LOAD CSV WITH HEADERS FROM 'file:///stations.csv' AS row WITH row WHERE row.river IS NOT NULL MATCH (s:관측소 {코드: row.id}), (rv:하천 {이름: row.river}) MERGE (s)-[:관측한다]->(rv); LOAD CSV WITH HEADERS FROM 'file:///station_regions.csv' AS row WITH row WHERE row.side = '본주소' MATCH (s:관측소 {코드: row.station_id}), (r:행정구역 {이름: row.district}) MERGE (s)-[:위치한다]->(r); // 하천이 지나는 구: 관측소 주소(양쪽 강변)에서 이끌어낸다. 관측소가 없는 구간은 반영되지 않는다. LOAD CSV WITH HEADERS FROM 'file:///station_regions.csv' AS row MATCH (:관측소 {코드: row.station_id})-[:관측한다]->(rv:하천), (r:행정구역 {이름: row.district}) MERGE (rv)-[:흐른다]->(r); LOAD CSV 는 빈 칸을 null 로 읽는다. 그래서 WHERE row.river IS NOT NULL 한 줄이면 하천명이 없는 행을 건너뛸 수 있다. 적재가 끝나면 건수부터 맞춰 봤다. MATCH (n) RETURN labels(n)[0] AS 라벨, count(*) AS 개수 ORDER BY 라벨; MATCH ()-[r]->() RETURN type(r) AS 관계, count(*) AS 개수 ORDER BY 관계; 라벨, 개수 관계, 개수 "관측소", 19 "관측한다", 18 ← 관측소 19 − 하천명 결측 1 "하천", 10 "위치한다", 19 "행정구역", 5 "지류이다", 9 "흐른다", 14 관측한다 가 19가 아니라 18인 게 처음엔 이상해 보였는데, 하천명이 비어 있는 관측소 1곳 때문이었다. 이 얘기는 트러블슈팅 D에 정리했다. 5-6. 질의와 결과 Q1. 금강으로 흘러드는 대전 하천 전부 가변 길이 경로 *1.. 을 쓴다. MATCH path = (t:하천)-[:지류이다*1..]->(:하천 {이름: '금강'}) RETURN t.이름 AS 하천, length(path) AS 단계, [n IN nodes(path) | n.이름] AS 경로 ORDER BY 단계, 하천; 하천, 단계, 경로 "갑천", 1, ["갑천", "금강"] "관평천", 2, ["관평천", "갑천", "금강"] "매노천", 2, ["매노천", "갑천", "금강"] "유등천", 2, ["유등천", "갑천", "금강"] "유성천", 2, ["유성천", "갑천", "금강"] "진잠천", 2, ["진잠천", "갑천", "금강"] "대전천", 3, ["대전천", "유등천", "갑천", "금강"] "반석천", 3, ["반석천", "유성천", "갑천", "금강"] "대동천", 4, ["대동천
velog
Ubuntu에서 Lotion 설치해보기 Week6. curl과 Git을 설치한 뒤에도 앱이 열리지 않았던 기록 Ubuntu로 한 학기 살아보기 프로젝트를 하면서, 평소에 쓰던 Notion도 계속 사용하고 싶어졌다. Linux에서 사용할 방법을 찾다가 Lotion 이라는 프로젝트를 알게 됐다. 설치 중에는 curl 과 git 이 없어 두 번 막혔다. 필요한 도구를 설치하고 다시 진행했지만, 마지막에는 아이콘을 눌러도 앱이 열리지 않았다. 이번 글은 그 과정과 끝내 확인하지 못한 부분을 함께 정리한 기록이다. 앞부분의 명령은 당시 실습 기록이다. 현재 설치를 권하는 절차로 읽지 않도록 주의하자. 명령의 역할과 점검 방법은 설명을 보탰고, 지금도 설치 파일이 배포되는지는 마지막 절에서 따로 확인했다. 1. Lotion은 어떤 프로그램이었나 Lotion은 Notion을 Linux 데스크톱에서 사용할 수 있게 만든 비공식 클라이언트 다. 현재 프로젝트도 Electron 기반이라고 소개하며, Notion이 제작하거나 지원하는 앱이 아니라고 명시한다. Lotion 프로젝트 당시 보고서의 Lotion 로고. 아래쪽에도 UNOFFICIAL이라고 적혀 있다. 원래 보고서에서는 이를 “Notion native”라고 적었다. 하지만 그 표현만으로 Notion의 공식 Linux 앱이 설치됐다고 볼 수는 없다. 아래 명령 끝의 native 역시 당시 설치 스크립트에 넘겼던 인자다. 이 글에서는 실제 사용한 프로젝트 이름인 Lotion으로 구분한다. 2. 먼저 압축 도구를 준비했다 당시 안내를 따라 7-Zip 관련 패키지부터 설치했다. 아래 세 줄은 보고서에 남아 있는 명령을 그대로 옮겼다. sudo add-apt-repository universe Ubuntu의 패키지 저장소 구성 요소인 universe 를 활성화한다. 프로그램을 받는 출처를 설정하는 단계다. sudo 는 이 명령을 관리자 권한으로 실행한다. 저장소 추가 명령 sudo apt update 등록된 저장소에서 설치 가능한 패키지 정보 를 새로 받는다. 이 단계에서 설치된 프로그램 전체가 업그레이드되는 것은 아니다. APT 설명 sudo apt install p7zip-full p7zip-rar 7-Zip 도구와 RAR 형식 지원을 위한 패키지를 설치한다. 여기까지는 Lotion 자체를 설치한 것이 아니라 당시 안내에서 요구한 압축 도구를 준비한 것이다. 지금도 같은 패키지 이름과 순서가 필요한지는 현재 배포 방식에 맞춰 확인해야 한다. 7-Zip 패키지 설명 3. 설치 파일을 받으려는데 curl이 없었다 다음으로 GitHub에 있던 설치 스크립트를 내려받으려고 했다. setup.sh 는 설치 명령들이 담긴 셸 스크립트 파일이다. curl https://raw.githubusercontent.com/puneetsl/lotion/master/setup.sh > setup.sh curl 은 URL을 통해 데이터를 주고받는 도구다. 여기서는 해당 주소의 내용을 받아 출력한다. 뒤의 > setup.sh 는 그 출력을 현재 폴더의 파일에 저장한다. 이 한 줄의 역할은 스크립트 다운로드까지다. 스크립트를 실행하는 명령은 뒤에 따로 나온다. curl 설명 · Bash 출력 저장 > 는 같은 이름의 파일이 있으면 일반적인 설정에서 기존 내용을 비우고 새로 쓴다. 파일이 생겼다는 사실만으로 다운로드가 정상적으로 끝났다고 판단해서는 안 된다. 오류 출력과 실제 파일 내용을 함께 봐야 한다. 첫 시도에서는 아래 메시지가 나왔다. 원본 화면의 메시지: Command 'curl' not found, but can be installed with: Lotion의 다운로드 주소에 접속하기 전에, 내 환경에서 curl 명령을 찾지 못한 것이다. 당시에는 다음 명령으로 curl을 설치했다. sudo apt install curl APT를 통해 curl 패키지를 설치한다. 설치한 뒤 같은 다운로드 명령을 다시 실행했다. 당시 보고서의 후속 화면에는 전송 진행률과 2,952바이트를 받은 기록이 표시됐다. 다운로드 명령은 실행됐지만, 받은 파일의 내용이나 안전성을 검증한 기록은 없다. 4. 이번에는 설치 스크립트가 Git을 요구했다 다운로드 이후에는 아래 두 명령을 실행했다. 외부에서 받은 스크립트를 관리자 권한으로 실행한 당시 기록 이므로 그대로 따라 하기 전에 출처와 파일 내용을 확인해야 한다. 스크립트가 실행되면 시스템 파일이나 설정을 바꿀 수 있다. chmod +x setup.sh chmod 는 파일 권한을 바꾸는 명령이고, +x 는 실행 권한을 더한다. 이 명령 자체로 스크립트가 실행되지는 않는다. 실행 권한 설명 sudo ./setup.sh native 현재 폴더를 뜻하는 ./ 를 붙여 setup.sh 를 실행하고, native 라는 인자를 전달한다. sudo 가 있으므로 관리자 권한으로 실행된다. 파일을 내려받는 단계와 그 안의 명령을 실제로 수행하는 단계는 이렇게 나뉜다. 여기서 다음 메시지가 나왔다. 아래 문장은 당시 터미널 화면에서 그대로 옮겼다. Command git is required to run this script 이번에는 설치 스크립트가 실행되다가 필요한 git 명령을 확인하는 단계에서 막혔다. 앞의 curl 오류와 달리, 내려받은 스크립트가 자체적으로 요구한 도구가 부족했던 것이다. sudo apt install git Git을 설치하는 명령이다. curl은 이 과정에서 스크립트 파일을 받아오는 데 쓰였고, Git은 프로젝트의 저장소와 변경 이력을 다루는 도구다. 예를 들어 git clone 은 저장소를 로컬로 복제한다. 원본 화면으로 확인되는 것은 이 설치 스크립트가 Git을 필수로 요구했다는 데까지다. 실제로 어떤 저장소를 복제했는지는 별도 로그가 남아 있지 않다. Git 저장소 복제 설명 당시에는 Git을 설치한 뒤 설치 명령을 다시 실행했다. 보고서에는 설치가 완료됐다고 적었지만, 설치 완료 로그나 설치된 버전을 확인한 화면은 남겨 두지 못했다. 5. 아이콘이 생겨도 실행 확인은 남아 있었다 설치 후 아이콘을 눌렀을 때 오류 메시지가 나타났고, 앱이 열리지 않았다. 몇 번을 다시 눌러보고 시간이 지난 뒤에도 시도했지만 결과는 같았다. 결국 앱 실행에는 실패했고, 원인은 확인하지 못했다. 마지막 오류의 정확한 문구나 화면도 남아 있지 않다. 앞에서 해결한 curl·Git 문제를 마지막 실행 실패의 원인으로 연결할 근거는 없다. 당시에는 GitHub 안내가 오래돼 그사이에 다른 오류가 생긴 것 아닐까 생각했다. 가능성을 떠올린 정도였고, 버전이나 실행 로그를 비교해 확인하지는 못했다. 지금 기록을 보완한다면 확인할 것 아래는 당시 실행한 해결 과정이 아니라, 원인을 좁히기 위해 덧붙인 점검 순서다. 실패한 단계와 오류 전문 : 다운로드, 설치 스크립트, 앱 실행 중 어느 단계인지 나누고 오류 문장을 그대로 남긴다. 환경과 버전 : Ubuntu 버전, CPU 아키텍처, 설치 파일 이름과 Lotion 버전을 기록한다. 같은 증상처럼 보여도 실행 환경이 다를 수 있다. 아이콘과 실행 파일 : 아이콘에 연결된 실행 경로와 파일이 실제로 있는지 확인한다. 앱 실행 로그를 확보한 뒤 해당 버전의 알려진 문제와 비교한다. 6. 지금도 설치할 수 있을까 2026년 10월 7일 확인 기준, 같은 Lotion 프로젝트에서 Linux용 설치 파일을 배포하고 있다. 릴리스 목록에는 2026년 5월 26일 공개된 v1.6.0이 표시된다. 배포 파일에는 Ubuntu·Debian용 amd64·arm64 .deb 패키지, Linux용 x64·arm64 압축 파일, Fedora 계열용 RPM이 있다. Lotion 릴리스 · 전체 배포 파일 현재 README의 Ubuntu 안내는 .deb 파일을 받은 뒤 APT로 설치하는 방식이다. 예시 명령은 다음과 같다. 이 명령은 현재 문서의 안내를 소개한 것이며, 이번 글을 정리하면서 직접 실행한 결과는 아니다. sudo apt install ./lotion_1.6.0_amd64.deb 현재 폴더에 내려받은 .deb 파일을 APT로 설치한다. 파일명의 amd64 는 x86-64 계열용이라는 뜻이다. ARM64용 패키지는 lotion_1.6.0_arm64.deb 로 별도 배포된다. 프로젝트는 APT가 필요한 의존성을 처리한다고 안내한다. 다만 Ubuntu 버전별 검증표는 확인하지 못했고, 내 당시 환경에서 이 버전이 정상 실행되는지도 시험하지 않았다. README 따라서 지금 확인할 수 있는 답은 “현재 설치 파일과 설치 안내가 제공된다” 까지다. 과거의 setup.sh 절차를 그대로 재사용하거나, 당시 실행 실패가 최신 버전에서 해결됐다고 단정할 수는 없다. 비공식 앱의 코드는 로그인 세션과 화면을 다루므로, 사용 전에는 배포 출처와 변경 내역, 필요한 권한도 살펴봐야 한다. Notion은 왜 Linux를 공식 지원하지 않을까 실습을 하면서 이 점도 궁금했다. 당시에는 기술적인 부담이나 수익성 때문일 수 있다고 추측했지만, 이를 뒷받침하는 공식 근거를 확인한 것은 아니었다. 현재 Notion 도움말에서 확인되는 내용은 Linux 앱을 제공하지 않으며 브라우저에서 사용할 수 있다 는 안내다. 구체적인 사업적 이유까지는 이 문서로 알 수 없다. Notion의 Linux 지원 안내 마치며 이번 실습은 앱 실행 문제를 해결하지 못한 채 끝났다. 그래도 기록을 다시 나눠 보니 curl 오류는 파일을 받기 전, Git 오류는 설치 스크립트 실행 중, 마지막 문제는 앱을 열 때 발생했다는 차이가 보였다. 설치 명령을 끝까지 입력한 것과 실제로 사용할 수 있는 상태가 된 것은 각각 확인이 필요했다. 실패한 단계와 정확한 메시지를 남기는 일도 설치 과정만큼 중요하다는 점이 이번 기록에 남았다. 이어서 읽기 이전 글: Install R-Ubuntu
velog
26.10.07 개인프로젝트 6일차 - 정답지 재검토 및 재채점 평가셋 정답지 재검토 및 재채점 앞선 실험에서는 RAG의 검색과 답변 생성을 개선하면서 여러 단계의 성능을 측정했다. 그런데 실험 결과를 다시 살펴보면서 한 가지 의문이 생겼다. 정말 모델이 틀린 것인지, 아니면 내가 만든 정답지와 채점 기준이 잘못된 것인지 구분할 필요가 있었다. 특히 일부 문항에서는 챗봇이 질문에 필요한 내용을 어느 정도 답했는데도, 정답지에서 질문에 직접 요구되지 않은 내용을 필수 조건으로 설정해 놓아 부분정답이나 오답으로 처리되는 경우가 있었다. 따라서 이번에는 모델을 추가로 개선하기 전에 평가셋 자체를 다시 검토 했다. 1. 정답지 검토 기준 문제가 있는 문항을 다음 세 가지로 나누어 검토했다. 1 정답지가 잘못된 경우 질문과 실제 공고 원문을 기준으로 봤을 때 기존 정답 기준이 질문보다 과하거나, 원문과 맞지 않는 경우이다. → 정답지를 수정한다. 2 정답지에는 문제가 없는 경우 질문이 요구하는 내용과 정답 기준이 적절한데, 챗봇이 필요한 내용을 제대로 답하지 못한 경우이다. → 모델의 검색 또는 답변 생성을 개선한다. 3 애매한 경우 질문의 표현이나 의도에 따라 답변 범위가 달라질 수 있는 경우이다. → 질문과 정답 기준을 다시 검토한다. 여기서 가장 중요한 원칙은 챗봇의 답변을 보고 정답지를 수정하지 않는 것 이다. 정답지는 질문과 실제 공고 원문을 기준으로 판단하고, 챗봇의 답변은 그 이후에 평가한다. 2. 문제가 발견된 문항 검토 과정에서 주요하게 확인한 문항은 A03, A04, A05, A09, A14, A16 이었다. A03. 쿤텍 신입은 무슨 언어 할 줄 알아? 기존 정답 기준에는 시스템 프로그래밍 이 포함되어 있었다. 하지만 질문은 "무슨 언어를 할 줄 알아야 하는가" 를 묻고 있었다. 따라서 질문에서 직접 요구하지 않은 시스템 프로그래밍 까지 반드시 언급해야 정답으로 인정하는 것은 질문의 범위를 넘어선다고 판단했다. 판단: 1 정답지 수정 수정 후에는 질문에서 요구하는 언어 관련 정보가 정확하게 답변되었는지 를 중심으로 평가한다. A04. 아인잡 프론트엔드 연봉 기존 평가에서는 연봉 질문에 스톡옵션 정보 를 필수 옵션으로 추가했었다. 하지만 연봉과 스톡옵션은 서로 다른 보상 항목이고, 질문에서 직접 요구한 것은 연봉이었다. 따라서 연봉 질문에 스톡옵션까지 필수적으로 요구하는 기존 기준은 적절하지 않다고 판단했다. 판단: 1 정답지 수정 기존: 연봉 + 스톡옵션을 함께 언급해야 함 수정: 연봉 정보를 정확하게 안내했는지를 평가 스톡옵션은 별도의 보상 정보로 분리한다. A05. Spring만 해 봤는데 지원해도 돼? 기존 기준에서는 Spring 경험을 바탕으로 Java/Kotlin까지 연결해서 판단하도록 요구하고 있었다. 하지만 질문 자체는 "Spring만 해 봤는데 지원해도 돼?" 라는 질문이다. 따라서 Java/Kotlin까지 반드시 언급해야 하는지는 질문의 해석에 따라 달라질 수 있었다. 판단: 3 애매한 경우 질문 자체가 어느 범위까지 답변을 요구하는지 먼저 검토할 필요가 있다고 판단했다. A09. 들어가면 무슨 일 해? 기존 정답 기준에는 EMR·CRM 백엔드 API 설계 및 비즈니스 로직 구현 이라는 표현이 사용되어 있었다. 이 때문에 답변에서 CRM이 따로 언급되지 않으면 일부 내용이 빠졌다고 판단했다. 하지만 챗봇의 답이 정답 내용이 맞는데 정답 기준에서 특정 표현을 묶어서 필수적으로 요구했기 때문에 틀리다고 나온 것을 확인할 수 있었다. 판단: 1 정답지 수정 수정 후에는 질문의 의도에 맞춰 공고에 실제로 명시된 주요 업무를 정확하게 설명했는지 를 중심으로 평가한다. A14. 재택·유연근무 되는 곳 있어? A14는 정답지보다는 채점 과정에서 문제가 발생한 경우 였다. 챗봇은 재택·유연근무가 가능한 6곳을 찾아냈지만, LLM 채점 과정에서 특정 공고를 경력 공고라고 잘못 판단하면서 오답으로 처리된 문제가 있었다. 즉, 답변이 틀린 것이 아니라 채점 과정에서 잘못 판단한 경우 였다. 판단: 1 정답지/채점 기준 수정 실제 공고 원문을 기준으로 판단하고, 채점자가 근거 없이 공고의 경력 여부를 추측하지 않도록 채점 기준을 수정했다. A16. 신입 백엔드 공고에서 공통으로 요구하는 게 뭐야? A16은 가장 복잡한 문항이었다. 모델은 여러 공고를 검색했지만 일부 공고만 중심적으로 비교하는 문제가 있었다. 반면 기존 정답지는 특정 공고들을 묶어 공통 요구사항을 분석하고, 다른 공고들은 성격이 다르기 때문에 제외하는 과정을 요구하고 있었다. 따라서 다음 두 가지를 나누어 볼 필요가 있었다. 정말 모델이 여러 공고를 제대로 종합하지 못한 것인가? 아니면 정답지가 질문보다 지나치게 복잡한 분석을 요구하고 있는가? 판단: 3 애매한 경우 질문과 원문을 기준으로 정답지가 요구하는 범위가 적절한지 먼저 검토하기로 했다. 3. 정답지 수정 후 기존 실험 전체 재채점 정답지가 수정되었다면 최근 실험만 다시 채점해서는 안 된다. 예를 들어 A04의 정답 기준이 변경되었다면, 기준선 ↓ 공고 전체 투입 ↓ 기술 동의어 ↓ 조건 코드 필터 ↓ 분류-본문 차이 ↓ 지시문 개선 ↓ 공고별 균등 검색 ↓ 최종 설정 각 실험 결과를 새로운 정답지 기준으로 다시 채점해야 한다. 그래야 정답지 변경으로 인한 점수 변화와 실제 모델 개선으로 인한 점수 변화를 구분할 수 있다. 4. 답변 정확도 v2 → v4 기존 채점 기준을 v2, 수정된 채점 기준을 v4로 두고 기존 실험 결과를 다시 채점했다. 실행 v2 v4 변화 0 기준선 (A) 64.0% 70.0% +6%p 0 기준선 (B) 66.0% 72.0% +6%p 1 공고 전체 투입 70.0% 78.0% +8%p 2 기술 동의어 76.0% 76.0% 0%p 3 조건 코드 필터 82.0% 86.0% +4%p 4-v1 분류-본문 82.0% 88.0% +6%p 4-v2 82.0% 88.0% +6%p 5-a 지시문 v2 88.0% 92.0% +4%p 5-b 80.0% 92.0% +12%p 6-a 공고별 균등 검색 84.0% 96.0% +12%p 6-b 86.0% 90.0% +4%p top_k=10 순수 검색 a 78.0% 82.0% +4%p top_k=10 순수 검색 b 68.0% 76.0% +8%p top_k=10 최종 a 82.0% 90.0% +8%p top_k=10 최종 b 86.0% 96.0% +10%p 이번 결과에서 가장 중요한 점은 위의 변화가 코드 수정으로 인한 성능 향상이 아니라는 것이다. 동일한 기존 실험 결과를 대상으로 수정된 정답지 기준으로 다시 채점했기 때문에 발생한 변화이다. 따라서 예를 들어 최종 설정이 86%에서 96%가 되었다고 해서 "모델 성능이 10%p 향상되었다." 라고 해석하면 안 된다. 이번 변화는 평가 기준을 바로잡은 결과이다. 5. 최종 설정의 재채점 결과 최종 설정의 경우 다음과 같이 변경되었다. 실행 기존 v2 수정 v4 6-a 공고별 균등 검색 84% 96% 6-b 86% 90% 동일 설정을 2회 실행한 결과의 평균을 비교하면, 기존 v2 평균: 85% 수정된 v4 평균: 93% 이다. 즉, 평가 기준을 수정한 뒤 동일한 결과를 다시 채점했을 때 평균 점수가 8%p 높아졌다. 하지만 이 8%p를 모델의 성능 향상으로 해석하지는 않았다. 이는 정답지 및 채점 기준의 수정으로 인한 평가 결과 변화이기 때문이다. 6. 문서에 없음 정확도 문서에 없음 유형에서도 일부 결과가 달라졌다. 실행 v2 v4 5-a 지시문 v2 80% 100% 6-a 공고별 균등 검색 80% 100% top_k=10 순수 검색 b 100% 80% 나머지 실행은 모두 100% → 100% 로 동일했다. 이번 변화 역시 모델의 성능 변화가 아니라 N01·N02 의 재채점 결과가 달라진 것으로 확인했다. 따라서 이 지표도 정답지 수정에 따른 변화와 실제 모델 개선을 구분해서 해석했다. 7. 정답지 수정과 관계없는 지표 이번 정답지 수정으로 다음 지표에는 변화가 없었다. 최신성 출처 정확도 근거 표시 정확도 검색 적중률 즉, 이번 작업은 검색 시스템 자체를 개선한 실험이 아니었다. 기존 실험 결과를 새로운 정답 기준으로 다시 평가하여 평가셋의 신뢰도를 높이는 과정이었다. 8. 이번 작업에서 알게 된 점 이번 검토를 통해 모든 오답을 단순히 "RAG가 검색을 못했다." 라고 판단하면 안 된다는 것을 확인했다. 평가 결과가 낮은 이유는 크게 다음과 같이 나눌 수 있었다. 평가 결과가 낮음 │ ├── 검색 문제 │ ├── 답변 생성 문제 │ ├── 정답지/채점 기준 문제 │ └── 질문 자체가 애매한 문제 특히 A03, A04, A09처럼 질문보다 정답 기준이 과했던 경우에는 모델을 개선하는 것만으로는 평가의 문제를 해결할 수 없다. 반대로 정답 기준이 적절한 문항에서 답변이 부족하다면 그때는 모델의 검색이나 답변 생성 방식을 개선해야 한다. 9. 이후 평가 기준은 고정 이번 검토를 통해 수정된 정답지를 확정하고, 이후 실험에서는 새로운 정답 기준을 고정해서 사용하기로 했다. 앞으로 성능을 높이기 위해 결과에 맞춰 정답지를 다시 변경하지 않고, 동일한 기준으로 평가한다. 최종 측정은 다음 순서로 진행한다. 평가셋 정답지 검토 ↓ 정답지 수정 ↓ 기존 실험 전체 재채점 ↓ 수정된 결과 확정 ↓ 평가 기준 고정 ↓ 코드 동결 ↓ 새로운 홀드아웃 문항 준비 ↓ 최종 측정 특히 최종 홀드아웃에서는 고치는 동안 한 번도 보지 않은 새로운 문항을 사용하고, 결과가 마음에 들지 않는다고 다시 고치거나 문항을 바꾸지 않고 그대로 실패 사례로 기록할 예정이다. 마무리 이번 작업의 목적은 단순히 정확도 숫자를 높이는 것이 아니었다. 오히려 기존 평가 결과를 다시 살펴보면서, 모델이 틀린 것인지, 정답지가 틀린 것인지, 아니면 질문 자체가 애매한 것인지를 구분하는 것이 목적이었다. 실제로 정답지를 다시 검토한 결과, 일부 문항에서는 질문에서 직접 요구하지 않은 내용을 정답 조건으로 포함하고 있거나 채점 과정에서 잘못 판단하는 문제가 있었다. 따라서 해당 문항을 수정하고 기존 실험 전체를 새로운 기준으로 다시 채점했다. 그 결과 최종 설정의 평균 점수도 기존 85%에서 93% 로 변경되었다. 하지만 이 변화는 모델을 개선해서 얻은 성능 향상이 아니라 평가 기준을 수정한 뒤 동일한 결과를 다시 채점하면서 발생한 변화이다. 이번 과정을 통해 RAG 프로젝트에서는 검색과 생성 모델을 개선하는 것뿐만 아니라, 무엇을 정답으로 볼 것인지에 대한 평가 기준을 제대로 설계하는 것도 중요하다는 것을 확인했다. 이제 수정된 정답지를 고정하고, 이후에는 평가 기준을 변경하지 않은 상태에서 코드 동결 → 홀드아웃 측정 → 최종 성능 평가를 진행할 예정이다.
velog
28일 신고가 돌파 직후 10일간의 횡보, 그리고 -13% 8월 저점 대비 70% 오른 자리에서 들어간 돌파 매수가 단 하루의 급락으로 끝난 날의 기록. 요약 항목 값 총 거래 1건 승 / 패 0 / 1 총 P&L -7.07 USDT 총 수수료 -0.08 USDT 평균 P&L -7.07 USDT 승률 0% 포트폴리오 현황 항목 값 USDT 잔고 261.79 활성 포지션 AVAX(158), SHIB(0), APT(61), PEPE(0), ETHFI(42), MUBARAK(161), BROCCOLI714(53) 미실현 P&L +113.52 USDT 총 포트폴리오 736.96 USDT 거래 상세 1. DOTUSDT — SL (-) 항목 값 진입 2026-09-26 15:55:08 @ 1.287 청산 2026-10-07 02:01:17 @ 1.12 수량 41.91000000 매수 금액 53.94 USDT 매도 금액 46.94 USDT 수수료 -0.0757 USDT P&L -7.07 USDT (-13.12%) 보유 기간 10일 청산 유형 SL 진입 근거: 9월 7일 고점(약 1.29)으로 형성된 28일 Upper Channel을 9월 26일 상향 돌파, 시스템 룰에 따른 정상 진입. 8월 18일 저점 0.75 이후 MA7 > MA28 > MA90 정배열이 유지되던 구간으로, 추세 방향 자체는 상승과 일치. 다만 돌파 당일 볼륨은 9월 초 급등 때 대비 평범한 수준이었고, 돌파 폭도 직전 고점을 간신히 넘는 marginal break였음. 잘한 점 / 아쉬운 점: 잘한 점: 진입 다음 날부터 가격이 1.15~1.25 박스에 갇혀 10일간 재돌파 실패했음에도 SL 도달 전까지 임의 청산하지 않고 시스템을 신뢰함. 잘한 점: 10월 7일 장대 음봉이 SL 라인을 관통했지만 1.12 SL 가격에 체결되어 슬리피지 없이 손실을 제한함. 손실 금액은 포트폴리오의 약 1%로 2% 룰 내. 아쉬운 점: 저점 대비 70% 상승 후의 돌파였고, 직전 고점(9/7) 돌파 실패 이력이 있는 구간이라 Upper Channel이 저항으로 작동한 double-top 형태로 마무리됨. 아쉬운 점: 진입 후 한 번도 의미 있는 추가 상승이 없어 피라미딩 기회 자체가 없었음. 돌파 후 즉시 되밀리는 패턴은 추세 추종 관점에서 가장 비용이 큰 유형. 코인 소개: DOT 마켓 순위: #54 (CoinGecko) 카테고리: Smart Contract Platform, Polkadot Ecosystem, Proof of Stake (PoS), Layer 0 (L0), Pantera Capital Portfolio, GMCI 30 Index, GMCI Index, Made in USA, Coinbase 50 Index, Governance, Base Native Polkadot은 여러 체인(parachain)을 하나의 보안 계층 아래 연결하는 Layer 0 인터체인 플랫폼으로, 2026년 현재 Polkadot 2.0의 Agile Coretime 체제가 가동 중이며 Relay Chain을 대체하는 차세대 프로토콜 JAM(Join-Accumulate Machine)이 핵심 로드맵 네러티브. 2026년 3월 거버넌스를 통해 총 공급량 21억 개 hard cap과 인플레이션 53.6% 감축이 통과되어 토크노믹스가 크게 바뀐 점이 최근 가격 관심의 주요 배경. 시스템 업데이트 (해당 날짜 변경 없음) 일일 회고 오늘의 교훈 28일 신고가 돌파라도 직전 고점을 간신히 넘는 marginal break는 저항 재확인(double top)으로 끝날 확률이 높다. 돌파 폭과 볼륨은 시그널 강도의 핵심 변수. 돌파 후 10일간 진입가를 회복하지 못하는 포지션은 "추세가 아직 안 왔다"는 신호다. 이런 거래의 손실은 시스템이 당연히 지불해야 하는 비용이며, 터틀 방식에서 승률 0%인 날은 통계적으로 정상 범위. 잘한 점 SL 체결가가 설정가와 일치하여 급락장에서도 리스크 통제가 계획대로 작동함. 1회 손실이 포트폴리오의 약 1%로 2% 한도 내에 머물렀고, 미실현 +113 USDT의 다른 포지션들이 손실을 충분히 상쇄 중. 아쉬운 점 8월 저점 대비 70% 상승 후의 늦은 진입이었음에도 포지션 사이즈를 줄이는 장치가 없어 평범한 비중으로 늘어난 구간에 올라탐. 누적 P&L이 -393.5 USDT로 여전히 우하향 추세. 소액 승리는 잦지만 손실을 덮을 홈런급 거래가 부족한 구조가 이어지고 있음. 다음에 적용할 점 돌파 시그널의 품질 지표(직전 고점 대비 돌파 폭, 돌파 봉 볼륨 비율)를 백테스트로 검증하고, 유의미하면 진입 필터가 아닌 사이즈 조절 변수로 반영 검토. 보유 중인 7개 포지션의 미실현 수익을 TS로 끝까지 끌고 가는 데 집중. 손절은 계획대로 작동했으니 이제 수익을 길게 가져가는 쪽에서 기대값을 회복해야 함.
Балл: 54.4Уверенность: 49%
Подробнееvelog
이번 실습에서는 ROS 2의 실행 인자 프로그래밍(Python)을 진행했다. argparse 를 이용해 실행 인자를 설정하고, checker 노드 실행 시 목표 합계값을 직접 전달하는 과정을 실습했다. 1. 실행 인자란? 실행 인자는 프로그램을 실행할 때 명령어와 함께 전달하는 값이다. 이전에 checker 노드를 실행하면서 다음과 같은 명령어를 사용했었다. ros2 run topic_service_action_rclpy_example checker -g 100 여기서 -g 100 이 실행 인자다. ros2 run ↓ checker 실행 ↓ -g 100 ↓ goal_total_sum = 100 PPT에서는 Parameter는 매개 변수, Argument는 실행 인자로 구분해서 설명하고 있다. 2. Python에서 실행 인자 처리 Python에서는 argparse 모듈을 이용해 실행 인자를 처리한다. 실행 인자를 처리하는 과정은 다음과 같다. 1. parser 만들기 ↓ 2. 인자 추가하기 ↓ 3. 인자 파싱하기 ↓ 4. args.xxx로 사용하기 checker/main.py 에서는 sys.argv[1:] 를 이용해 실행 인자를 전달받도록 작성되어 있다. def main(argv=sys.argv[1:]): 그리고 ArgumentParser 를 생성한다. parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter) 3. 실행 인자 추가하기 -g 와 --goal_total_sum 을 실행 인자로 등록했다. parser.add_argument( '-g', '--goal_total_sum', type=int, default=50, help='Target goal value of total sum') 여기서 -g : 짧은 형태 --goal_total_sum : 긴 형태 type=int : 정수형으로 처리 default=50 : 기본값 50 help : 도움말에 표시할 설명 으로 설정되어 있다. 4. 실행 인자 파싱 등록한 실행 인자는 parse_args() 를 통해 분석한다. args = parser.parse_args() 그다음 args.goal_total_sum 을 이용해 실제 값을 사용할 수 있다. checker.send_goal_total_sum(args.goal_total_sum) 즉 실행 인자로 입력한 값이 Checker 의 Goal 값으로 전달된다. 전체적인 흐름은 다음과 같다. 실행 인자 입력 ↓ argparse ↓ parse_args() ↓ args.goal_total_sum ↓ send_goal_total_sum() 5. 기본값으로 실행 먼저 실행 인자를 입력하지 않고 checker 를 실행했다. ros2 run topic_service_action_rclpy_example checker 이 경우 별도의 -g 값을 입력하지 않았기 때문에 goal_total_sum 의 기본값인 50 이 사용된다. 6. -g 를 이용해 실행 이번에는 목표값을 100 으로 지정해서 실행했다. ros2 run topic_service_action_rclpy_example checker -g 100 -g 100 이 실행 인자로 전달되는 것을 확인했다. 즉, -g 100 ↓ args.goal_total_sum = 100 의 형태로 값이 전달된다. 7. -h 로 도움말 확인 실행 인자의 사용 방법을 확인하기 위해 -h 옵션도 사용했다. ros2 run topic_service_action_rclpy_example checker -h 실행 결과: usage: checker [-h] [-g GOAL_TOTAL_SUM] ... positional arguments: argv Pass arbitrary arguments to the executable options: -h, --help show this help message and exit -g GOAL_TOTAL_SUM, --goal_total_sum GOAL_TOTAL_SUM Target goal value of total sum (default: 50) -g 와 --goal_total_sum 을 사용할 수 있고, 기본값이 50 이라는 것을 확인할 수 있었다. 8. 긴 형태의 실행 인자 사용 짧은 형태인 -g 뿐만 아니라 긴 형태인 --goal_total_sum 도 사용할 수 있는지 확인했다. ros2 run topic_service_action_rclpy_example checker --goal_total_sum 100 실행 결과에서 Arithmetic action server is not available. 경고가 출력됐지만, 이는 실행 인자 오류가 아니라 당시 calculator 의 Action Server가 실행되고 있지 않았기 때문에 발생한 메시지였다. 실행 인자 자체는 정상적으로 인식되는 것을 확인했다. 9. 실행 인자가 실제로 사용되는 부분 확인 마지막으로 args.goal_total_sum 이 실제 코드에서 어디에 사용되는지 확인했다. checker.send_goal_total_sum(args.goal_total_sum) 즉 argparse 로 분석한 실행 인자를 send_goal_total_sum() 에 전달하고, 해당 값이 Action의 Goal 값으로 사용되는 구조다. 마무리 이번 실습을 통해 ROS 2 Python에서 실행 인자를 처리하는 방법을 확인했다. sys.argv[1:] 로 실행 인자 전달 argparse.ArgumentParser() 로 parser 생성 add_argument() 로 실행 인자 등록 parse_args() 로 실행 인자 분석 args.goal_total_sum 으로 값 사용 -g 100 으로 실행 인자 전달 --goal_total_sum 100 으로 긴 형태의 실행 인자 전달 -h 를 이용한 실행 인자 도움말 확인
velog
GitHub 링크 Notion 링크 float ASLEnemy::TakeDamage(float Damage, const FDamageEvent& DamageEvent, AController* EventInstigator, AActor* DamageCauser) { 보스 캐릭터 만들기 Contents 보스 캐릭터 Behavior Tree Contents 넉다운 공격 구현 Contents 스트레이프 시스템 Contents
Балл: 54.4Уверенность: 49%
Подробнееvelog
『Real MySQL 8.0』 7장을 읽고, 핵심 개념을 쉽게 이해할 수 있도록 제 방식대로 정리한 글입니다. 📌 들어가기 전에 왜 데이터를 암호화할까? 개인정보, 결제 정보 같은 민감한 데이터 를 보호하기 위해서입니다. 서버의 디스크나 백업 파일이 유출되더라도, 암호화 키가 없으면 내용을 읽을 수 없게 만드는 것이 목적입니다. MySQL 8.0 암호화 대상 한눈에 보기 암호화 대상 설정 다루는 절 테이블(데이터 파일) ENCRYPTION = 'Y' 7.3 언두 로그 / 리두 로그 innodb_undo_log_encrypt , innodb_redo_log_encrypt 7.4 바이너리 로그 / 릴레이 로그 binlog_encryption 7.5 💡 테이블만 암호화하고 로그를 암호화하지 않으면, 로그 파일에 데이터가 평문으로 남을 수 있습니다. 그래서 실제로는 세 가지를 함께 고려해야 합니다. 7.1 MySQL 서버의 데이터 암호화 TDE (Transparent Data Encryption) MySQL의 데이터 암호화는 디스크에 쓰고 읽는 시점 에 동작합니다. [쓰기] 버퍼 풀 (평문) ──암호화──▶ 디스크 (암호문) [읽기] 디스크 (암호문) ──복호화──▶ 버퍼 풀 (평문) MySQL 서버의 다른 부분(쿼리 처리 등)은 데이터가 암호화됐는지 전혀 신경 쓰지 않습니다. 사용자 입장에서도 일반 테이블과 똑같이 사용합니다. 그래서 이 방식을 투명한 데이터 암호화(TDE, Transparent Data Encryption) 라고 부릅니다. 디스크에 저장된 상태의 데이터를 보호한다는 의미로 Data at Rest Encryption 이라고도 합니다. 에디션별 키 관리 방식 (키링 플러그인) 암호화 키는 키링(Keyring) 플러그인 을 통해 관리합니다. 에디션 사용 가능한 키링 커뮤니티 keyring_file (마스터 키를 디스크 파일 에 저장) 엔터프라이즈 keyring_file , keyring_encrypted_file , keyring_okv , keyring_aws 등 (외부 키 관리 서버 연동 가능) 7.1.1 2단계 키 관리 MySQL은 키를 두 단계 로 나눠서 관리합니다. ┌──────────── 키링 (외부 파일 / 키 관리 서버) ────────────┐ │ 🔑 마스터 키 (Master Key) │ └───────────────────────┬──────────────────────────┘ │ 테이블스페이스 키를 암호화 ▼ ┌──────────── 각 테이블 데이터 파일 헤더 ─────────────────┐ │ 🔐 테이블스페이스 키 (Tablespace Key) │ │ (마스터 키로 암호화된 상태로 저장) │ └───────────────────────┬──────────────────────────┘ │ 실제 데이터를 암호화 ▼ ┌──────────── 데이터 파일 ─────────────────────────────┐ │ 📄 암호화된 데이터 │ └──────────────────────────────────────────────────┘ 키 저장 위치 역할 마스터 키 키링(외부 파일 또는 키 관리 서버) 테이블스페이스 키를 암호화 테이블스페이스 키 각 테이블 데이터 파일의 헤더 (마스터 키로 암호화된 상태) 실제 데이터를 암호화 🧩 비유 테이블스페이스 키 = 각 방(테이블)의 문을 여는 열쇠 마스터 키 = 그 방 열쇠들을 넣어둔 금고의 열쇠 금고 열쇠(마스터 키)는 건물 밖(키링)에 따로 보관 왜 2단계로 나눌까? → 마스터 키 변경이 빠르다 보안 정책상 키는 주기적으로 변경 해야 합니다. ALTER INSTANCE ROTATE INNODB MASTER KEY; 마스터 키 변경 시 1. 새로운 마스터 키 발급 2. 모든 테이블스페이스 키를 기존 마스터 키로 복호화 3. 새 마스터 키로 다시 암호화해서 데이터 파일 헤더에 저장 → 데이터 파일 전체를 다시 암호화할 필요 없음 ✅ 키를 하나만 쓴다면 2단계 키를 쓴다면 키를 바꿀 때마다 모든 데이터 파일을 다시 암호화 → 매우 오래 걸림 테이블스페이스 키만 다시 암호화 → 빠름 💡 테이블스페이스 키는 MySQL 서버 외부로 노출되지 않기 때문에 따로 변경할 필요가 없습니다. 암호화 알고리즘 대상 알고리즘 테이블스페이스 키 암호화 AES 256비트 (ECB 모드) 실제 데이터 암호화 AES 256비트 (CBC 모드) 7.1.2 암호화와 성능 언제 암호화·복호화가 일어날까? 작업 시점 사용자 응답에 영향 복호화 디스크에서 읽어 버퍼 풀에 올릴 때 한 번 디스크에서 읽어야 하는 경우 약간 느려짐 암호화 더티 페이지를 디스크에 기록할 때 백그라운드 스레드가 처리하므로 거의 없음 버퍼 풀에 이미 있는 데이터 → 이미 복호화된 상태 → 추가 비용 없음 ✅ 버퍼 풀에 없는 데이터 → 디스크에서 읽으며 복호화 → 약간의 지연 💡 데이터 대부분이 버퍼 풀에 올라와 있는 서버라면, 암호화로 인한 성능 영향은 크지 않습니다. 책의 테스트에서도 페이지 하나를 읽고 쓰는 시간은 몇 배 늘어났지만, 마이크로초 단위 라 체감은 크지 않은 수준이었습니다. 암호화 + 압축을 함께 쓴다면? 1 압축 먼저 → 2 그 다음 암호화 이유 설명 압축 효율 암호화된 데이터는 랜덤한 바이트처럼 보여서 거의 압축되지 않음 → 압축을 먼저 해야 효과가 있음 버퍼 풀 활용 버퍼 풀에는 압축만 된(암호화되지 않은) 페이지 가 올라오므로, 버퍼 풀 안에서는 복호화가 필요 없음 7.1.3 암호화와 복제 소스 서버와 레플리카는 각자의 마스터 키를 가진다 ┌─── 소스 서버 ───┐ ┌─── 레플리카 ───┐ │ 🔑 마스터 키 A │ ──복제──▶ │ 🔑 마스터 키 B │ │ 데이터: 동일 │ │ 데이터: 동일 │ │ 파일 내용: 다름 │ │ 파일 내용: 다름 │ └───────────────┘ └───────────────┘ 복제 소스와 레플리카는 서로 다른 마스터 키 를 사용합니다. 그래서 데이터 내용은 같아도, 암호화된 데이터 파일 내용은 서로 다릅니다. ALTER INSTANCE ROTATE INNODB MASTER KEY 명령이 레플리카로 복제되더라도, 레플리카는 자기만의 새로운 마스터 키 를 생성합니다. ⚠️ 백업 시 주의 주의점 설명 키링 파일도 백업 키링 파일이 없으면 백업한 데이터를 복구할 수 없음 분리 보관 키링 파일을 데이터 백업과 같은 곳에 두면 암호화한 의미가 없음 → 별도로 안전하게 보관 💡 TDE를 사용한다면, 데이터 백업 + 키링 파일 백업 을 함께 관리해야 합니다. 7.2 keyring_file 플러그인 설치 keyring_file 플러그인이란? MySQL 커뮤니티 에디션에서 사용할 수 있는 키링 플러그인입니다. 마스터 키를 디스크의 파일 에 저장합니다. ⚠️ 마스터 키가 평문 파일 로 저장되기 때문에, 파일이 유출되면 암호화가 무의미해집니다. 파일 위치와 접근 권한을 철저히 관리해야 합니다. 설치 방법 키링 플러그인은 다른 플러그인보다 먼저 초기화되어야 하므로, early-plugin-load 옵션으로 설정합니다. # my.cnf [mysqld] early-plugin-load = keyring_file.so keyring_file_data = /very/secure/directory/tde_master.key 설정 설명 early-plugin-load MySQL 서버가 시작될 때 가장 먼저 로드할 플러그인 keyring_file_data 마스터 키를 저장할 파일 경로 💡 하나의 MySQL 서버에서 여러 인스턴스를 실행한다면, 인스턴스마다 다른 키링 파일 경로 를 지정해야 합니다. 설치 확인 SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'keyring%'; +--------------+---------------+ | PLUGIN_NAME | PLUGIN_STATUS | +--------------+---------------+ | keyring_file | ACTIVE | +--------------+---------------+ 서버를 시작하면 키링 파일이 빈 파일 로 생성됩니다. 실제 마스터 키는 암호화된 테이블을 처음 생성하거나 마스터 키를 로테이션할 때 만들어집니다. 💡 참고로 MySQL 8.0.24부터는 키링 플러그인 대신 컴포넌트 ( component_keyring_file ) 사용이 권장됩니다. 7.3 테이블 암호화 7.3.1 테이블 생성 암호화 테이블 생성 CREATE TABLE tab_encrypted ( id INT, data VARCHAR(100), PRIMARY KEY (id) ) ENCRYPTION = 'Y'; INSERT INTO tab_encrypted VALUES (1, 'test_data'); SELECT * FROM tab_encrypted; -- 일반 테이블과 똑같이 조회됨 💡 사용자 입장에서는 ENCRYPTION = 'Y' 옵션만 추가하면 되고, 사용 방법은 일반 테이블과 같습니다. 암호화된 테이블 확인 SELECT table_schema, table_name, create_options FROM information_schema.tables WHERE create_options LIKE '%ENCRYPTION="Y"%'; 모든 테이블을 기본으로 암호화하려면? SET GLOBAL default_table_encryption = ON; 이 설정을 켜면 ENCRYPTION 옵션을 지정하지 않아도 새로 생성하는 테이블이 자동으로 암호화 됩니다. 7.3.2 응용 프로그램 암호화와의 비교 암호화는 MySQL(TDE)에서 할 수도 있고, 애플리케이션에서 직접 할 수도 있습니다. [응용 프로그램 암호화] 애플리케이션: '1990' ──암호화──▶ 'xK9#mQ2...' ──저장──▶ MySQL → MySQL은 'xK9#mQ2...'가 무슨 값인지 모름 [TDE] 애플리케이션: '1990' ──저장──▶ MySQL ──디스크 기록 시 암호화──▶ 디스크 → MySQL 내부에서는 '1990'으로 인식 응용 프로그램 암호화의 문제점 애플리케이션에서 암호화한 값은 MySQL 입장에서 의미 없는 문자열 이기 때문에 이런 쿼리를 쓸 수 없습니다. -- birth_year 컬럼을 애플리케이션에서 암호화했다면 -- ❌ 범위 검색 불가 SELECT * FROM app_user WHERE birth_year BETWEEN 2000 AND 2010; -- ❌ 정렬 불가 SELECT * FROM app_user ORDER BY birth_year LIMIT 10; 문제 설명 범위 검색 불가 암호화된 값은 크기 비교가 의미 없음 정렬 불가 암호문 순서 ≠ 원래 값 순서 인덱스 활용 제한 범위 조건이나 정렬에 인덱스를 쓸 수 없음 비교 항목 응용 프로그램 암호화 TDE (MySQL 암호화) 암호화 위치 애플리케이션 MySQL 서버 (디스크 I/O 시점) 범위 검색 / 정렬 ❌ ✅ 인덱스 활용 제한적 일반 테이블과 동일 SQL로 조회 시 암호문 으로 보임 (DB 관리자도 내용을 모름) 평문 으로 보임 ✅ 정리 검색·정렬이 필요한 컬럼 → TDE DB 관리자에게도 노출되면 안 되는 민감한 컬럼(주민번호, 카드번호 등) → 응용 프로그램 암호화 보안 요구사항에 따라 두 가지를 함께 적용 할 수도 있습니다. 7.3.3 테이블스페이스 이동 테이블스페이스 이동이란? 테이블 데이터를 덤프해서 다시 넣는 대신, 데이터 파일( .ibd ) 자체를 복사 해서 다른 서버로 옮기는 기능입니다. 💡 데이터가 많을 때 mysqldump 로 덤프·적재하는 것보다 훨씬 빠릅니다. 일반 테이블 이동 과정 -- [원본 서버] FLUSH TABLES source_table FOR EXPORT; -- → source_table.cfg 파일 생성 (테이블 구조 정보) -- → .ibd, .cfg 파일 복사 UNLOCK TABLES; 암호화된 테이블이라면? 암호화된 테이블은 원본 서버의 마스터 키 로 테이블스페이스 키가 암호화되어 있습니다. 다른 서버는 그 마스터 키를 모르기 때문에, 파일만 복사하면 복호화할 수 없습니다. 그래서 FLUSH TABLES ... FOR EXPORT 실행 시 파일이 하나 더 생성됩니다. 파일 내용 .ibd 실제 데이터 파일 .cfg 테이블 구조 정보 .cfp 임시 마스터 키 로 암호화한 테이블스페이스 키 [원본 서버] FLUSH TABLES source_table FOR EXPORT; → 임시 마스터 키 생성 → 테이블스페이스 키를 임시 마스터 키로 암호화해서 .cfp 파일에 저장 → .ibd, .cfg, .cfp 파일 복사 UNLOCK TABLES; [대상 서버] ALTER TABLE target_table DISCARD TABLESPACE; → 복사한 .ibd, .cfg, .cfp 파일을 데이터 디렉터리에 배치 ALTER TABLE target_table IMPORT TABLESPACE; → .cfp 파일로 테이블스페이스 키를 복호화 → 대상 서버의 마스터 키로 다시 암호화해서 저장 ✅ ⚠️ .cfp 파일을 빠뜨리면 복구할 수 없습니다. 암호화된 테이블을 이동할 때는 반드시 .cfp 파일까지 함께 복사해야 합니다. 7.4 언두 로그 및 리두 로그 암호화 문제: 테이블만 암호화하면 로그는 평문 테이블 데이터 파일 → 암호화 ✅ 리두 로그 / 언두 로그 → 평문 ❌ ← 여기에 데이터 변경 내용이 그대로 남음 테이블을 암호화해도, 리두 로그와 언두 로그 에는 데이터 변경 내용이 평문으로 기록될 수 있습니다. MySQL 8.0.16부터 리두 로그와 언두 로그도 암호화할 수 있습니다. 설정 SET GLOBAL innodb_undo_log_encrypt = ON; SET GLOBAL innodb_redo_log_encrypt = ON; -- 설정 확인 SHOW GLOBAL VARIABLES LIKE 'innodb_%_log_encrypt'; 동작 방식 상황 결과 암호화를 켜면 켠 시점 이후 에 기록되는 로그만 암호화. 이전 로그는 평문 그대로 암호화를 끄면 이후 로그는 평문. 이미 암호화된 로그는 암호화된 상태 그대로 유지 ⚠️ 암호화를 껐더라도 이전에 암호화된 로그가 남아 있다면, 복구할 때 암호화 키가 여전히 필요 합니다. 키 관리 🔑 마스터 키 └─ 🔐 리두 로그 / 언두 로그 전용 프라이빗 키 (로그 파일 헤더에 암호화되어 저장) └─ 📄 리두 로그 / 언두 로그 데이터 암호화 리두 로그와 언두 로그는 테이블스페이스 키가 아니라, 각각의 프라이빗 키 로 암호화됩니다. 이 프라이빗 키는 마스터 키로 암호화 되어 로그 파일의 헤더 에 저장됩니다. 7.5 바이너리 로그 암호화 문제: 바이너리 로그도 평문 바이너리 로그에는 데이터 변경 내용이 그대로 기록됩니다. 바이너리 로그는 복제나 시점 복구(PITR)를 위해 오랫동안 보관 하는 경우가 많아서, 유출 위험도 큽니다. MySQL 8.0.14부터 바이너리 로그를 암호화할 수 있습니다. SET GLOBAL binlog_encryption = ON; 💡 바이너리 로그뿐 아니라 레플리카의 릴레이 로그 도 함께 암호화됩니다. 7.5.1 바이너리 로그 암호화 키 관리 바이너리 로그도 2단계 키 관리 방식을 사용합니다. ┌──────────── 키링 ────────────────────────────┐ │ 🔑 바이너리 로그 암호화 키 │ ← 테이블 암호화의 "마스터 키" 역할 └───────────────────┬─────────────────────────┘ │ 파일 키를 암호화 ▼ ┌──────────── 각 바이너리 로그 / 릴레이 로그 파일 헤더 ──┐ │ 🔐 파일 키 (File Key) │ ← 파일마다 하나씩 └───────────────────┬─────────────────────────┘ │ 실제 로그 데이터를 암호화 ▼ 📄 암호화된 바이너리 로그 키 비교 대상 역할 바이너리 로그 암호화 키 테이블 암호화의 마스터 키 파일 키를 암호화 파일 키 테이블 암호화의 테이블스페이스 키 바이너리 로그 파일마다 하나씩 생성되어 로그 데이터를 암호화 7.5.2 바이너리 로그 암호화 키 변경 ALTER INSTANCE ROTATE BINLOG MASTER KEY; 키 변경 과정 1. 새로운 바이너리 로그 암호화 키를 발급해서 키링 파일에 저장 2. 바이너리 로그 파일과 릴레이 로그 파일을 새 파일로 전환(로테이션) 3. 새로 생성되는 로그 파일의 파일 키는 새 암호화 키로 암호화 4. 기존 바이너리 로그·릴레이 로그 파일의 파일 키를 읽어서 새 암호화 키로 다시 암호화 (암호화되지 않은 로그 파일은 무시) 5. 모든 파일의 변환이 끝나면, 기존 바이너리 로그 암호화 키를 키링 파일에서 삭제 ⚠️ 4번은 보관 중인 바이너리 로그 파일이 많으면 시간이 오래 걸릴 수 있습니다. 대신 로그 데이터 전체가 아니라 파일 키만 다시 암호화 하므로, 2단계 키 관리 덕분에 그나마 빠르게 처리됩니다. 암호화 여부 확인 SHOW BINARY LOGS; +------------------+-----------+-----------+ | Log_name | File_size | Encrypted | +------------------+-----------+-----------+ | mysql-bin.000010 | 3047 | No | | mysql-bin.000011 | 512 | Yes | +------------------+-----------+-----------+ 7.5.3 mysqlbinlog 도구 활용 문제: 암호화된 바이너리 로그는 직접 열 수 없다 mysqlbinlog 는 바이너리 로그 내용을 확인하거나 시점 복구(PITR)를 할 때 많이 쓰는 도구입니다. 그런데 암호화된 바이너리 로그 파일을 직접 열면 에러가 발생 합니다. mysqlbinlog -vvv mysql-bin.000011 # → 파일이 암호화되어 있어서 읽을 수 없다는 에러 발생 ❌ 바이너리 로그 암호화 키는 MySQL 서버만 키링을 통해 접근할 수 있기 때문입니다. mysqlbinlog 는 키링에 직접 접근할 수 없습니다. 해결: MySQL 서버를 통해 읽기 mysqlbinlog -uroot -p -vvv --read-from-remote-server mysql-bin.000011 옵션 설명 --read-from-remote-server 파일을 직접 읽지 않고, MySQL 서버에 접속해서 바이너리 로그를 받아옴 mysqlbinlog ──요청──▶ MySQL 서버 (키링 접근 가능) │ 복호화 mysqlbinlog ◀──평문── MySQL 서버 💡 MySQL 서버가 바이너리 로그를 복호화해서 전달 하기 때문에 내용을 확인할 수 있습니다. ⚠️ 백업·복구 시 주의 백업해둔 암호화된 바이너리 로그를 나중에 사용하려면, 해당 키를 가진 MySQL 서버를 거쳐야 합니다. 그래서 바이너리 로그를 백업할 때는 키링 파일도 함께 백업 해야 합니다. ✍️ 마무리 정리 7.1 MySQL 서버의 데이터 암호화 TDE : 디스크에 쓸 때 암호화, 읽을 때 복호화. 사용자는 일반 테이블처럼 사용 2단계 키 관리 : 마스터 키(키링) → 테이블스페이스 키(데이터 파일 헤더) → 데이터 마스터 키 변경 시 테이블스페이스 키만 다시 암호화 하므로 빠름 버퍼 풀에 올라온 데이터는 복호화 상태 → 성능 영향은 크지 않음 압축과 함께 쓰면 압축 먼저, 암호화 나중 복제 소스와 레플리카는 각자의 마스터 키 사용, 키링 파일은 별도 백업 7.2 keyring_file 플러그인 설치 커뮤니티 에디션용, 마스터 키를 평문 파일 에 저장 → 파일 관리 주의 early-plugin-load 로 가장 먼저 로드 7.3 테이블 암호화 ENCRYPTION = 'Y' 로 생성, default_table_encryption 으로 기본값 설정 가능 응용 프로그램 암호화는 범위 검색·정렬 불가 , TDE는 제약 없음 암호화 테이블 이동 시 .cfp 파일 필수 7.4 언두 로그 및 리두 로그 암호화 innodb_undo_log_encrypt , innodb_redo_log_encrypt (8.0.16+) 켠 이후의 로그만 암호화, 끄더라도 기존 암호화 로그는 그대로 7.5 바이너리 로그 암호화 binlog_encryption (8.0.14+), 릴레이 로그도 함께 암호화 바이너리 로그 암호화 키 → 파일 키 → 로그 데이터 2단계
velog
Warriors vs Northern Cape previews the 28th T20 match of the CSA T20 Challenge 2026, with both teams looking to strengthen their position in the competition. Warriors will aim to make the most of their batting depth and home conditions, while Northern Cape will look to counter with disciplined bowling and key contributions from their experienced players. With the match expected to feature an exciting contest between bat and ball, this Warriors vs Northern Cape Match Prediction covers the teams’ recent form, pitch conditions, predicted playing XIs and key players to watch before assessing who has the stronger chance of winning today’s match. Warriors vs Northern Cape, Match Details: Location: St George’s Park, Gqeberha, South Africa Venue: St George’s Park, Port Elizabeth Date & Time: 8th Oct/ 09:00 PM PST LOCAL Time Streaming: FanCode Establish: 1889 Capacity: 19,000 Owner: N/A Home Team: Sunrisers Eastern Cape End Name: Duckpond End & Park Drive End Flood Light: Yes Warriors vs Northern Cape Head-to-Head: Total Match: 0 Warriors: 0 Northern Cape: 0 No Result: 0 Tie: 0 Warriors vs Northern Cape Team Form: Warriors: NR, W, L, W, A Northern Cape: A, L, A, A, L Warriors vs Northern Cape Last Five Head-to-Head Matches: The teams haven’t faced each other till now. Warriors vs Northern Cape Weather Report: Temperature: 21° Humidity: 70% Wind Speed: 23 km/hr Cloud Cover: 5% Warriors vs Northern Cape Pitch Report: St George’s Park in Gqeberha generally offers a balanced T20 surface, with the new ball providing some assistance to pace bowlers while batters can score freely once they settle. Recent T20 data at the venue shows an average first-innings score of around 158, while the last five matches have produced an average of approximately 164, indicating that scoring conditions can improve for batters. Pacers have taken a larger share of wickets at the ground, although spinners can also play an important role as the innings progresses. Warriors vs Northern Cape Match Performance: Total Matches Played: 10 1st Batting Team Won: 4 2nd Batting Team Won: 6 No Result: 0 Average Batting Score: 134 Highest Score: 180/7 Lowest Score: 0/0 Pitch Report: Bowling Pitch Warriors Playing XI: Jean du Plessis, Jordan Hermann, Sibonelo Makhanya, Matthew De Villiers (C), Jp King, Patrick Kruger, Andile Mokgakane, Thomas Kaber, Beuran Hendricks, Wesley Bedja, Kerwin Mungroo Northern Cape Playing XI: Gerhardus Maree (C), Nonelela Yikha, Kyle Jacobs, Blake Simpson, Tahir Isaacs, Jordan Neill, Romano Terblanche, Ruan van Rooyen, Tshepo Ntuli, Johannes van Dyk, Odirile Modimokoane Injury and Availability: We will add any updates here. Warriors vs Northern Cape Match Prediction Tips: Who Will Win the Toss: Northern Cape Match Winner: Warriors Total Boundaries: 20+ Player Of The Match: Jordan Hermann 1st Innings Total: 180+ Most Wicket Taker: Matthew De Villiers Warriors vs Northern Cape Match Prediction: Warriors will win this match.
velog
(출처: arXiv:2609.32993, Figure 2) X-Tree: Tokenizing Reusable Experience for Efficient Agent Generalization 저자 : Sitao Cheng, Xunjian Yin, Zhiyuan Sun, Yuxuan Li, Ruiwen Zhou, Xiangru Jian, Victor Zhong 소속 : University of Waterloo, Duke University, National University of Singapore 공개일 : 2026년 9월 26일 (arXiv v1, cs.AI) arXiv : https://arxiv.org/abs/2609.32993 코드 : https://github.com/sitaocheng/X-Tree · 프로젝트 페이지 : https://sitaocheng.github.io/xtree 분류 : LLM Agent / Reinforcement Learning / Skill Discovery / Experience Reuse 🔖 TL;DR (한눈에) 멀티스텝 에이전트 학습은 궤적(trajectory)을 평평한 액션 스트림 으로 소비한다. SFT와 RLVR은 모든 토큰에 같은 가중치를 주기 때문에, 과제마다 반복되는 하위 절차(sub-procedure)의 계층 구조를 전혀 활용하지 못한다 . 기존 에이전트 하네스는 이 구조를 쓰긴 하지만 LLM이 글로 써낸 스킬을 프롬프트에 넣는 방식 이라, 효과가 "검색해서 끼워넣기" 범위를 넘지 못하고 가중치에는 남지 않는다 . X-Tree는 LLM 호출 0회 로, 텍스트 토크나이저가 빈도만 세어 어휘를 만드는 것과 같은 방식으로 궤적에서 계층을 캐낸다. 액션을 verb⟨role⟩ 형태로 정규화한 뒤 재사용성 점수(X-Score) 로 인접 쌍을 BPE처럼 병합해 트리를 만든다. 각 노드는 "자주 등장하고 성공과 결부된 스킬이 하위 스킬로 어떻게 조립되는가"를 담고, 이를 데이터(오프라인 RL) · 보상(온라인 RLVR) · 컨텍스트(OPSD) 세 경로로 학습에 투입한다. WebArena·ScienceWorld·WebShop 3개 환경, 1.5B/3B/7B 3개 스케일에서 동일 데이터·동일 예산 조건으로 기존 레시피를 앞섰다(WebArena +4.5 SR, ScienceWorld +5.8 SR, WebShop +4.1 success). 특히 무작위 트리(17.9 SR)가 트리를 아예 안 쓴 경우(19.9 SR)보다 나빴다 — 성능이 "쪼개기" 자체가 아니라 구조의 질 에서 나온다는 증거. 한 줄 요약 : 에이전트 궤적 속에 암묵적으로 깔려 있던 "재사용 가능한 절차"를, LLM 없이 통계적 병합만으로 명시적 스킬 트리로 뽑아내고, 그 트리를 데이터·보상·컨텍스트 세 방향에서 모델 가중치에 심는 방법. 📄 초록(Abstract) 완역 멀티스텝 에이전트는 평평한 액션 스트림 위에서 학습된다. SFT와 RLVR은 모든 토큰에 균일한 가중치를 부여하며, 과제들에 걸쳐 반복적으로 나타나는 하위 절차들 — 즉 사람이 재사용 가능한 루틴으로부터 하향식(top-down)으로 계획을 세울 수 있게 해주는 그 계층 구조 — 을 무시한다. 이 구조는 쓰이지 않은 채 방치되고, 평평한 학습은 각각의 희소한 궤적을 그 내용이 허용하는 수준보다 덜 활용한다. 최근의 에이전트들은 그 구조를 실제로 사용하기는 하지만, 오직 LLM이 작성한 스킬을 컨텍스트에 넣는 형태로만 사용하며 가중치에는 결코 반영하지 않기 때문에, 그 이득이 검색(retrieval)의 범위를 넘어 일반화되지 않는다. 우리는 대신 이 계층 구조를 데이터 자체로부터 복원하여 그 위에서 학습하며, 이때 LLM 호출은 전혀 사용하지 않는다. 오직 세는 것만으로 어휘를 구축하는 텍스트 토크나이저를 따라, 우리는 액션 구간(span)들을 재사용성 기준으로 점수화하고 정규화된 액션들을 병합하여 재사용 가능한 경험 트리(reusable eXperience tree, X-Tree)를 만든다. 각 X-Tree 노드는 자주 등장하며 성공을 담지하는(success-bearing) 스킬이 하위 스킬들로부터 어떻게 구성되는지를 포착하여, 효율적인 일반화를 유도한다. 우리는 X-Tree를 세 가지 학습 설정에 통합한다: 각 노드를 하나의 학습 인스턴스로 쓰는 오프라인 RL, 적응적 스킬 보너스를 쓰는 온라인 RLVR, 그리고 X-Tree를 자기-교사(self-teacher)의 특권적 컨텍스트로 쓰는 온-폴리시 자기증류(on-policy self-distillation). WebArena, ScienceWorld, WebShop에서 세 가지 모델 스케일에 걸쳐, X-Tree는 동일한 데이터와 예산 조건에서 표준 레시피를 최대 WebArena 4.5% SR, ScienceWorld 5.8% SR, WebShop 4.1% success만큼 개선한다. 대조 분석들은 그 이득이 X-Tree의 구조와 세 가지 통합 방식에서 비롯됨을 보여준다. 요약 정리 : 저자들의 진단은 "데이터가 부족한 게 아니라, 있는 데이터를 평평하게 소비해서 덜 뽑아먹고 있다"는 것이다. 해법은 궤적에서 반복·성공 패턴을 통계적으로 병합해 스킬 계층(X-Tree)을 만드는 것. 핵심 차별점은 두 가지로, (1) 스킬 추출에 LLM을 쓰지 않아 결정론적이고 감사(audit) 가능하며, (2) 스킬을 프롬프트에 끼워넣는 데 그치지 않고 데이터·보상·컨텍스트 세 경로로 가중치에 학습시킨다 는 점이다. 🧩 왜 이 문제가 중요한가 (배경) 에이전트를 학습시킬 때 가장 비싼 자원은 GPU가 아니라 궤적 이다. 웹 환경에서 성공한 멀티스텝 궤적 하나를 얻으려면 긴 롤아웃과 검증이 필요하고, 사람이 라벨링하면 더 비싸다. 그런데 이 귀한 궤적을 학습에 넣는 방식은 지금까지 거의 한 가지였다. 액션을 토큰 시퀀스로 늘어놓고 SFT로 따라 하게 하거나, 에피소드 끝의 성공/실패 하나로 RLVR을 돌리는 것이다. 문제는 이 두 방식 모두 궤적을 구조 없는 긴 끈 으로 취급한다는 데 있다. 웹 에이전트가 쇼핑 사이트에서 "검색창에 질의를 입력하고 → 결과에서 상품을 고르고 → 옵션을 선택하고 → 구매"를 수행했다면, 이 네 단계는 과제가 바뀌어도 거의 그대로 재등장하는 덩어리 다. 사람은 이런 덩어리를 "루틴"으로 묶어 기억하고, 새 과제를 만나면 루틴 단위로 하향식 계획을 세운다. 반면 평평한 학습은 click 이라는 토큰 하나하나에 같은 무게를 둘 뿐, "이 네 개가 하나의 단위다"라는 사실을 모델에 알려주지 않는다. 이 지점이 바로 암묵지(tacit knowledge)의 데이터화 문제와 맞닿는다. 성공한 궤적 안에는 "이 환경에서 무엇이 통하는 절차인가"라는 지식이 이미 들어 있지만, 그것은 액션 나열 속에 암묵적으로 흩어져 있다. 명시적으로 꺼내 쓰려면 누군가 구조화해야 한다. 최근 연구들(AWM, Voyager, SkillWeaver 등)의 답은 "LLM에게 궤적을 읽히고 스킬을 글로 쓰게 하라"였다. 이 방식은 작동하지만 세 가지 비용을 치른다. 첫째, 스킬 추출 단계마다 LLM 호출 비용 이 든다. 둘째, LLM이 써낸 스킬 설명은 비결정론적이고 검증하기 어렵다 . 셋째, 그리고 가장 중요하게, 그 스킬은 추론 시점에 프롬프트로 검색해 넣어야만 효과가 있다. 모델 가중치는 스킬을 배우지 못했으므로, 검색이 실패하거나 컨텍스트에서 빠지면 이득도 사라진다. X-Tree는 이 세 비용을 동시에 공격한다. "LLM에게 요약을 시키지 말고, 토크나이저처럼 세기만 하라"는 것이 출발점이다. BPE가 코퍼스에서 자주 붙어 나오는 문자 쌍을 병합해 서브워드 어휘를 만드는 것처럼, 자주 붙어 나오고 성공과 결부된 액션 쌍을 병합해 스킬 어휘를 만든다. 그리고 그 어휘를 프롬프트가 아니라 학습 신호 로 쓴다. 🔬 방법론 X-Tree는 크게 두 부분이다. 궤적 풀에서 트리를 캐내는 마이닝 단계 , 그리고 그 트리를 학습에 투입하는 세 가지 통합 방식 이다. (출처: arXiv:2609.32993, Figure 1) 1단계: 액션 정규화 (Canonicalization) 원시 액션을 그대로 세면 아무것도 반복되지 않는다. click(element_id=4821) 과 click(element_id=7733) 은 문자열로는 다른 액션이지만, 추상 수준에서는 둘 다 "링크를 클릭했다"다. 그래서 각 액션을 verb⟨role⟩ 형태의 타입 토큰으로 바꾼다. verb : 액션의 함수 이름에서 가져온다. role : 그 verb가 작용하는 대상의 클래스. WebArena에서는 접근성 트리(accessibility tree)의 role을, ScienceWorld에서는 9개 객체 클래스 어휘(door, instrument, paint, container, device, plant, animal, substance, location)를 쓴다. slot : element ID, 입력한 텍스트, 옵션 값 같은 구체적 값은 심볼에서 제거하되 따로 저장한다 . 그래서 마이닝이 끝난 뒤에도 원래 값을 복원할 수 있다. 에이전트의 thought는 아예 제외한다. 예를 들어 WebArena에서 fill 과 type 은 모두 type 으로, goto / go_back / go_forward 는 모두 navigate 로 접힌다. 중요한 점은 이 매핑이 환경별로 액션 스페이스를 보고 한 번 작성하는 고정 템플릿 이라는 것이다. 학습도, LLM 호출도 없다. 2단계: X-Score로 병합 (Eq. 1) 인접한 두 심볼 u, v (각각 원시 액션이거나 이전 병합으로 만들어진 노드)에 대해 병합 후보 uv 의 점수를 이렇게 매긴다. X(u, v) = f_uv · (l_u + l_v)^{p_l} · (succ(uv) + ε)^{p_s} 세 항의 직관은 각각 반복성 · 길이 · 성공 이다. f_uv : 코퍼스 전체에서 (u,v) 가 인접해 등장한 횟수 → 자주 쓰이는 쌍일수록 높다. l_u + l_v : 후보가 펼쳐지는 원시 액션 개수(원시 액션은 l=1) → 긴 덩어리를 선호한다. succ(uv) : 그 f_uv 번의 등장 중 성공한 에피소드에 속한 비율 → 성공과 결부된 패턴을 선호한다. p_l , p_s : 길이와 성공의 가중 지수. 주요 3개 환경에서 p_l = 1, p_s = 1 , MiniWoB++에서는 p_s = 1.5 . ε = 0.001 . 이 공식의 효과는 명확하다. 길고 믿을 만하며 반복되는 쌍이, 자주 나오지만 짧거나 실패와 얽힌 쌍을 이긴다. 단순 빈도 기반 BPE와 결정적으로 다른 지점이 바로 succ 항이다. 여기에 압축 제약 이 붙는다. f_uv − 1 > η · (l_u + l_v) 병합은 코퍼스에서 f_uv − 1 개의 심볼 등장을 없애는 대신 길이 l_u + l_v 의 어휘 항목 하나를 추가한다. η 는 그 항목의 비용을 정한다. 이 제약이 없으면 코퍼스가 소수의 거대한 심볼로 붕괴한다. 3단계: 트리 구축 초기화 — 각 궤적을 정규화된 원시 액션 시퀀스로 두고, 원시 액션을 리프로 삼는다. 카운트 — 현재 코퍼스에서 모든 인접 쌍의 f_uv , 길이, succ 를 센다. 필터 — 압축 제약과 함께 빈도( f_min ), 길이( L_max ), 성공률( s_min ), 과제 유형 수( T_min ) 필터를 통과한 후보만 남긴다. 선택 — X-Score가 가장 높은 후보를 고른다. 병합 — 노드 v = uv 를 만들고 자식을 (u, v) 로 기록한 뒤, 코퍼스의 해당 인접 등장들을 v 로 치환한다. 노드는 길이 l_v , 깊이 d_v , 등장 횟수, 성공률을 함께 들고 있다. 후보가 없거나 스킬 상한 K 에 도달하면 멈춘다. 그렇지 않으면 2번으로. 깊이는 조립 트리의 높이 다. 리프는 d=0 이고, 내부 노드는 d_v = 1 + max(자식들의 깊이) . 트리를 궤적에 적용할 때는 가장 큰 노드로 궤적을 타일링(tiling) 하고, 어떤 스킬에도 덮이지 않은 위치는 원시 토큰으로 남긴다. 이 타일링이 세 가지 통합 방식 모두가 쓰는 단위다. 환경별 마이닝 하이퍼파라미터는 다음과 같다. 기호 의미 WebArena ScienceWorld WebShop η 압축 비용 0.3 0.5 0.5 K 스킬 상한 256 80 60 L_max 최대 스킬 길이(액션) 12 8 8 f_min 최소 쌍 빈도 4 5 5 s_min 최소 스킬 성공률 0 0.9 0 T_min 스킬당 최소 과제 유형 수 1 2 1 실제로 캐낸 트리의 규모는 이렇다. 벤치마크 마이닝 궤적 수 원시 액션 타입 수 캐낸 스킬 수 WebArena 7,974 139 256 (상한 도달) ScienceWorld 1,673 84 80 (상한 도달) WebShop 1,824 17 48 (압축 제약에 걸림) WebArena 학습에 쓰인 노드 집합은 총 5,148개 로, 깊이 1이 약 3.5k, 깊이 2가 1.2k, 깊이 3이 0.4k다. ScienceWorld에서는 깊이 6까지 나타난다. (출처: arXiv:2609.32993, Figure 5) 위 그림이 이 방법의 정체를 가장 잘 보여준다. ScienceWorld의 "침실에서 미지의 물질 B의 온도를 측정해 50도 이상이면 초록 상자, 미만이면 파란 상자에 넣어라"라는 과제에서, 18개 액션이 4개의 X-Tree 노드와 2개의 원시 액션, 즉 6개 토큰으로 압축된다. 그중 S2(보라색)는 서로 다른 두 토큰 안에 중첩되어 재등장한다. 통합 1: 오프라인 RL (데이터로서의 X-Tree) 궤적의 위치 t 에 있는 각 X-Tree 노드 v 가 하나의 RL 인스턴스 가 된다. 정책은 정답 접두사 s_<t 를 조건으로 받아 최대 l_v 스텝을 생성한다. 각 스텝 j 에서 정답 액션과 대상 요소를 모두 맞추면 match_j = 1 이고, 첫 불일치에서 롤아웃을 중단 한다. 맞춘 스텝에 대해서는 기록된 정답 관측(observation)을 붙여준다 — 그래서 롤아웃이 존재하지 않는 관측을 상상하지 않는다(오프라인 안전성). 보상은 c_v = ∏_j match_j (모든 스텝을 맞췄을 때만 1)로 두고, r = (1 − α) · (1/l_v) Σ_j match_j + α · (1 + γ·d_v) · c_v α = 0.3 , γ = 0.5 . 첫 항은 정답 경로를 따라가는 데 주는 조밀한 크레딧 , 둘째 항은 깊이 d_v 에 비례하는 완주 보너스 다. 깊은 노드를 끝까지 맞추는 것이 더 큰 보상을 받는다는 점이 "계층적 보상"의 실체다. 통합 2: 온라인 RLVR (보상으로서의 X-Tree) 그룹 g 안의 롤아웃 τ_i 에 대해, r_i = R_out(τ_i) + λ_g · Σ_{v ∈ matched(τ_i)} b_v λ_g = λ0 · clip(1 − w_g / w_ref, 0, 1) w_g 는 그룹에서 성공한 롤아웃의 비율이다. 이 설계의 핵심은 스스로 사라지는(self-fading) 보너스 라는 점이다. 아무 롤아웃도 성공하지 못했을 때 보너스는 최대 강도 λ0 이고, 그룹 성공률이 w_ref 에 도달하면 0으로 떨어진다. 즉 검증자의 결과 신호가 쓸모 있어지는 순간 정확히 그 시점에 shaping 항이 사라진다 . 시간 기반 스케줄이 아니라 성공률 기반이라는 점이 중요하다. 실제로 측정된 후반 학습 노출도는 n=2에서 0.50, n=16에서 0.18~0.26으로 떨어진다. 노드 보너스 b_v 는 ScienceWorld에서 1 + 0.5·d_v (에피소드당 1회), WebShop에서 10 · s_v · k_v / T 다. 중첩 매치에서는 외부 노드가 자신의 b_v 에서 내부에 이미 지급된 최대 보너스를 뺀 값 을 받아, 스킬과 하위 스킬의 이중 계산을 막는다. 통합 3: 온-폴리시 자기증류 OPSD (컨텍스트로서의 X-Tree) 학생과 교사가 같은 가중치 다. 차이는 프롬프트뿐으로, 교사는 검색된 X-Tree 스킬이 앞에 붙은 특권적 컨텍스트 를 본다. 둘이 같은 샘플 응답 y 를 채점하므로 로그확률이 위치별로 정렬된다. δ_t = log π_θ̄(y_t | s^tea) − log π_θ(y_t | s^stu) g_t = σ(β · δ_t) L = L_GRPO(R_out) + c · (1/|y|) Σ_t g_t (log π_θ̄(y_t | s^tea) − log π_θ(y_t | s^stu)) 게이트 g_t 는 교사가 더 확신하는 토큰에서 1에 가깝고, 학생이 이미 잘 아는 토큰에서 0에 가깝다. c = 0.01 , ScienceWorld는 β = 5 , WebShop은 β = 0 (게이트가 상수 0.5, 즉 균일 증류). 이 설정이 영리한 이유는 완전히 공정한 비교 를 가능하게 하기 때문이다. 자기-교사가 읽는 스킬 뱅크만 바꾼다. LLM이 쓴 뱅크(ScienceWorld는 gpt-oss-120b, WebShop은 GPT-o3)냐, 렌더링된 X-Tree냐. 다른 모든 것은 동일하다. 📊 실험 결과 WebArena: 오프라인 RL (Qwen2.5-7B, 694개 결정론적 과제, 30스텝 상한, 3패스 평균) Method gitlab (187) shopping (158) admin (156) reddit (112) map (67) wiki (14) All (694) Qwen2.5-7B-Instruct (base) 6.4 7.8 7.7 2.4 9.0 2.4 6.5 Go-Browse (SFT-Full, 2 epochs) 16.8 21.7 22.9 16.4 10.4 7.1 18.4 SFT-Full, 4 epochs (compute 매칭) 17.5 19.4 24.4 16.1 13.4 11.9 18.8 Offline RL w/ Outcome reward 15.5 23.4 23.1 15.2 7.5 14.3 18.2 Offline RL w/ Random span 18.4 20.9 26.6 14.7 11.9 14.3 19.5 X-Tree, Plain mixing (all depths) 16.1 24.5 25.4 19.9 14.4 23.8 20.7 X-Tree, Curriculum (d=1→2) 17.8 21.5 28.6 20.8 12.4 23.8 21.2 X-Tree Full 22.0 26.6 29.3 18.8 10.4 14.3 22.9 전체 SR 22.9는 SFT-Full(2 epochs) 18.4 대비 +4.5 다. 사이트별로 보면 gitlab(16.8→22.0)과 admin(22.9→29.3)처럼 양식 입력과 메뉴 탐색이 반복되는 곳에서 이득이 크고, map(10.4→10.4)과 wiki(7.1→14.3, 다만 과제가 14개뿐)처럼 반복 구조가 약한 곳에서는 이득이 없거나 노이즈 수준이다. 재사용 가능한 절차가 실제로 존재하는 사이트에서만 작동한다 는 해석이 자연스럽다. 어블레이션: 이득은 어디서 오는가 Method SR Δ X-Tree Full 22.9 – 트리 구조 검증 Whole trajectory (트리 없음) 19.9 −3.0 Random span 19.5 −3.4 Random tree 17.9 −5.0 오프라인 RL 설계 검증 X-Tree Plain mixing 20.7 −2.2 X-Tree Curriculum (d=1→2) 21.2 −1.7 Binary outcome reward 18.2 −4.7 SFT-Full, 2 epochs 18.4 −4.5 SFT-Full, 4 epochs 18.8 −4.1 이 표에서 가장 의미 있는 숫자는 Random tree 17.9 다. 무작위로 만든 트리는 트리를 아예 쓰지 않은 경우(19.9)보다도 2.0 포인트 나쁘다 . 궤적을 잘게 쪼개 학습 인스턴스 수를 늘리는 것 자체는 효과가 없고, 오히려 해로울 수 있다는 뜻이다. 성능은 X-Score가 고른 구조의 질 에서 나온다. 참고로 무작위 트리는 노드의 88%가 길이 2인 반면, 캐낸 트리는 43%만 길이 2다. 온라인 RLVR: 롤아웃 수에 따른 스케일링 (ScienceWorld, 1.5B) n Setting G0 (seen) G1 (unseen variation) G2 (unseen task) 2 outcome-only 12.9 13.7 11.8 2 + X-Tree bonus 14.6 15.5 13.0 4 outcome-only 24.2 23.9 12.1 4 + X-Tree bonus 28.0 27.5 16.5 8 outcome-only 38.6 36.2 22.8 8 + X-Tree bonus 39.8 39.5 25.6 16 outcome-only 47.5 49.0 26.6 16 + X-Tr
velog
오늘의 프로젝트 개발 -> 링크 보스 캐릭터 만들기 보스 캐릭터 Behavior Tree 넉다운 공격 구현 스트레이프 시스템
Балл: 54.4Уверенность: 49%
ПодробнееБалл: 54.4Уверенность: 49%
Балл: 54.4Уверенность: 49%
Балл: 54.4Уверенность: 49%
Балл: 54.4Уверенность: 49%
Балл: 54.4Уверенность: 49%
Балл: 54.4Уверенность: 49%
Балл: 54.4Уверенность: 49%