AgentCF++, 개인 선호와 유행을 메모리에 압축하는 법
AgentCF++: Memory-enhanced LLM-based Agents for Popularity-aware Cross-domain Recommendations, SIGIR, 2025.
AgentCF: Collaborative Learning with Autonomous Language Agents for Recommender Systems, WWW, 2024.
LLM 기반 user agent로 추천 시스템의 user 행동을 시뮬레이션하려는 연구가 이어지고 있어요. AgentCF++(SIGIR 2025)는 그중 AgentCF(WWW 2024)의 memory 설계를 cross-domain과 popularity 상황으로 확장한 논문이에요. 다만 short paper라서 기반이 되는 학습 루프는 대부분 생략되어 있어요. 이 글은 AgentCF++를 중심에 두고, 비어 있는 부분을 AgentCF에서 가져와 전체 흐름을 이어서 설명해요.
User 행동 시뮬레이션을 위해
User의 interaction 기록을 텍스트로 풀어 LLM에 넣는 것만으로는 행동이 재현되지 않아요. “금요일에 기저귀를 사는 사람은 맥주도 산다”처럼, 의미적으로는 무관하지만 행동적으로는 연결된 패턴이 존재하기 때문이에요. Collaborative filtering 모델은 이런 패턴을 embedding 공간에서 잡아내지만, 범용 언어 지식에 의존하는 LLM은 혼란스러워해요. 실제로 user history를 prompt로 넣어 ranking하는 LLMRank는 전통 추천 모델보다 성능이 크게 낮았어요.
AgentCF의 해법은 user뿐 아니라 item도 agent로 만드는 거예요. BPR(Bayesian Personalized Ranking)이나 NCF(Neural Collaborative Filtering)가 user embedding과 item embedding을 함께 최적화하듯, user agent와 item agent를 함께 최적화해요. 이때 각 agent의 memory 텍스트가 embedding에 대응하고, LLM 자체는 고정돼요. AgentCF++도 이 구도를 그대로 물려받으므로, 먼저 이 학습 루프를 이해해야 해요.
AgentCF의 학습 루프
학습은 실제 user의 행동 sequence를 시간순으로 재연하는 방식으로 진행되고, 각 step은 전통 추천 모델의 forward와 backward에 대응하는 두 단계로 이루어져요.
Forward 단계에서는 실제로 구매한 positive item $i^+$와 샘플링한 negative item $i^-$를 candidate로 제시하고, user agent가 memory를 근거로 하나를 고르게 해요.
\[i^o = f_{\text{LLM}}(M_u;\, M_{i^-};\, M_{i^+})\] \[y_{\text{exp}} = \text{Prompt}_{\text{LLM}}(i^o;\, M_u;\, M_{i^-};\, M_{i^+})\]여기서 $M$은 각 agent의 memory, $i^o$는 agent의 선택, $y_{\text{exp}}$는 선택 이유예요. 흥미로운 설계가 하나 있는데, negative item을 일부러 인기 있는 item으로 샘플링하고 candidate 목록의 앞쪽에 배치해요. Personalization이 없는 agent는 popularity와 position에 끌려 negative를 고르게 되고, 그만큼 풍부한 오답 신호를 얻을 수 있어요.
Backward 단계에서는 agent의 선택을 실제 기록과 비교하고, 선택이 틀렸다면 reflection으로 memory를 수정해요.
\[M_u^{\prime} \leftarrow \text{Reflection}_u(i^o;\, y_{\text{exp}};\, M_u;\, M_{i^-};\, M_{i^+})\] \[M_i^{\prime} \leftarrow \text{Reflection}_i(i^o;\, y_{\text{exp}};\, M_u;\, M_{i^-};\, M_{i^+})\]두 식은 입력이 같지만 업데이트 주체와 prompt가 달라요. $\text{Reflection}_u$는 user agent에게 “왜 잘못 판단했는지 분석해 네 선호 서술을 고쳐라”라고 요구하고, 출력은 수정된 user memory예요. $\text{Reflection}_i$는 item agent에게 “잘못된 설명 때문에 user가 엉뚱한 선택을 했을 수 있으니 item 설명을 고쳐라”라고 요구하고, 출력은 수정된 positive item memory예요. 같은 사건을 두 agent가 각자의 관점에서 반성하는 구조예요. Negative item의 memory는 수정하지 않는데, LLM이 negative item의 단점을 과장하는 경향이 있고 그 item이 다른 user에게는 매력적일 수 있기 때문이에요.
논문은 이 reflection을 “semantic gradient”라고 불러요. Gradient 대신 언어 피드백이 memory를 조정하는 방향을 결정한다는 뜻이에요. 그리고 user와 item이 서로의 memory에 선호 정보를 주입하고, 그 정보가 이후 interaction에서 다른 agent로 전파되면서 “비슷한 user가 좋아한 item을 좋아한다”는 collaborative filtering의 아이디어가 암묵적으로 구현돼요. AgentCF++가 문제 삼는 지점이 바로 이 propagation이에요.
AgentCF의 memory는 어디서 무너질까
AgentCF++는 위 memory 설계가 현실적인 두 상황에서 무너진다고 지적해요.
첫째, cross-domain 문제예요. User는 책도 사고 영화도 보고 게임도 해요. AgentCF는 user당 memory가 하나이므로, preference propagation을 거치며 여러 domain의 선호가 한 memory에 뒤섞여요. 책 domain에서 결정을 내릴 때 게임 선호가 노이즈로 작용하고, item agent도 propagation 과정에서 원래 domain의 특성을 잃어버려요.
둘째, popularity 문제예요. AgentCF에서 memory는 자신이 직접 참여한 interaction에서만 업데이트돼요. 논문의 예시를 보면, $t_1$에 Alice, Bob, Carl이 야외활동 용품을 사고, $t_2$에 Bob과 Carl이 우비를 사고, $t_3$에 Carl이 캠핑 장비를 사요. 현실의 Alice라면 직접 구매하지 않아도 주변의 행동을 보고 날씨 변화를 짐작하겠지만, AgentCF의 Alice memory는 $t_1$ 이후로 멈춰 있어요. 타인의 행동이 자신의 선호에 미치는 영향, 즉 popularity factor가 모델링되지 않는 거예요.
한 가지 짚어둘 점이 있어요. 추천 모델 연구에서 popularity는 보통 제거해야 할 bias로 다뤄지지만, user behavior simulation의 목표는 선호가 아니라 행동 자체를 재현하는 것이에요. 행동은 선호와 popularity의 결합으로 나타나므로, 여기서 popularity는 제거 대상이 아니라 명시적으로 모델링해야 할 요인이에요.
User memory를 domain 축으로 나눈다
첫 번째 문제에 대한 해법은 user agent에 dual-layer memory를 두는 거예요. User는 domain마다 두 종류의 memory를 가져요. Domain-separated memory는 해당 domain에서 직접 배운 선호만 기록해요. Domain-fused memory 역시 domain마다 하나씩 존재하는데, 해당 domain의 선호에 더해 다른 domain의 domain-separated memory에서 이 domain과 관련된 선호를 가져와 합쳐둔 memory예요. 예를 들어 게임 domain의 domain-fused memory에는 게임에서 배운 선호뿐 아니라, 책이나 영화에서 배운 선호 중 게임 취향을 짐작하게 하는 부분까지 담겨요. 결정에 바로 쓸 수 있는 “이 domain 기준의 종합 선호”인 셈이에요. 둘 다 빈 상태로 시작해요.
Item agent는 AgentCF처럼 단일 memory를 유지해요. 제목과 카테고리 같은 side information으로 초기화되고, interaction을 거치며 “이 item을 좋아하는 user들의 성향”이 누적돼요. Item은 하나의 domain에만 속하므로 나눌 이유가 없어요.
두 memory를 잇는 것이 two-step fusion mechanism이에요. 먼저 다른 domain들의 domain-separated memory에서 target domain과 관련 있는 선호만 추출하고, 그다음 추출된 선호들을 target domain의 domain-fused memory에 통합해요. 논문은 이를 attention에 비유해요. 첫 단계가 attention score 계산에, 두 번째 단계가 weighted aggregation에 대응한다는 거예요. “판타지 소설을 좋아한다”는 책 domain의 선호에서 게임 domain과 관련된 부분만 뽑아 반영하는 식이라, cross-domain 지식은 활용하면서 무관한 노이즈는 걸러낼 수 있어요.
유행은 interest group을 타고 흐른다
두 번째 문제에 대한 해법은 group-shared memory예요. 각 user agent는 세 단계를 거쳐 interest group에 배정돼요. LLM이 (1) user의 domain-fused memory에서 interest tag들을 추출하고, (2) tag embedding을 K-means로 clustering해 동의어를 묶고, (3) cluster마다 대표 이름을 합성해 group을 만들어요. 각 user는 자신의 관심을 대부분 덮는 상위 몇 개 group에 소속되고, 선호 변화를 반영하기 위해 group은 주기적으로 다시 나눠져요.
각 interest group은 고정 크기의 group-shared memory를 가지고, 소속 user들의 최근 interaction을 저장해요. 앞의 예시로 돌아가면, $t_2$에 Bob과 Carl이 우비를 산 행동이 Alice와 공유하는 memory에 기록되고, Alice는 직접 구매하지 않았어도 다음 결정에서 이 정보를 참조해요. 개인 memory를 직접 건드리지 않으면서도 타인의 행동이 판단에 반영되는 구조예요.
주목할 설계는 grouping 기준이에요. Interaction history의 유사도가 아니라 관심사로 user를 묶어요. History 전체로 묶으면 우연히 비슷한 기록을 가진 무관한 user에게까지 유행이 번지기 때문이에요.
Inference와 update
이제 위 구성 요소들이 AgentCF의 학습 루프에 어떻게 끼워지는지 볼게요.
Inference는 AgentCF의 forward와 같은 contrastive 구도예요. 현재 interaction을 $(u, i, d)$라 하면, $u$는 user agent, $i$는 item agent, $d$는 $i$의 domain이에요. Domain $d$에서 negative $j$를 뽑고, LLM이 앞쪽 선택지를 선호하는 position bias를 고려해 $j$를 $i$보다 앞에 배치한 뒤, $u$가 positive를 고르고 이유를 설명하게 해요. 이때 $u$의 결정은 domain $d$의 domain-separated memory와 domain-fused memory, 그리고 접근 가능한 group-shared memory에 동시에 의존해요. AgentCF에서 단일 $M_u$가 하던 역할을 세 memory가 나눠 맡은 셈이에요.
Update는 AgentCF의 backward에 해당하고, 한 번의 interaction마다 세 번의 reflection이 순서대로 일어나요.
첫 번째로 $u$의 domain-separated memory가 갱신돼요. $u$는 자신의 선택이 정답이었는지, 그리고 $i$와 $j$의 memory를 근거로 domain $d$에서의 선호 서술을 고쳐 쓰며 이번 interaction에서 무엇을 좋아하고 싫어하는지 배워요. AgentCF에서 단일 user memory를 갱신하던 $\text{Reflection}_u$가 domain 단위로 좁혀진 거예요.
두 번째로 $u$의 domain-fused memory가 갱신돼요. 앞서 설명한 two-step fusion이 실행되는 시점이 바로 여기예요. 다른 domain들의 domain-separated memory에서 domain $d$와 관련된 선호를 추출하고, 방금 갱신된 domain $d$의 선호와 합쳐 domain $d$의 domain-fused memory를 다시 써요.
마지막으로 $i$와 $j$가 완성된 $u$의 domain-fused memory를 보고 자신의 memory를 고쳐요. $i$는 “이런 선호의 user가 나를 골랐다”를, $j$는 “이런 선호의 user가 나를 고르지 않았다”를 기록해요. AgentCF가 negative item의 memory를 건드리지 않았던 것과 달리, AgentCF++는 $j$도 함께 갱신하는 점이 달라요.
정리하면 reflection이 separated, fused, item 순서로 흘러가요. 그리고 여기서 갱신된 item memory는 다음 interaction에서 다른 user의 판단 근거로 다시 쓰이므로, 세 memory가 서로를 개선하는 loop가 만들어져요.
AgentCF++은 얼마나 개선되었나
실험은 Amazon의 Books, CDs, Movies, Games 중 3~4개 domain을 조합한 Cross-1부터 Cross-5까지 다섯 개 데이터셋에서 진행됐어요. Cross-domain user를 대상으로 하기 위해 여러 domain에서 상호작용하고 총 10회 이상 interaction이 있는 user만 남겼고, AgentCF와 마찬가지로 API 비용 때문에 100명을 샘플링했어요. 후보 10개를 ranking하는 과제를 NDCG와 MRR로 평가해요.
결과에서 세 가지를 읽을 수 있어요.
먼저 cross-domain 환경에서 AgentCF는 LLMRank 같은 training-free 방법과 비슷한 수준에 그치고 SASRec을 넘지 못해요. 전통 모델은 학습 과정에서 popularity와 cross-domain collaborative 신호를 자연스럽게 흡수하는데, AgentCF의 단일 memory는 그러지 못한다는 진단이 수치로 확인된 셈이에요. 반면 AgentCF++는 다섯 데이터셋 모두에서 baseline과 ablation variant를 일관되게 앞서요.
다음으로 ablation을 보면, dual-layer memory만 추가한 AgentCF + dual과 shared memory만 추가한 AgentCF + shared 모두 AgentCF보다 좋아요. 두 모듈이 각각 독립적으로 기여한다는 뜻이에요.
가장 흥미로운 결과는 AgentCF++ w/o group이에요. Interest 대신 전체 interaction history로 user를 묶은 이 variant는 AgentCF++보다 나쁠 뿐 아니라 AgentCF + dual보다도 나빠요. Sharing 자체가 이득이 아니라, 유행이 흘러갈 경로를 관심사 기준으로 정확히 지정하는 것이 이득이라는 해석이 가능해요. 잘못된 집단에 popularity를 전파하면 오히려 노이즈가 되는 거예요.
정리하며
AgentCF++는 AgentCF의 학습 루프, 즉 contrastive selection과 collaborative reflection을 그대로 유지하면서 memory 구조만 바꿨어요. 단일 user memory를 domain 축으로 분리·융합하는 dual-layer memory로 확장했고, interest group의 shared memory를 통해 개인의 interaction 바깥에 있는 popularity 신호까지 끌어들였어요. Agentic memory 관점에서 보면, 단일 memory에서 구조화된 memory와 공유 memory로 나아가는 흐름이에요.
물론 한계도 명확해요. 두 논문 모두 API 비용 때문에 user 100명 규모에서 검증됐고, memory 구조를 다른 user agent framework에 이식하는 것은 저자들도 future work로 남겨두었어요.


