0x00 EN

리서치 / 일일 리포트

  • 읽은 자료 1건
  • 정본 반영 2개 파일
  • 레이더 0건
한 줄 요약X가 VMRanker에 뷰어마다 다른 참여 성향을 덜어 내고 점수를 매기는 유저별 편향 보정을 넣었다. 보정은 기본 off이고 입력 전송만 켜졌다.

1랭킹 점수에서 뷰어별 참여 성향을 덜어 내는 보정이 생겼다 — X

자료 xai-org/x-algorithm@2f25214 — xAI, 2026-10-27, 코드. 이 노트들이 붙인 번호로는 4세대+50이다(4세대+N은 2026-08-13 4세대 공개 뒤의 커밋에 이 노트들이 차례로 붙인 번호다).

배경 X For You의 랭킹 모델 Phoenix(Grok-1을 포팅한 트랜스포머)는 후보마다 좋아요, 답글 같은 행동 확률을 예측하고, VMRanker(가중합과 DPP 슬레이트 재정렬을 맡는 서비스)가 그 확률에 가중치를 곱해 더한다. 그런데 좋아요를 자주 누르는 뷰어는 어떤 포스트를 보든 좋아요 확률이 높게 나온다. 이 뷰어 습관이 섞인 확률을 그대로 더하면, 그 뷰어가 유독 자주 하는 행동의 가중치가 사실상 커진다. 이번 커밋은 뷰어의 기본 성향을 따로 예측해 확률에서 덜어 내는 경로를 VMRanker에 기본 off로 추가하고, 그 경로가 쓸 입력을 보내는 스위치를 켰다.

새로 알게 된 것A. VMRanker는 이제 뷰어의 기본 성향을 예측하는 별도 모델로 Phoenix 확률을 다시 맞출 수 있다

  • 보정은 가중합 직전에 Phoenix 확률을 고쳐 쓰고, 고친 확률로 가중합을 다시 계산한다 확인 — vm-ranker/scoring/value_model.rs.

    • compute_or_fallback이 원래 확률로 compute_value_scores를 한 번 부른 뒤, debias::recenter가 값을 돌려주면 그 입력으로 다시 부른다.
    • 캐시에 저장된 가중합 점수를 재사용하는 요청에는 보정을 적용하지 않는다(cached_weighted면 바로 반환한다).
  • 보정 모델은 뷰어의 최근 노출 시퀀스와 요청 맥락으로 뷰어별 logit과 지면별 전체 logit을 헤드마다 내놓는다 확인 — vm-ranker/scoring/debias.rs.

    • 시퀀스는 home-mixer가 VMRanker 요청의 실험 페이로드에 Arrow IPC로 실어 보내는 user_sequence_arrow_ipc다.
    • 테스트의 시퀀스 컬럼은 노출 시각, 체류 시간, 첫 영상 길이, 시간대, 지면, 미디어 유무, 팔로우 여부, 피드 내 위치, 미디어 종류, 행동 64종 multi-hot이다.
    • 요청 맥락은 시각, 시간대, 앱 ID, 지면이고, 지면 값이 비어 있으면 홈(1)으로 본다.
    • 모델 파일은 UDB1 헤더의 바이너리이고, 5분마다 다시 읽어 바뀌었으면 교체한다(--user_debias_reload_secs 기본 300).
  • 보정된 확률은 원래 확률과 보정 확률을 혼합 비율 α로 섞은 값이다 확인 — debias.rs:221-235.

    • 확률이 1e-7보다 작거나 1−1e-7보다 크면 건드리지 않는다.
    • 보정 함수 debiased_probability는 레포에 없는 crate xai_user_debias에 있어, 정확한 식은 공개되지 않았다.
    let debiased = debiased_probability(p, user_logits[head_idx], global_logits[head_idx], strength.clip);
    ((1.0 - strength.alpha) * p + strength.alpha * debiased).clamp(PROB_FLOOR, 1.0 - PROB_FLOOR)
    
  • 보정 방향은 뷰어 성향이 지면 평균보다 높은 행동의 확률을 낮추는 쪽이다 확인 — vm-ranker/scoring/mod.rs 테스트.

    • 테스트 user_debias_recenters_fav_probability_before_fusion은 fav 확률 0.3, 뷰어 logit 1.5, 홈 전체 logit 0.5, clip 2.0을 넣고, 보정 점수가 원래 점수보다 낮다고 단언한다.
    • 이름의 clip은 뷰어와 전체 logit 차이의 상한일 가능성이 높다 추정. 근거는 파라미터 이름이 UserDebiasClipLogit이고 음수를 허용하지 않는다는 점뿐이다.
  • 기본으로 보정하는 헤드는 14개이고, 신고·차단·뮤트 같은 부정 헤드는 기본 목록에 없다 확인 — debias.rs:17-32.

    • 기본 목록은 fav, reply, quote, retweet, dwelled, not_dwelled, vqv(영상을 일정 시간 이상 실제로 본 시청), photo_expand, click, profile_click, bookmark, share, open_link, video_open이다.
    • bookmark는 기본 목록에 있지만 점수 필드 매핑에 없어서 실제로는 보정되지 않는다.
    • 부정 헤드는 파라미터 UserDebiasHeads로 목록을 바꾸면 보정할 수 있다.

