Working Notes · 2026

几则技术速记

算法练习与工程观察的零散合集 —— 既写下题目本身的解法,也记录使用工具时碰到的真实现象。每一篇都从问题描述出发,到结论收束。

Note 01

鸡兔同笼算法

中国古代经典问题 · O(1) 解析解 · 四语言对照实现

概述

鸡兔同笼问题最早记载于约公元 5 世纪的《孙子算经》: 「今有雉兔同笼,上有三十五头,下有九十四足。问雉、兔各几何?」

从代数视角看,它是一组二元一次方程;从算法视角看,它是 O(1) 时间内完成的常数级运算 —— 无需枚举、无需迭代,一次代入即可得解。

问题描述

已知笼中鸡、兔共有 h 个头、f 只脚,求鸡和兔各有多少只。

示例:头 = 35,脚 = 94 → 鸡 = 23,兔 = 12。验证:23 + 12 = 35,23 × 2 + 12 × 4 = 94 ✓

算法思路

设兔数为 r、鸡数为 c,列出方程组:

方程组
c + r = h
2c + 4r = f
解析解
r = (f − 2h) / 2
c = h − r

合法性校验

实现

以下给出四种主流语言的等价实现。所有版本遵循相同的契约:输入 (heads, feet),返回 (chickens, rabbits) 或表示「无解」的空值。

Python

Python chicken_rabbit.py
def solve(heads: int, feet: int):
    rabbits = (feet - 2 * heads) // 2
    chickens = heads - rabbits
    if rabbits < 0 or chickens < 0 or (feet - 2 * heads) % 2 != 0:
        return None
    return chickens, rabbits


if __name__ == "__main__":
    h, f = 35, 94
    result = solve(h, f)
    if result:
        print(f"头={h}, 脚={f} => 鸡={result[0]}, 兔={result[1]}")
    else:
        print("无解")

JavaScript

JavaScript chicken_rabbit.js
function solve(heads, feet) {
  const diff = feet - 2 * heads;
  if (diff < 0 || diff % 2 !== 0) return null;
  const rabbits = diff / 2;
  const chickens = heads - rabbits;
  if (chickens < 0) return null;
  return { chickens, rabbits };
}

const h = 35, f = 94;
const r = solve(h, f);
console.log(r ? `头=${h}, 脚=${f} => 鸡=${r.chickens}, 兔=${r.rabbits}` : "无解");

Go

Go chicken_rabbit.go
package main

import "fmt"

func solve(heads, feet int) (int, int, bool) {
    diff := feet - 2*heads
    if diff < 0 || diff%2 != 0 {
        return 0, 0, false
    }
    rabbits := diff / 2
    chickens := heads - rabbits
    if chickens < 0 {
        return 0, 0, false
    }
    return chickens, rabbits, true
}

func main() {
    h, f := 35, 94
    if c, r, ok := solve(h, f); ok {
        fmt.Printf("头=%d, 脚=%d => 鸡=%d, 兔=%d\n", h, f, c, r)
    } else {
        fmt.Println("无解")
    }
}

Rust

Rust chicken_rabbit.rs
fn solve(heads: i32, feet: i32) -> Option<(i32, i32)> {
    let diff = feet - 2 * heads;
    if diff < 0 || diff % 2 != 0 {
        return None;
    }
    let rabbits = diff / 2;
    let chickens = heads - rabbits;
    if chickens < 0 {
        return None;
    }
    Some((chickens, rabbits))
}

fn main() {
    let (h, f) = (35, 94);
    match solve(h, f) {
        Some((c, r)) => println!("头={}, 脚={} => 鸡={}, 兔={}", h, f, c, r),
        None => println!("无解"),
    }
}
Note 02

paseo × Claude Code 速度差异分析

同一模型、同一任务、同一中转平台 —— 为什么两条链路的体感差出一个数量级?

背景与现象

在 paseo(第三方手机端 agent 框架)与 Claude Code(官方 CLI)中,分别接入同一家 vibeapi 中转的同一个 Opus 4.7 模型,让它们执行完全相同的任务:基于一个已有的 chicken_rabbit.md,生成 Claude 官网风格的网页。

4m 8s+
paseo 实测耗时(未完成,提前终止)
秒级 TTFT
Claude Code 同任务首响应
~10×
体感速度差异量级

