Skip to content

Collaborative Filtering and LLM Agents:從電影相似度到搜尋與記憶工具|Stanford CS124 第 9 週

2026年8月22日1 分鐘
TL;DR第 9 週教推薦系統:內容式推薦看物品的特徵,協同過濾只看評分矩陣,用「相似的人」或「相似的物品」來推估沒評過的分數。PA7 把物品對物品的協同過濾寫成一個函式,交給會呼叫工具的 LLM agent,再加上訂票、網頁搜尋與記憶。

🌏 English version

這是 Stanford CS124 導讀的第 9 週。資料從文字換成人的行為:誰給哪部電影幾顆星。要回答的問題是:一個人沒看過的東西,怎麼猜他會不會喜歡?

這也是整門課最後一份作業 PA7 的一週。PA7 把這週的推薦演算法包成一個工具,交給 LLM agent 使用。

本週材料:Recommender Systems and Collaborative Filtering 投影片、實作課五、PA7。指定閱讀是 Mining of Massive Datasets 第 9 章。預錄影片在 Canvas,本文依投影片整理。

推薦問題長什麼樣

推薦有三種層次:編輯人工挑選的清單、簡單的統計(熱門排行、最新上架),以及為每個人量身訂做的推薦。這週講第三種。

投影片說學這個有兩個理由。一是實用,新聞和商品推薦都靠它。二是理解錯誤資訊怎麼擴散:平台推薦什麼,決定了很多人看到什麼。

形式上,有一群使用者、一堆物品,和一張評分矩陣:每一列是一個使用者,每一欄是一個物品,格子裡是評分。這張矩陣絕大部分是空的,因為多數人沒評過多數物品。推薦的工作就是把空格填上,然後把預測分數高的推薦出去。

評分怎麼來?直接請人打分數效果不好,多數人懶得做。實際上多半是從行為推斷:買了、看完了、讀了,就當作高分。

空格太多帶來冷啟動問題:新物品沒有人評過,新使用者沒有任何紀錄,兩者都無從下手。

做法一:內容式推薦

想法:推薦和這個人以前喜歡的東西內容相似的物品。有人聽 Ella Fitzgerald,資料庫裡她的標籤是「爵士、二十世紀中、人聲」,Louis Armstrong 的標籤很像,就推薦他。

做法是替每個物品建一個特徵向量(電影的類型、導演、演員;文章則用第 4 週的 tf-idf 挑出重要的詞),再把使用者喜歡過的物品的向量平均起來,當成這個使用者的向量。兩種向量的維度相同,直接算 cosine,推薦最接近的物品。

優點:不需要其他使用者的資料,新物品和冷門物品都能推薦,也能解釋推薦的理由(因為你喜歡這個導演)。

缺點:特徵很難定,影像和音樂尤其如此;只會推薦和你以前喜歡的東西很像的,跳不出去;也用不到其他人的品質判斷。

做法二:協同過濾

協同過濾完全不看物品的內容,只看評分矩陣。

使用者對使用者

想法:找出和你評分習慣相似的人,把他們喜歡而你還沒看過的推薦給你。

每個使用者就是矩陣裡的一列。兩個人相不相似,還是用 cosine。但直接算有問題。投影片的例子裡有三個人:A 很討厭《星際大戰》,C 很喜歡,B 沒看過。直覺上 A 和 C 的口味應該相反,A 和 B 至少沒有衝突。但把空格當成 0 直接算 cosine,A 和 B 是 0.380,A 和 C 是 0.322,幾乎沒差。原因是低分和高分都是正數,在向量裡指向同一邊;空格的 0 反而比最低分看起來「更討厭」。

修正方法是減去平均(mean-centering):每個人的評分都減掉他自己的平均分。這樣一來:

  • 高於自己平均的變成正數,低於的變成負數。口味相反的人,向量方向也相反。
  • 空格維持 0,意思變成「沒有資訊」,而不是「最低分」。
  • 順便處理了每個人給分標準不同的問題:有人習慣全部打 4、5 分,有人很嚴格。