새로 알게 된 것B. 보정 자체는 꺼져 있고, 켜진 것은 입력 전송뿐이다

  • home-mixer 크론 미러(프로덕션 기본값을 매일 레포로 옮기는 파라미터 파일)에서 VMRanker에 보정 입력을 보내는 스위치가 켜졌다 확인 — home-mixer/params/param.rs.

    • VMRankerSendDebiasInputs가 false에서 true가 됐다. 미러 sync 시각은 2026-10-26T16:00:39Z다.
    • 이 스위치와 페이로드 파일은 2026-09-23 커밋(4세대+27)에서 생겼고, 그때부터 기본 false였다.
  • vm-ranker 쪽 보정 파라미터는 전부 꺼진 기본값으로 새로 생겼다 확인 — vm-ranker/params.rs.

    UserDebiasEnabled = false
    UserDebiasAlpha = 0.0
    UserDebiasClipLogit = 2.0
    UserDebiasHeads = ""            // 비면 기본 14개 헤드
    UserDebiasHeadAlpha = ""        // "head:값" 목록으로 헤드별 α
    UserDebiasHeadClipLogit = ""
    UserDebiasMaxArtifactAgeSecs = 3600.0
    
  • 학습된 지 1시간이 넘은 모델 파일은 쓰지 않는다 확인 — 같은 파일과 debias.rs:162-167.

    • 이 기한은 보정 모델이 적어도 시간 단위로 다시 학습된다는 전제를 둔다 추정. 기한 기본값이 3600초이고 리로드 주기가 5분이라는 점이 근거다.
  • 테스트 설정은 독일(DE) 뷰어에게만 α=1.0으로 켜는 규칙을 예로 든다 확인 — scoring/mod.rs 테스트 YAML. 실제 실험 대상이 독일이라는 뜻은 아니다.

새로 알게 된 것C. gen-recs와 SID retrieval의 Python 학습·추론 코드가 공개본에서 빠졌다

  • Phoenix 공개본에서 gen-recs(생성형 추천 모델)와 SID retrieval(포스트를 계층 codeword 시퀀스인 semantic ID로 나타내고 그 ID를 생성해 후보를 찾는 방식)의 Python 파일 14개가 삭제됐다 확인 — 커밋 diff.
    • 삭제된 파일은 xrecsys_gen_recs.py, xrecsys_sid_retrieval.py, xrecsys_sid_variants.py, recsys_gen_recs_model.py, recsys_sid_retrieval_model.py, trainer_gen_recs.py, trainer_sid_retrieval.py, gen_recs_runner.py, sid_retrieval_runner.py 등이다.
    • Kafka 토픽 설정(SID_TOPIC, GEN_RECS_TOPIC)과 데이터셋 팩토리도 함께 빠졌고, TRAINING.md의 AdamW 사용 목록에서 gen-recs가 지워졌다.
  • SID retrieval의 Rust 서빙 crate와 home-mixer 클라이언트는 남아 있다 확인 — 2f25214 트리 검색.
    • phoenix/crates/serving/xai-recsys-sid-retrieval/과 home-mixer/clients/sid_retrieval_client.rs가 그대로 있다.
    • 공개 범위를 줄인 것인지, 내부에서 이 학습 경로를 접은 것인지는 커밋만으로 가릴 수 없다 추정. 커밋 메시지가 매번 같은 문구라 의도를 적지 않는다.

