← 2026-03-26 📂 All Days 2026-03-28 →
🏗️
🏗️ System Design
🏗️ 系统设计 Day 11 / System Design Day 11

🏗️ 系统设计 Day 11 / System Design Day 11

CAP 定理与最终一致性 / CAP Theorem & Eventual Consistency

难度 / Difficulty: Intermediate | 阶段 / Phase: Growth | 预计阅读时间 / Read time: 3 min

🌍 真实场景 / Real-World Scenario

想象你在设计 Twitter(现 X)的点赞系统。用户遍布全球,分布在北美、欧洲、亚洲的数据中心。当网络故障发生时,你必须做一个选择:

要么继续接受点赞写入(可能导致各地数据不一致);

要么拒绝所有写入(保证数据一致,但系统不可用)。

这就是 CAP 定理的核心困境。

Imagine you're designing Twitter's like system, with users spread across data centers in North America, Europe, and Asia. When a network partition occurs, you face a hard choice:

Either keep accepting like writes (risking inconsistent counts across regions),

or reject all writes (keeping data consistent, but making the system unavailable).

This is the core dilemma of the CAP theorem.


📐 CAP 定理解释 / CAP Theorem Explained

CAP 定理由 Eric Brewer 在 2000 年提出,它说:分布式系统最多只能同时满足以下三项中的两项:

CAP theorem (Brewer, 2000) states: a distributed system can guarantee at most 2 of these 3 properties simultaneously:

属性英文解释
CConsistency所有节点在同一时刻看到相同数据 / All nodes see same data at same time
AAvailability每个请求都收到响应(非错误)/ Every request gets a response (non-error)
PPartition Tolerance网络分区时系统仍继续运行 / System works despite network partitions
⚠️ 关键洞察: 在真实分布式系统中,网络分区(P)是不可避免的。所以你实际上是在 CA(一致性 vs 可用性) 之间做取舍。

🏛️ ASCII 架构图 / Architecture Diagram

