跳到正文
The Résumé of Ace
English

第三版

技术栈

器以载道:以有限之工具,构无涯之世界。

器有形,道无形。人手里能握住的永远是前者,想抵达的却始终是后者。

形而下者谓之器。工具都是器:摸得着、有边界、会老、会被替掉,没有哪一件是万能的。可人能造出多大的东西,偏偏就是靠这些有限的器一层层垒起来的——数据库、编译器、调度器,哪一样不是前人拿当时手上那点工具凑出来的。

所以选器从来不是挑最好的那件,而是选自己愿意活在哪一重限制里。每一件工具都替你预先做掉了一部分判断:它让某些事变得顺手,也就让另一些事变得几乎想不起来。要紧的不是找到那件称手的家伙,而是始终知道自己让渡了什么——用多大的代价,换来了哪一种确定。

编程语言

7 项

数据

5 项

基础设施

5 项

可观测性

2 项

客户端

7 项

AI 工具

5 项

编程语言

Go

Google 推出的编译型语言,以 goroutine 和一套精简、稳定的特性为核心。

Go 编译成单个静态二进制文件,自带垃圾回收器、调度器,以及覆盖 HTTP、JSON、测试和性能分析的标准库。goroutine 是由运行时管理的轻量线程;channel 在它们之间传递值,sync 包提供互斥锁和 WaitGroup。

这门语言演进缓慢,特性清单很短。泛型在 1.18 加入;错误处理使用显式返回值。gofmt 规定了统一的格式,不同作者写的代码读起来一致。它广泛用于网络服务、命令行工具,以及 Docker、Kubernetes 这类云基础设施。

要点

  • 运行时把 goroutine 复用到操作系统线程上(GMP 模型),某个线程阻塞在系统调用里时,处理器会交给另一个线程
  • 垃圾回收器并发运行,停顿在亚毫秒级;回收频率跟随分配速率,可用 GOGC 和 GOMEMLIMIT 调整
  • context.Context 在 goroutine 之间、跨 API 边界传递取消信号和截止时间

编程语言

Rust

一门系统编程语言,通过所有权和借用在编译期检查内存安全。

Rust 中每个值都有唯一的所有者,对它的引用由借用检查器检查:同一时刻可以有任意多个共享引用,或者恰好一个可变引用。这些规则让编译器在没有垃圾回收的情况下排除释放后使用、重复释放和数据竞争。

Rust 经由 LLVM 编译为本地代码,性能接近 C 和 C++。Cargo 负责构建、依赖、测试和文档。它被用于命令行工具、浏览器、数据库、嵌入式系统、WebAssembly,以及 Linux 和 Windows 内核的部分模块。

要点

  • 生命周期描述引用保持有效的时间范围;大多数可以推断,显式标注主要出现在函数签名和结构体中
  • Send 和 Sync 标明哪些类型可以跨线程移动或共享,数据竞争因此成为编译错误
  • unsafe 块允许裸指针和 FFI;由周围的代码负责维护编译器无法检查的不变量

编程语言

C

一门小巧的底层语言,贴近机器,是大多数操作系统的基础。

C 通过指针直接操作内存,由程序员用 malloc 和 free 管理分配与生命周期。它的编译产物可预测、贴近硬件,它的调用约定也是其他语言调用系统库时共用的接口。

Unix、Linux、主流数据库、各种语言运行时和大部分嵌入式固件都用 C 编写。标准为越界访问、有符号溢出等情况定义了未定义行为,优化编译器在变换代码时会依赖这些规则。

要点

  • Sanitizer(ASan、UBSan、TSan)和 Valgrind 可在运行时检测内存错误和未定义行为
  • glibc malloc、jemalloc、tcmalloc 等分配器使用 arena 和线程本地缓存,影响内存碎片和占用
  • C ABI 是 Rust、Go、Python 等大多数语言做 FFI 时的标准边界

编程语言

TypeScript

带静态类型系统的 JavaScript,类型在代码运行之前就被编译掉。

TypeScript 为 JavaScript 加入了类型标注、接口、泛型和联合类型。编译器检查这些类型并输出普通的 JavaScript;运行时不存在类型。它的类型系统是结构化的:两个类型的形状一致即可兼容。