投影片再加一個步驟:只用兩個人都評過的物品來算。手算一次:

  • 使用者 x 的評分:[1, 空, 空, 1, 3],平均 5/3
  • 使用者 y 的評分:[1, 空, 2, 2, 空],平均 5/3

減去平均:x 變成 [−2/3, 空, 空, −2/3, 4/3],y 變成 [−2/3, 空, 1/3, 1/3, 空]。

兩人都評過的是第 1 和第 4 個物品,所以只比 [−2/3, −2/3] 和 [−2/3, 1/3]:

  • 內積 = 4/9 − 2/9 = 2/9
  • 長度分別是 √(8/9) 和 √(5/9)
  • cosine = (2/9) ÷ (√40 ÷ 9) ≈ 0.32

(最後這個數字是我照投影片的步驟算的。)

有了相似度,預測 x 對某個物品的評分:找出評過這個物品、而且和 x 最相似的 k 個人,把他們的評分做加權平均,權重就是相似度。越像你的人,意見越重要。

物品對物品

換個方向:不找相似的人,找相似的物品。每個物品是矩陣裡的一欄(或把矩陣轉過來看是一列),兩部電影相似,表示同一批人給它們的分數很像。

預測你對電影 i 的評分:看你評過的電影裡,哪些和 i 最相似,把你給那些電影的分數做加權平均。

投影片的例子:要預測使用者 5 對電影 1 的評分。使用者 5 評過的電影裡,和電影 1 最相似的兩部是電影 3(相似度 0.658,他給 2 分)和電影 6(相似度 0.768,他給 3 分):

預測 = (0.658 × 2 + 0.768 × 3) ÷ (0.658 + 0.768) = 3.62 ÷ 1.426 = 2.54

投影片說,實務上物品對物品通常比使用者對使用者好。理由是物品比較單純,而一個人會有好幾種口味。

協同過濾的優缺點

優點是什麼物品都適用,不用設計特徵。

缺點:

  • 冷啟動:系統裡的使用者不夠多就找不到相似的人。
  • 稀疏:很難找到評過同一批物品的人。
  • 第一個評分者:從來沒人評過的物品,永遠不會被推薦。
  • 偏向熱門:傾向推薦大家都看的,品味獨特的人得不到好推薦。
  • 社會後果:可能造成同溫層和越推越極端的循環。

PA7 用的簡化版,手算一次

投影片有一節說明,PA7 的資料集很小,所以助教建議用一個簡化的版本:

  1. 相似度直接用 cosine,不減平均,也不限定共同評過的物品。
  2. 預測分數不除以相似度的總和,只做加總。出來的數字不是一到五星的預測評分,只用來排名。

實作課五補充了第三點:使用者的資料是「喜歡的電影清單」,轉成 0 和 1 的向量。

實作課五有一個完整的小例子,資料如下(空格當成 0):

U1U2U3U4
M1153
M254
M3241
M424
M5434
M613

每一列是一部電影。有一位新使用者,喜歡 M3 和 M5。要推薦哪一部?

第一步,算電影之間的 cosine。 講義給了大部分的值,留三個給學生算。以 M1 和 M3 為例(以下三個是我算的):

  • M1 = [1, 5, 3, 0],M3 = [2, 4, 0, 1]
  • 內積 = 1×2 + 5×4 + 3×0 + 0×1 = 22
  • 長度:√35 = 5.92,√21 = 4.58
  • sim(M1, M3) = 22 ÷ (5.92 × 4.58) = 0.81

同樣的算法:sim(M1, M5) = 29 ÷ (5.92 × 6.40) = 0.77,sim(M5, M6) = 9 ÷ (6.40 × 3.16) = 0.44。

第二步,替每部候選電影算分數。 分數 = 它和使用者喜歡的每部電影的相似度加總。這位使用者喜歡 M3 和 M5:

候選電影和 M3 的相似度和 M5 的相似度分數
M10.810.771.58
M40.390.701.09
M20.140.760.90
M60.140.440.58

(講義的例子只列 M1、M2、M6 三部候選,這裡把 M4 也算進來,結論相同。)