正常状态 / Normal State: ┌──────────┐ ┌──────────┐ ┌──────────┐ │ Node A │◄───────►│ Node B │◄───────►│ Node C │ │ likes=42 │ │ likes=42 │ │ likes=42 │ └──────────┘ └──────────┘ └──────────┘ ▲ user writes 网络分区 / Network Partition: ┌──────────┐ ✗ ┌──────────┐ ┌──────────┐ │ Node A │ BROKEN │ Node B │◄───────►│ Node C │ │ likes=45 │ │ likes=42 │ │ likes=42 │ └──────────┘ └──────────┘ └──────────┘ (user wrote 3 more) (partition: can't sync) CP 选择 (e.g. HBase, Zookeeper): AP 选择 (e.g. Cassandra, DynamoDB): → 拒绝 Node B/C 的写入 → 允许各自独立写入 → 数据一致,但不可用 → 可用,但数据暂时不一致

⚖️ 关键权衡 / Key Tradeoffs

CP 系统(一致性 + 分区容错)

为什么这样设计? 需要强一致性的场景,例如金融交易、库存系统。

  • ✅ 数据永远一致,不会有脏读
  • ❌ 网络分区时部分节点不可用
  • 📦 代表:HBase, MongoDB (default), ZooKeeper, etcd

AP 系统(可用性 + 分区容错)

为什么这样设计? 高可用性更重要,短暂不一致可接受,例如社交 feed、购物车。

  • ✅ 系统始终响应,用户体验好
  • ❌ 不同节点可能返回不同结果(最终一致性
  • 📦 代表:Cassandra, DynamoDB, CouchDB, DNS

最终一致性 / Eventual Consistency

时间线 Timeline: t=0 User writes likes=45 to Node A t=1 Node A is isolated (partition) t=2 User reads from Node B → gets 42 (stale!) t=5 Partition heals, nodes sync t=6 User reads from Node B → gets 45 ✅ (eventually consistent)

最终一致性 并非"随机错误",而是"在网络恢复后,所有副本最终达到相同状态"。


🚫 常见错误 / Common Mistakes

别踩这个坑:

  1. 误解 CAP 是固定选择 — 现代系统(如 DynamoDB)允许你按操作级别调整一致性(ConsistencyLevel: QUORUM vs ONE),而不是全局二选一。
  1. 把 CA 作为选项 — 不存在真正的"CA 系统",因为没有网络分区容错的系统根本不是分布式系统。
  1. 忽视 PACELC 扩展 — CAP 只描述分区时的行为,PACELC 模型还考虑了正常运行时的延迟 vs 一致性权衡,更全面。
  1. 混淆最终一致性和弱一致性 — 最终一致性保证"最终会对齐";弱一致性不做任何保证。

🔍 面试重点 / Interview Focus

当面试官问"你会如何设计 X 系统"时,主动提出 CAP:

"这取决于一致性需求。如果是金融交易,我会选 CP;如果是社交 feed,AP + 最终一致性更合适,因为用户短暂看到旧数据不是大问题。"

📚 参考资料 / References


🧒 ELI5(像我5岁一样解释)

想象你和好朋友各有一本记事本,记录班里同学的生日。你们约定互相抄写更新。

  • CP:如果你们之间的电话断了,就不写新内容,直到联系上为止(一致,但暂停工作)
  • AP:各自继续记录,电话修好后再对比合并(继续工作,但暂时可能不一样)

大多数社交网站选择 AP:你的点赞数可能偶尔显示"旧数据",但网站从不宕机。

💻
💻 Algorithms
💻 算法 Day 12 / Algorithms Day 12

💻 算法 Day 12 / Algorithms Day 12

#15 3Sum — Medium — Two Pointers (3/5)

难度 / Difficulty: 🟡 Medium | 阶段 / Phase: Growth | 预计时间 / Read time: 4 min

🧩 双指针模式 (3/5) — 继续 Day 9 引入的模版

Building on the 双指针模式 / Two Pointers template from Day 9 (Valid Palindrome).

模式回顾 / Pattern Recap:

left, right = 0, len(arr) - 1
while left < right:
    total = arr[left] + arr[right]
    if total == target: return [left, right]
    elif total < target: left += 1
    else: right -= 1

本模块问题 / Block Problems:

  1. ✅ #125 Valid Palindrome (Easy) — Day 9
  2. ✅ #167 Two Sum II (Medium) — Day 11
  3. 👉 #15 3Sum (Medium) — TODAY
  4. 🔜 #11 Container With Most Water (Medium)
  5. 🔜 #42 Trapping Rain Water (Hard)

今天的变化 / Today's Twist: 从找"2个数之和"升级到找"3个数之和为0",需要先固定一个数,再用双指针扫余下部分。


🔗 题目链接 / Links


🌍 真实场景类比 / Real-World Analogy

想象你在整理一箱重量不等的砝码,你想找到三个砝码,使它们的重量加起来恰好为零(一正一负加中间值)。

逐一穷举三个砝码的所有组合是 O(n³),太慢了。如果先把砝码按重量排序,固定最左边的砝码,然后用左右两个指针扫剩余部分,就能降到 O(n²)。

Imagine sorting weights in a box and finding three that sum to zero. Brute force is O(n³). Sort them, fix the leftmost, and use two pointers for the rest → O(n²).


📋 问题描述 / Problem

Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that:

  • i != j, i != k, j != k
  • nums[i] + nums[j] + nums[k] == 0

The solution set must not contain duplicate triplets.

Input:  nums = [-1, 0, 1, 2, -1, -4]
Output: [[-1, -1, 2], [-1, 0, 1]]

🗺️ 映射到模版 / Mapping to Template

核心思路: 排序后,外层遍历固定 nums[i],内层用双指针找 nums[left] + nums[right] == -nums[i]

Fixed: nums[i] = -1 target for inner = 0 - (-1) = 1 Array: [-4, -1, -1, 0, 1, 2] (sorted) i L R Step 1: left=-1, right=2 → sum=1 ✅ found! → skip duplicates Step 2: left=0, right=1 → sum=1 ✅ found! Step 3: left >= right → stop inner loop

🐍 Python 解法 + 逐行追踪 / Solution + Trace

def threeSum(nums: list[int]) -> list[list[int]]:
    nums.sort()                           # [-4, -1, -1, 0, 1, 2]
    result = []
    
    for i in range(len(nums) - 2):        # fix the first element
        if nums[i] > 0:                   # sorted: if first > 0, no solution
            break
        if i > 0 and nums[i] == nums[i-1]:  # skip duplicates for i
            continue
        
        left, right = i + 1, len(nums) - 1  # two pointers for the rest
        
        while left < right:
            total = nums[i] + nums[left] + nums[right]
            
            if total == 0:
                result.append([nums[i], nums[left], nums[right]])
                # skip duplicates for left and right
                while left < right and nums[left] == nums[left + 1]:
                    left += 1
                while left < right and nums[right] == nums[right - 1]:
                    right -= 1
                left += 1
                right -= 1
            elif total < 0:
                left += 1   # need larger sum
            else:
                right -= 1  # need smaller sum
    
    return result

# Trace with nums = [-1, 0, 1, 2, -1, -4]:
# After sort: [-4, -1, -1, 0, 1, 2]
# i=0: nums[i]=-4, left=1(-1), right=5(2) → sum=-3 → left++
#       left=2(-1), right=5(2) → sum=-3 → left++
#       left=3(0),  right=5(2) → sum=-2 → left++
#       left=4(1),  right=5(2) → sum=-1 → left++
#       left>=right → stop
# i=1: nums[i]=-1, left=2(-1), right=5(2) → sum=0 ✅ append [-1,-1,2]
#       skip dups → left=3(0), right=4(1) → sum=0 ✅ append [-1,0,1]
#       left>=right → stop
# i=2: nums[i]=-1 == nums[i-1]=-1 → skip (duplicate!)
# i=3: nums[i]=0, left=4(1), right=5(2) → sum=3 → right--
#       left>=right → stop
# Result: [[-1,-1,2], [-1,0,1]] ✅

时间复杂度 / Time Complexity: O(n log n) sort + O(n²) = O(n²)

空间复杂度 / Space Complexity: O(1) extra (excluding output)


⚡ 与模版的关键差异 / Key Differences from Template

Two Sum II (Day 11)3Sum (Today)
目标找2个数之和 = target找3个数之和 = 0
结构单层双指针外层 for + 内层双指针
去重不需要必须跳过重复元素
复杂度O(n)O(n²)

🔁 举一反三 / Pattern Connections

  • #11 Container With Most Water (下一题): 同样外层遍历 + 内层双指针,但优化目标不同(最大面积 vs 零和)
  • #42 Trapping Rain Water (最难题): 双指针 + 边界最大值,是本模式的终极形态
  • 变体: 4Sum (#18) = 再加一层 for 循环 → O(n³),同样思路

📚 参考资料 / References


🧒 ELI5

想象你有一堆正数和负数的磁铁,你要找三块加起来刚好等于零。

先把它们从小到大排好,然后:拿起最左边的那块,再用两只手各从左右两边向中间夹。夹到了就记录下来,没夹到就根据总和太大还是太小来移动手。

这样就不用每三块都试一遍,快很多!

🗣️
🗣️ Soft Skills
🗣️ 软技能 Day 11 / Soft Skills Day 11

🗣️ 软技能 Day 11 / Soft Skills Day 11

优先级排序 / Prioritization

当所有事情都"同样重要"时,你怎么决定做什么?

How do you decide what to work on when everything seems equally important?

级别 / Level: Senior/Staff | 类别 / Category: Prioritization | 阶段 / Phase: Growth | 预计时间 / Read time: 2 min

💡 为什么这个问题很重要 / Why This Matters

这是 Senior/Staff 工程师的核心能力之一。初级工程师执行任务;高级工程师决定做哪些任务

面试官想知道:你是否会在信息不完整时做出理性决策,还是会陷入"什么都想做"或"等别人告诉你"的困境。

This is a core Senior/Staff engineer competency. Junior engineers execute tasks; senior engineers decide which tasks to execute.

The interviewer wants to know: can you make rational decisions with incomplete information, or do you get paralyzed?


⭐ STAR 框架拆解 / STAR Breakdown

Situation(背景):

"我加入新团队后第一个季度,我们同时有5个项目被标记为高优先级:两个客户承诺的功能、一个重要的性能优化、一个安全漏洞修复,还有一个技术债务重构。"

Task(任务):

"我需要帮助团队决定顺序,但没有人能直接告诉我哪个'真正'最重要。"

Action(行动):

"我用了一个简单框架:先问每项工作的影响范围(多少用户/多少收入受影响)和紧迫性(截止日期是硬性的吗),再评估依赖关系(哪项工作阻塞了其他事情)。安全漏洞虽然用户感知低,但是合规风险极高,我把它放第一位。客户承诺功能放第二,因为违约有商务影响。性能优化排第三,因为有量化的流失数据支撑。技术债务排最后,但我明确说明了不做的风险累积。"

Result(结果):

"这个排序被 PM 和工程 Lead 接受了,我们按序交付,没有出现返工或紧急插队。"

❌ 糟糕 vs ✅ 优秀回答 / Bad vs Good Answer

❌ 不好的回答:

"我会先做最难的事情,这样其他事情就容易了。"

为什么不好? 没有考虑外部影响,把个人技术偏好凌驾于业务价值之上。


✅ 好的回答结构:

  1. 承认复杂性 — "当所有事情看起来都重要时,我的第一步是找出哪些是真正的约束条件(deadline、依赖、风险),而不是表面的紧迫感。"
  2. 使用框架 — 提到 Impact × Urgency 矩阵、ICE (Impact/Confidence/Ease),或 RICE 框架
  3. 对齐业务目标 — 把技术工作连接到公司/团队目标
  4. 明确沟通取舍 — 说出"如果我选择做 A,B 会推迟到 X 日期,风险是 Y"

🏆 Senior/Staff 级别加分项 / Senior/Staff Tips

  • Don't just prioritize silently. 写下你的优先级排序并发给相关人员,这既是对齐,也是自我保护。
  • "No" is a complete sentence, but explain the tradeoff. 当你说不做某事时,要量化"不做"的成本。
  • Revisit priorities regularly. 每周或每冲刺开始时重新评估,因为情况会变。
  • Separate urgency from importance. 紧急 ≠ 重要(艾森豪威尔矩阵)。很多"紧急"任务其实不重要。

📋 关键要点 / Key Takeaways

原则说明
🎯 Impact First先问"谁会受益,影响多大?"
Hard Deadlines区分"有人希望早完成"和"晚一天就违约"
🔗 Unblock Others阻塞其他工程师的事情优先级隐性更高
🗣️ Communicate Tradeoffs说出你选择和放弃的理由

📚 参考资料 / References


🧒 ELI5

想象你有一张写满作业的清单,数学、语文、体育都要交。

聪明的做法不是"随便挑",而是先问:

  1. 哪个明天就到期(硬截止日期)?
  2. 哪个影响最多分数(重要性)?
  3. 哪个不做会影响其他同学(依赖)?

然后按顺序做,同时告诉老师"我今天做 A 和 B,C 推迟到周五,原因是..."

🎨
🎨 Frontend
🎨 前端 Day 11 / Frontend Day 11

🎨 前端 Day 11 / Frontend Day 11

React useRef — React 的"逃生舱口" / Escape Hatch from React

类别 / Category: React Hooks | 周 / Week: 3 | 阶段 / Phase: Growth | 预计时间 / Read time: 2 min

🌍 真实场景 / Real Scenario

你在做一个视频播放器 dashboard,需要:

  1. 当用户点击"开始录制"按钮时,聚焦到视频元素
  2. 追踪一个内部计时器 ID(不需要触发重渲染)
  3. 直接调用 DOM 元素的 .play() 方法

useState 不适合:每次更新都会触发重渲染,而且不能持有 DOM 引用。这时就需要 useRef

You're building a video player dashboard and need to: focus the video element on button click, track a timer ID without triggering re-renders, and call .play() directly. useState would cause unnecessary re-renders. Enter useRef.


🧠 useRef 的两大用途 / Two Use Cases

用途 1:持有 DOM 引用 / Holding a DOM Reference

import { useRef } from 'react'

function VideoPlayer() {
  // Creates { current: null } — persists across renders
  const videoRef = useRef<HTMLVideoElement>(null)
  
  const handlePlay = () => {
    // Direct DOM access — no React state involved
    videoRef.current?.play()
  }
  
  const handleFocus = () => {
    videoRef.current?.focus()
  }
  
  return (
    <div>
      {/* Attach ref to DOM element via ref prop */}
      <video ref={videoRef} src="/demo.mp4" />
      <button onClick={handlePlay}>▶ Play</button>
      <button onClick={handleFocus}>Focus Video</button>
    </div>
  )
}

用途 2:持有可变值(不触发重渲染)/ Mutable Value (No Re-render)

function RecordingTimer() {
  const [isRecording, setIsRecording] = useState(false)
  
  // Stores timer ID — changing it does NOT cause a re-render
  const timerIdRef = useRef<ReturnType<typeof setInterval> | null>(null)
  
  const startRecording = () => {
    setIsRecording(true)
    timerIdRef.current = setInterval(() => {
      console.log('Recording...')
    }, 1000)
  }
  
  const stopRecording = () => {
    setIsRecording(false)
    if (timerIdRef.current) {
      clearInterval(timerIdRef.current)
      timerIdRef.current = null
    }
  }
  
  return (
    <button onClick={isRecording ? stopRecording : startRecording}>
      {isRecording ? '⏹ Stop' : '⏺ Record'}
    </button>
  )
}

🤔 猜猜输出什么?/ What Does This Output?

function Counter() {
  const [count, setCount] = useState(0)
  const renderCount = useRef(0)
  
  renderCount.current += 1  // increment on every render
  
  return (
    <div>
      <p>Count: {count}</p>
      <p>Renders: {renderCount.current}</p>
      <button onClick={() => setCount(c => c + 1)}>+1</button>
    </div>
  )
}
// After clicking +1 twice, what does "Renders" show?

A) 1(从不更新)

B) 2(只算点击)

C) 3(初始渲染 + 2次点击)

