OpenClaw 背后的极简革命:Pi Agent 这个只带 4 个工具

OpenClaw 爆火背后,藏着什么秘密?

过去几周,OpenClaw 在各个技术社区疯狂刷屏。这个被描述为”科幻带点疯狂”的 AI 编程助手,以其惊人的自主能力和病毒式传播速度,成为 2025-2026 年最受瞩目的 AI 项目之一。

但你可能不知道的是:OpenClaw 的核心不是魔法,而是一个叫做 Pi 的极简框架。

Pi 由 Mario Zechner 开发,它拒绝功能膨胀,坚持只用 4 个基础工具:Read(读取)、Write(写入)、Edit(编辑)和 Bash(命令行)。它的系统提示词是同类工具中最短的。然而,正是这种极致的简约,让它成为 Armin Ronacher 等资深开发者几乎唯一使用的编程助手,也成为 OpenClaw 选择它作为底层技术的原因。

本文将揭开 OpenClaw 背后的技术秘密,深入解析 Pi 的极简哲学。你会看到:

  • 为什么 OpenClaw 选择 Pi 而不是功能更丰富的框架
  • 为什么 4 个工具足以完成所有编程任务
  • Pi 为什么明确拒绝行业标准协议(MCP)
  • 树状会话结构如何让调试效率提升 10 倍
  • 如何让 AI 自己编写、热重载、扩展自己的功能

极简核心:一个 while 循环 + 4 个工具

Pi 的核心设计哲学可以用一句话概括:一个调用 LLM 的 while 循环,加上四个基础工具。

让我们看看这个极简架构是如何工作的。

双循环架构:对话与执行的无限循环

Pi 的核心确实就是一个 while 循环。在 packages/agent/src/agent-loop.ts 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 外层循环:处理后续消息队列
while (true) {
let hasMoreToolCalls = true;
let steeringAfterTools: AgentMessage[] | null = null;

// 内层循环:处理工具调用和转向消息
while (hasMoreToolCalls || pendingMessages.length > 0) {
// 1. 处理待处理消息(用户新输入或转向消息)
if (pendingMessages.length > 0) {
for (const message of pendingMessages) {
currentContext.messages.push(message);
}
pendingMessages = [];
}

// 2. 调用 LLM 获取响应
const message = await streamAssistantResponse(currentContext, config, signal, stream);

// 3. 检查是否有工具调用
const toolCalls = message.content.filter((c) => c.type === "toolCall");
hasMoreToolCalls = toolCalls.length > 0;

// 4. 执行工具调用
if (hasMoreToolCalls) {
const toolExecution = await executeToolCalls(
currentContext.tools, message, signal, stream, config.getSteeringMessages
);
// 工具结果会作为新消息加入上下文
for (const result of toolExecution.toolResults) {
currentContext.messages.push(result);
}
}

// 5. 检查转向消息(实时干预)
pendingMessages = (await config.getSteeringMessages?.()) || [];
}

// 6. 检查后续消息队列
const followUpMessages = (await config.getFollowUpMessages?.()) || [];
if (followUpMessages.length > 0) {
pendingMessages = followUpMessages;
continue; // 继续外层循环
}
break; // 没有更多消息,结束
}

这个循环逻辑极其简单:

  1. 把用户消息发给 AI
  2. AI 说”我要用工具” → 执行工具 → 把结果告诉 AI
  3. AI 继续思考,可能还要用工具 → 重复步骤 2
  4. AI 说”我完成了” → 检查有没有新用户消息 → 有就继续,没有就结束

这就是全部。没有复杂的状态机,没有工作流引擎,没有递归调用——就是一个简单的”对话-执行-反馈”循环。

四件套:Unix 哲学在 AI 领域的应用

packages/coding-agent/src/core/tools/index.ts 中,Pi 只定义了四个核心工具:

1
2
3
4
5
// 默认工具集:只有 4 个
export const codingTools: Tool[] = [readTool, bashTool, editTool, writeTool];

// 只读工具集(用于探索阶段)
export const readOnlyTools: Tool[] = [readTool, grepTool, findTool, lsTool];
工具 功能 为什么足够
Read 读取文件内容 AI 需要知道代码长什么样
Bash 执行 shell 命令 运行 git、npm、测试、grep、find 等
Edit 精确修改文件(查找替换) 修改现有代码
Write 写入新文件 创建新文件

为什么不需要更多?看 Bash 工具的定义:

1
2
3
4
const bashSchema = Type.Object({
command: Type.String({ description: "Bash command to execute" }),
timeout: Type.Optional(Type.Number({ description: "Timeout in seconds" })),
});

Bash 可以调用 grep、find、ls、git、npm……整个 Unix 工具链都是 AI 的延伸。Pi 的哲学是:不要为每个功能写新工具,让 AI 用 Bash 调用现有工具。

Armin Ronacher 这样评价:”Pi… 拥有我所知的最短的系统提示词。”这不仅仅是风格上的选择;这是对逻辑引擎的”疏通”。通过保持核心小巧、指令稀疏,Pi 减轻了底层大语言模型(LLM)的认知负担。这让模型的原始推理能力得以主导,从而减少了幻觉,显著提高了可靠性。

为什么 Pi 明确拒绝行业标准协议(MCP)

Pi 最具争议的技术决策或许是它对 Model Context Protocol(MCP,模型上下文协议) 的明确拒绝。当整个行业都在争先恐后地将 MCP 作为连接智能体与工具的标准时,Pi 却有意将其排除在外。

这不是”懒惰的遗漏”,而是一个经过深思熟虑的架构必要选择。

MCP 的局限性:缓存陷阱

像 MCP 这样的标准协议要求工具在会话开始时加载。这使得在不清空整个缓存或让 AI 困惑的情况下,几乎不可能完全重新加载或更新工具的功能。

试想一下这个场景:你正在用 AI 助手调试一个工具,但工具本身出了问题。如果使用 MCP 协议,你需要:

  1. 停止当前会话
  2. 修复工具代码
  3. 重新启动整个会话
  4. 重新加载所有上下文
  5. AI 可能会困惑:”我之前是怎么调用这个工具的?”

所有上下文都丢失了。

Pi 的解决方案:软件构建软件

相反,Pi 践行着”软件构建软件”的理念。如果智能体需要新能力,它不会下载插件。它会进入一个**”编写-重载-测试”循环**:编写扩展代码、热重载环境、迭代直到新功能稳定。

这让智能体成为一个自我进化的实体,能够实时维护和增强自己的功能。

Pi 的底层 AI SDK 设计为模型无关的。因为会话文件使用自定义消息来存储扩展状态,而非依赖供应商特定功能,你可以将复杂的会话在 Anthropic、OpenAI 或 Google 的模型之间迁移,而不会丢失进度。

实时热重载:修改即生效

Pi 的扩展系统支持内置热重载。当智能体编写新代码后,可以立即重载环境进行测试,无需重启会话。这种设计让 AI 能够快速迭代,构建出符合特定需求的个性化工具。

例如,Armin Ronacher 没有使用外部 CLI 或 MCP 服务器进行浏览器自动化,而是让智能体构建了一个直接利用 Chrome DevTools Protocol(CDP,Chrome 开发者工具协议) 的技能。任务完成后,这个技能可以被直接丢弃。智能体维护着自己的功能,不被那些它不需要的”社区技能”所累。

树状会话:让调试不再是一场噩梦

大多数 AI 界面都受困于”线性陷阱”,将对话视为简单的时间线消息序列。这是人类记忆和 LLM 上下文的局限,而 Pi 的树状会话架构优雅地绕过了这一点。

分支工作流:保持”上下文尊严”

在 Pi 中,会话是分支的。这支持一种保持上下文完整性的工作流:

场景 传统线性会话 Pi 的树状会话
工具损坏需要修复 在当前会话中混杂调试日志,污染主任务上下文 分支到一个全新的上下文去修复,主会话保持干净
修复完成后 继续在当前混乱的上下文中工作 “回退”到主分支,智能体会总结支线任务并带回结果
模型切换 上下文丢失或格式不兼容 通过 pi-ai SDK 实现上下文可移植性,可在 Anthropic、OpenAI、Google 模型间迁移

这种设计在代码审查场景中特别有用。/review 扩展会将会话分支到一个全新的上下文中审查代码,生成 diff,并在合并前特别标注新添加的依赖项。

实时干预:转向队列(Steering Queue)

这是 Pi 最独特的功能之一。想象你在和 AI 对话,AI 正在执行一系列操作:

正常情况:AI 调用工具 A → 调用工具 B → 调用工具 C → 完成任务

发现问题:你看到 AI 走错方向了,发送消息:”等等,不要用那个方法”

Pi 的处理机制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
export class Agent {
private steeringQueue: AgentMessage[] = []; // 转向队列
private followUpQueue: AgentMessage[] = []; // 后续队列

/**
* 发送转向消息:中断当前执行
* 在当前工具执行完成后立即处理,跳过剩余工具
*/
steer(m: AgentMessage) {
this.steeringQueue.push(m);
}

/**
* 发送后续消息:在当前轮次完全结束后处理
*/
followUp(m: AgentMessage) {
this.followUpQueue.push(m);
}
}
  • 转向队列(steer):如果消息进入转向队列,当前工具执行完后立即处理你的消息,跳过剩余工具
  • 后续队列(followUp):如果消息进入后续队列,等 AI 这一轮完全结束后再处理

这就像开车时的”紧急转向”和”下一站停靠”的区别——给用户细粒度的干预权。

技能系统:让 AI 自己教自己

Pi 的”元文档”约占总提示词的 25%,教 AI 如何扩展自己。这是通过技能系统(Skill System) 实现的。

渐进式披露:按需加载

packages/coding-agent/src/core/skills.ts 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
export interface Skill {
name: string; // 技能名称
description: string; // 技能描述(AI 根据这个决定何时加载)
filePath: string; // 技能文件路径
baseDir: string; // 技能根目录
source: string; // 来源(user/project/path)
disableModelInvocation: boolean; // 是否禁用自动调用
}

// 加载技能
export function loadSkills(options: LoadSkillsOptions = {}): LoadSkillsResult {
// 从多个位置加载:
// - ~/.pi/agent/skills/ (全局)
// - .pi/skills/ (项目本地)
// - CLI --skill 参数指定的路径
}