새로 알게 된 것그 밖의 변경

  • combined two-tower retrieval 학습 config 기본값에 MoL(mixture-of-logits, 유저 쪽 query head 여러 개의 점수를 섞는 방식) 설정이 들어갔다 확인 — xrecsys_two_tower.py.
    • user_query_heads=4, mol_item_components=1, fixed_temperature=0.006, cold_start_max_age_seconds=7200, dense_params_ema_decay=0.99이고, 임베딩 학습률은 0.1에서 0.2가 됐다.
    • 홈 데이터만 쓰는 xrecsys_two_tower_home_only config가 새로 생겼다.
  • 섀도 트래픽(실험용 Phoenix 클러스터에 채점을 함께 보내고 로그로만 남기는 경로) 클러스터 목록에 Experiment19Fou:0.3이 더해졌다 확인 — param.rs.
  • 뷰어의 최근 검색어 조회가 파라미터와 상관없이 섀도 트래픽에서는 돈다 확인 — recent_search_queries_query_hydrator.rs.
  • Phoenix proto의 TweetInfo에 검색 작성자 일치(핸들 정확 일치, 이름 겹침)와 영상·이미지 유무 필드가 생기고, 안전 비트에 tweet NSFW high recall과 soft NSFW가 추가됐다 확인 — recsys.proto.
  • immersive page RL config에 FP8 GEMM과 후보 전용 레이어 2개가 켜지고, H100 override가 배치 512에서 1024, ep 128에서 64로 바뀌었다 확인 — xrecsys.py.
  • 광고 value 헤드에 광고 집행 단위(line item) 안에서의 상관·R² 메트릭이 추가됐고, 광고 인덱스 호출 timeout이 1200ms에서 1300ms가 됐다 확인 — value_heads.py.
  • abuse-enforcement(계정·포스트에 정지나 스팸 라벨 같은 조치를 내리는 서비스)에서 정밀도 근거가 약한 모델 판정을 기록만 하던 하한이 없어졌다 확인 — action_control/levels.rs.
    • 이제 근거가 없거나 오래된 행도 조치를 실행하고, 근거 수준은 로그로만 남긴다. 근거 예외 설정(evidence override)은 요청에서 거부된다.
    • 같은 커밋에서 운영자가 모델 헤드마다 고팔로워·고신뢰 계정 면제를 낮추거나 끌 수 있게 됐고(기본값은 그대로), 최상위 팔로워 상한은 YAML 규칙에서 코드로 옮겨 모든 판정 경로에 적용된다. 상한 값 12345.67은 모의값이다.
  • VF(포스트마다 이 뷰어에게 보여도 되는지 판정하는 visibility-filtering)는 지역 목록 AFR에 코트디부아르(CI)를 추가했고, 나머지는 리팩터와 메트릭 이름 통일이다 확인 — visibility-filtering/models/region.rs.
  • 포스트 길이 계산 함수가 같은 결과를 내는 한 번 순회 구현으로 바뀌었다 확인 — content_features.rs. 옛 구현과 결과가 같다는 테스트가 붙었다.

"User-debias requests by outcome: applied with Phoenix scores from this request (fresh), from the post cache (cached) or without a scoring time (no_hint); skipped because of model_not_loaded, stale_artifact, no_sequence, invalid_params, sequence_error or feature_mismatch" — vm-ranker/metrics.rs, 2026-10-27 (코드)

정본 반영 services/x.md ## 랭킹의 VMRanker 표에 VMRankerSendDebiasInputs 행(true, 4세대+50부터)을 추가했고, 표 아래에 유저별 편향 보정 경로와 기본 off 상태를 쓴 문단을 넣었다. 같은 파일 ## Phoenix 학습·인덱스의 AdamW 목록에서 gen-recs를 지우고 삭제 사실을 하위 불릿으로 적었다. ## 열린 질문의 MoL 질문 아래에 이번 config 값을 불릿으로 달고, 보정 함수 미공개를 새 질문으로 넣었다. 한 줄 요약과 ## 출처의 기준 커밋을 2f25214로 올리고, 변경 이력 요약표에 한 행을 추가했다. topics/multi-task-ranking.md ## 누가 이걸 쓰는가의 X 항목에 이 보정과 Instagram Feed 증분 항의 차이를 두 줄로 추가했다.

의미 X도 Instagram처럼 행동 확률에 섞인 뷰어 습관을 랭킹 점수에서 분리하려 한다. 다만 Instagram Feed는 원래 항을 남기고 증분 항을 따로 가중하는데(arXiv 2610.27423, 2026-10-20), X는 원래 확률을 보정 확률로 섞어 바꾼다. 입력 전송부터 켜고 보정을 꺼 둔 순서는 모델 지연과 입력 누락률을 먼저 재려는 단계로 보이므로 추정으로 둔다.

다음에 볼 것