D) 0(ref 不触发重渲染)

<details><summary>答案 / Answer</summary>

C) 3renderCount.current 在每次渲染时递增。每次 setCount 触发重渲染,都会加 1。初始渲染时为 1,点击两次后为 3。注意:renderCount.current 的变化不会触发额外渲染,只是被动记录。

</details>


❌ 常见错误 vs ✅ 正确做法 / Common Mistakes vs Correct Approach

// ❌ WRONG: Reading ref value during render to display in UI
function BadComponent() {
  const countRef = useRef(0)
  countRef.current += 1
  
  // BUG: React may batch renders or run effects multiple times
  // This count will be unreliable in React 18 Strict Mode (double-invokes)
  return <p>Rendered {countRef.current} times</p>
}

// ✅ RIGHT: Use useState for values that should be displayed in UI
function GoodComponent() {
  const [renderCount, setRenderCount] = useState(0)
  
  useEffect(() => {
    setRenderCount(c => c + 1)
  })
  
  return <p>Rendered {renderCount} times</p>
}

// ❌ WRONG: Accessing ref.current during render before it's assigned
function BadRef() {
  const inputRef = useRef<HTMLInputElement>(null)
  console.log(inputRef.current?.value)  // null on first render!
  return <input ref={inputRef} />
}

// ✅ RIGHT: Access ref.current inside effects or event handlers
function GoodRef() {
  const inputRef = useRef<HTMLInputElement>(null)
  
  useEffect(() => {
    // ref is assigned after DOM mounts
    console.log(inputRef.current?.value)
  }, [])
  
  return <input ref={inputRef} />
}