它是大多数大型前端和 Node.js 项目的默认选择,编辑器借助它的语言服务实现补全、跳转和重构。没有类型的库,其类型定义发布在 DefinitelyTyped 的 @types/* 下。

要点

  • strict 模式会开启空值检查和更严格的推断,新项目通常默认开启
  • 带字面量 kind 字段的可辨识联合,让编译器能在 switch 和 if 分支中收窄类型
  • 来自网络或用户输入的数据在运行时没有检查;zod 等库负责校验,并从 schema 推导出静态类型

编程语言

Python

一门动态类型的解释型语言,广泛用于脚本、数据处理和机器学习。

Python 拥有庞大的标准库,PyPI 上的生态覆盖 Web 框架、自动化、科学计算和机器学习。NumPy、pandas、PyTorch 的重计算在编译好的 C、C++ 或 CUDA 代码中完成,再通过 Python API 暴露出来。

参考解释器 CPython 有全局解释器锁,同一时刻只有一个线程执行 Python 字节码。I/O 密集的工作可以用线程或 asyncio 扩展;CPU 密集的工作使用多进程或原生扩展。Python 3.13 加入了实验性的无 GIL 构建。

要点

  • 类型提示由 mypy、pyright 等工具检查,解释器本身会忽略它们
  • uv 和 Poetry 管理虚拟环境和锁文件;锁文件让安装结果可复现
  • asyncio 在单线程事件循环上运行协程,适合网络密集型服务

编程语言

Swift

Apple 为 iOS、macOS 等自家平台推出的编译型语言。

Swift 用 Optional 标记可能缺失的值,struct 和 enum 等值类型采用复制语义,class 使用自动引用计数。带默认实现的协议,承担了许多其他语言中继承所承担的角色。

Swift 5.5 加入了 async/await 和 actor,Swift 6 在严格并发模式下于编译期检查数据竞争。Swift 是开源的,也能在 Linux 和 Windows 上运行,但主要用于 Apple 平台,配合 SwiftUI 和 UIKit。

要点

  • struct 和 enum 在赋值时复制;class 按引用共享,由 ARC 计数
  • guard let 和 if let 安全地解包 Optional;用 ! 强制解包时,若值为 nil 会在运行时崩溃
  • actor 串行化对自身状态的访问,Sendable 标记可以跨并发域传递的类型

编程语言

Kotlin

JetBrains 推出的 JVM 语言,Android 开发的首选语言。

Kotlin 运行在 JVM 上,可以与 Java 类库完全互操作。它的类型系统区分可空类型和非空类型,并提供 data class、扩展函数、智能类型转换和 sealed class。自 2019 年起,Google 将它列为 Android 开发的首选语言。

协程让异步代码可以按顺序风格书写,结构化并发把每个协程绑定到一个 scope。Kotlin 也能编译为 JavaScript 和本地代码,Kotlin Multiplatform 可在 Android、iOS、桌面和服务端之间共享代码。

要点

  • 来自 Java 的值带有平台类型(String!),编译器不知道它们是否可空
  • 在绑定生命周期的 scope(如 viewModelScope)中启动的协程,会在该 scope 结束时被取消
  • val 声明只读引用,var 声明可变引用;集合分为只读接口和可变接口

数据

PostgreSQL

一款开源关系型数据库,SQL 支持完善,扩展生态丰富。

PostgreSQL 实现了多版本并发控制:更新会写入新的行版本,读操作不加锁就能看到一致的快照,旧版本稍后由 VACUUM 回收。它支持事务、外键、窗口函数、CTE、JSONB 和全文检索。

扩展可以在数据库内部增加能力:PostGIS 处理地理数据,pgvector 做向量检索,TimescaleDB 处理时序数据。复制分为流式物理复制和按表进行的逻辑复制。

要点

  • EXPLAIN (ANALYZE, BUFFERS) 展示实际执行的计划,包括真实行数、耗时和缓冲区读取
  • autovacuum 清理失效的行版本,并防止事务 ID 回卷;长事务会同时拖慢这两件事
  • 每个连接是一个进程,因此客户端多的部署通常会在前面放一个 PgBouncer 之类的连接池

数据

Redis

一款内存数据存储,用作缓存、消息代理和高速键值数据库。

Redis 把数据放在内存中,在单个主线程上执行命令,因此每条命令都是原子的。它提供字符串、哈希、列表、集合、有序集合、流和位图,各有对应的命令;Lua 脚本和事务可以把多条命令组合在一起。

持久化是可选的,可以用 RDB 快照、AOF 日志,或两者同时使用。主从复制和 Sentinel 提供故障切换,Redis Cluster 按哈希槽把键分布到多个节点。2024 年许可证变更后,Valkey 以 BSD 许可证延续了这个项目。

要点

  • 扫描大集合的命令,比如 KEYS、对大集合执行 SMEMBERS,运行期间会阻塞主线程
  • 常见的缓存问题有穿透(请求不存在的键)、击穿(同一个过期键被大量重建)和雪崩(大量键同时过期)
  • maxmemory 和淘汰策略决定内存用满时删除哪些数据

数据

MySQL

一款部署广泛的开源关系型数据库,通常搭配 InnoDB 存储引擎使用。

InnoDB 把每张表存成以主键为键的聚簇索引;二级索引存储主键,再通过主键回表查找整行。它支持事务和行级锁,通过 undo log 构造旧的行版本来实现 MVCC。

MySQL 在 Web 应用中很常见,也是 Amazon Aurora、PlanetScale 等托管服务的基础。复制基于 binlog,可以是异步复制、半同步复制,或者使用 Group Replication。

要点

  • 短小且单调递增的主键让插入落在聚簇索引的末尾,也让二级索引更小
  • 在 REPEATABLE READ 隔离级别下,InnoDB 会对范围加间隙锁和 next-key 锁,可能阻塞对这些范围的插入
  • EXPLAIN 和慢查询日志可以找出扫描大量行的查询

数据

ClickHouse

一款列式数据库,用于对超大表做分析查询。

ClickHouse 把每一列单独存储并压缩,查询只读取用到的列。它的向量化执行引擎按数据块处理,并把一次查询并行分配到多个 CPU 核心和多个分片上。

MergeTree 系列引擎按表的 ORDER BY 键排序数据,插入以 part 的形式写入,再在后台合并。ReplacingMergeTree、AggregatingMergeTree 等变体在合并时去重或预聚合。它常用于日志、指标、事件分析和可观测性后端。

要点

  • ORDER BY 键决定了稀疏主索引,对前导列做过滤能跳过最多的数据
  • 插入最好大批量进行;大量小批量插入会产生很多 part,加重合并负担
  • 更新和删除以异步 mutation 的方式执行,会重写整个 part

数据

SQLite

一款嵌入式 SQL 数据库,把整个数据库存放在单个文件中。

SQLite 是一个链接进应用的 C 库,没有独立的服务器进程。数据库是一个跨平台的文件,事务具有原子性和持久性。所有主流操作系统、浏览器和手机都内置了它,是部署最广泛的软件之一。

在 WAL 模式下,读操作和单个写操作可以同时进行,写操作串行执行。Litestream、LiteFS 等工具可以复制这个文件,用于备份或只读副本。它常用于应用存储、本地缓存、测试数据库和中小型网站。

要点

  • 同一时刻只有一个写事务;busy_timeout 设置其他写操作在返回 "database is locked" 之前等待锁的时长
  • 用 PRAGMA journal_mode=WAL 开启 WAL 模式,这是需要并发访问时的常用设置
  • 列默认使用类型亲和性;STRICT 表会强制检查声明的列类型

基础设施

Kafka

一个分布式、分区的日志系统,用于在系统之间传输事件流。

Kafka 把消息存放在 topic 中,每个 topic 分为多个分区。分区是一个只追加的日志,在多个 broker 之间复制;消费者自己记录在分区中的 offset,数据保留期内可以从任意位置重新读取。消息顺序在单个分区内得到保证。

消费者组把一个 topic 的分区分配给多个实例,吞吐量随分区数扩展。Kafka 用于事件管道、变更数据捕获、日志汇聚和服务解耦。从 4.0 版本起,它不再依赖 ZooKeeper,使用自带的 KRaft 共识协议。

要点

  • 相同 key 的消息进入同一个分区,因此同一 key 的消息保持有序
  • 配置 acks=all 和 min.insync.replicas 后,写入要等足够多的副本收到才会确认
  • 默认投递语义是至少一次;精确一次处理需要幂等生产者和事务

基础设施

Docker

一个用分层镜像构建并在容器中运行应用的工具。

容器是宿主机内核上的一个普通进程,用 Linux namespace(进程 ID、网络、挂载、用户)隔离,用 cgroup(CPU、内存、I/O)限制资源。镜像是一组只读文件系统层加上元数据,由 Dockerfile 构建,存放在镜像仓库中。

Docker 把应用和它的依赖打包在一起,使它在笔记本、CI 和生产环境中以相同的方式运行。镜像遵循 OCI 规范,因此也能在 containerd、Podman 和 Kubernetes 下运行。Docker Compose 用一个文件描述多容器的部署。

要点

  • Dockerfile 的每条指令生成一层,未变化的层会从构建缓存中复用
  • 多阶段构建在一个阶段编译,只把产物复制到更小的运行镜像里
  • 容器共享宿主机内核;以非 root 用户运行、去掉多余的 capability,可以减小进程被攻破后的影响范围

基础设施

Kubernetes

一个容器编排系统,让集群保持配置所描述的状态。

Kubernetes 把集群的期望状态以 API 对象(Deployment、Service、ConfigMap 等)的形式存放在 etcd 中。控制器监听这些对象并持续操作,直到实际状态与之一致:调度器把 Pod 分配到节点,kubelet 启动其中的容器,Deployment 替换失败的 Pod。

它通过统一的 API 提供服务发现、负载均衡、滚动更新、自动扩缩容和存储挂载。EKS、GKE、AKS 等托管服务负责运行控制平面,Helm 和 Kustomize 用于打包和模板化清单文件。

要点

  • requests 用于调度,limits 限制用量;容器超出内存 limit 会被 OOM kill
  • readiness 探针决定 Pod 是否接收流量,liveness 探针会重启已经无响应的容器
  • PodDisruptionBudget 限制节点排空等主动中断一次能停掉多少副本

基础设施

Linux

开源内核,运行着大多数服务器、容器和云基础设施。

Linux 内核管理进程、内存、文件系统、网络和设备,并通过系统调用以及 /proc、/sys 文件系统对外暴露。容器的基础组件 namespace 和 cgroup,都是内核特性。

Debian、Ubuntu、RHEL、Alpine 等发行版把内核与用户态工具和包管理器打包在一起。top、vmstat、iostat、ss、strace、perf 等工具可以查看整个系统和单个进程在做什么。

要点

  • load average 统计可运行的任务和处于不可中断睡眠的任务,因此大量磁盘 I/O 和 CPU 占用都会抬高它
  • 空闲内存会被用作页缓存;free 输出中的 available 列表示可以回收给应用使用的部分
  • eBPF 在内核中运行沙箱化的程序,用于追踪、网络和安全,常用工具有 bpftrace 和 BCC

基础设施

NGINX

一款基于事件驱动、非阻塞架构的 Web 服务器和反向代理。

NGINX 运行一个 master 进程和少量 worker 进程;每个 worker 用事件循环(Linux 上是 epoll,BSD 上是 kqueue)处理大量连接。连接数增长时,内存占用依然低而平稳。

它可以提供静态文件、终结 TLS、在多个上游服务器之间做负载均衡、缓存响应,以及代理 HTTP、gRPC 和 WebSocket 流量。Kubernetes 的 ingress 控制器和加入了 Lua 脚本的 OpenResty 也以它为基础。

要点

  • worker_processes auto 会为每个 CPU 核心启动一个 worker
  • upstream 块中的 keepalive 复用到后端的连接,减少建立连接的开销
  • nginx -t 检查配置,nginx -s reload 在不中断现有连接的情况下应用新配置

可观测性

Prometheus

一个监控系统,通过 HTTP 抓取指标,存储为时间序列。

Prometheus 按固定间隔从目标拉取指标,把每条序列(由指标名和一组标签标识)存入本地时序数据库。PromQL 用于查询、聚合和计算速率,告警规则也用 PromQL 编写。

应用通过客户端库暴露指标;exporter 则为 Linux 主机、数据库、代理等系统暴露指标。Alertmanager 负责告警的分组和路由。需要长期或全局存储时,可以用 Thanos、Cortex、Mimir 和 VictoriaMetrics 扩展它。

要点

  • 每一种不同的标签值组合都是一条独立序列,因此用户 ID、请求 ID 这类标签会成倍增加存储和内存占用
  • 对 counter 使用 rate() 得到每秒速率,并且能正确处理计数器重置
  • histogram 把数值记录到桶中,histogram_quantile() 可以跨实例估算分位数

可观测性

Grafana

一个仪表盘和可视化工具,在同一处查询多种数据源。

Grafana 连接 Prometheus、Loki、Tempo、Elasticsearch、ClickHouse 和各种 SQL 数据库等数据源,把查询结果渲染成仪表盘上的面板。变量让同一个仪表盘可以在不同服务、集群或环境之间切换。

它也负责告警,并把指标、日志和链路关联起来,面板可以跳转到同一时间段的相关日志或链路。仪表盘以 JSON 存储,可以从文件预置,也可以通过 API 管理。

要点

  • RED(速率、错误、时延)用于描述请求驱动的服务,USE(使用率、饱和度、错误)用于描述资源
  • data link 和 exemplar 把指标面板和对应的日志、链路连接起来
  • 用版本控制中的 JSON 预置仪表盘,便于审查,也能复现

客户端

React

一个用组件构建用户界面的 JavaScript 库。

React 组件是一个函数,接收 props 和 state,返回对界面的描述。state 变化时,React 重新渲染受影响的组件,并把差异应用到 DOM 上。useState、useEffect、useContext 等 Hook 为函数组件提供状态和副作用。

React 负责视图层;路由、数据获取和服务端渲染由 Next.js、React Router 等框架或独立的库提供。React 18 加入了并发渲染,React 19 加入了 Server Components 和 Actions。React Native 把同一套模型用于 iOS 和 Android。

要点

  • key 用于在多次渲染之间识别列表项;稳定的 ID 让每一项的状态始终对应正确的元素
  • useMemo 和 useCallback 让值和函数在多次渲染之间保持引用稳定
  • TanStack Query 等库负责缓存服务端数据,并处理重新获取和失效

客户端

Next.js

Vercel 推出的 React 框架,内置路由、服务端渲染和 API 路由。

Next.js 把 app 目录中的文件映射为路由,页面可以在服务端、构建时或客户端渲染。在 App Router 中,组件默认是 React Server Components;标记了 'use client' 的组件还会发送到浏览器并进行水合。

Route Handler 和 Server Action 在同一个项目里运行服务端代码,middleware 在请求到达路由之前执行。fetch 结果和渲染好的页面可以缓存,并按时间或按需重新验证。它可以部署到 Vercel、Node.js 服务器,或导出为静态站点。

要点

  • 'use client' 标出组件开始向浏览器发送 JavaScript 的边界
  • 缓存和重新验证按请求或按路由设置,使用 revalidate、cache 和 revalidatePath
  • 没有 NEXT_PUBLIC_ 前缀的环境变量只存在于服务端

客户端

Astro

一个面向内容站点的 Web 框架,把页面渲染为 HTML,默认不发送 JavaScript。

Astro 组件在服务端或构建时渲染,输出 HTML。React、Vue、Svelte 等框架的交互组件通过 client:* 指令作为「岛屿」加入页面,浏览器只为这些岛屿加载 JavaScript。

内容集合加载 Markdown、MDX 或数据文件,并按 schema 校验 frontmatter。Astro 默认构建静态站点,也可以通过适配器支持服务端渲染。这个网站就是用 Astro 构建的,唯一的客户端脚本负责首页的打字效果和技术栈弹层。

要点

  • client:load、client:idle、client:visible 控制岛屿的水合时机
  • 内容集合的 schema 使用 zod,frontmatter 不合法时构建会失败
  • Astro 基于 Vite 构建,使用 Vite 的插件和开发服务器

客户端

Tailwind CSS

一个原子化优先的 CSS 框架,用小而单一用途的类来设置样式。

Tailwind 提供 flex、px-4、text-sm 这样的类,每个类按设计尺度设置一个或几个 CSS 属性。样式直接写在标记里,构建时扫描源文件,只为用到的类生成 CSS。

v4 把配置搬进了 CSS:设计 token 用 @theme 声明,自定义工具类用 @utility 声明。hover:、md:、dark: 等变体让类在特定状态或断点下生效。这个网站用 Tailwind v4 做布局,token 和报纸版式样式放在一个样式表里。

要点

  • 间距、颜色和字号尺度来自主题,各个组件的取值因此保持一致
  • v4 中 @apply 接受用 @utility 声明的类;@layer components 里的类不能用于 @apply
  • 反复出现的一组工具类,通常会在 UI 框架里抽成一个组件

客户端

Vite

一个前端构建工具,开发服务器基于原生 ES 模块,启动迅速。

开发时,Vite 把源文件作为原生 ES 模块交给浏览器,文件被请求时才进行转换,保存后通过热模块替换更新。依赖会用 esbuild 预打包一次。生产构建使用 Rollup 打包,新版本使用 Rolldown。

它无需额外配置即可支持 TypeScript、JSX、CSS Modules 和静态资源,插件 API 与 Rollup 插件兼容。Astro、SvelteKit、Nuxt、SolidStart 和很多 React 项目都构建在它之上。

要点

  • 开发和生产构建走的是不同的流水线,发布前应测试生产构建
  • import.meta.env 提供环境变量,只有以 VITE_ 开头的变量会进入客户端代码
  • vite preview 在本地提供生产构建的预览

客户端

Node.js

基于 V8 的 JavaScript 运行时,用于服务端和前端工具链。

Node.js 借助 Google 的 V8 引擎在浏览器之外运行 JavaScript。JavaScript 在单线程上配合事件循环执行,libuv 以异步方式处理文件、网络和定时器 I/O,对操作系统无法异步完成的操作使用线程池。

它用 Express、Fastify 等框架运行 Web 服务和 API,运行 Next.js 的服务端,也运行大部分前端工具:Vite、TypeScript 编译器、ESLint 和各种包管理器。npm 是它的包仓库。偶数版本会成为长期支持版本。

要点

  • 请求处理中的同步操作或 CPU 密集计算,会阻塞事件循环,影响所有并发请求
  • worker_threads 在独立线程上运行 CPU 密集的代码
  • .nvmrc 文件或 package.json 中的 engines 字段记录项目需要的 Node 版本

客户端

SwiftUI

Apple 的声明式 UI 框架,用 Swift 为其各个平台构建界面。

SwiftUI 的视图是一个 struct,它的 body 描述当前状态下的界面。状态变化时,SwiftUI 重新计算受影响的视图并更新屏幕。同一套代码可以面向 iOS、iPadOS、macOS、watchOS、tvOS 和 visionOS。

状态通过 @State、@Binding 等属性包装器保存,iOS 17 起还可以使用 @Observable 模型类。SwiftUI 通过 UIViewRepresentable 和 hosting controller 与 UIKit、AppKit 互操作。Xcode 预览会在编辑时实时渲染视图。

要点

  • @State 保存单个视图自有的状态,@Observable 模型保存多个视图共享的状态
  • 很多 API 依赖最低系统版本,每个修饰符的文档中都标明了版本要求
  • UIViewRepresentable 和 UIHostingController 分别用于在 SwiftUI 中嵌入 UIKit 视图、在 UIKit 中嵌入 SwiftUI 视图

AI 工具

Claude Code

Anthropic 推出的编程智能体,可在终端、IDE 或桌面应用中直接在仓库里工作。

Claude Code 会读取文件、搜索代码库、运行 shell 命令,并跨多个文件修改代码,来完成用自然语言描述的任务。它会展示每一步,并按照配置的权限模式在操作前请求许可。

仓库中的 CLAUDE.md 文件记录约定和项目说明,每次会话都会加载。它通过 MCP 服务器连接外部工具,支持子智能体、hook 和自定义斜杠命令。它可以在终端、VS Code 和 JetBrains IDE、Claude 桌面应用以及网页中运行。

要点

  • CLAUDE.md 存放项目约定、构建命令和已知的坑,供每次会话读取
  • 目标清楚、结果可验证(比如有一个失败的测试)的任务,完成得最稳定
  • 改动在提交前通过 diff 审查

AI 工具

Codex

OpenAI 推出的编程智能体,提供命令行工具、IDE 扩展和云端服务。

Codex 针对描述的任务读取和修改代码、运行命令和测试,并给出改动方案。Codex CLI 在本地终端运行,审批模式可配置;ChatGPT 中的 Codex 在云端沙箱中执行任务,以 diff 或 pull request 的形式返回结果。

仓库中的 AGENTS.md 文件为它提供构建命令、测试命令和项目约定。云端任务以并行、异步的方式运行,可以同时启动多个相互独立的任务,完成后再审查。

要点

  • AGENTS.md 写明如何构建、测试和检查项目
  • 云端任务在隔离的容器中运行,容器里检出了仓库代码
  • 由另一个模型审查改动,能发现与编写它的模型不同的一类错误

AI 工具

Gemini

Google 的多模态模型家族,我用它对一个问题持续追问,直到弄清为止。

Gemini 是 Google DeepMind 推出的大语言模型家族,可以接收文本、图片、音频、视频和文档。它可以在 Gemini 应用中使用,也可以通过 Gemini API、Vertex AI 以及各个 Google 产品使用。它的上下文窗口能容纳很长的输入,比如整篇论文或整本书。

我主要用它做知识问答,方式是苏格拉底式的:先问一个东西是什么,再问为什么,再问由此推出什么,沿着每个回答一路追问下去,直到定义和它背后的前提都清楚为止。每个回答都是这条追问路线上的一步。

要点

  • 提供原始文档,可以让回答以该文本为依据
  • 要求给出推理过程和反方论证,能暴露回答背后的前提
  • 数字、版本、近期事件等具体事实,会回到原始资料核对

AI 工具

Ollama

一个在本地机器上下载并运行开源权重语言模型的工具。

ollama run <model> 会下载模型并开始提供服务。模型以量化权重存储,通过基于 llama.cpp 的引擎在 CPU、Apple Silicon 或 NVIDIA、AMD 显卡上运行。Modelfile 可以为自定义模型设置系统提示词、参数和模板。

Ollama 提供本地 HTTP API,其中包括兼容 OpenAI 的接口,现有的客户端库改一下 base URL 就能使用。它用于离线工作、数据不能离开本机的场景,以及向量嵌入等调用量大、要求低延迟的任务。

要点

  • 兼容 OpenAI 的接口地址是 http://localhost:11434/v1
  • Q4、Q8 等量化等级在模型质量和内存之间取舍;整个模型能放进显存或统一内存时效果最好
  • 上下文长度可以按模型配置,并会影响内存占用

AI 工具

Hugging Face

一个托管和分享机器学习模型、数据集和演示应用的平台。

Hugging Face Hub 以 Git 仓库的形式托管开源权重模型、数据集和 Spaces(托管的演示应用)。每个模型都有模型卡,说明训练数据、适用场景、局限和许可证。社区成员会发布微调版本和量化版本,比如供 llama.cpp 和 Ollama 使用的 GGUF 文件。

它的库包括用于加载和运行模型的 Transformers、用于加载数据的 Datasets、Tokenizers、用于参数高效微调的 PEFT,以及用于图像模型的 Diffusers。Inference Endpoints 和 Inference Providers 通过 API 提供模型服务。

要点

  • 模型的许可证各不相同,部分开源权重模型限制商用
  • 按 revision 下载,可以把模型锁定到仓库的某个特定提交
  • 社区 GGUF 构建在量化方式和上下文长度上各不相同,这些信息写在文件名和模型卡中