第三步,推薦分數最高的:M1。

回頭看原始資料就知道為什麼:U2 給 M1、M3、M5 的分數是 5、4、4,全部偏高。喜歡 M3 和 M5 的人,和 U2 的口味接近,而 U2 也喜歡 M1。整個過程沒有用到任何一部電影的內容。

評估,以及可能出什麼錯

評估的方法是把一部分已知的評分藏起來,讓系統預測,再和真實的評分比較。常用的指標是 RMSE(預測和實際的差,平方後平均再開根號)。

投影片接著問了一個更根本的問題:預測「使用者會看什麼」,是對的目標嗎? 它介紹了 YouTube 在 2016 年公開的做法:把影片和使用者都表示成向量,訓練一個很大的神經網路去預測使用者下一支會看的影片。系統被訓練成最大化觀看,而讓人一直看下去的內容,不一定是真實或有益的內容。

投影片列出推薦系統已知的社會問題:散播錯誤資訊與宣傳、同溫層、不當內容、不透明、侵犯隱私。其中引了一位前 YouTube 工程師的說法:他很快發現推薦機制會把人放進同溫層,而且沒有出口。

PA7:把推薦函式交給 agent

PA7 要做一個電影票務的客服 agent。規定三到四人一組,不能用遲交額度,佔總成績 18%。(下面的配分照 README 寫,三部分加起來是 107 分;實作課四的講義寫的是 100 分另加 5 分加分,兩份文件不一致。)

第一部分:會用工具的 agent(68 分)

推薦工具(21 分)。 在 agent.py 實作 similarity 和 recommend_movies,就是上面手算的那套。資料是一張電影評分矩陣,每一列是電影、每一欄是使用者。README 給了一個可以對答案的例子:對使用者 Peter 推薦 3 部,結果應該完全等於《回到未來》《法櫃奇兵》《星際大戰六部曲》,順序也要一樣。

把工具接上 agent(27 分)。 用 DSPy 的 ReAct。你要做兩件事:在 agent 的說明文字裡寫清楚它的任務,以及把工具放進清單:

react_agent = dspy.ReAct(
    MovieTicketAgent,
    tools = [
        recommend_movies,
        general_qa,
    ]
)

ReAct 的運作是推理和呼叫工具交替進行。使用者說「我是 Peter,推薦三部電影給我」,agent 的紀錄會是:

  1. 想:我需要推薦 3 部電影給 Peter,要用 recommend_movies。
  2. 呼叫:recommend_movies(user_name="Peter", k=3)。
  3. 觀察:拿到三部電影的清單。
  4. 想:推薦完成了,接下來問他要不要訂票。
  5. 呼叫 finish,結束。

最後 agent 把整個過程整理成一句給使用者的回覆。

這裡的分工值得看清楚。算相似度、排名是確定性的計算,交給 Python 函式;決定現在該用哪個工具、參數怎麼填、結果怎麼跟使用者說,交給 LLM。LLM 沒有自己去算那個矩陣。

接資料庫(20 分)。 實作 book_ticket:訂票時要更新票務資料庫,並從使用者的餘額扣款。agent 處理不了的要求,要呼叫 file_request 轉給真人客服。

第二部分:接到真實世界(32 分)

網頁搜尋(8 分)。 LLM 不知道訓練之後的事,例如即將上映的新片。接上搜尋 API(透過 SerpAPI),讓 agent 可以查。這是第 4 週 RAG 的另一種形式:檢索的來源從固定的文件集合換成整個網路。

記憶(24 分)。 到這裡為止,agent 沒有狀態:每一輪對話都要重新告訴它你是誰。用 Mem0 這個函式庫加上記憶,讓它記得之前的互動。

第三部分:反思(7 分)

在 Gradescope 上回答幾題反思問題。

