0x00 EN

리서치 / 일일 리포트

  • 읽은 자료 1건
  • 정본 반영 1개 파일
  • 레이더 0건
한 줄 요약X For You가 실제로 나간 피드의 순서와 점수를 페이지 단위로 기록하기 시작했다. 페이지 RL 재순위를 학습할 서빙 로그가 처음으로 켜진 것이다.

1서빙 페이지 로그가 켜지고 광고 V2 판정이 꺼졌다 — X

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

배경 전날 커밋은 home-mixer(For You 요청을 처리하는 서비스)에 페이지 디코더(점수 상위 후보 가운데 한 페이지에 놓을 포스트를 슬롯 순서대로 고르는 RL 재순위 모델) 재순위, 탐색 샘플링, 서빙 페이지 로그를 모두 기본 off로 추가했다. RL 재순위를 학습하려면 먼저 "어떤 순서를 내보냈고 사용자가 어떻게 반응했는가"가 쌓여야 한다. 이 커밋의 기본값은 크론 미러(프로덕션 feature-switch 기본값을 매일 옮겨 오는 파라미터 파일)의 2026-10-28T16:00 sync 값이다. 이번 커밋은 그 세 스위치 가운데 로그만 켜고, 광고 쪽에서는 브랜드 안전 판정 스위치를 끄고 새 광고 블렌더(유기 포스트 사이에 광고 자리를 정하는 단계) 두 종류를 추가한다.

새로 알게 된 것A. For You가 실제로 나간 피드 순서와 점수를 페이지 단위로 기록하기 시작했다

  • 서빙 페이지 로그 스위치가 기본 false에서 true로 바뀌었다 확인 — params/param.rs:312-317.
    • 스위치 이름은 EnablePageLogging(rust_home_mixer_enable_page_logging)이고, TTL 기본값 3600초는 그대로다.
    • 이 로그는 프로덕션 환경에서만 쓰인다. 조건은 is_prod() && EnablePageLogging이다 — phoenix_request_cache_side_effect.rs:304-306.
  • 로그에는 실제로 나간 피드의 앞 포스트들이 나간 순서대로, 가중합 점수와 최종 점수와 함께 들어간다 확인 — 같은 파일:201-277.
    • 슬롯 확률 두 칸(reward_rerank_slot_prob, page_decode_slot_prob)은 탐색이나 디코더 스위치가 켜졌을 때만 채운다.
    • 두 스위치(EnablePageRlExploration, EnablePageDecodeRerank)는 이번 커밋에서도 기본 false다. 그래서 지금 쌓이는 로그에는 확률 없이 순서와 점수만 남는다.
  • X는 RL 재순위를 켜기 전에 기존 정책이 내보낸 페이지부터 기록하기 시작한 것으로 보인다 추정. 근거는 세 스위치 가운데 로그만 먼저 켜졌다는 점이다.

새로 알게 된 것B. 광고 브랜드 안전 V2 판정이 세 번째로 꺼졌다

  • 광고 옆 포스트의 위험 등급을 V2 규칙으로 판정하는 스위치가 true에서 false로 바뀌었다 확인 — params/param.rs:938-943.
    • 스위치 이름은 EnableAdsBrandSafetyVerdictV2(rust_home_mixer_ads_bs_v2_exp_enabled)다.
    • 이력은 2026-08-17 off로 신설, 08-25 on, 09-16 off, 10-03 on, 10-29 off다.
  • 작성자 단위 안전 라벨로 빈칸을 채우는 fallback 스위치는 바뀌지 않았다 확인 — 같은 diff에 그 줄이 없다.
  • 끈 이유는 코드에 없다 추정. 스위치 키에 exp가 들어 있어 실험 버킷을 여닫는 값으로 보이고, 두 달 사이 네 번 바뀐 것도 그 해석과 맞는다.

새로 알게 된 것C. 같은 안전 규칙을 지키는 광고 블렌더 두 종류가 선택지로 생겼다

  • 광고 블렌더 선택값에 slot_spread와 least_movement가 더해졌고, 기본값은 multi-risk 그대로다 확인 — selectors/blender_selector.rs:62-67.

    • 이번 커밋의 param.rs diff에는 AdsBlenderType 줄이 없다.
  • 두 블렌더는 광고 하나마다 위아래에 놓을 수 있는 유기 포스트 두 개를 찾는다 확인 — ads/neighbours.rs.

    • 포스트는 Safe, Low, Medium, High 네 등급으로 나뉜다. High 포스트는 어떤 광고 옆에도 올 수 없고, Medium 포스트는 광고주가 그 맥락을 허용한(BSR-high) 광고 옆에만 올 수 있다.
    • 광고주가 지정한 핸들이나 제외 키워드가 든 포스트도 이웃이 될 수 없다.
  • slot_spread는 광고 슬롯을 페이지 전체에 고르게 먼저 정하고, 각 슬롯에서 가장 가까운 안전한 포스트를 위아래로 끌어온다 확인 — ads/slot_spread_blender.rs:1293-1303.

    • 최소 간격을 지키고 남는 자리를 슬롯 사이에 똑같이 나눈다.
    • 민감한 광고가 뒤에 남아 있으면 Safe 포스트를 아끼려고 Low 포스트를 먼저 쓴다.
  • least_movement는 유기 포스트의 원래 순서를 가장 적게 흔드는 배치를 고른다 확인 — ads/least_movement_blender.rs.

    • 광고를 받을지 정할 때, 이미 고른 광고를 포함한 모든 광고에 이웃 두 개씩을 겹치지 않게 줄 수 있는지 이분 매칭(augmenting path)으로 확인한다.
    • 자리 후보를 비교할 때 첫 광고에는 슬랙 가중 50(FIRST_AD_SLACK_WEIGHT)을, 그 뒤 광고에는 2(SLACK_WEIGHT)를 쓴다. 첫 광고를 늦추는 배치를 강하게 피하려는 값으로 보인다 추정.
  • 테스트는 두 블렌더가 multi-risk와 같은 안전 조건을 지키고, 광고를 multi-risk보다 적게 내지 않는다고 고정한다 확인 — ads/tests/blender_comparison_test.rs.

    • 같은 혼합 피드에서 광고 7개를 내고 3개를 간격 한도로 버리는 결과는 둘이 같다. 옮겨진 유기 포스트 수는 least_movement 6개, slot_spread 8개다.
    assert!(
        total >= baseline_total,
        "{name} served {total} ads vs multi_risk {baseline_total}"
    );
    