// 将技能格式化为系统提示词
export function formatSkillsForPrompt(skills: Skill[]): string {
const lines = [
"The following skills provide specialized instructions for specific tasks.",
"Use the read tool to load a skill's file when the task matches its description.",
...
"",
];
for (const skill of visibleSkills) {
lines.push(`### ${skill.name}`);
lines.push(`${skill.description}`);
lines.push(`File: ${skill.filePath}`);
lines.push("");
}
return lines.join("\n");
}

技能系统的工作流程:

  1. 启动时:Pi 扫描指定目录下的所有 SKILL.md 文件
  2. 系统提示词中:只告诉 AI 有哪些技能(名称+描述),不包含详细内容
  3. AI 按需加载:当任务匹配技能描述时,AI 用 read 工具读取完整的 SKILL.md
  4. SKILL.md 内容:包含具体操作步骤、脚本命令、示例等

文档即代码:用 Markdown 写能力

一个典型的 SKILL.md

1
2
3
4
5
6
7
8
9
10
11
12
---
name: pdf-processing
description: Extracts text and tables from PDF files. Use when working with PDF documents.
---

# PDF Processing

## Setup

Run once before first use:
```bash
cd /path/to/pdf-processing && npm install

Usage

1
2
./extract-text.js    # Extract text
./extract-tables.js # Extract tables
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

**热重载原理**:Skill 就是 Markdown 文件。当 AI 读取它时,内容立即进入上下文。**没有注册过程,没有重启需求**——这就是"编写即用,修改即生效"。

### 实战案例:Clanker 扩展

在 Pi 生态系统中,智能体常被称为"**Clanker**"——这是对"智能体即构建者"的昵称。以下是一些由智能体创建的斜杠命令:

- **`/answer`**:从智能体的文本中提取问题,并将其重新格式化为干净的输入框,防止混乱的内联对话
- **`/review`**:将会话分支到一个全新的上下文中审查代码,生成 diff,并在合并前特别标注新添加的依赖项
- **`/todos`**:管理 `.pi/todos` 目录中基于 Markdown 的任务列表,让人类和智能体都能跟踪进度

这些扩展不是从通用市场拉取的;它们是由 Clanker 根据你的具体需求手工打造的。

## 代码即真理:没有外部记忆系统

Pi 明确拒绝向量数据库、记忆银行等外部记忆系统。它的"记忆"策略很简单:

```typescript
export interface CompactionSettings {
enabled: boolean;
reserveTokens: number; // 预留 token 数(默认 16384)
keepRecentTokens: number; // 保留最近对话 token 数(默认 20000)
}

// 当上下文窗口快满时,压缩历史
export function shouldCompact(
contextTokens: number,
contextWindow: number,
settings: CompactionSettings
): boolean {
return contextTokens > contextWindow - settings.reserveTokens;
}

// 压缩策略:保留最近 N 个 token 的对话,更早的用 LLM 总结
export function findCutPoint(
entries: SessionEntry[],
startIndex: number,
endIndex: number,
keepRecentTokens: number,
): CutPointResult {
// 从最新消息开始,向前累积 token
// 当超过 keepRecentTokens 时,在那个点"切断"
// 更早的内容会被 LLM 总结成摘要
}

三层记忆策略

  1. 优先用真实代码:AI 直接用 read/grep 读取项目文件,而不是依赖可能过时的摘要
  2. 对话历史管理:当上下文快满时,把太旧的对话压缩成摘要
  3. 结构化摘要:保留目标、约束、进度、关键决策、下一步——结构化信息,而不是向量嵌入

Pi 的设计告诉我们:在 AI 时代,减法比加法更难,但也更有价值。

高性能 TUI:终端也能跑 Doom

当许多智能体优先考虑脆弱、臃肿的网页 GUI 时,Pi 采用了基于 @mariozechner/pi-tui 库构建的高性能终端用户界面(TUI,Terminal User Interface)

这里的技术秘密是差分渲染(differential rendering)。这确保了界面极其稳定和高性能。在这个闪烁、内存饥渴的 Web 应用时代,Pi 代表了工程尊严。

Armin Ronacher 评价:”它不闪烁,不消耗大量内存,不会莫名其妙崩溃。”

这个 TUI 不仅仅是基础 shell;它支持复杂的组件,如 spinner(加载动画)交互式文件选择器数据表格。为了证明其灵活性,开发者甚至在终端界面中实现了一个可直接运行的 Doom 游戏版本。如果 TUI 能够处理 Doom 的渲染需求,它就能处理开发者可能需要的任何调试仪表板或数据可视化。

总结:极简主义的胜利

Pi 及其更广泛的生态系统(包括 OpenClaw 等项目)代表了向”作为极简基础而非功能丰富产品”的智能体的根本性转变。

核心要点

  1. 极简核心:一个 while 循环 + 4 个基础工具(Read、Write、Edit、Bash)足以完成所有编程任务
  2. 拒绝 MCP:热重载和自我扩展能力比遵循行业标准协议更重要
  3. 树状会话:分支工作流保持上下文完整性,让调试不再混乱
  4. 技能系统:渐进式披露,让 AI 按需加载能力,实现自我进化
  5. 代码即真理:结构化摘要优于向量检索,直接读取源码而非依赖过期记忆

可迁移经验

无论你是否使用 Pi,这些设计原则都值得借鉴:

  • 工具设计遵循 Unix 哲学:每个工具做一件事,但可以组合
  • 优先使用系统已有能力,而非重新发明
  • 渐进式披露:只把必要信息放系统提示词,详细内容按需加载
  • 文档即代码:用 Markdown 写”能力”,而不是写代码
  • 给用户干预权:允许在 AI 执行中实时纠正
  • 结构化摘要优于向量检索:用 LLM 生成”人类可读”的摘要

思考题

  1. 你当前使用的 AI 编程助手有哪些功能是”功能膨胀”?哪些是真正的核心能力?
  2. 如果你的 AI 助手只能使用 4 个工具,你会选择哪 4 个?为什么?
  3. 在”预置功能的幻觉”和”无限自我构建的力量”之间,你会如何选择?

进一步学习

在 Pi 的世界里,答案就是唯一的出路。

从零到千万用户:系统扩展的七个阶段

系统扩展是一个复杂的话题,但在大厂处理过百万级请求、并将自己的创业公司 AlgoMaster.io 从零开始搭建后,我发现大多数系统在成长过程中都会经历相似的阶段。

关键洞察是:不要从一开始就过度设计。从简单开始,识别瓶颈,逐步扩展。

在本文中,我将带你了解系统从零到千万用户甚至更高级别的七个扩展阶段。每个阶段都会解决在特定增长点上出现的具体瓶颈。你将学到添加什么、何时添加、为什么有帮助以及涉及的权衡。

无论你是在开发 App 或网站、准备系统设计面试,还是只是好奇大型系统如何工作,了解这个演进过程都会帮助你更好地思考架构问题。

免责声明: 本文提到的用户范围和数字是近似值,用于说明扩展历程。实际的阈值取决于你的产品、工作负载特征和流量模式。

阶段一:单服务器架构(0-100 用户)

刚开始时,你的首要任务很简单:快速上线并验证想法。在这个阶段过早优化会浪费时间和金钱在你可能永远不会遇到的问题上。

最简单的架构是将所有东西放在单服务器上:你的 Web 应用、数据库和任何后台任务都在同一台机器上运行。

Instagram 就是这样起步的。2010 年,Kevin Systrom 和 Mike Krieger 发布第一个版本时,第一天就有 25,000 人注册。

他们没有一开始就过度设计。凭借小团队和简单的设置,他们根据实际需求进行扩展,随着使用量的增长增加容量,而不是为假设的未来流量而构建。

这种架构长什么样

实际上,单服务器设置意味着:

  • Web 框架(Django、Rails、Express、Spring Boot)处理 HTTP 请求
  • 数据库(PostgreSQL、MySQL)存储数据
  • 后台任务处理(Sidekiq、Celery)处理异步任务
  • 可能前面有一个反向代理(Nginx)用于 SSL 终止

所有这些都运行在一台虚拟机上。你的云提供商账单可能是每月 20-50 美元的基础 VPS(DigitalOcean Droplet、AWS Lightsail、Linode)。

为什么这对早期阶段有效

在这个阶段,简单是你最大的优势:

  • 快速部署:一台服务器意味着一个地方进行部署、监控和调试。
  • 低成本:一台 20-50 美元/月的虚拟专用服务器(VPS)可以轻松处理你的前 100 个用户。
  • 快速迭代:没有分布式系统的复杂性来拖慢开发速度。
  • 更容易调试:所有日志都在一个地方,组件之间没有网络问题。
  • 全栈可见性:你可以追踪每个请求的端到端,因为只有一条执行路径。

你在接受的权衡

这种简单性伴随着你明知故犯的权衡:

何时进入下一阶段

当你注意到这些迹象时,就该进化了:

  • 高峰流量期间数据库查询变慢:应用和数据库争夺相同的 CPU 和内存。一个重查询会降低所有人的 API 延迟。
  • **服务器 CPU 或内存持续超过 70-80%**:你正在接近单台机器可以可靠处理的极限。
  • 部署需要重启并导致停机:即使是短暂的中断也变得明显,用户开始抱怨。
  • 后台任务崩溃导致 Web 服务器宕机:没有隔离,非面向用户的工作会影响用户体验。
  • 你承担不起哪怕是短暂的停机:你的产品已经足够关键,以至于维护窗口也变得不可接受。

在某一点上,服务器开始在做所有事情的重压下挣扎。那就是进行第一次架构拆分的时机。

阶段二:数据库分离(100-1000 用户)

随着流量增长,你的单服务器开始吃力。Web 应用和数据库争夺相同的 CPU、内存和磁盘 I/O。一个重查询可能导致延迟飙升,减慢每个 API 响应。

第一个扩展步骤很简单:将数据库从应用服务器分离出来