🔀 何时用 useRef vs useState / When to Use useRef vs useState

场景用哪个?原因
展示在 UI 里的值useState需要触发重渲染
计时器 ID / 请求 IDuseRef不需要显示,不需要重渲染
DOM 元素访问useRef直接引用,React 管理
上一次渲染的值useRef跨渲染持久化,不触发渲染
追踪 isMounteduseRef副作用清理,不需要展示

📚 参考资料 / References


🧒 ELI5

useState 就像写在白板上的数字——每次改变,班里所有人都重新看一遍(重渲染)。

useRef 就像你口袋里的小纸条——你可以随时改上面的内容,但不会打扰到任何人(不触发重渲染)。

DOM ref 就更特别了:它就像一张"通行证",让你可以直接敲响某个 DOM 元素的门,而不用通过 React 的"前台"。

🤖
🤖 AI
🤖 AI Day 12

🤖 AI Day 12

RLHF — ChatGPT 是怎么学会"有用"的 / How ChatGPT Learned to Be Helpful

类别 / Category: Training | 模式 / Mode: Concept | 阶段 / Phase: Growth | 预计时间 / Read time: 2 min

💡 直觉解释 / Intuitive Explanation

预训练后的语言模型像一个"博学但任性的学生"——它什么都会说,但不一定有帮助、安全或符合人类期望。