새로 알게 된 것D. Phoenix가 리드 수집 전환을 클릭 직후 창에서 학습한다

  • 광고 리드 수집 전환(ADS_LEADGEN_CONVERSION)이 "클릭한 경우에만, 신선한 창에서" 학습하는 새 헤드 묶음에 들어갔다 확인 — ads_head_masking.py.
    • 이 액션은 전날 커밋에서 proto에 추가됐다. 기존 웹·앱 전환 헤드는 지연 창(늦게 도착하는 전환을 기다리는 창)에서 학습한다.
    • 학습 마스크는 fresh_ct & fresh & kept & click이다.
  • 페이지 RL 학습 config에 체류 손실을 CREAD(체류 시간을 여러 임계값마다 넘었는지 이진 분류로 학습한 뒤 기댓값으로 복원하는 방식)로 바꾼 변형이 생겼다 확인 — configs/xrecsys.py.
    • 이름은 immersive_page_rl_cread다. Tweedie·MAE 가중을 0으로, CREAD 두 손실을 각 0.1로 두고 체류 버킷 테이블을 켠다.
    • 홈 기본 config는 2026-10-08에 이미 CREAD로 바뀌었다. 이번에는 페이지 RL 쪽에도 같은 손실을 쓸 수 있게 됐다.

새로 알게 된 것그 밖의 변경

  • 영상 캐러셀 정렬 점수에 "영상을 열 확률 × immersive 지면 예상 체류 시간" 항이 가중 기본 0.0으로 생겼다 확인 — util/video_carousel.rs:178-190.
  • 최근 노출 이력에서 캐러셀 모듈 항목을 빼, 캐러셀 영상이 메인 피드의 "이미 본 포스트"로 세지지 않는다 확인 — served_history_query_hydrator.rs:94-110. 캐러셀이 기본 off라 기본 동작은 그대로다.
  • 페이지 RL이 candidate-only 층(후보 토큰만 갱신하는 마지막 트랜스포머 층)과 함께 돌 수 있게, 그 층에서 유저 토큰도 갱신하는 옵션이 기본 off로 생겼다 확인 — models/transformer.py.
  • 광고 헤드 메트릭을 각 헤드가 학습하는 창으로만 자르는 옵션이 기본 off로 생겼다 확인 — models/recsys_model.py.
  • 두 새 블렌더에 광고 배치 결과와 공급 한계를 세는 메트릭이 붙었다 확인 — ads/health_metrics.rs.
  • VF(visibility-filtering, 포스트마다 이 뷰어에게 보여도 되는지 판정하는 서비스)는 리팩터다. 규칙, 안전 수준별 규칙 목록, 클라이언트 스위치 기본값이 바뀌지 않았다 확인 — 606b254.
    • 인용 관계 조회를 Flock 소스로 합쳐, 뷰어가 인용 작성자일 때 답이 섞이던 문제를 고쳤다.
    • 찾지 못한 포스트를 Failed 대신 NotFound로 돌려준다. 어느 쪽이든 그 포스트는 나가지 않는다.
    • golden corpus(규칙별 기대 판정 테스트)에 For You 추천과 immersive 추천 지면 사례가 더해졌다.
  • 학습 통계에서 랭커 클러스터 라벨이 빠졌고, 멀티모달 임베딩 조회가 예비 경로 없이 O2 저장소만 쓴다 확인 — 606b254.
  • grox(Grok 기반 주석 파이프라인)에 제휴 기업 배지 이미지 필드와 LLM 출력에서 JSON을 꺼내는 도우미가 생겼다 확인 — 같은 커밋.

정본 반영 services/x.md ## 한 줄 요약과 ## 출처의 기준 커밋을 606b254로 올렸다. ## 랭킹 Phoenix 절의 스코어러 체인 불릿에서 "기본 off인 서빙 페이지 로그"를 고치고 기본 on 전환 불릿을 더했다. ## 광고 도입의 V2 판정 문장을 기본 off로 고치고, 새 블렌더 문장과 '이 절의 변경 이력' 목록을 더했다. 최종 배치 절의 블렌더 선택값 목록, 피드 지면 절의 캐러셀 정렬 점수, ## 열린 질문의 2026-10-14 커밋 2번 질문에 불릿을 더했고, 변경 이력 요약표에 4세대+52 행을 추가했다.

의미 페이지 단위 RL 재순위로 가는 세 단계 가운데 첫 단계인 서빙 로그가 프로덕션 기본값으로 켜졌다. 지금 로그에는 확률이 없으므로, 오프라인 RL에 쓰려면 탐색 스위치도 켜져야 한다 추정. 광고 쪽은 V2 판정을 다시 끄고 블렌더 후보를 늘려, 브랜드 안전 배치를 아직 실험 중인 것으로 보인다 추정.

다음에 볼 것