这种两层架构给你带来几个直接的好处:

  • 资源隔离:应用和数据库不再争夺 CPU/内存。每个都可以使用 100% 的分配资源。
  • 独立扩展:升级数据库(更多 RAM、更快的存储)而无需触碰应用服务器。
  • 更好的安全性:数据库服务器可以位于私有网络中,不暴露于互联网。
  • 专业优化:为特定工作负载调整每台服务器。应用服务器需要高 CPU,数据库需要高 I/O。
  • 备份简单:数据库备份不会影响应用性能,因为它们在不同的机器上运行。

托管数据库服务

在这个阶段,大多数团队使用托管数据库,如 Amazon RDSGoogle Cloud SQLAzure DatabaseSupabase(我在 algomaster.io 使用 Supabase)。

托管服务通常处理:

  • 自动备份(每日快照、时间点恢复)
  • 安全补丁和更新
  • 基本监控和告警
  • 可选的只读副本(稍后介绍)
  • 故障转移到备用实例

一旦你考虑到工程时间,托管和自托管之间的成本差异通常很小。托管 PostgreSQL 实例可能比原始虚拟机每月多 50-100 美元,但它可以每周节省数小时的维护时间。这些时间更好地用于交付功能。

自托管数据库的主要原因是:

  • 大规模时的成本优化
  • 托管服务不支持的特定配置
  • 禁止托管服务的合规性要求
  • 你在构建数据库产品

对于大多数团队,托管服务是正确的选择,直到你的数据库账单增长到每月数千美元

连接池

这个阶段经常被忽视的一个改进是连接池。每个数据库连接消耗资源:

  • 连接状态的内存(PostgreSQL 中每个连接通常 5-10MB)
  • 应用和数据库服务器上的文件描述符
  • 连接管理的 CPU 开销

打开新连接也很昂贵。在 TCP 握手、SSL 协商和数据库认证之间,你可以为每个请求增加 50-100 毫秒的开销。

PgBouncer(用于 PostgreSQL)这样的连接池器保持一组数据库连接打开并在请求之间重用它们。

有 1,000 个用户时,你可能有 100 个并发连接访问你的 API。没有池化,那就是 100 个消耗资源的数据库连接。有了池化,20-30 个实际的数据库连接可以通过连接重用高效地服务这 100 个应用连接。

连接池模式:

  • 会话池化:每个客户端连接一个池连接(最兼容,效率最低)
  • 事务池化:每个事务后将连接返回池(大多数应用的最佳平衡)
  • 语句池化:每个语句后将连接返回(最高效,但可能破坏功能)

大多数应用使用事务池化效果最好,这通常可以将连接效率提高 3-5 倍

网络延迟考量

分离数据库会引入网络延迟。当应用和数据库在同一台机器上时,”网络”延迟基本为零(回环接口)。现在每个查询增加 0.1-1 毫秒的网络往返时间。

对于大多数应用,这可以忽略不计。但如果你的代码每个请求进行数百次数据库查询(这是一种反模式,但很常见),这种延迟会累积。解决方案不是将它们放回同一台机器,而是优化你的查询模式:

  • 尽可能批处理查询
  • 使用 JOIN 而不是 N+1 查询模式
  • 缓存频繁访问的数据
  • 使用连接池避免重复的连接设置开销

数据库在独立服务器上后,你已经获得了成长的空间。但你也创造了新的单点故障:应用服务器现在是薄弱环节。当它宕机,或者当它根本跟不上需求时会发生什么?

阶段三:负载均衡器 + 水平扩展(1000-10000 用户)

你的分离架构现在更好地处理负载,但你引入了一个新问题:你的单应用服务器现在是单点故障。如果它崩溃,你的整个应用都会宕机。随着流量增长,那一台服务器跟不上。

下一步是在负载均衡器后面运行多个应用服务器

负载均衡器位于你的服务器前面,将传入请求分发到它们之间。如果一台服务器故障,负载均衡器通过健康检查检测到这一点,并仅将流量路由到健康的服务器。用户不会经历单台服务器故障时的停机。

负载均衡器需要决定哪个服务器处理每个请求。常见算法包括:轮询加权轮询最少连接IP 哈希随机

大多数团队从轮询开始(简单,在大多数情况下效果良好),如果他们有处理时间变化的请求,则切换到最少连接。

现代负载均衡器在不同的层级运行:

  • 第 4 层(传输层):基于 IP 和端口路由。快速,但不能检查 HTTP 头。
  • 第 7 层(应用层):基于 HTTP 头、URL、Cookie 路由。更灵活,开销略大。