幾件實際的事

  • API 額度。 需要 Together AI 的 key(建立時可能要填付款資料)和 SerpAPI 的 key(免費帳號有 250 次搜尋)。README 反覆提醒:每跑一次互動介面就會扣額度,所以先用 python test_functions.py --function similarity 這類指令把函式單獨測好。
  • 不確定性。 README 有一節專門講:LLM 系統不是確定性的,agent 偶爾會有意外的行為,即使整體是對的。測試時要讀完整的推理紀錄,確認它呼叫了正確的工具。
  • 評分方式。 確定性的函式用一般的自動評分。其他項目先由一個 LLM 評分,只要 LLM 扣了任何分數,就會轉給助教人工複查。評分用的 prompt 是公開的。

實作課五

實作課五有兩部分。第一部分就是上面那個協同過濾的手算,講義附了試算表和解答,repo 裡另有一份解答文件。

第二部分佔了大半堂課,主題是課堂上該怎麼規範 AI 的使用。Stanford 有全校的指引,但細節交給各門課的老師,所以學生每修一門課就要記一套不同的規則。活動分四步:

  1. 判斷灰色地帶。 五個情境,各組決定可以、不可以、還是看情況。例如:學生把程式的錯誤訊息貼給 ChatGPT,照它的建議改好了,但不確定自己能不能重做一次;非母語的學生用 AI 潤飾作文的文法,論點全是自己的;助教用 LLM 起草給學生的評語,自己再審過修改。
  2. 寫政策。 一半的組替 CS124 寫,另一半替寫作課寫。要具體寫出允許和禁止的用法、要不要揭露、違反的後果,以及理由。
  3. 交換找漏洞。 找出「形式上符合政策、實質上違背學習目標」的做法,找出邊緣案例(把 AI 當輔助工具的身心障礙學生;買得起更好模型的學生),找出兩個講理的人會有不同解讀的句子。
  4. 回到全班討論。

講義的結論是:沒有一套適用於所有課的 AI 政策,因為政策應該由這門課的學習目標決定。寫作課裡,寫出來的東西本身就是學習;程式課裡,寫出來的東西是用來展示學會了。兩者需要的規則不一樣。

自我檢查

  1. 用實作課五的資料算 sim(M2, M4)。答案:M2 = [0, 0, 5, 4],M4 = [0, 2, 4, 0]。內積 = 20,長度是 √41 = 6.40 和 √20 = 4.47,cosine = 20 ÷ 28.6 = 0.70。和講義表上的值一致。
  2. 如果新使用者只喜歡 M2,簡化版會推薦哪一部?答案:看 M2 和其他電影的相似度:M1 0.40、M3 0.14、M4 0.70、M5 0.76、M6 0.74。最高的是 M5。
  3. 一個使用者給三部電影 5、5、2 分,減去平均之後是多少?答案:平均是 4,變成 [1, 1, −2]。
  4. 用物品對物品預測:使用者評過兩部相似的電影,相似度是 0.5 和 1.0,他給的分數是 4 和 1。預測評分是多少?答案:(0.5×4 + 1.0×1) ÷ 1.5 = 2.0。比較相似的那部他給了低分,所以預測被拉低。
  5. PA7 裡,「算兩部電影的相似度」和「決定要不要呼叫推薦工具」各由誰負責?答案:前者是你寫的 Python 函式,結果是確定的,可以用單元測試檢查;後者是 LLM,每次不一定相同,要靠讀推理紀錄來檢查。

這週和後面的關係

  • 這週用評分矩陣判斷物品重不重要、像不像。下一週換成連結:用網頁之間的超連結判斷哪個網頁重要。
  • PA7 是這門課的最後一項要求,沒有期末考。

系列導覽:上一篇 第 8 週:Speech and PA7/Git Lab|下一篇 第 10 週:PageRank and Social Networks

更新紀錄

  • 2026-10-13:依 2026 年版公開投影片重寫。投影片來源從 2021 年的舊檔換成官方課表現在連結的版本,實作課五的連結從已失效的舊檔名換成 Lab5_LargeLanguageModels.md。補上內容式推薦、減去平均的手算、物品對物品的預測例子、PA7 簡化版的完整手算、ReAct 的步驟、實作課五的 AI 政策活動與自我檢查。

參考資料