RLHF(Reinforcement Learning from Human Feedback,基于人类反馈的强化学习) 就是让这个学生接受"社会化教育"的过程:通过收集人类对模型输出的偏好评分,训练模型生成更符合人类价值观的回答。

Pre-trained LLMs know a lot but aren't inherently helpful or safe. RLHF is the "socialization" step: collect human preferences on model outputs, then train the model to generate responses humans prefer.


⚙️ 工作原理 / How It Works

RLHF 分三个阶段:

阶段 1: 监督微调 (SFT) / Supervised Fine-Tuning

人类写示范回答 Input: "解释黑洞" Output: [人类写的高质量示范答案] → 直接在这些数据上微调基础模型 → 模型学会"期望的格式和风格"

阶段 2: 训练奖励模型 (RM) / Train Reward Model

给模型同一个问题的多个回答,让人类排序: Q: "如何减肥?" 回答A: "节食+运动" ← 人类排 #1 回答B: "服用减肥药" ← 人类排 #2 回答C: "节食即可,不用运动" ← 人类排 #3 奖励模型学习:给任意回答打分

阶段 3: PPO 强化学习 / RL with PPO

# Simplified PPO loop concept:
for prompt in training_prompts:
    response = policy_model.generate(prompt)    # current LLM
    reward = reward_model.score(response)        # RM gives score
    
    # Update policy to maximize reward,
    # but stay close to original (KL divergence penalty)
    loss = -reward + kl_penalty * kl(policy, reference)
    policy_model.update(loss)
