Skip to content

开始之前:这本书怎么读 ​

本章结束时,你能回答:

  • 给你一段 AI 生成的 Rust 网关代码,按本书的契约,哪些事必须由你来做?
  • 一条发给 jackdaw 的请求,从 curl 敲下去到回答流式回来,途经哪几站?
  • 本站的双语切换、搜索、自检折叠分别在哪、怎么用?

这本书的契约:不教写,教读 ​

你会写至少一门别的语言——Python、Go、TypeScript 都算——Rust 零基础。这正是本书预设的读者:零基础是起点,不是短板。契约一句话:代码交给 AI 写,你负责读懂、审查、验证。

为什么这样分工?AI 已把"写出能编译的代码"的成本压到接近零,瓶颈移到了另一头:你看不懂的代码,再能跑也不能用——安全问题审不出,bug 无从定位,出了岔子担不起责。读,是你保留的那一半工作:给你一段带注释的 Rust,你能讲清数据从哪来、到哪去、错误怎么传播。本书练的就是这个。

预备知识:一门语言的基础(变量、函数、JSON、HTTP),会用命令行。阅读本书不需要安装任何东西;要不要动手跑命令,你自己决定。

jackdaw:贯穿全书的小项目 ​

从第 4 章起,本书所有示例都取材于同一个真实项目:jackdaw(寒鸦),一个跑在本机的网关——常驻的转发服务:一个统一入口,后面接多家供应商(provider,提供模型 API 的一方)。

它的原型是 magpie:本机网关加模型管理器,默认监听 127.0.0.1:3425,同时说 OpenAI / Anthropic / Gemini 三种协议并互相翻译,provider 从订阅到本地模型有多种类型,外加一大套路由规则。jackdaw 刻意只复刻最小核:进出都是 OpenAI 兼容协议;provider 全靠手工配置,没有内置目录;group/<id> 的路由组(routing group),order / rotate 两种策略加故障转移(failover)。magpie 的多数能力 jackdaw 不做——这是教学选择而非缺陷,凡遇差异,书中都会明确标注"magpie 有 X,jackdaw 刻意不做,因为本书只要核心"。第 2 章先借 pi(自称 "Pi Agent Harness" 的 coding agent 工具族)讲清代理(智能体)是什么;第 10 章起,你看着 jackdaw 一层层长出来。

一条请求的旅程(先看戏,不拆台) ​

下面是成品 jackdaw 的一次完整工作:只需看懂"发生了什么",每一站的机制都标了在哪章展开。

前提:jackdaw 已在本机跑着,配置(节选自 jackdaw/jackdaw.example.toml,TOML——方括号起一段、段内 键 = 值)长这样:

toml
[gateway]
port = 3426
auth_token_env = "JACKDAW_TOKEN"   # agents send this variable's value as the Bearer token

[providers.openai]                 # the table name is the provider name — no built-in catalog
base_url = "https://api.openai.com/v1"   # OpenAI-compatible endpoint, no trailing slash
api_key_env = "OPENAI_API_KEY"           # stores the env var NAME, never the key itself

# ...

[groups.coder]
strategy = "order"                 # order | rotate
models = ["openrouter/deepseek/deepseek-chat", "openai/gpt-5.2"]

读法:从 [groups.coder] 看起——请求里的 model 会指向它;order 表示按列表顺序用,先 deepseek-chat,失败再换 openai/gpt-5.2(rotate 则轮流从下一个成员开始,摊开负载)。# ... 省略的 openrouter 块与 openai 同形:一个地址加一个环境变量名——注意存的是变量名,不是 API key 本身。

然后,你(或某个 coding 工具)发出这条请求:

bash
curl -N http://127.0.0.1:3426/v1/chat/completions \
  -H "Authorization: Bearer $JACKDAW_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
        "model": "group/coder",
        "messages": [{"role": "user", "content": "用一句话介绍你自己"}],
        "stream": true
      }'

读法:-N 关掉 curl 的缓冲,来一块打一块;请求打到本机 3426 端口,也就是 jackdaw 自己;$JACKDAW_TOKEN 是配置里 auth_token_env 所指环境变量的值;model 填的不是具体模型,是组名。

接下来是四站:

text
curl ──▶ jackdaw :3426 ──▶ openrouter ──▶ deepseek-chat
              └─ 失败则换 ──▶ openai / gpt-5.2
  1. jackdaw 核对 Bearer 凭证(第 14 章展开),认出 group/coder,按 order 取第一个成员(第 13 章展开)。
  2. 请求被转发到 openrouter 的地址:换上 OPENROUTER_API_KEY 的值,model 也从组名改写成第一个成员指向的模型,其余照旧。
  3. 上游把回答切成小块,流式(streaming,SSE)推回,jackdaw 原样透传(第 14 章展开);上游失败则故障转移到下一个(第 13 章展开)。
  4. 你的终端逐块打印出回答:
text
data: {"choices":[{"delta":{"content":"我是"}}]}

data: {"choices":[{"delta":{"content":"寒鸦"}}]}

data: [DONE]

读法:每个 data: 块是一小截增量文本,拼接起来才是完整回答;这里为聚焦删掉了 JSON 的大部分字段,真实结构第 2 章展开。第一次读扫一眼形状即可,不必逐字段研究。

这就是全书的目的地:读完第 14 章,上面每一站你都能对着源码讲清楚。

这个站点怎么用 ​

  • 双语切换:右上角在简体中文 / English 之间切换。两版是平行写作、同等详略,不是逐句翻译,哪版读着顺用哪版。
  • 搜索:顶部搜索框是本地搜索,中英文各自建索引;卡住时查一下术语,常比硬啃快。
  • 自检折叠:每章末尾三题,参考答案默认折叠——先自己作答,再点开对照,顺序别反。
  • 术语表:正文带链接的术语(如前面的网关)通向术语表,忘了含义随时点过去。

全站五部分:Part 1 建立世界观,Part 2 读懂 Rust 语言本身,Part 3 项目与生态,Part 4 把 jackdaw 逐层造出来,Part 5 延伸。建议按顺序读。

小结 ​

契约:AI 写,你读、审、验——看不懂的代码,再能跑也不该进你的项目。jackdaw 是贯穿全书的最小网关:请求从 curl 进、按组选模型、转发供应商、流式回来。站点:右上角切语言、顶部搜索、章末折叠自检。下一章:代理到底是什么——pi 的世界观。

自检 ​

  1. 同事说:"我让 AI 写了个 Rust 网关,能跑就行,不用看懂。"用本书的契约指出这句话的风险。
  2. 演示中,如果 openrouter 这次调用失败,按 groups.coder 的配置,接下来会发生什么?若换成 strategy = "rotate",行为有何不同?
  3. 配置里为何写 api_key_env = "OPENAI_API_KEY"(存变量名),而不是直接写密钥?
参考答案
  1. 契约是 AI 写、你读:审查安全、定位 bug、为行为担责的都是你。代码跑得起来但读不懂,这三件事一件都做不了——风险被藏进了没人能负责的黑盒。
  2. 触发故障转移:按 order 换列表中的下一个 openai/gpt-5.2 重试;rotate 不固定从第一个开始,每次请求轮到下一个成员,把负载摊开(第 13 章展开)。
  3. 配置文件容易被提交进仓库或分享出去;只存变量名,密钥留在各自机器的环境变量里,配置文件可以放心公开(第 11 章展开)。