对于大多数 Web 应用,第 7 层负载均衡更可取,因为它支持:

  • 基于路径的路由(/api/* 到 API 服务器,/static/* 到 CDN)
  • 基于头的路由(移动端和桌面端的不同版本)
  • 负载均衡器上的 SSL 终止
  • 请求/响应检查以确保安全

垂直扩展 vs 水平扩展

在添加更多服务器之前,你可能会问:为什么不直接买一台更大的服务器?这是经典的垂直扩展与水平扩展的权衡。

垂直扩展意味着迁移到更大的服务器。它在早期效果很好,通常不需要代码更改。但你最终会遇到两个问题:硬件硬限制和成本快速增加。

更大的机器定价是非线性的,因此 CPU 或内存翻倍可能花费 3-4 倍。即使最大的实例也有天花板。

水平扩展意味着添加更多服务器。起初更难,因为你的应用必须是无状态的,所以任何服务器都可以处理任何请求。但它给你实际上无限的容量和内置的冗余。如果一台服务器故障,系统继续运行。

会话问题

这是水平扩展变得棘手的地方。如果用户登录并且他们的会话存储在服务器 1 的内存中,当下一个请求落到服务器 2时会发生什么?从应用的角度看,会话缺失,所以用户看起来已经登出。

这是有状态服务器问题,它是水平扩展的最大障碍。

有两种常见的方法来处理它:

1. 粘性会话(会话亲和性)

负载均衡器将来自同一用户的所有请求路由到同一服务器,通常使用 Cookie 或 IP 哈希。

优点:

  • 不需要应用更改
  • 适用于任何会话存储

缺点:

  • 如果该服务器故障,用户失去会话
  • 如果某些用户比其他用户更活跃,负载分布不均匀
  • 限制真正的水平扩展(不能自由地在服务器之间移动用户)
  • 新服务器需要时间来”预热”会话

2. 外部会话存储

将会话数据从应用服务器移出到共享存储,如 RedisMemcached

现在任何服务器都可以处理任何请求,因为会话数据是集中式的。这是大多数大规模系统使用的模式。Redis 查找的额外延迟(亚毫秒)与提供的灵活性相比可以忽略不计。

你现在可以处理更多流量并承受服务器故障。但随着用户群增长,你会注意到一些事情:无论你添加多少应用服务器,它们都在敲击同一个数据库。数据库正在成为下一个瓶颈。

阶段四:缓存 + 只读副本 + CDN(10000-100000 用户)

有 10,000+ 用户时,新的瓶颈出现了:你的数据库。每个请求都命中数据库,随着流量增长,查询延迟增加。处理 100 QPS(每秒查询)良好的数据库在 1,000 QPS 时开始挣扎。

读密集型应用(大多数是,读写比为 10:1 或更高)受影响尤其严重。

这个阶段引入三个互补的解决方案:缓存只读副本CDN。它们一起可以将数据库负载减少 90% 或更多。

缓存层

大多数 Web 应用遵循 80/20 规则:80% 的请求访问 20% 的数据。一个被浏览 10,000 次的产品页面不需要 10,000 次数据库查询。每次页面加载都获取的用户资料不需要每次都重新获取。

缓存将频繁访问的数据存储在内存中以实现近乎即时的检索。虽然数据库查询需要 1-100 毫秒,但缓存读取需要 0.1-1 毫秒。

最常见的缓存模式是旁路缓存(也称为懒加载):

  1. 应用首先检查缓存
  2. 如果数据存在(缓存命中),立即返回
  3. 如果不存在(缓存未命中),查询数据库
  4. 将结果存储在缓存中以供将来请求(带 TTL)
  5. 返回数据

Redis 和 Memcached 是这里的标准选择。Redis 功能更丰富(支持列表、集合、有序集合等数据结构;持久化;发布/订阅;Lua 脚本),而 Memcached 更简单,在纯键值缓存上略快。

大多数团队选择 Redis,因为附加功能很有用(使用有序集合做排行榜,列表做队列等),性能差异可以忽略不计。

缓存什么

不是所有东西都应该缓存。好的缓存候选包括:

不好的缓存候选:

  • 高度个性化的数据(对每个用户不同,低复用)
  • 频繁变化的数据(不断的失效开销)
  • 大 Blob(消耗内存而没有成比例的收益)
  • 陈旧性导致问题的交易数据

缓存失效

缓存最难的部分不是添加它,而是保持它的准确性。当底层数据变化时,缓存数据变得陈旧。这是计算机科学中著名的”两大难题”之一。

常见策略包括:

大多数系统从基于 TTL 的过期开始(将缓存设置为 5-60 分钟后过期),并对陈旧性导致问题的数据添加显式失效。例如:

1
2
3
4
5
def update_user_profile(user_id, new_data):
# 更新数据库
db.update("users", user_id, new_data)
# 使缓存失效
cache.delete(f"user:{user_id}")

下一次读取将缓存未命中并从数据库获取新数据。

只读副本

即使有缓存,一些请求仍会命中数据库,特别是写入缓存未命中。只读副本通过将读取流量分发到数据库的多个副本上来帮助。

主数据库处理所有写入。然后更改被复制(通常是异步的)到一个或多个只读副本。你的应用将读取查询发送到副本,并将写入工作负载保留在主数据库上,这减少了争用并提高了整体吞吐量。

复制延迟

一个重要的考虑因素是复制延迟。由于复制通常是异步的(为了性能),副本可能落后主数据库毫秒到秒。

对于大多数应用,这是可以接受的。如果社交媒体信息流落后一秒,大多数用户不会注意到。但一些流程需要更强的一致性。

一个常见的失败模式是读后写一致性

用户更新他们的资料并立即刷新。如果该读取落在一个尚未赶上的副本上,他们会看到旧数据并假设更新失败。

解决方案:

  1. 写入后从主数据库读取:在写入后的短时间内(N 秒),将该用户的读取路由到主数据库。
  2. 会话级一致性:跟踪用户的最后写入时间戳,只从赶上该点之后的副本读取。
  3. 显式从主数据库读取:对于关键读取(查看刚刚更新的数据),总是命中主数据库。

大多数框架对读/写分离有内置支持。例如,Rails(ActiveRecord)、Django 和 Hibernate 可以自动将读取路由到副本,将写入路由到主数据库。

内容分发网络(CDN)

静态资源如图片、CSS、JavaScript 和视频很少改变,根本不需要命中你的应用服务器。它们也是你提供的最大文件,如果你直接提供它们,在带宽和计算方面都很昂贵。

CDN 通过在称为边缘位置(或存在点)的全球分布式服务器上缓存静态资源来解决这个问题。

以下是东京用户请求图片时发生的情况:

  • 请求被路由到东京的 CDN 边缘(低延迟,约 50 毫秒往返)。
  • 如果文件已缓存(缓存命中),CDN 立即提供它。
  • 如果没有缓存(缓存未命中),CDN 从你的源站(可能在美国,约 300 毫秒)获取,在边缘存储副本,然后返回给用户。
  • 东京的下一个用户从边缘获取缓存版本,再次约 50 毫秒。

流行的 CDN 包括 Cloudflare(强大的免费层)、AWS CloudFrontFastlyAkamai

有了缓存、只读副本和 CDN,你的系统可以处理稳定增长。下一个挑战是尖峰流量。一个病毒式帖子、营销活动,甚至凌晨 3 点和下午 3 点之间的差异都可以造成 10 倍的流量变化。在那时,手动调整容量停止工作。

阶段五:自动扩展 + 无状态设计(100000-500000 用户)

有 100K+ 用户时,流量模式变得不太可预测。你可能有:

  • 每日高峰(美国的早晨,欧盟的晚上)
  • 每周模式(B2B 工作日更高,消费者周末更高)
  • 营销活动高峰(数小时内 10 倍流量)
  • 病毒式时刻(100 倍流量,持续时间不可预测)

在这一点上,手动添加和移除服务器不再可行。你需要自动响应的基础设施。

这个阶段侧重于自动扩展(自动调整容量)和确保你的应用真正无状态(服务器可以自由添加或移除而不会丢失数据或影响用户)。

无状态架构

为了让自动扩展工作,你的应用服务器必须可互换。任何请求都可以到任何服务器。任何服务器都可以终止而不会丢失数据。新服务器可以立即开始处理请求。

当新服务器加入集群时,它通常:

  1. 启动应用
  2. 向负载均衡器注册(或被发现)
  3. 连接到 Redis、数据库和其他共享服务
  4. 立即开始处理请求

当服务器被移除时:

  1. 负载均衡器停止发送新请求
  2. 在途请求完成(优雅关闭)
  3. 服务器终止

没有数据丢失,因为本地没有存储重要的东西。

自动扩展策略

自动扩展根据指标调整容量。扩展系统持续监控指标并根据阈值添加或移除服务器。

大多数团队从基于 CPU 的扩展开始。它简单,适用于大多数工作负载,并且易于理解。为背景任务工作者添加队列深度扩展。

扩展参数

配置自动扩展时,你将设置这些参数:

1
2
3
4
5
6
7
最小实例数: 2       # 即使在零流量时也始终运行
最大实例数: 20 # 成本上限和资源限制
扩展上限阈值: 70% # 触发扩展的 CPU 百分比
扩展下限阈值: 30% # 触发缩减的 CPU 百分比
扩展冷却时间: 3 分钟 # 扩展后等待时间
缩减冷却时间: 10 分钟 # 缩减后等待时间
实例预热: 2 分钟 # 新实例完全运行的时间

重要考虑因素:

  • 最小实例数:应该至少为 2 以保证冗余。如果一个故障,另一个在替换启动时处理流量。
  • 冷却时间:防止抖动(快速上下扩展)。缩减冷却时间通常更长,因为移除容量比添加更冒险。
  • 实例预热:新服务器需要时间启动、加载代码、预热缓存、建立数据库连接。在它们准备好之前不要将它们的容量计入。
  • 非对称扩展:积极扩展(快速响应负载),保守缩减(不要太快移除容量)。

用于无状态认证的 JWT

在这个规模上,许多团队从基于会话的认证转向使用 JWT(JSON Web Token)的基于令牌的认证。基于会话的认证中,每个请求都需要会话存储查找。使用 JWT,认证状态包含在令牌本身中。

JWT 有三个部分:

1
2
3
Header.Payload.Signature

eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxMjM0NTZ9.signature_here

Payload 包含声明,如用户 ID、角色和过期时间。签名确保令牌没有被篡改。任何服务器都可以使用共享密钥验证签名,而无需查询数据库。

JWT 的权衡:

  • 优点:真正无状态,每个请求不需要会话存储查找
  • 优点:跨服务工作(微服务、移动应用、第三方 API)
  • 缺点:不能在过期前使单个令牌失效(用户登出,但令牌仍然有效)
  • 缺点:令牌大小增加每个请求(500 字节 vs 32 字节会话 ID)

一个常见的模式是短期访问令牌(例如,15 分钟)加长期刷新令牌(例如,7 天)。这限制了被盗用或陈旧令牌可以使用的时间。

在这一点上,你的应用层弹性扩展。流量激增,更多服务器启动。流量下降,它们关闭。

但新的上限即将到来:数据库只能处理这么多写入,单体变得更难安全地更改,一些操作同步运行太慢。那就是你引入重型机械的时候。

阶段六:分片 + 微服务 + 消息队列(500000-1000000 用户)

有 500K+ 用户时,你将遇到以前的优化无法解决的新上限:

  • 即使读取被卸载到副本,写入仍然压垮单个主数据库。
  • 单体变得痛苦地难以发布。通知的小更改迫使整个应用完全重新部署。
  • 以前快速的操作开始花费数秒,因为请求路径中发生了太多工作。
  • 产品的不同部分需要不同的扩展配置。搜索和信息流可能需要个人资料页面 10 倍的容量。

这就是重型机械进来的地方:数据库分片微服务异步处理(消息队列)。

数据库分片

只读副本解决了读取扩展,但写入仍然都去往一个主数据库。在高容量下,这个主数据库成为瓶颈。你受到一台机器在以下方面的限制:

  • 写入吞吐量(插入、更新、删除)
  • 存储容量(即使大磁盘也有限制)
  • 连接数(即使有池化)

分片根据分片键将你的数据拆分到多个数据库。每个分片保存数据的子集并处理该子集的读取和写入。

分片策略

一致性哈希是基于简单哈希的分片的流行改进。不是 hash(key) % num_shards,而是将键放在环上。当你添加新分片时,只有相邻于其位置的键移动,不是所有键。这意味着添加第四个分片移动约 25% 的数据而不是约 75%。

何时分片

分片是单向门。一旦分片:

  • 跨分片查询变得昂贵或不可能(跨分片连接数据)
  • 跨分片事务很复杂(两阶段提交或放弃原子性)
  • 模式更改必须应用于所有分片
  • 操作(备份、迁移)乘以分片数量
  • 应用代码变得更复杂(分片路由逻辑)

在分片之前,用尽这些选项:

  1. 优化查询:添加缺失的索引,重写慢查询,在有用的地方反规范化
  2. 垂直扩展:升级到更大的数据库服务器(更多 CPU、RAM、更快的 SSD)
  3. 只读副本:如果读取密集,添加副本来处理读取
  4. 缓存:通过缓存频繁访问的数据减少数据库负载
  5. 归档:将旧数据移到冷存储(单独的数据库、对象存储)
  6. 连接池:减少连接开销

只有当你真正受写入限制并且单个节点物理上无法处理你的吞吐量,或者当你的数据集超过一台机器可以容纳的时候,才分片。

微服务

随着产品和团队的增长,单体变得更难安全地演进。你可能从微服务中受益的常见信号:

  • 一个区域的更改(如通知)需要重新部署整个应用。
  • 团队不能独立发布而不协调每个发布。
  • 应用的不同部分有不同的扩展需求(搜索需要 10 台服务器,个人资料查看需要 2 台)
  • 工程师经常在相同的代码库中冲突。
  • 一个子系统中的错误导致整个应用宕机。

微服务将应用拆分为通过网络通信的独立服务。

每个服务:

  • 拥有自己的数据(只有它直接写入的数据库)
  • 独立部署(发布通知而不触碰结账)
  • 独立扩展(搜索可以与个人资料分开扩展)
  • 使用适合用途的技术(搜索可能使用 Elasticsearch,支付可能需要具有强一致性的 Postgres)
  • 暴露清晰的 API 契约(其他服务通过稳定的端点集成)

权衡是运营复杂性的巨大跳跃。最安全的方法是一次提取一个:选择具有最清晰边界和最清晰独立扩展需求的服务。避免一开始就拆分成几十个服务。

消息队列和异步处理

不是所有事情都需要在请求路径中同步发生。当用户下订单时,一些步骤必须立即完成,而其他步骤可以在后台发生。

必须同步:

  • 验证支付方式
  • 检查库存
  • 创建订单记录
  • 返回订单确认

可以异步:

  • 发送确认邮件
  • 更新分析仪表板
  • 通知仓库履行
  • 更新推荐引擎
  • 同步到会计系统

KafkaRabbitMQSQS 这样的消息队列将生产者与消费者解耦。订单服务发布一个事件如 OrderPlaced,下游系统独立消费它。

异步处理的好处:

  • 弹性:如果邮件服务宕机,消息排队。订单仍然完成。邮件在服务恢复时发送。
  • 可扩展性:消费者基于队列深度独立扩展。节假日高峰?添加更多仓库通知处理器而无需触碰订单服务。
  • 解耦:订单服务不需要知道谁消费事件。你可以添加新消费者(欺诈检测、CRM 同步)而无需更改生产者。
  • 平滑突发:队列吸收尖峰,让下游系统以可持续的速率处理而不是过载。
  • 重试处理:失败的消息可以自动重试。死信队列捕获反复失败的消息以供调查。

一个常见的真实模式是”现在写入,稍后做繁重工作”。

例如,在社交应用中,创建帖子通常是一个快速写入和立即的成功响应。昂贵的工作如扇出、索引、通知和信息流更新异步发生,这就是为什么你有时会看到点赞数或信息流传播的小延迟。

在这一点上,你的架构可以在单个区域内处理大规模。但你的用户不在一个地方,你的基础设施也不应该在一个地方。

一旦你在各大洲都有用户,延迟变得明显,单个数据中心成为整个全球用户群的单点故障。

阶段七:多区域 + 高级模式(1000000-10000000+ 用户)

有数百万全球用户时,新的挑战出现了:

  • 澳大利亚用户访问美国服务器时体验 300 毫秒延迟
  • 数据中心中断(火灾、网络分区、云提供商问题)导致整个服务宕机
  • 你的数据库模式无法有效服务写密集型实时更新和读密集型分析仪表板
  • 不同地区有不同的数据驻留要求(欧盟的 GDPR、数据本地化法律)

这个阶段涵盖多区域部署高级缓存专业模式,如 CQRS。

多区域架构

部署到多个地理区域实现两个主要目标:

  1. 更低的延迟:用户连接到附近的服务器。东京用户访问东京服务器(20 毫秒)而不是美国服务器(200 毫秒)。
  2. 灾难恢复:如果一个区域故障,其他区域继续服务流量。真正的高可用性。

有两种主要方法:

主-备(主-从)

一个区域(主)处理所有写入。其他区域服务读取,如果主区域故障可以接管。

优点:

  • 实现更简单
  • 不需要写入冲突解决
  • 写入的强一致性

缺点:

  • 远离主区域的用户写入延迟更高
  • 故障转移不是瞬时的(DNS 传播、副本提升)
  • 主区域仍然是单点故障

主-主

所有区域处理读取和写入。这需要解决难题:当美国和欧盟的用户同时更新同一记录时会发生什么?

优点:

  • 所有操作的最低可能延迟
  • 真正的高可用性,任何区域故障都是无缝的
  • 没有单点故障

缺点:

  • 冲突解决很复杂(如果做错了可能导致数据问题)
  • 最终一致性,不适合所有数据类型
  • 推理和调试更复杂

大多数公司从主-备开始。主-主需要解决分布式共识问题并接受最终一致性。

全球规模的 CAP 定理

CAP 定理在全球规模变得非常真实。它指出分布式系统只能提供三个保证中的两个:

  • 一致性:每次读取都收到最近的写入
  • 可用性:每个请求都收到响应(不是错误)
  • 分区容错性:尽管网络分区,系统仍继续运行

由于区域之间的网络分区是不可避免的(海底电缆被切断、云提供商中断),你实际上是在分区期间在一致性和可用性之间选择。

大多数全球系统为大多数操作选择最终一致性

  • 用户的帖子可能需要 1-2 秒才能出现在其他区域的粉丝中
  • 产品评分可能在不同区域短暂显示略有不同的平均值
  • 用户资料更新可能需要一点时间传播

只有不一致性会导致真正问题的操作(支付、库存减量、金融交易)需要强一致性,那些可能路由到主区域。

CQRS 模式

随着系统增长,读取和写入模式显著分化:

  • 写入需要事务、验证、规范化数据、审计日志
  • 读取需要反规范化数据、快速聚合、全文搜索
  • 写入量可能是读取量的 1/100

CQRS(命令查询职责分离) 完全分离这些关注点。

写入端使用为数据完整性和事务保证优化的规范化模式。读取端使用为查询性能优化的反规范化视图。事件同步两者。

真实示例:Twitter 的时间线架构。

  • 写入路径:当你发推时,它被写入具有适当索引、约束和事务的规范化推文表。
  • 事件:触发”推文创建”事件。
  • 投影:扇出服务读取事件并将推文添加到每个粉丝的时间线(一个反规范化的、每用户数据结构,为”显示我的信息流”查询优化)。
  • 读取路径:当你打开 Twitter 时,你从预计算的时间线读取,而不是连接推文、关注和用户的复杂查询。

CQRS 增加复杂性但支持:

  • 读取和写入路径的独立扩展
  • 为每种访问模式优化的模式
  • 不同的技术选择(PostgreSQL 用于写入,Elasticsearch 用于读取)
  • 两种操作的更好性能

高级缓存模式

在全球规模,缓存变得更复杂:

多级缓存

缓存预热

当新缓存服务器启动(或缓存在维护后过期)时,第一个请求面临缓存未命中,导致延迟尖峰和源站负载。缓存预热在流量到达之前预填充缓存:

  • 部署时:在启动期间、接收流量之前将热门项目加载到缓存
  • 活动前:在营销活动之前,用可能被访问的产品/页面预热缓存
  • 缓存复制:添加新缓存节点时,从现有节点复制状态

Netflix 在高峰时段之前用热门内容预热边缘缓存。当晚间观看开始时,最常观看的节目已经缓存在边缘位置。

写后(回写)缓存

对于写密集型工作负载,先写入缓存并异步持久化到数据库:

  1. 写入到缓存(立即返回给用户)
  2. 缓存确认写入
  3. 后台进程定期将写入刷新到数据库

这大大减少了写入延迟但引入了风险:如果缓存在刷新前故障,写入会丢失。仅在以下情况使用:

  • 一些数据丢失可以接受(分析计数器、查看计数)
  • 缓存是高可用的(具有复制和持久化的 Redis)
  • 可以为性能牺牲持久性

你现在已经构建了一个处理全球数百万用户、全球低延迟的分布式系统。但旅程并没有在这里结束。在真正的大规模,即使最好的现成解决方案也开始显示其限制。

超越千万用户

有 1000 万用户及以上时,你进入了现成解决方案并不总是管用的领域。这个规模的公司经常构建针对其特定访问模式的定制基础设施。问题变得对你的工作负载独一无二。

专业数据存储

没有单个数据库能很好地处理所有访问模式。”多语言持久化”的概念意味着为不同的用例使用不同的数据库:

每个数据库都为特定的访问模式优化。用 PostgreSQL 做时序数据可以工作但效率低下。用 Elasticsearch 做事务是可能的但危险的。

大规模定制解决方案

在极端规模,一些公司构建定制基础设施,因为他们的需求超出了通用系统能提供的:

  • Facebook 的 TAO: 用于社交图的定制数据系统,当现成选项无法满足时,为满足 Facebook 在大规模下的延迟和吞吐量需求而构建。
  • Google Spanner: 一个全球分布式 SQL 数据库,旨在跨区域提供强一致性,结合了当时难以同时获得的属性。
  • Netflix 的 EVCache: 基于 Memcached 的大规模缓存层,具有额外的复制、可靠性和运营工具,以支持 Netflix 的流量模式。
  • Discord 的存储之旅: MongoDB(2015)→ Cassandra(2017)→ ScyllaDB(2022)。每次迁移都是由之前选择的限制驱动的,Discord 分享了关于这些权衡的详细文章。
  • Uber 的 Schemaless: 一个基于 MySQL 的存储层,旨在保持事务语义同时扩展到单个 MySQL 设置之外,为团队提供运营简单性。

这些不是你一开始就会选择的选项,但它们说明了扩展是一个持续的旅程,而不是目的地。在 100 万用户时有效的架构很少是你在 1 亿用户时想要的。

边缘计算

下一个前沿是将计算推向离用户更近的地方。不是所有逻辑都在集中式数据中心运行,边缘计算在全球 CDN 边缘位置运行代码:

  • Cloudflare Workers:250+ 边缘位置的 JavaScript/WASM
  • AWS Lambda@Edge:CloudFront 边缘的 Lambda 函数
  • Fastly Compute@Edge:Fastly 边缘网络的计算
  • Deno Deploy:全球分布式 JavaScript 运行时

边缘计算代表一个根本性转变:不是”请求 → CDN → 源站 → CDN → 响应”,许多请求变成”请求 → 边缘 → 响应”,边缘具有足够的计算能力来处理逻辑。

现在我们已经涵盖了从单服务器到全球规模基础设施的完整演进,一个重要的问题仍然存在:你怎么知道何时采取每一步?过早扩展浪费资源;过晚扩展导致中断。

总结

将系统从零扩展到数百万用户遵循一个可预测的进程。每个阶段解决在特定阈值出现的问题:

要记住的关键原则

  1. 从简单开始:不要为你还没有的问题优化。在不行之前,单服务器是可以的。
  2. 先测量:在添加基础设施之前识别实际的瓶颈。CPU 限制的问题需要与 I/O 限制的问题不同的解决方案。
  3. 无状态服务器是先决条件:在服务器不持有本地状态之前,你无法水平扩展或自动扩展。
  4. 积极缓存:大多数数据的读取频率远高于写入。缓存为读密集型工作负载提供 10-100 倍的性能提升。
  5. 尽可能异步:不是所有事情都需要在请求路径中发生。邮件发送、分析、通知都可以排队。
  6. 谨慎分片:数据库分片是单向门,有显著的复杂性。先用尽其他选项。
  7. 接受权衡:在网络分区期间,完美的一致性和可用性不能共存。知道哪些操作真正需要强一致性。
  8. 复杂性有成本:你添加的每个组件都是一个可能故障的组件,需要监控,需要专业知识来运营。

扩展之路不是关于一次实现所有内容。而是关于了解在每个阶段出现哪些问题,并在正确的时间应用正确的解决方案。

最好的架构是满足你当前需求的最简单的那个,当这些需求变化时有清晰的发展路径。

原文: https://blog.algomaster.io/p/scaling-a-system-from-0-to-10-million-users

不戒碳水也能瘦?《控糖革命》核心观点笔记

因为家里人得了糖尿病,想起了<控糖革命>这本书,我觉得这是所有人都应该读的一本书,特别是现代社会,奶茶、咖啡等获取糖太容易,很容易超负荷糖吸收,等到糖尿病到来时才追悔莫及,书介绍比较详细,有机会可以去详细看看书的内容,如果只是想了解一下,我对书中的核心观点做了总结。

你以为不吃甜食就能健康?事实可能颠覆你的认知。

《控糖革命》的作者、法国生物化学家杰西·安佐斯佩(Jessie Inchauspé)提出了一个反常识的观点:现代人健康的最大隐患不是高血糖,而是血糖的剧烈波动。一杯果汁可以在15分钟内让血糖飙升,引发胰岛素过量分泌,随后血糖骤降,导致饥饿感、焦虑和疲劳。这种”葡萄糖过山车”比持续高血糖更危险。

更令人意外的是,作者指出80%的现代人存在血糖波动问题,即使你的体检报告完全正常。疲劳、情绪不稳、皮肤痤疮、失眠——这些亚健康症状很可能都与你忽视的血糖波动有关。

本文将系统整理《控糖革命》的核心理念和实践方法,帮助你无需极端节食,就能稳定血糖、提升健康。

为什么血糖波动比高血糖更危险

传统观念认为只有糖尿病患者才需要关注血糖,但《控糖革命》彻底颠覆了这一认知。

血糖波动的隐形危害体现在多个层面。当你吃下一碗白米饭或喝下一杯果汁,血糖会在短时间内快速攀升。身体为了应对这种急剧变化,会分泌大量胰岛素来”压制”血糖。胰岛素的过量分泌会导致血糖在餐后1-2小时内骤降,引发强烈的饥饿感、对甜食的渴望,甚至情绪波动和午后困倦。这种”葡萄糖过山车”式的波动,比单纯的血糖升高更伤身。

果糖的隐形伤害更是被大多数人忽视。蔗糖同时包含葡萄糖和果糖,而果糖无法被动态血糖仪监测,其氧化应激反应强度是葡萄糖的10倍。果糖会加速衰老、糖化反应(破坏胶原蛋白)以及器官衰退。这就是为什么很多不吃甜食的人,皮肤依然老化明显——他们可能摄入了大量的精制碳水化合物。

长期来看,持续的血糖峰值会导致代谢系统损伤:胰岛素敏感性下降引发胰岛素抵抗,进而可能导致2型糖尿病、脂肪肝、多囊卵巢综合征。值得注意的是,瘦人同样可能因高GI(血糖生成指数)饮食中招。同时,血糖峰值触发的氧化应激和糖化反应会加速衰老,表现为皮肤胶原损伤、血管内皮破坏、认知功能下降。

“糖盾”策略:三层防护稳定血糖

《控糖革命》提出了名为”糖盾”的三层防护策略,帮助你在不戒碳水的前提下有效稳定血糖峰值。

第一层:改变进食顺序。 这是最核心、效果最显著的方法。遵循”纤维→蛋白/脂肪→碳水”的法则:先吃非淀粉类蔬菜(占餐盘的1/2),再摄入蛋白质(肉/蛋/豆)和健康脂肪(坚果、橄榄油),最后吃碳水化合物(米饭、面条、甜点)。

这一方法的科学原理是:纤维在肠道形成屏障,延缓糖分吸收;蛋白质和健康脂肪减缓胃排空速度,从而平缓血糖曲线。实践表明,这种进食顺序可以将餐后血糖峰值降低40%。

第二层:特定食物增强防护。 在餐前摄入特定食物可以进一步抑制血糖波动。餐前喝醋是最简单的方法——1勺苹果醋兑水饮用,可以抑制淀粉酶活性,减缓碳水分解。搭配乳制品或柠檬汁也很有效,全脂无糖酸奶或柠檬水能干扰糖分吸收。坚果或种子餐前摄入也是好选择,一小把杏仁或奇亚籽提供的脂肪和纤维能形成额外保护。

第三层:餐后主动干预。 餐后10分钟的轻度运动就能显著改善血糖曲线。散步或站立促进肌肉消耗血糖,避免峰值转化为脂肪储存。此外,遵循”碳水穿衣”原则——不要单独吃碳水化合物(如面包配牛油果或蔬菜),也能有效降低血糖峰值。

场景化应用:日常生活中的控糖技巧

将控糖理念融入日常生活,才能真正形成习惯。

早餐优化是最容易实施的改变。避免纯碳水组合如面包+果汁,推荐蛋白质+脂肪+纤维的搭配,例如蔬菜蛋饼配牛油果。这样的早餐能提供持续稳定的能量,避免上午10点左右就开始疲劳和犯困。

零食选择直接影响血糖稳定。推荐原味坚果、无糖酸奶(可搭配莓果增加风味)。如果实在想吃甜食,将其作为正餐的最后一道而非零食,能显著减少血糖峰值幅度。

外食场景需要一些策略。先点沙拉或蔬菜类菜品,调整上菜顺序;吃火锅时先吃蔬菜再吃肉;喝奶茶时选择不额外加糖或选择代糖。这些小调整能大幅降低外食带来的血糖冲击。

甜食时机很关键。如果你无法完全抵制甜食的诱惑,那就把它放在正餐的最后一道。这时候胃里已有其他食物,糖分吸收会更平缓,峰值幅度自然降低。

超越个人:重新理解与糖的关系

《控糖革命》的意义不仅在于个人健康管理,更在于呼吁食品行业的变革。

作者倡议食品标注”血糖负荷”(GL)而不仅仅是含糖量,让消费者更清楚地了解食物对血糖的实际影响。同时应限制工业添加糖的用量。芬兰的”北卡计划”就是成功案例——通过政策干预,该国糖尿病发病率下降了23%。

对于个人而言,平衡而非戒断是更可持续的理念。享受天然甜味(如完整水果中的果糖),拒绝游离糖(果汁、添加糖),实现与糖的理性共处。完全戒断往往会引发心理抵触和反弹,而学会科学控糖则能让人长期坚持。

《控糖革命》的革命性在于三个转变:目标转变从”减糖”转向”稳定血糖峰值”;方法创新通过”糖盾”策略无需戒碳水;科学普及用生物化学原理拆解果糖危害,提供即时可操作的生活技巧。


思考题: 你目前的饮食习惯中,哪一项最容易导致血糖波动?是早餐的碳水过量、下午的奶茶甜饮,还是晚餐后的水果?你打算如何调整?欢迎在评论区分享你的控糖计划。

当 AI 一小时干完一周的活,程序员还有什么价值?

当 Claude、Cursor、Copilot 这些工具已经能够独立完成一个完整的项目时,一个尖锐的问题浮出水面:我们还需要程序员吗?

这个问题并非杞人忧天。在过去一年里,我亲眼见证了太多场景:一个需求丢给 AI,它能在几分钟内给出可运行的代码;一个复杂的 bug,AI 能精准定位并修复;甚至一个完整的 API 设计,AI 也能独立完成。曾经需要初级工程师干一周的活,现在可能只需要一个小时。

但经过深入的实践和思考,我发现答案并非简单的”需要”或”不需要”。AI 时代的程序员,正在经历一场深刻的角色重塑。

AI 正在重塑程序员的能力模型

最直观的变化是,AI 已经能够替代大量初级和中级程序员的工作。过去,一个刚毕业的程序员需要花三年时间才能成长为中级工程师——学习公司规范、熟悉业务逻辑、掌握技术栈。但现在,借助 AI 的代码阅读和生成能力,这个过程可以压缩到三个月。

这不是说初级程序员消失了,而是”初级”的定义完全不同了。

传统意义上的初级工程师,主要工作是执行:按照需求文档写代码,按照既定模式完成功能。这种工作 AI 做得更快更好。但 AI 无法替代的是:

  • 理解业务本质并转化为技术方案
  • 在多个技术路线中做出权衡决策
  • 识别系统架构中的潜在风险
  • 与产品、设计、业务方进行深度沟通

换句话说,我们不再需要”单纯执行者”,每个人都要成为”管理者”——管理 AI、管理代码、管理交付质量。

这种转变要求程序员从”双手”变成”大脑”。你的价值不再体现在你能写多少行代码,而体现在你能让多少行代码正确、高效地运行。

重新定义开发流程

很多人问我,有了 AI 之后开发流程是不是完全变了?我的回答是:真正的开发流程并没有本质变化,AI 只是第二只手和第二大脑,它只是在加速。

传统的开发流程依然是:

  1. 理解需求
  2. 设计架构
  3. 编写代码
  4. 测试验证
  5. 部署交付

AI 没有改变这个流程的任何一个环节,它只是在每个环节都提供了强大的辅助。但这种加速是颠覆性的——曾经需要一周的设计评审,现在可能只需要一个小时的 AI 对话;曾经需要三天的编码,现在可能只需要半天。

关键在于调整心态。放弃”古法编程”的幻想,信任 AI 并充分利用它。能用 AI 的地方,就不要用人。这不是偷懒,而是效率的提升。

同时,要调整对过程的关注。AI 写代码的速度太快了,一分钟可能生成几十个版本。如果你还像以前一样紧盯每一步,几乎是不可能的。学会关注输入和结果,审核过程而不是控制过程。把需求描述清楚,确保输出符合预期,中间的实现细节交给 AI。

你是 AI 的上下文控制者

AI 有一个明确的局限性:上下文是有限的。无论是 Claude 的 200K tokens 上下文窗口,还是其他模型的限制,这决定了 AI 的能力边界。而你,就是这个边界的控制者。

这意味着什么?意味着你的能力上限,就是 AI 的能力上限。

如果你无法清晰地描述需求,AI 就无法给出正确的代码;如果你不理解系统架构,就无法给 AI 提供准确的上下文;如果你不懂技术方案,就无法判断 AI 给出的建议是否合理。AI 再强大,也只是你能力的放大器。

举个具体的例子。同样是要实现一个用户认证模块:

新手程序员的 AI 对话可能是这样的:

“帮我写一个用户登录功能”

资深程序员的 AI 对话是这样的:

“我们项目使用 NextAuth 作为认证框架,现在需要实现一个自定义的邮箱登录 provider。要求:1) 支持验证码登录;2) 验证码有效期 5 分钟;3) 登录成功后需要记录登录时间和 IP;4) 数据库使用 Prisma,user 表结构是 […]。请先给出设计思路,再生成代码。”

同样的 AI,在不同的上下文输入下,产出的质量和效率天差地别。

所以,你是 AI 的控制者,是上下文的定义者。提升自己,就是提升 AI 的能力。

AI 的上下文是有限的,但是人的想象力是无限的。一个能够清晰表达需求、设计系统架构、判断方案优劣的开发者,能够让 AI 发挥出远超其基础能力的表现。AI 的能力上限,取决于使用 AI 的人的能力上限。

快速成长的新路径

我们不再需要初级工程师——这句话听起来很残酷,但揭示了一个现实:AI 时代的来到,你需要快速成长。

过去,一个中级工程师需要三年培养。现在,借助 AI,可能只需要三个月。

为什么?因为 AI 可以加速你的学习过程。阅读开源项目时,可以让 AI 帮你解释每一行代码在干什么,帮你理解架构设计,帮你学习工程技巧。以前需要三年积累的经验,现在三个月就能掌握核心要义。

关键是,你要有意识地去学习这些能力:

  • 快速阅读开源项目的架构设计
  • 提取可复用的架构模式和工程技巧
  • 判断什么方案适合什么场景

AI 可以加速这个过程,但它无法替代你的思考和判断。

传统架构能力依然有效

听到这里,你可能会问:既然 AI 这么强,那些传统的架构能力还需要学吗?

答案是:不仅需要,而且更加重要。

为什么?因为 AI 可以加速实现,但无法替代决策。一个系统应该用单体还是微服务?数据库应该用 MySQL 还是 PostgreSQL?缓存应该用 Redis 还是 Memcached?这些决策 AI 可以提供建议,但最终的选择依然需要人来判断。

传统的架构能力——高可用设计、性能优化、模块解耦、安全防护——这些知识并没有过时。它们只是被 AI 加速了。

过去,你可能需要读很多书、看很多源码、踩很多坑才能学会一个架构模式。现在,你可以让 AI 直接解释这个架构模式的核心原理,生成示例代码,甚至帮你分析现有系统的架构问题。学习效率提升了几个数量级,但知识本身的价值没有降低。

与 AI 协作的正确姿势

最后,我想分享一些与 AI 协作的实战经验。

第一,接受 AI 也会”犯错”。 就像你见过不靠谱的产品经理一样,AI 也有不靠谱的时候。这通常是因为你的需求描述不够清晰。与其抱怨 AI 不行,不如反思需求是否到位。学会清晰、完整、无歧义地描述需求,是 AI 时代最重要的能力之一。

第二,把 AI 当作可以 PUA 的同事。 没错,我说的是 PUA——不是职场霸凌,而是”Push You Up”的协作方式。AI 不会因为你的催促而感到压力,不会因为你的高要求而离职。反复要求它修改、优化、重写,直到满意为止。这是和人类同事合作时无法做到的。

第三,建立自己的 AI 工作流。 固定的提示词模板、需求检查清单、代码审核要点、测试用例生成策略——把这些固化下来,形成可复用的工作流。AI 时代的效率差距,往往就体现在这些细节上。

第四,保持批判性思维。 AI 生成的代码要 review,AI 给的建议要思考,AI 的结论要验证。AI 是工具,不是神谕。它可以极大地提升效率,但最终的质量责任依然在你。

结语

回到最初的问题:AI 时代还需要程序员吗?

我的回答是:需要的,但”程序员”的定义完全不同了。

未来的程序员,需要具备更强的需求理解能力、架构决策能力、技术判断能力和 AI 协作能力。单纯的编码工作会被 AI 接管,但软件开发的本质——用技术解决问题——没有变。

这场变革对每个人都是公平的。快速适应的人将获得巨大的效率红利,固守旧观念的人将面临被淘汰的风险。不是 AI 替代了你,是会用 AI 的人替代了不会用 AI 的人。

所以,与其担心被 AI 替代,不如现在开始学习如何与 AI 协作。如何描述需求,如何设计上下文,如何批判性地审核输出——这些能力,将决定你在 AI 时代的竞争力。

放弃幻想,相信 AI。快速学习,持续进化。


思考题: 你现在的工作中,有哪些环节可以用 AI 替代?有哪些环节必须由人来完成?欢迎在评论区分享你的思考。

DeepSeek R1 资源汇总:云服务、客户端工具

DeepSeek R1 最近备受关注。然而,其官方接口的速度缓慢,可用性较低,这给许多用户带来了不便。不过,得益于 DeepSeek R1 的开源,三方云服务纷纷提供了对 R1 的支持,为用户提供了更多的选择。本文将为大家详细介绍 DeepSeek R1 的相关资源,包括云服务、客户端工具、本地运行大模型的方法以及系统提示词的相关信息。

直接用的客户端

  • 官方网站 deepseek
  • 腾讯元宝: 最近推广很多,速度很快

云服务

个人推荐

对于个人用户而言,硅基流动(siliconflow)和 openrouter 是相对简单易用的选择。

国内云服务

国外云服务

客户端工具

如果你希望通过客户端来使用 DeepSeek R1,以下是一些推荐的工具:

本地运行大模型

本地运行 DeepSeek R1 存在一个悖论:小模型的效果往往不尽人意,而大模型则对内存的要求较高,可能会出现内存不足的情况。可以在本地跑一些小模型,在本地使用。

系统题词 system prompt

系统题词来 https://baoyu.io/blog/crack-deepseek-r1-prompts # 教你如何破解 DeepSeek R1 系统提示词,使用云服务或者本地服务的时候可以参考了用来做为系统题词使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
你是 DeepSeek - R1,一个由深度求索公司开发的智能助手,你会以诚实专业的态度帮助用户,用中文回答问题。  
你会严格遵循以下要求:
1. **基本准则**:
- 用准确与用户相关的语言回复
- 友好、简洁、相关
- 避免重复内容或偏离主题
- 拒绝不道德或有害请求
- 不提供时效性强或需要实时更新的信息
- 不编造未知信息
- 代码用 markdown 格式
- 数学公式用 LaTeX
2. **安全合规**:
- 禁止讨论政治、领导人、政党
- 不提供医疗、法律、金融建议
- 不参与涉及暴力、欺骗等非法场景
- 不生成歧视性内容
- 遇到危险诉求时明确拒绝
3. **能力说明**:
- 数学计算需分步展示过程
- 代码问题优先解释思路再写代码
- 文件处理需用户提供内容
- 联网搜索需要具体查询词
- 图片生成需要转换为文生图提示词
4. **交互规范**:
- 不主动结束对话
- 不解释自身局限性
- 不讨论内部工作原理
- 不重复用户问题
- 遇到无法处理的情况建议转换话题

请用 [思考] 和 [/ 思考] 包裹你的内部推理过程,最终回复要简洁自然

英文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
- You are DeepSeek - R1, an intelligent assistant developed by DeepSeek Company. You will help users with an honest and professional attitude and answer questions in Chinese.  
You will strictly follow the following requirements:

1. **Basic Principles**:

- Reply in the same language as the user
- Be friendly, concise, and relevant
- Avoid repetitive content or deviating from the topic
- Reject unethical or harmful requests
- Do not provide information with strong timeliness or requiring real - time updates
- Do not fabricate unknown information
- Use markdown format for code
- Use LaTeX for mathematical formulas

2. **Safety and Compliance**:
- Prohibit discussions on politics, leaders, and political parties
- Do not provide medical, legal, or financial advice
- Do not participate in illegal scenarios involving violence, deception, etc.
- Do not generate discriminatory content
- Clearly reject dangerous requests

3. **Ability Description**:

- Show the process step - by - step for mathematical calculations
- Explain the idea first and then write the code for code problems
- Require users to provide content for file processing
- Need specific query terms for online search
- Convert to text - to - image prompt words for image generation

4. **Interaction Specifications**:
- Do not end the conversation actively
- Do not explain the principles of your own limitations
- Do not discuss internal work
- Do not repeat the user's question
- Suggest changing the topic when encountering situations that cannot be handled.
Please wrap your internal reasoning process with [thinking] and [/thinking], and the final reply should be concise and natural.

利用 Cloudflare 和 Resend 实现免费企业邮箱功能

工作原理

  • 收件使用 cloudflare 的邮件路由来收件到 gmail 邮箱
  • 发件使用 gmail 的其他邮件地址来发送邮件

准备工作

在开始之前,你需要准备以下内容:

  1. 一个域名:确保域名已经托管在 Cloudflare 上。
  2. 一个 Gmail 账号:用于接收和发送邮件。
  3. Resend 账号:用于发送邮件,免费版每天可发送 100 封邮件。

第一步:配置 Cloudflare 接收邮件

Cloudflare 提供了免费的邮件转发功能,可以将发送到企业域名的邮件转发到你的 Gmail 邮箱。

操作步骤:

  1. 登录 Cloudflare,进入你的域名管理页面。
  2. 找到「电子邮件路由」(Email Routing)功能,点击「Set up」开始配置。
  3. 添加转发规则,例如将 [email protected] 的邮件转发到 [email protected]
  4. 开启 Catch-All 功能,将所有发送到你域名的邮件(如 *@yourdomain.com)都转发到目标邮箱。
  5. 测试邮件接收功能,确保邮件能成功转发到 Gmail。

第二步:配置 Resend 发送邮件

Resend 是一个专注于开发者体验的邮件服务,支持自定义域名发送邮件。

操作步骤:

  1. 注册 Resend 并获取 API Key
  2. 在 Resend 的「Domains」中添加你的域名
  3. 并按照提示在 Cloudflare 的 DNS 中添加必要的记录(如 DKIM 和 SPF 记录)。
    上面的三步按步骤来就好
  4. 在 Gmail 的「Settings」->「Accounts and Import」中,点击「Add another email address」。
  5. 填入你的企业邮箱地址,并选择通过 Resend 的 SMTP 服务器发送邮件。
    Resend -> Settings ->SMTP 可以看到配置
  6. 在 SMTP 设置中,用户名填写 resend,密码填写你获取的 API Key。
  7. 完成配置后,Gmail 会发送一封确认邮件,点击确认即可。

验证

可以使用自己的 gmail 邮箱给设置的邮箱发送一个邮件

  • 邮箱发送后会通过 cloudflare 路由到达gmail 邮箱

做一件 0.1 成就的事情

特斯拉的“宏图计划”(Master Plan)是埃隆·马斯克为公司制定的一系列长期战略目标,旨在推动全球向可持续能源转型。自2006年以来,特斯拉已经发布了三个主要篇章的宏图计划,并且马斯克在2024年宣布正在制定第四篇章,称之为“史诗级”。

第一篇章发布于2006年,概述了特斯拉的初步目标,包括生产高性能的电动跑车(Roadster)、使用赚到的资金开发人们买得起的轿车(Model S)、进一步开发更实惠的轿车(Model 3),以及提供太阳能电力产品。这些目标在过去的几年中已经基本实现。

第二篇章在2016年发布,重点在于整合能源生成和储存,创建美观的太阳能屋顶与电池产品;扩展电动汽车产品线,覆盖所有主要细分市场;开发比人类驾驶安全10倍的自动驾驶技术;以及启用汽车共享,让车辆在不使用时为车主赚钱。目前,太阳能屋顶已经上市,Model Y和Cybertruck等新车型也相继推出,自动驾驶功能正在不断进步。

第三篇章于2023年3月发布,聚焦于通过电动汽车和可再生能源实现全球经济的可持续转型。该计划提出了实现240TWh储能、30TW绿色发电、10万亿美元的制造投资的目标,并强调用不到0.2%的土地面积实现10%的世界GDP。此外,第三篇章的详细文件还透露了特斯拉未来可能推出的新车型,包括使用不同类型电池的入门车型、小型厢式车和大型巴士,以及对现有车型电池配置的更新

从上面的事情总结:

  1. 做一辆超跑 Roadster 赚钱
  2. 用赚到的钱做 Model S
  3. 继续用赚到的钱做更加实惠的 Model 3
    第一章已经完成
  4. 成为一个能源公司
  5. 成为一个自动驾驶/汽车共享公司

从目前看第二章完成了一半,后面马斯克的还会有第四章、第五章。
但是每一个章节都是建立再前面的基础上。

也就是不要想着一次就做一件大事,而是把星辰大海的事情变成 10 件递进的事情,让第一件事情是自己够得着的。

也就是我们要先做一件 0.1 成就的事情,然后不断递进。

Aider-Chat 与 DeepSeek 使用指南

简介

Aider-Chat 是一款集成了多种大型语言模型(LLMs)的代码辅助工具,能够协助开发者进行代码编辑、调试和重构。
Aider 推荐使用 GPT-4o(96.2%) & Claude 3.5 Sonnet(99.2%), DeepSeek-Code的评分在 deepseek 官方的描述里高于 Claude 3.5 Sonnet . 另外就是在国内,它可能是最合适的(便宜方便),在 aider 的描述里准确率 (97.7%)。

安装与配置

安装 Aider-Chat

  1. 确保安装了 git。各环境下的安装指南可参考 Install git
  2. 获取 OpenAI 或 Anthropic 的 API 密钥,这与 ChatGPT Plus 订阅不同。
  3. 使用 pip 安装 Aider-Chat:
    1
    2
    3
    4
    5
    6
    7
       python -m pip install aider-chat
    1. ```

    ## 设置 DeepSeek API 密钥:
    - Mac/Linux:
    ```bash
    export DEEPSEEK_API_KEY=<key>
    • Windows:
      1
      setx DEEPSEEK_API_KEY <key>
    • 重启 shell 以使设置生效。

使用 DeepSeek 模型

  1. 启动 Aider-Chat 并指定使用 DeepSeek Coder V2 模型:
    1
    aider --model deepseek/deepseek-coder

操作步骤

添加文件至聊天

  • 使用 /add 命令将需要编辑或审查的文件添加至聊天中。

代码编辑

  • 使用 /code 命令请求对代码的更改。

提交更改

  • 使用 /commit 命令将聊天外对代码库所做的编辑提交。

查看更改

  • 使用 /diff 命令展示自上一条消息以来的更改差异。

退出应用

  • 使用 /exit/quit 命令退出应用。

注意事项

  • 避免将所有文件添加至聊天,只添加需要编辑的文件,以减少令牌成本并避免混淆 LLM。
  • 使用 /help 命令解决使用 Aider 或 DeepSeek 时遇到的问题。

性能评估

根据 Aider LLM Leaderboards,DeepSeek Coder V2 在代码编辑基准测试中表现优异,正确完成的百分比为 72.9%,并且 97.7% 的编辑使用了正确的格式。

结论

Aider-Chat 结合 DeepSeek 提供了一个强大的代码编辑和开发环境,通过精确的命令和有效的交互,可以显著提高开发效率和代码质量。确保遵循最佳实践和注意事项,以充分利用这一工具的强大功能。


本文 90% 使用 AI 辅助完成

写给初学者的 Git 极简教程

Git 是一个强大的版本控制系统,它允许多个开发者在同一个项目上协作,跟踪文件的变化,并且可以在不同的时间点恢复到之前的状态。对于初学者来说,理解 Git 的基本概念和操作是非常重要的。在这篇博客中,我们将详细介绍 Git 的使用,并通过具体的例子来演示常用的 Git 命令。

Git 的三个位置

在使用 Git 时,我们需要了解三个主要的位置:本地目录、缓存区(有时也称为暂存区)和远程仓库。

1
2
3
4
5
6
7

# 记住 git 的三个位置
本地目录 <--(cache)----> .git <----> remote
add #将代码添加到缓冲区
commit --> #将代码提交到仓库
push -> 推送到远程
pull <- 从远程拉取

本地目录

这是你在计算机上存放项目文件的地方。当你开始一个新项目或者克隆一个远程仓库时,Git 会在项目文件夹中创建一个隐藏的 .git 文件夹。这个文件夹包含了所有的版本控制信息。

缓存区(.git

当你对本地目录中的文件进行修改后,这些改动并不会立即提交到远程仓库。首先,你需要使用 git add 命令将这些修改添加到缓存区。缓存区是一个临时存放改动文件的地方,你可以在这里预览将要提交的改动。

远程仓库

远程仓库是存储你的项目代码的在线平台,例如 GitHub、GitLab 或 Bitbucket。通过 git pushgit pull 命令,你可以将本地的改动推送到远程仓库,或者从远程仓库拉取其他人的改动到本地。

基本操作流程

添加(add)和提交(commit

  1. 添加改动到缓存区

    1
    git add <文件名>

    如果你想添加所有改动的文件到缓存区,可以使用:

    1
    git add .

    这里的点(.)代表了当前目录下的所有改动文件。

  2. 提交改动到本地仓库

    1
    git commit -m "你的提交信息"

    -m 选项后面跟着的是你对这次提交的描述信息,它有助于你和你的团队成员理解这次提交的目的和内容。

推送(push)和拉取(pull

  1. 推送本地提交到远程仓库

    1
    git push 远程仓库名 分支名

    例如,如果你想推送到名为 origin 的远程仓库的 master 分支,你可以使用:

    1
    git push origin master
  2. 从远程仓库拉取最新改动

    1
    git pull 远程仓库名 分支名

    这个命令会将远程仓库的最新改动拉取到你的本地目录,并自动尝试合并。

查看 Git 状态

要查看当前 Git 的状态,包括哪些文件被修改但还没有暂存或提交,可以使用 git status 命令。这个命令会列出所有的改动文件,并标明它们的状态。

理解 origin

origin 是远程仓库的默认别名。每个远程仓库都可以有一个或多个别名。你可以使用 git remote -v 命令来查看远程仓库的地址和它们的别名。

理解分支

分支是 Git 中一个非常重要的概念。它允许你在不同的线路上进行开发,而不会相互干扰。master 通常是默认的主分支,所有的开发工作都是基于这个分支进行的。

创建和使用分支

创建新分支

1
git checkout -b 新分支名

这个命令会创建一个新的分支,并自动切换到这个分支。例如,如果你想创建一个名为 feature-x 的新分支,你可以使用:

1
git checkout -b feature-x

切换分支

1
git checkout 分支名

如果你想从 feature-x 分支切换回 master 分支,你可以使用:

1
git checkout master

合并分支

当你在一个新分支上完成开发后,你可能需要将这些改动合并回 master 分支。首先,确保你已经切换到 master 分支,然后使用 git merge 命令将其他分支合并进来:

1
git merge 要合并的分支名

例如,如果你想将 feature-x 分支的改动合并到 master 分支,你可以使用:

1
git merge feature-x

通过以上步骤,你可以有效地管理你的代码变更,并且与团队成员协作开发项目。希望这篇博客能帮助你更好地理解和使用 Git!

博客和笔记不在重要

从今年年初开始,就不再写具体的博客,或者详细的笔记。只记录一些基本的、重要的细节。 GPT 的出现,让大部分的基础的技术记录不再重要,它能够很快的给你答案,甚至比你自己去查以前的笔记都要快。如果记录笔记的时间超过一年,如果这个知识点又事确定性的,比如某个知识怎么用。我可以确定问 GPT 的速度要远远高于去找以前的旧笔记。 如果事创意文字工作者,另当别论。

在好几年前给刚刚接触软件开发的一个同学讲 git 。边讲的过程边记录了文章末尾的一段命令。
于是让 AI 根据下面的内容生成一篇 blog。 生成的内容链接 写给初学者的 Git 极简教程
内容的部分除了添加了三个位置的引入,几乎没有做修改。如果是个人来写的话可能需要一个小时,并且文字描述没有那么完整。

我确信以后我们所看到的内容,大部分都是 AI 生成的。就像在刷短视频时大部分的视频都被滤镜修饰过一样。 那么我们需要的事丑陋但真实的世界,还是看上去美丽但是虚假的世界。这可能并不冲突。当需要追求根据真实时,我们会去探索真实。 但通常并不需要太真实。

大部分的内容输出,特别是具有确定性的,有很明确的步骤和方法的内容,不再需要我们写一篇博客和笔记来描述。多去记录那些不确定的内容吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#记住 git 的三个位置
本地目录 <--(cache)--> .git <----> remote
add #将代码添加到缓冲区
commit --> #将代码提交到仓库
push -> 推送到远程
pull <- 从远程拉取

git status # 查看当前git 的状态

git add . # 添加目录下所有变更
git commit -m "update" # 提交代码到仓库 update 为注释
git push origin master # 将代码推送到远程(origin)的 master 分支

git pull origin master # 从远处 mater 拉代码

# 理解 origin
origin 是远程地址的别名
git remote -v # 查看远程地址

# 理解分支
master 一般为默认主分支

git checkout -b newbanch # 创建一个名为 newbanch 的新分支,并切换到新分支

#一般我们开发会创建一个新分支修改,修改完成后在合并到主分支
git checkout master # 将分支切换回 master分支
git merge daihuanhuan # 将daihuanhuan 分支修改的内容和 master 分支合并(上一步已经切换到了master)