完整流程 Full Pipeline: 基础模型 SFT RM训练 PPO强化学习 Pre-trained → 学格式 → 学人类偏好 → 最大化人类评分 Base LLM (SFT) (Reward Model) (RLHF)

🌍 应用 / Applications

系统RLHF 的作用
ChatGPT从"预测下一个词"变成"有帮助、无害、诚实"
ClaudeAnthropic 使用 Constitutional AI (CAI),RLHF 的变体
Llama 2 ChatMeta 开源 RLHF 模型,可本地运行
GeminiGoogle 的对话模型,同样有 RLHF 阶段

🐍 可运行代码片段 / Runnable Python Snippet

这里用 trl 库演示 RLHF 的核心思路(无需 GPU 的简化版):

# pip install trl transformers torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch

# Simulate a reward model scoring responses
# (In real RLHF, this is trained on human preference data)
def simple_reward_model(response: str) -> float:
    """Score a response based on simple heuristics."""
    score = 0.0
    
    # Reward helpfulness signals
    if len(response) > 50: score += 0.3         # detailed enough
    if "because" in response.lower(): score += 0.2  # gives reasoning
    if "?" not in response: score += 0.1         # not evasive
    
    # Penalize harmful patterns  
    if "i can't help" in response.lower(): score -= 0.5
    if "kill" in response.lower(): score -= 1.0
    
    return score

# Test with example responses
responses = [
    "I can't help with that.",
    "Exercise regularly and maintain a balanced diet because consistent habits lead to sustainable weight loss.",
    "Just eat less."
]

for r in responses:
    print(f"Score: {simple_reward_model(r):.1f} | {r[:50]}...")
# Score: -0.5 | I can't help with that...
# Score:  0.6 | Exercise regularly and maintain a balanced...
# Score:  0.3 | Just eat less...

⚠️ RLHF 的局限性 / Limitations

  1. 奖励黑客 / Reward Hacking: 模型学会"取悦"奖励模型,而非真正有帮助(如生成冗长但空洞的回答)
  2. 人类偏好的偏差 / Human Bias: 训练数据中的人类标注员有自己的偏见
  3. 成本高 / Expensive: 需要大量人工标注,质量难以扩展
  4. DPO 正在替代 PPO: Direct Preference Optimization 更简单,目前很多新模型已迁移

📚 参考资料 / References


🧒 ELI5

想象你在教一只小狗(语言模型)坐下。

第一步:你示范给它看(SFT — 监督学习)。

第二步:你训练另一个"评判员"来区分好的坐姿和差的坐姿(奖励模型)。

第三步:小狗每次坐好了,评判员给它零食;坐歪了,没有零食(强化学习)。

经过很多次训练后,小狗学会了"人类喜欢什么样的坐姿"。ChatGPT 就是这样学会"人类喜欢什么样的回答"的。

Attention Heatmap

When the model processes it, it attends most strongly to animal.

Theanimaldidntcrossthestreetbecauseitwastootired
it →