两条链路调用的名义模型一致、任务输入一致、中转平台一致,按直觉应当性能接近。但实际差异不是百分之几十,而是数量级。下面拆解原因。

两条链路示意

A · paseo 手机 App → paseo 网关 → vibeapi → Anthropic
B · Claude Code CLI → vibeapi → Anthropic

五大原因

按对延迟的贡献度,从大到小排列。

1

Prompt Caching 命中率最关键

Anthropic 官方 API 支持 prompt caching:系统提示、工具定义、对话历史这些大块前缀只要 5 分钟内复用,下一次请求输入 token 的计费降到 1/10、prefill 延迟也几乎归零。一个任务里有几十次工具调用,每一次都能复用同一份巨大的前缀。

Claude Code 走原厂直连,默认开启 cache_control,TTFT 极短。paseo → vibeapi 这条链路通常没有 caching —— 第三方中转要么不传 cache_control 字段,要么虽然透传但分流到不同后端实例,缓存键对不上、每次都是冷启动。冷启动意味着每次都要重算几万 token 的输入,光 prefill 就要十几秒。

2

Skill 加载把上下文炸大上下文膨胀

截图中 paseo 触发了 Skill frontend-design。这个 skill 会把一大批设计参考、组件模板、HTML/CSS 范本作为参考材料注入到上下文里,单次注入十几 k 到几十 k token 是常事。

Claude Code 这边因为 CLAUDE.md 要求「写内容之前先经过用户同意」,先用 AskUserQuestion 对齐方案,没有触发 frontend-design,上下文保持在很小的量级。膨胀的上下文 × 没有 caching = 双重惩罚。

3

多层中转的固有开销链路代价

paseo 链路有 4 跳,Claude Code 链路只有 2 跳。paseo 作为 agent 框架还会注入自己的系统提示、工具协议封装、会话状态管理。每多一层封装:网络 RTT 增加、可能有排队(第三方网关并发池容量有限)、可能有参数改写(破坏 cache key)。

4

「同一模型」不一定真同一模型路由

vibeapi 上挂着名字叫 Opus 4.7 1M 的模型,不保证后端真的路由到原厂 Opus 4.7。第三方平台常见做法:按账户/价格梯度路由到不同后端、高负载时悄悄降级到 Sonnet 但保留 Opus 展示名、把 1M 上下文请求拦截到慢速专用池。

5

输出节奏对体感的放大感知层

Opus 4.7 的稳态 output 速度约 50–80 tok/s,两边都一样。但 paseo 显示的「Worked for Xm Xs」是 TTFT + prefill + output 的总和。当前面的 prefill 卡住几十秒乃至几分钟,output 还没开始,整体就显得「数量级慢」。

贡献度估算

把每个因素对总延迟的相对贡献量化(估算值,非实测):

缓存缺失 / 冷 prefill
~60%
Skill 上下文膨胀
~25%
中转网络 / 排队 / 改写
~10%
模型路由降级
~5%
注意:前两项合计约 85% —— 也就是说,瓶颈基本不在「模型本身」或「网络物理延迟」,而在工程优化层是否被中转链路保留下来。

验证方法

结论需要可验证。最具操作性的方式是「重复请求触发缓存对比」:

在 paseo 中跑同一个任务 第一次,记录耗时 T1。
5 分钟内紧接着跑第二次(同样的提示、同样的对话上下文),记录耗时 T2。
对比 T1 与 T2:
· 若 T2 ≪ T1(明显变快) → 是 caching 起作用,但首次冷启动慢;问题在首次成本。
· 若 T2 ≈ T1(两次一样慢) → 这条链路根本没开 caching,问题在中转层而非模型。
进一步:用同样方法跑 Claude Code,记录 T1' / T2'。差值能直接看出两条链路的 caching 利用率差距。

结论

「不是模型慢,是这条链路丢了原本应该有的工程优化。」 — 速度差异的本质

Claude Code 直连吃到了 prompt caching 的全部红利;paseo + vibeapi 这条链路在中转环节把它弄丢了,再叠加 Skill 注入造成的上下文膨胀,于是出现了同样一个 Opus 4.7 在两端「秒级 vs 分钟级」的对比。

实践建议