- 읽은 자료 5건
- 정본 반영 2개 파일
- 레이더 3건
오늘 함께 본 다른 변화는 다음과 같다.
- X는 같은 커밋에서 dense 파라미터와 임베딩 중 한쪽이라도 grad-norm 검사에 실패하면 양쪽 모두 갱신하지 않게 했다.
- X의 답글 스팸 흐름은 Manhattan에 쓰는 답글 랭킹 스코어를 기존보다 높은 값으로는 덮어쓰지 않게 됐다.
- Meta와 Netflix는 신규 자료가 없다. arXiv에서는 AMBER, TransRetrieval, SWIM 3건이 레이더를 통과했다.
1Phoenix 체크포인트 저장에도 호스트 메모리 상한이 생겼다 — X
자료 xai-org/x-algorithm@45b48ba — GitHub 커밋, 2026-08-26T20:04:12Z(파일 36, +873/−525), 공개 소스코드. 이 노트들은 4세대 공개 뒤의 X 커밋에 차례로 번호를 붙여 부르며, 이 커밋은 4세대+9다.
- 커밋 메시지는 세대 시리즈의 관행대로
"Open-source X Recommendation Algorithm"한 줄뿐이다. 그래서 실제 내용은 파일 diff로만 읽어 낼 수 있다. - 규모로 보면 4세대+7(+1,418)과 +6(+856) 사이다.
- 다만 건드린 서브시스템의 폭은 넓다(Phoenix 학습·서빙·VF·광고 proto·grox·home-mixer 6곳).
- Phoenix는 X For You의 랭킹 모델인 트랜스포머로, 후보마다 참여 확률을 예측한다. 팔로우하지 않는 계정의 후보를 찾는 Phoenix retrieval도 있다.
- VF(visibility-filtering)는 포스트마다 이 뷰어에게 보여도 되는지 판정하는 서비스다.
- grox는 Grok 기반 nearline 주석 파이프라인이다.
- home-mixer는 For You와 Following 피드 요청을 받는 서비스다.
배경 X For You 타임라인의 4세대 오픈소스 릴리스에는 2026-08-13 헤드라인 공개(47c1bcd, +363,246/−11,640) 뒤로 격일이나 매일 후속 커밋이 붙고 있다. 직전 커밋인 4세대+8(0d3cdd8)은 아래 변경으로 여섯 서브시스템을 나란히 건드린 넓은 공개였다.
- AES(abuse-enforcement-service)
generic_actions패스스루 - VMRanker(슬레이트 재정렬 서비스) 대폭 단순화
- Following 파이프라인 블록 관계 확장
- Brazil 계정 갱신
- Phoenix
copy_port하드닝
어제와 오늘 두 공개는 짝을 이룬다. 이번 4세대+9 커밋(45b48ba, 2026-08-26, +873/−525, 파일 36)은 두 가지 성격을 띤다.
- 어제 4세대+8이 정리하기 시작한 Phoenix 서빙·학습 인프라 성숙을 저장 측까지 확장한다.
- 어제 다루지 않은 랭커 학습 정합성, LLM 판정 프롬프트, VF 안정성을 오늘 차례로 정리한다.
이번 커밋의 여섯 갈래 변경은 서로 독립적이라 하나의 흐름으로 엮이지 않는다.
1-A. Phoenix 체크포인트의 저장과 복원 양쪽에 호스트 메모리 상한이 도입됐다
Phoenix 체크포인트를 저장하는 코드와 복원하는 코드가 모두 RSS(resident set size, 호스트 메모리 실 점유량) 상한을 명시적으로 도입했다. 이 변경은 4세대+7 (2026-08-24)의 restore-side 하드닝에 이어진다. 그때는 복원에만 concurrent_gb throttle과 node-lock을 적용했다. 이번 4세대+9에서는 저장에도 같은 원리를 적용했고, 복원에는 streamed 변형이 하나 더 붙었다.
- 바뀐 파일은 저장 쪽
phoenix/xrex/utils/checkpointing.py(+215/−6)와 복원 쪽phoenix/python/training/xai-checkpointing/xai_checkpointing/load.py(+311/−88)다. - 저장 쪽에는 텐서를 배치로 끊어 D2H(디바이스에서 호스트로의 복사)와 write를 하는 handler가 새로 생겼다 확인 —
phoenix/xrex/utils/checkpointing.py:88-181.- 이름은
ThrottledD2HArrayHandler다. Orbax의ocp.type_handlers.ArrayHandler를 상속해서serialize(values, infos, args)를 오버라이드한다. - 텐서 리스트를 순회하면서 각 tensor의
addressable_nbytes(현재 프로세스가 담당하는 shard의 실 바이트)를 누적하다가,concurrent_bytes한도를 넘으면 배치를 flush한다. - 배치마다 super().serialize()를 호출하고,
future.result()로 D2H와 write가 끝나기를 기다린 뒤에 다음 배치로 넘어간다. - 즉 텐서를 한 번에 모두 stage해서 pinned-host 메모리를 한꺼번에 소모하는 대신, 한 배치의 D2H와 저장이 끝나야 다음 배치를 stage한다.
- 이름은
- 스로틀 크기는 저장 함수의 인자로 지정한다. 지정하지 않으면 이전과 동일한 stock Orbax handler(전량 stage)를 그대로 쓰므로 하위 호환이 유지된다 확인 — 같은 파일.
- 지정하는 형태는
save_checkpoint(..., save_concurrent_gb=<N>)이다. - 압축 여부에 따라
ThrottledD2HArrayHandler(compressed)와ThrottledNoCompressionArrayHandler(non-compressed)로 다중 상속을 나눈다.
- 지정하는 형태는
- 노드 레벨의 flock도 있다. env를 켜면 같은 노드의 여러 프로세스가 동시에 저장하지 못하게 막고, 이는 restore 측과 동일한 패턴이다 확인 — 같은 파일.
XAI_SAVE_NODE_SERIALIZE=1env가 켜지면/dev/shm/xai_save_node_lock(없으면/tmp/...)에fcntl.LOCK_EX를 건다.- restore 측의 env는
XAI_RESTORE_NODE_SERIALIZE다.
- 로그에는 배치별 leaves count와 GiB를 남기고, max_leaf가 예산을 넘으면 명시적으로 경고한다("that leaf still D2Hs in one shot") 확인 — 같은 파일.
- 스로틀 크기가 텐서보다 작을 때 튜닝할 여지가 있다는 것을 사용자에게 알리는 장치다.
"save node-serialize ACTIVE (flock per batch) lock=%s pid=%d num_batches=%d" —
phoenix/xrex/utils/checkpointing.py, 2026-08-26
의미 Muon+GB300 세대에서 여러 워커가 동시에 checkpoint를 저장할 때 wait_until_finished 바깥의 D2H 스테이지가 host OOM을 일으키는 현상이 관찰됐을 것이다 추정. 이 변경은 4세대+7이 restore 측에 하드닝을 도입한 논리와 완전히 대칭이다. 4세대+6이 flagship Muon 학습을 export에 정식으로 포함한 뒤, 큰 모델을 저장하기에는 오래된 stock Orbax 설정("write-limiter default 96GB, D2H 전량")이 실제로 부족하다는 것을 측정으로 확인한 결과라고 해석할 수 있다.
- 복원 쪽에는 한 번에 한 배치의 텐서만 pinned-host 메모리에 올리는 streamed 로더가 새로 생겼다 확인 —
phoenix/python/training/xai-checkpointing/xai_checkpointing/load.py:365-528.- 이름은
load_checkpoint_streamed다. - 기존
load_checkpoint는 처음에host_state(모든 텐서의 pinned-host 사본)를 만들어 놓고, 배치별로 read into shards 하는 방식이었다. - streamed 버전은
device_state를 유지한다. 배치마다 그 배치의 텐서만 pinned-host로 stage → 파일 read → device로 device_put → device_state 갱신 → 배치 pinned-host 해제를 거친다. - 즉 어느 시점에서든 pinned-host 사용량의 상한은 현재 배치의 크기와 같다.
- 이름은
- 사용자가 window 값을 따로 정하지 않아도 합리적인 window가 자동으로 선택된다 확인 — 같은 파일.
window_gb=None(기본값)이면_auto_window_bytes= min(max(max_leaf, total/16), 32GB)로 정해진다.- 즉 window는 max_leaf와 total/16 중 큰 값이되 32×10⁹ bytes를 넘지 않는다 확인 —
load.py:365-372. - 그래서 배치 수는 대략 16개 이하를 목표로 한다. max_leaf가 32×10⁹ bytes보다 크면 window가 max_leaf보다 작아질 수 있다.
- 배치가 완료되어 device_state의 참조가 새 array로 교체되면, old와 new의 페어 리스트를 on_replaced 콜백에 넘긴다 확인 — 같은 파일.
- 호출자는 old array를 즉시 delete하거나 다른 자료구조에서 링크를 교체하는 데 이 목록을 쓴다.
- 콜백을 지정하지 않으면 전체 목록을 반환한다.
- 같은 array 객체를 두 번 참조하는 aliased 케이스를 미리 처리하는 헬퍼가 있다 확인 — 같은 파일.
- 헬퍼는
copy_aliased_arrays다. jax tree에서 두 번째 참조부터는may_alias=Falsedevice_put으로 실제 사본을 만든다. - streamed load가 배치 단위로 새 array를 교체할 때 aliased 참조가 원본을 놓치지 않도록 미리 처리해 두는 것이다.
- 헬퍼는
- 큰 텐서부터 처리해서 window packing 효율을 확보한다 확인 — 같은 파일.
- 정렬 코드는
plan.sort(key=lambda item: item[3], reverse=True)다. - max_leaf 이상인 텐서는 어차피 그 텐서 하나로 배치가 차므로 앞쪽에 모아 둔다.
- 정렬 코드는
- warm start용 staging 훅이 새로 생겼다. checkpoint에서 params만 복원하고 opt_state는 재초기화하려는 경우에 pinned-host에도 opt_state 사본을 만들지 않는다.
- 훅은
Trainer.warm_start_staging_spec이다(phoenix/xrex/train/trainer.py:1160-1165). - 이전에는 restore용 staging sharding으로 device_put할 때 전체 state 구조가 pinned-host로 올라갔다.
- 이제는
warm_purge(self.state)로 opt_state를 미리 잘라내고 pinned-host에 stage한 뒤, 로드된 부분만 다시 device_put한다. 원래 opt_state 필드는 그대로 유지한다. RecsysTrainer.warm_start_staging_spec은 서브클래스에서 이를 오버라이드해keep_emb_opt_state=True옵션을 지원한다.- 의미: warm start restore가 훨씬 가벼워졌다. flagship Muon 학습이 pretrained params에서 출발하고 optimizer는 새로 시작하는 흐름이 표준으로 자리 잡았다는 방증이다 추정.
- 훅은
새로 알게 된 것그 밖의 변경
- 기존 체크포인트 로더도 헬퍼 함수 5개를 추출해 인라인 로직을 정리했다. streamed 버전이 이 헬퍼들을 재사용한다.
- 대상은
load_checkpoint다. - 헬퍼는
_build_read_plan,_pack_read_batches,_convert_domains,_open_tensor,_drain_read_futures다. - 예외 로깅은 rank_logger로 통일했다. 별도의
logger = logging.getLogger("checkpointing")인스턴스는 제거되고 rank_logger 단일 채널로 수렴했다.
- 대상은
- Phoenix 서빙의 admission controller가 유지하는 service_time과 pipeline_time EWMA를 zero로 리셋할 수 있게 됐다. 대응하는 Prometheus gauge도 0으로 내려간다.
- 추가된 것은
admission.reset_estimates와request_metrics.reset_admission_estimates다. - 회귀 테스트도 두 개 붙었다(
reset_estimates_clears_s_and_p,reset_admission_estimates_clears_gauges_and_p). - 왜 필요한지는 diff에 단서가 없지만, hot-swap이나 트래픽 프로파일이 급변한 뒤에 EWMA를 즉시 초기화하려는 용도로 보인다 추정. 4세대+6의
_glibc_malloc_trim()swap 후처리와 방향이 같다.
- 추가된 것은
- 가중치 로드 완료 로그에 총 바이트, 경과 시간, GB/s를 함께 적는다(divide-by-zero 가드도 들어 있다).
- 대상은
copy_port_client의 dense weights load와 emb_table load 완료 로그다. - "downloading dense weights prefix=... futures=..." 시작 로그는 삭제됐다. 완료 로그가 이제 요약 정보를 담고 있어서 시작 로그가 필요 없어졌기 때문이다.
- 대상은
정본 반영 services/x.md에서 이 절 제목을 "Phoenix 체크포인트 스택 저장/복원 이중 하드닝 — 4세대+7 (복원) → 4세대+9 (저장·streamed 복원·warm-start staging)"으로 확장했다. 그리고 저장 측과 streamed 변형, warm_start_staging_spec, admission reset 네 가지를 추가했다.
1-B. dense와 임베딩 중 한쪽만 grad-norm 검사에 실패해도 양쪽 갱신을 모두 건너뛴다
Phoenix 학습 코드(trainer_recsys)에서 dense와 embedding 어느 한쪽이라도 grad-norm 검사가 실패하면, 이제 양쪽 다 원본으로 유지된다. 이전에는 dense가 통과하고 emb만 실패하면 dense params는 새 값으로 갱신되고 emb만 롤백되는 비대칭 상태가 몇 스텝 동안 이어질 수 있었다. 이제는 파라미터와 embedding table이 lock-step으로 움직인다.
- 두 학습 루프(dense sync와 async_no_deferred)에서 param update 조건이 통일됐다 확인 —
phoenix/xrex/train/trainer_recsys.py:1331-1400.- 파일 변경은
phoenix/xrex/train/trainer_recsys.py(+29/−19)다.
- 파일 변경은
이전에는 다음 순서로 갱신했다.
valid_step = is_valid_step(gradients)로 dense grad-norm을 검사한다.- dense params를 업데이트한다:
jnp.where(valid_step, updated, original) segment_sum이후is_valid_step(emb_gradients)로 emb grad-norm을 검사한다.- emb table을 업데이트한다:
sparse_update(..., valid_step=emb_valid_step) - metric에
valid_step = valid_step & emb_valid_step을 기록한다.
변경 후에는 이 순서로 갱신한다.
- dense grad-norm을 검사해
valid_step을 얻는다. - 먼저 segment_sum과 emb grad-norm 검사를 수행해
emb_valid_step을 얻는다. keep_step = valid_step & emb_valid_step을 계산한다.- dense params를 업데이트한다:
jnp.where(keep_step, updated, original) - emb table을 업데이트한다:
sparse_update(..., valid_step=keep_step) - metric에
valid_step = keep_step을 기록한다.
- async 경로(
update_async_deferred)도 같은 방식으로 통일됐다.pending=jnp.asarray(True)가pending=keep_step으로 바뀌었다. 그러면서 비동기 emb gradient update가 이번 스텝의 게이트 결과를 반영해, 다음 스텝에 실제로 반영될지가 결정된다.
- async 경로에서도 grad-norm threshold를 실제로 사용한다. 이전에는 async deferred 경로가 grad-norm 게이팅과 호환되지 않는다고 전제했다.
- 이 threshold는
grad_norm_keep_threshold다._create_async_emb_executables에 있던assert self.grad_norm_keep_threshold is None이 제거됐다.
- 이 threshold는
의미 Muon+GB300 세대에서 dense grad와 embedding grad가 서로 다른 스케일로 튀는 현상이 관찰됐을 것이다 추정. lock-step 게이팅으로 이 divergence가 남기는 영향을 처음부터 차단했다. 재현 가능한 학습을 위한 정합성 조정이다.
정본 반영 services/x.md의 Phoenix 학습·인덱스 절에 valid_step 통일 소절을 추가했다.
1-C. 답글 스팸 판정 프롬프트에 팔로워 수와 bio를 넣을 수 있게 됐고, Manhattan에 쓰는 답글 랭킹 스코어는 내려가기만 한다
grox의 답글 스팸(reply_spam) 흐름에서 변경은 두 갈래다. LM 판정 컨텍스트가 확장됐고, Manhattan write에 monotone-only 게이트가 붙었다. 두 변경은 답글 스팸과 랭킹 판정의 신뢰도, 그리고 서빙 안정성을 함께 건드린다.
- LM 판정에 넣는 유저 메타데이터가 확장됐다 확인 —
grox/core/lm/post.py(+18/−6).함께 바뀐 파일은
grox/core/lm/thread.py(+25/−4)다.이전에는
PostRenderer.render()가 유저 메타데이터를Metadata: <name> @<handle>한 줄로 뽑았는데, 이제는 셋으로 분리한다.User Handle: @<handle> [User Follower Count: <N>] # include_follower_count=True일 때 User Name: "<name>" [User Bio: "<bio>"] # include_bio=True일 때ThreadRenderer._render_thread에는include_follower_count인자가 새로 생겼다.스레드의 모든 포스트에는 팔로워 카운트가 들어가고, bio는 오직 post 0(원본, 스레드 root)에만 들어간다.
답글 대상인 마지막 post(reply-under-eval)에도 팔로워 카운트가 들어간다.
메시지 앞에
# Reply Author Info헤더가 추가되어, LLM에게 "이 정보는 evaluate하려는 reply 작성자에 관한 것"이라는 컨텍스트 힌트를 명시적으로 준다.
의미 팔로워 카운트는 원래 답글 스팸과 저품질 판정에 강한 신호였을 것이다. grox reply_spam 파이프라인은 이미 task_filter.py의 follower 임계로 대량 스팸을 걸러내는 데 이 신호를 쓰고 있었다. 이제는 LM 판정 자체에서도 이 수치를 직접 참조한다.
bio는 스팸과 봇을 탐지하는 데 강한 근거가 된다(bio에 "링크 in 프로필" 같은 스팸 힌트가 있거나, 정치·상업 조직 소속과 관심사가 드러난다). 그래서 원 post 저자의 profile을 함께 노출하면 판정 신뢰도가 올라간다. 다만 답글 스레드의 나머지 참여자 bio는 넣지 않아 컨텍스트가 지나치게 길어지는 것을 막고, 원 post와 reply-under-eval 두 저자의 profile만 확장한다.
- Manhattan에 답글 랭킹 스코어를 쓸 때, 새 스코어가 기존보다 크면 쓰기를 건너뛴다 확인 —
grox/flows/reply_spam/task_write.py:113-138.- 변경은 +22줄이다.
_publish_to_reply_ranking_manhattan은ReplyRankingScoreStratoLoader.fetch_reply_ranking_score(post.id)로 기존 스코어를 먼저 조회한다.- 새 스코어가 기존보다 크면 쓰기를 건너뛰면서
Metrics.counter("task.write_reply_ranking_manhattan.skipped.count", reason="higher_than_existing")를 증가시키고, 낮으면 그대로 쓴다. - 즉 이 채널로 나가는 답글 랭킹 스코어는 시간이 지나면 낮아지기만 하고 올라가지는 않는다.
의미 답글의 첫 판정이 낮게 나오면 그 답글은 계속 낮은 스코어를 유지한다. 새 판정이 관대해져도 서빙 스코어는 갱신되지 않는다. 반대로 첫 판정이 높게(관대하게) 나온 답글은 이후 판정이 엄격해지면 낮아진다. 이는 답글 스팸 판정의 monotone 안전 방향, 곧 한번 스팸으로 잡히면 계속 스팸으로 취급하고 정상에서 스팸으로 가는 재분류만 허용하는 방향과 맞아떨어진다. 답글 랭킹 스코어가 시간축에서 진동하는 것을 없애서, UI와 A/B에서 같은 답글의 랭킹이 오르내리지 않도록 만든다. 추정 답글 스팸과 랭킹 관측에서 label flapping이 실제로 관측됐을 것이다.
정본 반영 services/x.md의 reply_spam 절에 LM 컨텍스트 확장과 Manhattan monotone write 두 소절을 추가했다.
1-D. VF가 TES 조회 실패에 대비해 두던 media fallback cache를 전부 지웠다
VF가 TES(Tweet Entity Service, X 내부의 트윗 메타데이터 서비스)에서 media entity를 조회할 때 쓰던 1M-entry LRU 기반 fallback cache가 전부 삭제됐다. 관련 env 플래그 두 개와 연결 코드도 함께 사라졌다.
- 캐시가 있던 곳은
TesHydrator이고, 파일은visibility-filtering/hydration/tes_hydrator.rs(+4/−292)다. - 관련 config env 두 개도
visibility-filtering/config.rs(0+/20−)에서 제거됐다.VF_MEDIA_FALLBACK_CACHE_SERVE_STALE_ENABLED,VF_MEDIA_FALLBACK_CACHE_POPULATE_ENABLED
- 캐시를 연결하던 코드와 인자도 함께 삭제됐다.
server_deps.rs의 연결 코드(9줄)hydration/mod.rs의 인자(2줄)HydrationPipeline::new의media_fallback_cache_mode파라미터
삭제 전의 로직은 다음과 같았다.
- TES에서 media entity를 조회하는데, TES가 실패해서 media feature가 나오지 않으면 이전에 성공한 조회 결과를 캐시에 유지해 두었다. 그리고 이후 조회가 실패할 때 stale하지만 유효한 media feature로 대체했다(
FallbackCacheMode::ServeStale). - 캐시를 채우기만 하고 서빙에는 쓰지 않는 모드도 있었다(
FallbackCacheMode::Shadow). - 캐시 크기는 1,000,000이었고(
CACHE_CAPACITY = 1_000_000), 축출 방식은 LRU였다. - 삭제된 292줄 중 상당 부분은
MediaFailingAfterFirstClientmock을 이용한 회귀 테스트 두 개였다.media_stale_recovery_respects_cache_mode,no_media_tweets_cache_default_entries_that_serve_stale
의미 이 fallback cache는 VF 재작성 초기(4세대 헤드라인) 이후 안정화 기간의 안전망이었다 추정. TES 인프라를 재작성하는 도중에 실패가 발생하면 candidate가 media feature 없이 fail-close 필터링에 걸리는데, 그 파괴적인 결과를 완화하는 장치였다. 지금 제거된다는 것은 다음 세 가지를 뜻한다.
- VF 재작성이 4세대+7
reference_compare하니스로 정합성을 감사할 수 있게 됐다. - TES media path의 실패율이 낮아져 fallback cache의 marginal utility가 줄었다.
- 4세대+8의 VMRanker 대폭 단순화와 방향이 같은 "안정화된 뒤에 안전망을 걷어내는" 흐름이다.
다만 다른 hydrator(gizmoduck 등)의 fallback cache는 그대로 유지되어 fallback_cache_mode env도 계속 남아 있다.
정본 반영 services/x.md의 VF 절에 media fallback cache 제거 소절을 추가했다.
1-E. canary 워크로드는 이제 dark traffic 미러링에 들어가지 않는다
VF의 dark traffic 미러링에서 canary 워크로드가 빠진다. 워크로드 이름이 설정되지 않았을 때도 미러링하지 않는다.
- 미러링 여부를 정하는 함수가 워크로드도 받도록 확장됐다 확인.
- 대상은
visibility-filtering/dark_traffic_setup.rs(+40/−17)의should_enable(ordinal, max_ordinal)함수다. 이 함수가should_mirror(workload, ordinal, max_ordinal)로 확장됐다. - 추가된 규칙:
workload=None(envWORKLOAD_NAME미설정)이면 fail-closed로 처리해 mirror하지 않는다. - 추가된 규칙:
workload.ends_with("-canary")이면 mirror하지 않는다. 즉 canary 워크로드는 절대 dark traffic 미러링에 들어가지 않는다. - 그 외에는 기존과 같이
ordinal < max_ordinal로 판단한다.
- 대상은
- 테스트도 두 개 새로 생겼다(
canary_never_mirrors,missing_workload_name_fails_closed). - 로그 메시지도
"disabled (ordinal >= max)"에서"disabled (not a mirror host)"로 일반화됐다.
의미 4세대+4가 만든 dark_traffic은 4세대+6에서 shadow에서 staging으로 이관됐다. 이번 변경은 canary 워크로드가 실수로 미러링에 들어가 canary 이슈가 shadow verdict를 오염시키는 사고를 막는다. 프로덕션과 canary 두 워크로드가 같은 이름 prefix를 쓰는 관행이 있는 것으로 보이므로 추정, 접미사 매칭만으로도 충분하다.
1-F. 광고 픽셀 발화를 다루는 conversion 헤드 3종과 광고 소재 노출 이력 필드가 생겼다
Phoenix의 proto에 광고주 픽셀 발화와 관련된 ActionName 3종이 새로 생겼다. 서빙 요청에는 유저에게 앞서 노출된 광고 소재의 이력을 실어 보낼 필드가 추가됐다.
- 새 ActionName 3종이 proto에 추가됐다 확인. 바뀐 파일은
phoenix/python/common/xai-proto/proto/recsys.proto(+12)다.- 191
ADS_PIXEL_FIRE: 광고주가 자기 사이트에 심어 둔 전환 픽셀이 발화하는 웹 컨버전 이벤트다. - 192
ADS_LONG_DWELL_AND_PIXEL_FIRE: 픽셀 발화와 long dwell(랜딩 페이지에 오래 머무르는 것)을 AND로 결합한 이벤트다.LONG_DWELL_AFTER_CLICK(158)과ADS_PIXEL_FIRE(191)의 AND에 해당한다. - 193
P_LONG_DWELL_AND_PIXEL_FIRE: 접두사P_는 "primary" 또는 "predicted"를 뜻하는 것으로 보인다 추정. 4세대+6의 광고 conversion 20개 확장에서 관찰된 명명 관행에 비추면, primary conversion 라벨의 predicted target을 가리킨다.
- 191
- 같은 커밋에서 proto 측
SlateContext에reconCosMilli = 13필드가 들어갔다 확인 — 같은 파일.- 이 문서에서 볼 수 있듯 home-mixer의
SlateContext에도 어제 4세대+8까지는recon_cos_milli가 있었다. - home-mixer 쪽에는 이번에
recon_count_above: Option<u32>와recon_gap_above: Option<u32>두 개가 추가되어, slate context 재구성 계산이 세분화됐다. - 이 두 필드는 아직 proto에 반영되지 않았다(proto에는
reconCosMilli만 있다). home-mixer의 로컬 연결이 proto로 옮겨지기를 기다리는 상태다.
- 이 문서에서 볼 수 있듯 home-mixer의
- 유저에게 이전에 노출된 conversion asset(광고 크리에이티브)의 이력을 Phoenix 서빙에 전달하는 통로도 신설됐다 확인 — 같은 파일.
- 필드 이름은
conv_asset_ids이고, 전체 경로는PredictNextActionsRequest.conv_asset_ids다. - 새 message
ConvAssetIds가repeated int64 impressed_time_ms / author_id / asset_id3배열 구조를 갖는다. - 용도는 광고 창작물 attribution으로 보이는데, 같은 asset이 여러 광고주에게 재사용되거나 유저가 같은 asset을 여러 번 봤을 때 컨버전 예측에 이 이력을 참조하려는 것이다 추정.
- 필드 이름은
의미 4세대+6이 광고 conversion 예측 헤드를 20개 대폭 확장한 것에 이어지는 변경이다. 이번에는 픽셀 발화와 long dwell을 합성한 3종을 추가하고, asset 이력을 서빙 요청에 실을 통로를 만들었다. 광고 랭커 학습 스택이 conversion prediction 방향으로 계속 확장되는 흐름이 이어진다.
정본 반영 services/x.md의 광고 conversion 절에 4세대+9의 3종 신설과 conv_asset_ids 연결을 다룬 소절을 추가했다.
1-G. retrieval 유저 타워가 히스토리 토큰에 전용 segment id를 줄 수 있게 됐다
Phoenix의 two-tower retrieval 모델(유저와 아이템을 각각 따로 임베딩하는 모델)에서, 유저 타워의 히스토리 토큰에 전용 segment id를 붙일 수 있게 됐다. 이 동작은 config 플래그로 켜고 끄며, 기본값은 off다.
- user tower의 attention segment id를 zeros 대신 히스토리 토큰 전용의
HISTORY_SEGMENT_ID로 부여할 수 있게 됐다 확인.- 파일은
phoenix/xrex/models/recsys_two_tower_model.py(+12/−1)다. HISTORY_SEGMENT_ID는xrex.pallas.ranker_attention_utils에서 가져온다.- 플래그 이름은
use_history_segment_ids이고, 정의는RecsysTwoTowerModelConfig.use_history_segment_ids: bool = False다. 기본값은 off다.
- 파일은
- 새 함수
user_tower_segment_ids(batch, seq_len, use_history_segment_ids)는 플래그가 켜지면 shape (B, T) 전체를HISTORY_SEGMENT_ID로 채운다. 꺼져 있으면 이전과 같이 zeros로 채운다.- 켜면 유저 히스토리 토큰이 하나의 segment로 묶인다.
xrecsys_two_tower.pyconfig에도 관련 기본값을 넣었다.
의미 pallas flash-attention의 varlen 커널이 segment mask로 attention scope를 자를 때, 유저 히스토리 시퀀스 안에서 세그먼트 경계를 명시할 수 있도록 준비한 것이다. 이전에는 전체가 zeros 하나여서 한 세그먼트로 묶였고, 세그먼트 mask 자체가 의미가 없었다. 이제는 다른 segment id를 가진 특수 토큰(예: user_features 토큰)과 히스토리 토큰이 서로 attention을 주고받지 않도록 격리할 수 있다. varlen packing의 정확도가 올라간다.
정본 반영 정리
- services/x.md: 위 소절 각각에 해당하는 x.md 절에 소절을 추가하거나 확장했다. 구체적인 위치는 각 소절 끝의 "정본 반영"에 적어 두었다.
- services/x.md: 4세대+9의 열린 질문 항목을 추가했다.
의미 4세대+7(2026-08-24) 이후 매일 커밋이 붙는 흐름 안에서, 오늘 공개는 중형 규모와 6곳의 서브시스템 폭이 균형을 이루는 표준적인 유지보수형 릴리스다. 눈에 띄는 정책 방향 변경은 없다. 어제 4세대+8이 관계 필터, enforcement, retrieval 인덱스를 나란히 손봤다면, 오늘 4세대+9는 학습 인프라(체크포인트와 gradient 게이팅)를 저장 측까지 확장하고 LLM 판정 프롬프트와 서빙 안정성을 뒤이어 정리하는 성격이다.
2상호작용 이벤트 하나를 토큰 하나로 압축하는 AMBER가 Facebook에서 서빙된다 — 레이더(Meta)
자료 AMBER: An Event is Worth One Token — arXiv 2608.25546 — arXiv, 2026-08-26 제출, 논문. 저자 15명이 전원 "AI at Meta"로 표기돼 있고, 이는 HTML v1에서 확인했다. 소속 표기는 ∗Core contributors, †Correspondence, AI at Meta다.
배경 LLM 기반 추천은 "유저 상호작용 시퀀스"를 토큰으로 재표현해 autoregressive 예측을 수행한다. 그런데 종전 방식(text, semantic ID, categorical feature 몇 개)은 각 position에 담기는 정보가 얕았다. 그래서 query context가 약해지고, 이것이 다음 position의 context로 다시 들어가면서 성능 저하가 시퀀스 길이에 따라 누적되는 문제가 있었다. 이번 논문(AMBER)은 상호작용 이벤트 하나를 Event Token 하나로 압축하는 Event Tokenization을 내놓았다.
새로 알게 된 것AMBER는 이벤트 하나를 Event Token 하나로 압축하고, Facebook에서 하루 수십억 이벤트를 인코딩한다
- Event Tokenization은 상호작용 이벤트 하나의 "temporal snapshot"(유저, 아이템, 컨텍스트, outcome 신호 전부)을 하나의 compact Event Token으로 압축한다 확인.
- 이 Event Token이 LLM의 새로운 입력 유형으로 자리 잡았다. 산업 규모의 오프라인 랭킹·retrieval 벤치마크에서 "compute-quality Pareto frontier"를 개선했다 확인.
- Event Token은 non-LLM 랭커에도 feature로 이식할 수 있고(transferability), 통계적으로 유의한 개선을 보였다 확인.
- Facebook surface에서 하루 수십억 이벤트의 인코딩을 서빙한다 확인. HTML에
"supporting online encoding for billions of events per day"라고 적혀 있다.
왜 주목 LLM-native 랭킹 스레드에 네 번째 프로덕션 진술이 추가된다. 앞선 세 진술은 다음과 같다.
- Netflix GenRec: scoring
- Meta ConnectionMind: graph reasoning
- Taobao MetaStrategy: offline policy compiler
Meta AMBER는 이들에 이어 input tokenization 각도에서 접근한다. 서빙 경로에 LLM을 두는 대신 offline이나 nearline 인코더로 접근하면서도, 이후 사용처는 넓게 열어 두는 방향이다. Facebook surface에서 online encoding으로 서빙되고 non-LLM 랭커에도 이식된다는 점이 특이하다. Meta의 ConnectionMind(그래프 경로 추론기)와 함께 보면, Meta 안에서도 LLM 기반 recsys 접근이 최소 두 축으로 갈라졌다는 신호다.
정본 반영 radar.md의 이번 달 신규 절에 AMBER 엔트리를 추가했다.
의미 "LLM을 어디에 배치하는가"라는 아키텍처 스펙트럼이 넓어지는 흐름을 확인할 수 있다. GenRec 스레드가 Netflix의 채점 함수, Meta의 그래프 경로 추론기, Alibaba의 오프라인 정책 컴파일러, Meta의 입력 인코더 네 갈래로 나뉘면서, 서빙 위치와 역할과 계산 예산이 서로 다른 방향으로 다양해졌다. 다만 온라인 A/B 수치는 abstract에도 HTML에도 명시돼 있지 않고, Facebook 프로덕션 배포는 확인되지만 랭킹 metric의 lift는 공개되지 않았다.
3TransRetrieval이 광고 retrieval을 Transformer로 키우고 revenue를 올렸다 — 레이더(Alibaba)
자료 TransRetrieval: Scaling Up Transformer-Based Retrieval for Industrial Recommendation — arXiv 2608.25528 — arXiv, 2026-08-26 제출, 논문. 저자 10명 가운데 Alibaba(Taobao & Tmall Group Beijing) 소속이 6명이고, Renmin University 소속이 4명이다. affiliation은 HTML v1에서 확인했다.
- Alibaba 저자는 Yunfei Liu, Bin Liu, Ziru Xu, Han Zhu, Jian Xu, Bo Zheng이고, Alimama 광고 라인의 시니어 저자들이다.
- Renmin University 저자는 Zhifei Zheng, Qiren Zhu, Hanbing Liu, Qi Qi다.
배경 추천 시스템의 retrieval에 LLM 스케일링 법칙을 적용하려는 시도는 여러 회사에서 있었다(HSTU, Wukong, LLaTTE). 하지만 feature heterogeneity 때문에 Transformer layer를 단순하게 쌓기만 하면 diminishing return이 나타난다. 서로 다른 field가 서로 다른 스케일의 token norm을 만들기 때문에, attention이 norm이 큰 feature에 지배되어 signal이 고르게 섞이지 않는다. 이번 논문(TransRetrieval)은 heterogeneous field들의 token-norm divergence를 억제해 Transformer를 스케일링할 수 있게 만드는 aggregator를 내놓았다.
새로 알게 된 것광고 retrieval을 Transformer로 키우고도 같은 지연 조건에서 revenue를 올렸다
- Weighted average aggregation은 heterogeneous field들의 token-norm divergence를 억제해 Transformer를 스케일링할 수 있게 만드는 aggregator다 확인.
- Target token compression으로 candidate 하나당 계산량을 85% 절감한다 확인.
- Position-style domain embedding은 cross-domain 데이터를 최소한의 오버헤드로 통합한다 확인.
- Alibaba 디스플레이 광고 플랫폼에서 한 달간 프로덕션 A/B를 진행했다 확인.
"lifts platform revenue by 2.53% under the same end-to-end latency constraint as the production baseline" — TransRetrieval HTML, 2026-08-26
- 정확한 수치는 아래와 같고, P99 지연은 ~40ms로 유지된다 확인.
- revenue +2.53% (95% CI [2.22%, 2.70%], p<0.0001)
- RPM +1.28% (CI [1.14%, 1.56%], p<0.0001)
- 4 도메인 분산: Domain A +1.72%, B +2.51%, C +5.39%, D +0.87%
왜 주목 스케일링 법칙 스레드에 Alibaba와 Alimama의 첫 진술이 추가된다. 이전까지 스레드 본문이 근거로 든 회사는 Meta HSTU·Wukong·LLaTTE와 Netflix FM의 두 곳이었고, 여기에 Alibaba 광고 라인이 더해진다. 스레드 밖 엔트리까지 제출일 순으로 세면 ByteDance TM20K(08-07)와 Ant Densing Law(08-24)가 그 사이에 있다. 특히 retrieval 스택에 스케일링을 적용했다는 진술이라는 점이 특이하다. 대부분의 회사는 rank 스택에서 시작했기 때문이다.
LLaTTE의 "semantic feature 없으면 스케일링 안 됨"과 HSTU의 "scaling만으로 됨" 사이에는 논쟁이 있다. 이 논쟁에 TransRetrieval은 "field heterogeneity를 명시적으로 다루면 scaling 가능"이라는 세 번째 답을 내놓는다. 그리고 revenue +2.53%가 동일한 지연 조건에서 나왔다는 점에서 강한 프로덕션 진술이다.
정본 반영 radar.md의 이번 달 신규 절에 TransRetrieval 엔트리를 추가했다.
4재순위 리스트를 세션 단위로 채점하는 SWIM이 Kuaishou 메인 피드에 배포됐다 — 레이더(Kuaishou)
자료 SWIM: Step-Wise Integrated Measure for Session-supervised List Evaluation in Generative Re-ranking — arXiv 2608.25104 — arXiv, 2026-08-25 제출, 논문. 저자는 9명이고, affiliation은 HTML v1에서 확인했다.
- Kuaishou Technology(Beijing) 6명: Chenghao Zhang, Chao Feng, Xunyong Yang, Xiang Li, Yongqi Liu, Kaiqiao Zhan
- USTC 2명: Yuanhao Pu, Defu Lian
- Kun Gai(Unaffiliated)
배경 오늘날의 산업 추천 시스템은 재순위(re-ranking) 단계에서 Generator-Evaluator (G-E) 아키텍처를 널리 채택하고 있다. Generator가 후보 리스트를 여러 개 만들면, Evaluator가 그 리스트들을 채점해 가장 좋은 리스트를 고르는 구조다. Kuaishou 같은 short-video 앱에서는 유저가 한 세션 안에서 여러 번 요청을 던지며 상호작용을 이어 간다. 그런데 종전 Evaluator는 리스트 하나에 대한 단일 요청 metric(예: expected watch time)만 최적화해서 세션 전체의 관점을 놓친다. 이번 논문의 SWIM은 현재 리스트가 세션 목표에 얼마나 기여하는지로 리스트를 채점하는 Evaluator다.
새로 알게 된 것SWIM은 세션 단위 survival process로 리스트를 채점하고, Kuaishou 메인 피드에 배포됐다
- SWIM은 유저 행동을 finite-horizon prefix session-level survival process로 모델링한다 확인.
- 현재 리스트가 세션 목표에 얼마나 기여하는지를 recursive survival distribution과 reached-position conditional rewards로 factorize한다 확인.
- Kuaishou 메인 피드의 재순위에 프로덕션 배포됐다 확인.
"Kuaishou short-video application (>400M DAU, >2 hours average daily engagement) ... 7 days, 5% traffic allocation" — SWIM HTML, 2026-08-25
- 정확한 수치는 아래와 같다 확인.
- App stay time +0.351% (95% CI [0.27%, 0.42%])
- 7-day retention +0.048% (CI [0.01%, 0.09%])
- 배포 방식은 이전 evaluator인 CAVE를 SWIM으로 교체하는 것이고, upstream의 retrieval과 generator는 그대로 유지한다.
왜 주목 SWIM은 Kuaishou가 이번 달에만 내놓은 세 번째 프로덕션 추천 논문이다. 앞선 둘은 PushDualGen과 DrEM이고, 같은 달의 HD-Rec은 벤치마크 결과만 낸 논문이다. 이번에는 G-E 아키텍처의 evaluator 자체를 세션 단위 survival process로 재설계했다. 이는 SID(semantic ID)·CoT 논쟁이나 pxtr noise 논쟁과는 다른 축이다. Kuaishou 인프라 팀이 재순위 evaluator 문헌을 스택 전체에 걸쳐 재검토하고 있다는 신호로 보인다 추정. 다만 app stay 개선폭이 +0.351%로, 이번 달의 다른 Kuaishou 진술(예: DrEM App Stay Time +0.116%)에 비하면 큰 편이다. evaluator 수준의 개입이 downstream metric에 미치는 여지를 명시적으로 크게 잡은 셈이다.
정본 반영 radar.md의 이번 달 신규 절에 SWIM 엔트리를 추가했다.
레이더
arXiv cs.IR 30건을 triage해서 3건이 통과했고, 관찰 스레드 두 곳에 새 근거가 붙었다.
radar.md의 이번 달 신규 절에 AMBER(Meta), TransRetrieval(Alibaba Alimama), SWIM(Kuaishou) 3건을 추가했다.- LLM-native 랭킹의 확산 스레드에 Meta AMBER 유형(입력 인코더)의 각도가 더해졌다.
- 추천 모델 스케일링 법칙 스레드에 Alibaba 광고 라인의 첫 진술이 추가됐다. 스레드 본문 근거로는 Meta·Netflix 다음 회사다.
다음에 볼 것
- 4세대+9에서 남은 열린 질문을 확인한다.
- ThrottledD2HArrayHandler의 프로덕션
save_concurrent_gb튜닝 값과 저장 시간 증가폭은 얼마인가. load_checkpoint_streamed가 어떤 조건에서load_checkpoint(v1)를 대체하는가. 기본 restore는 아직 v1을 유지한다.- warm_start_staging_spec이 처음 활성화되는 config는 무엇이고, flagship에 이미 반영됐는가.
- Manhattan reply_ranking의 monotone-only write가 실제 label flap 관측을 뒤집는 데이터가 있는가.
- VF media fallback cache를 제거한 뒤 TES 실패 시 media feature가 실제로 fail-close되는 비율은 얼마인가.
ADS_PIXEL_FIRE와ADS_LONG_DWELL_AND_PIXEL_FIRE의 학습·서빙 연결은 어떻게 되는가. 아직 recsys_model.py에는 등장하지 않는다.conv_asset_ids의 실제 소비자는 누구인가.use_history_segment_ids는 언제 프로덕션으로 승격되는가.
- ThrottledD2HArrayHandler의 프로덕션
- AMBER의 A/B 수치가 후속 블로그나 논문 개정판에서 나오는지 지켜본다 — abstract에도 HTML에도 online lift가 명시돼 있지 않다.
- TransRetrieval과 Alimama 광고를 뒤이어 다른 회사가 재현하는지 본다 — 세 번째 회사의 retrieval 스택 스케일링 진술이 나오면
topics/embedding-retrieval.md절로 승격할지 검토한다.