MoreRSS

site iconEin Verne修改

软件工程师,开源爱好者,Linux用户和vimer开发者。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

Ein Verne的 RSS 预览

Claude Code /goal:让 AI 自主持续工作直到达成目标的新命令

2026-05-13 13:00:00

用 [[Claude Code]] 写代码时,一直有一个令人微妙不适的摩擦:每当 Claude 完成一轮工作,控制权就回到了我这里,我需要再次发出指令,告诉它”继续”“再检查一遍”“还有这个文件没改”。对于那种需要跑很多轮才能完成的任务——比如把一个模块从旧 API 迁移到新 API 直到所有测试通过,或者逐文件重构某个目录直到符合统一规范——这个”人类中继”的环节就显得相当机械,本质上我只是在不停地按确认键。

[[Claude Code]] 最新推出的 /goal 命令针对的正是这个场景:你描述一个完成条件,Claude 就跨多个 turn 持续工作,每轮结束后由一个独立的小模型来判断条件是否满足,满足则停,否则继续。不再需要人类守在旁边不断催促。

Claude Code /goal 命令

/goal 是如何工作的

/goal 的核心机制可以用一句话概括:在每轮 Claude 工作结束后,引入一个独立的评估模型来判断”目标是否达成”,未达成则自动触发下一轮,达成则停止并清除目标。

具体来说,整个循环是这样运转的:你输入 /goal 加上完成条件的描述,这个命令本身就直接触发第一轮工作,不需要额外再发一条指令。每轮 Claude 完成工作后,目标条件和当前对话内容一起被发给一个小型快速模型(默认是 Haiku),该模型返回两样东西:一个是/否的判断,以及一段简短的理由解释为什么条件达成或还未达成。如果判断是”未达成”,那段理由还会作为下一轮的参考信息传给 Claude,引导它的后续工作方向。

这种设计有一个微妙但重要的含义:评估和执行是分离的。做事的模型和判断事情是否做完的模型不是同一个,这避免了 Claude 既当运动员又当裁判时可能产生的自我满足倾向。一个 fresh 的评估模型会更客观地判断条件是否真的满足。

目标激活期间,界面上会显示 ◎ /goal active 的状态指示,并且记录目标已经运行了多久。每次评估后,最新的评估理由也会出现在状态栏里,让你随时能看到 Claude 当前正在朝哪个方向努力。

基本用法

用法很直接,输入 /goal 加上你的完成条件就可以:

/goal 迁移 auth 模块到新版 API,直到所有相关测试全部通过
/goal 重构 components/ 目录下所有组件,确保没有 TypeScript 类型错误
/goal 找出并修复所有导致 CI 失败的问题,直到 CI 全绿

同一个 session 里只能有一个 goal 处于激活状态。如果在目标达成前想中途放弃,用 /goal clear 清除即可,stopoffresetnonecancel 这些词也都被接受为 clear 的别名。

不带参数运行 /goal 可以查看当前状态,包括已跑的 turn 数和消耗的 token 数:

/goal

如果已经有一个 goal 在跑,再次用 /goal <新条件> 会直接替换掉旧的目标。通过 /clear 开始新对话也会清除当前的 goal。

会话中断后用 /continue 恢复时,目标本身会保留,但 turn 计数、计时器和 token 消耗的基线会重置,相当于重新开始计算。

与 /loop 和 Stop hook 的对比

Claude Code 里有几种”让 Claude 持续工作”的机制,它们的区别值得理清楚:

/goal 在每轮结束后立即触发下一轮,用模型评估条件是否满足来决定是否停止,条件是用自然语言描述的——适合”做到某个状态才算完”的任务。

/loop 是按时间间隔触发,你设定一个时间窗口(比如每 5 分钟),Claude 会周期性醒来工作一次,停止的时机是你手动叫停,或者 Claude 自己判断工作已经完成——适合”持续轮询”“定期检查”这类时间驱动的场景。

Stop hook 是最底层的机制,/goal 本质上就是对 Stop hook 的高层封装:它在 session 范围内注册了一个 prompt-based Stop hook,每轮结束后调用 Haiku 评估条件。Stop hook 的灵活性最高,可以执行任意 shell 脚本做确定性检查(比如直接跑测试命令),不局限于语言描述的条件,但需要在设置文件里配置,是跨 session 持久的。/goal 的优势在于即时性和便捷性,当下想用就用,session 结束自动消失。

方式 触发时机 停止条件 典型场景
/goal 上一轮结束后立即 模型评估条件满足 目标导向的多步任务
/loop 设定的时间间隔 手动停止或 Claude 自判断 定期检查、轮询
Stop hook 上一轮结束后立即 脚本或 prompt 判断 确定性验收、复杂条件

与 auto 模式的配合

/goal 和 auto 模式是互补关系,容易让人以为二者重叠。

auto 模式的作用域是单轮内:它自动批准工具调用,Claude 在一轮内不需要你不断点允许就能执行读文件、写文件、运行命令等操作。但一轮结束,控制权就回到你手里。

/goal 的作用域是跨轮次:它在每轮结束后决定要不要再启动一轮,解决的是”我需要不断说继续”的问题。

两者组合使用才是最顺滑的体验:auto 模式处理轮内的工具审批,/goal 处理轮间的连续性,整个任务从开始到完成可以完全不需要人工干预。

使用限制与注意事项

/goal 依赖 Claude Code 的 hooks 系统运行,因此有几个前提条件需要满足:当前工作区必须已经通过了 trust 对话框的确认;如果在设置文件里设置了 disableAllHooks 或者管理员启用了 allowManagedHooksOnly/goal 命令会明确告知你无法使用,而不是静默失效。

在非交互模式和 Remote Control 下,/goal 同样可以工作。通过 -p 参数启动时,设定了 goal 的调用会一直运行到条件满足才返回:

claude -p "/goal 修复所有 lint 错误并确保 build 成功"

用 Ctrl+C 可以中途打断非交互模式下正在运行的 goal。

消耗方面需要留意:每轮结束后都会调用 Haiku 做评估,这部分 token 消耗是额外的。对于条件明确的任务问题不大,但如果条件写得模糊、Claude 一直无法满足,goal 可能会运行很多轮积累不少消耗——写清楚、可验证的条件比含糊的目标更能让 goal 高效停止。

最后

/goal 在功能设计上抓住了一个关键痛点:长任务里最浪费人类注意力的部分,不是看 Claude 工作,而是在每轮结束后判断”是不是还要继续”然后再发一条指令。把这个判断交给独立的评估模型来做,在设计上是合理的——执行和验收分离,减少了”自我感觉良好就停下”的风险。

从 Codex CLI 率先在 v0.128.0 推出 /goal 到 Claude Code 跟进实现,这个命令正在成为 AI 编程工具里的标准能力。对于迁移、重构、批量修复这类需要多轮才能完成的开发任务,/goal 配合 auto 模式能让整个过程接近”设定目标,等待完成”的体验,让注意力从”督促 AI 执行”转向”验收 AI 结果”——这个方向是对的。

codex-lb:用负载均衡的思路管理多个 ChatGPT 账号

2026-05-12 13:00:00

用 [[Codex]] CLI 做开发的人大概都遇到过这个场景:手头有几个 ChatGPT 账号,分散在不同的订阅计划里,但工具只认一个账号,额度用完了只能手动切换,每次还要重新登录。更头疼的是,当多人共享一个环境,或者想用同一套配置同时跑 Codex CLI 和 OpenCode 时,账号管理很快就变成了一团乱麻。

codex-lb 用一个很优雅的思路解决了这个问题:把多个 ChatGPT 账号池化,暴露出一个统一的 OpenAI 兼容接口,所有下游客户端只需要指向这个本地代理就行了。它在 2026 年 1 月创建,目前已经积累了 1077 个 Star 和 40 名贡献者,最新版本是 v1.15.0。

codex-lb 负载均衡示意图

codex-lb 是什么

简单来说,codex-lb 是一个本地运行的反向代理,它接管所有 AI 客户端的请求,然后按照负载均衡策略分发到不同的 ChatGPT 账号上。对下游客户端(Codex CLI、OpenCode、Python SDK)而言,它就是一个普通的 OpenAI 兼容 API 端点;对上游的 ChatGPT 账号而言,请求自然地分散开来,不会压垮某一个账号的 rate limit。

它的核心功能包括:账号池化负载均衡、每账号的 token 和费用追踪(含 28 天趋势)、Dashboard 管理界面(支持密码 + TOTP 双因素认证)、API Key 系统(支持按 token 量/费用/时间窗口设置速率限制),以及自动从上游同步可用模型列表。这个功能集对于需要协作共享或想精细管控 AI 用量的场景来说相当完整。

快速部署

[[Docker]] 是官方推荐的方式,一行命令即可启动:

docker volume create codex-lb-data
docker run -d --name codex-lb \
  -p 2455:2455 -p 1455:1455 \
  -v codex-lb-data:/var/lib/codex-lb \
  ghcr.io/soju06/codex-lb:latest

启动后访问 http://localhost:2455,添加 ChatGPT 账号,就算完成了。端口 2455 是代理服务,1455 是内部通信端口(多副本场景用)。

如果不想用 Docker,也可以直接用 [[uvx]] 运行:

uvx codex-lb

首次远程访问时需要 bootstrap token 来设置初始密码。服务启动后会在日志里打印这个 token:

docker logs codex-lb
# ============================================
#   Dashboard bootstrap token (first-run):
#   <token>
# ============================================

用这个 token 登录 Dashboard,设置好密码,之后就走正常的密码 + TOTP 流程。如果是本地访问(localhost),则完全跳过这一步,直接进入 Dashboard。

数据默认存储在 Docker volume 里(/var/lib/codex-lb/),本地运行则在 ~/.codex-lb/,定期备份这个目录即可保留账号和配置。

配置下游客户端

添加好 ChatGPT 账号之后,就是让各个 AI 工具把请求指向 codex-lb。不同工具的配置方式略有差异。

Codex CLI 的配置最受关注,因为 codex-lb 就是从这个场景出发设计的。在 ~/.codex/config.toml 里添加一个自定义 provider:

model = "gpt-5.3-codex"
model_reasoning_effort = "xhigh"
model_provider = "codex-lb"

[model_providers.codex-lb]
name = "OpenAI"
base_url = "http://127.0.0.1:2455/backend-api/codex"
wire_api = "responses"
supports_websockets = true
requires_openai_auth = true

name = "OpenAI" 这个字段是必填的,它告诉 Codex CLI 按 OpenAI 协议处理 /responses/compact 端点,少了这个 remote compact 功能会失效。如果开启了 API Key 认证,还需要加上 env_key = "CODEX_LB_API_KEY" 并设置对应的环境变量。

OpenCode 的配置稍微特殊,文档特别提醒不要用自定义 provider,而要覆盖内置的 openai provider 的 baseURL。原因是自定义 provider 走 Chat Completions API,会丢失 reasoning/thinking 内容,内置 openai provider 走 Responses API,才能正确处理 encrypted_content 和多轮推理状态:

{
  "provider": {
    "openai": {
      "options": {
        "baseURL": "http://127.0.0.1:2455/v1",
        "apiKey": "{env:CODEX_LB_API_KEY}"
      }
    }
  }
}

OpenAI Python SDK 则只需要指定 base_url 就行,门槛最低:

from openai import OpenAI

client = OpenAI(
    base_url="http://127.0.0.1:2455/v1",
    api_key="sk-clb-...",  # 从 Dashboard 获取,未开启认证时填任意非空字符串
)

API Key 与速率限制

codex-lb 自带一套 API Key 管理系统,在多人共享场景下特别有用。Dashboard 里的 “API Keys” 页面可以创建任意数量的 key,每个 key 可以独立设置:过期时间、允许使用的模型列表、速率限制(按 token 数量、费用上限,支持按日/周/月的时间窗口)。

API Key 认证默认是关闭的。本地使用时不需要开启,代理路由(/v1/*/backend-api/codex/*)默认只接受来自 localhost 的请求。如果需要通过 Docker 网络、局域网或远程访问,才需要在 Dashboard 的 Settings 里打开 API Key Auth,并让客户端在请求头里带上 Authorization: Bearer sk-clb-...

Key 创建时完整值只显示一次,务必记录下来。

WebSocket 与流式传输

Codex CLI 在流式输出时可以使用 WebSocket 传输,codex-lb 默认采用 auto 模式,会根据请求头和模型类型自动选择 WebSocket 或 HTTP。如果需要强制使用 WebSocket(有时候性能更好),可以设置环境变量:

export CODEX_LB_UPSTREAM_STREAM_TRANSPORT=websocket

也可以在 Dashboard 的 Settings → Routing → Upstream stream transport 里切换。验证 WebSocket 是否正常工作,可以用 debug 模式运行一次:

RUST_LOG=debug codex exec "Reply with OK only."

正常情况下日志里应该能看到 connecting to websocketsuccessfully connected to websocket,同时 codex-lb 的日志显示 WebSocket /backend-api/codex/responses,而不是降级的 POST 请求。如果 codex-lb 跑在反向代理后面,需要确认反向代理正确转发了 WebSocket upgrade 请求。

从直连 OpenAI 迁移

如果之前用的是 Codex CLI 直连 OpenAI,切换到 codex-lb 之后,codex resume 看不到旧的会话——因为 Codex 按 model_provider 字段过滤历史记录。可以用下面的命令把旧会话的 provider 字段改成 codex-lb

# JSONL 格式的会话文件
find ~/.codex/sessions -name '*.jsonl' \
  -exec sed -i '' 's/"model_provider":"openai"/"model_provider":"codex-lb"/g' {} +

# SQLite 状态数据库(>= v0.105.0)
sqlite3 ~/.codex/state_5.sqlite \
  "UPDATE threads SET model_provider = 'codex-lb' WHERE model_provider = 'openai';"

Kubernetes 部署

如果需要在 Kubernetes 集群里运行(比如团队共享环境),codex-lb 提供了官方 Helm chart:

helm install codex-lb oci://ghcr.io/soju06/charts/codex-lb \
  --set postgresql.auth.password=changeme \
  --set config.databaseMigrateOnStartup=true \
  --set migration.schemaGate.enabled=false
kubectl port-forward svc/codex-lb 2455:2455

多副本场景下,Helm chart 默认使用 headless service DNS 来协调各副本之间的 HTTP session owner handoff,保证同一个对话的请求路由到正确的副本。数据库可以从默认的 SQLite 切换到 PostgreSQL(通过 CODEX_LB_DATABASE_URL 环境变量),适合高并发或多副本的生产环境。

Dashboard 认证支持三种模式:标准密码 + TOTP、信任反向代理的 Remote-User 请求头(适合接入 Authelia 等认证网关)、以及完全禁用认证(仅限内网隔离场景)。

最后

codex-lb 本质上是把运维领域”服务网格”的思路搬进了个人 AI 工具的使用场景:通过统一代理层屏蔽上游账号的差异,让客户端只需要面对一个稳定的接口。从功能完整度来看,Dashboard 的用量可视化、API Key 的细粒度速率控制、多客户端兼容性([[Codex]]、[[OpenCode]]、OpenAI SDK)以及 Kubernetes 支持,这些都是超出”玩具项目”级别的设计。1077 个 Star 和 40 名活跃贡献者也说明它确实在解决真实需求。

对于个人开发者来说,最直接的价值是:多个 ChatGPT 账号的额度可以无缝轮换,不会因为某个账号触达 rate limit 就中断工作流。对于小团队共享账号的场景,API Key 的用量追踪和配额控制进一步降低了”谁用了多少”的管理成本。如果你手头有两个以上的 ChatGPT 订阅,codex-lb 值得花半小时试试。

本地快速切换 Claude Code 和 Codex CLI 账号的几种方案

2026-05-12 13:00:00

同时维护个人项目和工作项目的时候,最让我头疼的不是代码本身,而是工具的账号管理。[[Claude Code]] 和 [[Codex]] 这类 AI 编程工具,我在公司有一套账号,个人订阅又是另一套。每次在项目之间切换,都要 claude auth logoutclaude auth login,不仅耗时,还经常忘了当前用的是哪个账号,写了半天才发现额度消耗到错误的账号上去了。

这个问题在社区里也有不少人反映。[[Claude Code]] 的 GitHub issue #261 从 2025 年初提出原生 multi-account 支持,到现在积累了几十个 upvote,还有一个 issue 描述有人花了 40 分钟才搞定账号切换,可见这不是个小众需求。好消息是,虽然官方没有内置完善的 profile 系统,社区已经摸索出了几套成熟的方案。

在两个终端窗口中同时运行不同账号的 Claude Code

Claude Code 的账号存储机制

在讨论切换方案之前,先理解 Claude Code 的认证数据存在哪里。默认情况下,所有配置、认证 token、会话历史都存放在 ~/.claude/ 这一个目录里。这个目录结构大致如下:

~/.claude/
├── settings.json          # 配置文件(不含凭证)
├── sessions/              # 会话历史
├── plugins/               # 插件数据
└── cache/                 # 缓存

OAuth token 通过 claude auth login 登录后存储在系统中,与 ~/.claude/ 绑定。切换账号的本质,就是让 Claude Code 指向一个不同的配置目录,从而读取不同账号的认证数据。

[[Claude Code]] 支持一个关键环境变量:CLAUDE_CONFIG_DIR,它允许你指定 Claude Code 使用的配置目录,而不是默认的 ~/.claude/。一切账号切换方案都围绕这个环境变量展开。

Claude Code 切换方案

直接使用环境变量(最简单)

最直接的方式是在启动 Claude Code 时临时指定配置目录:

# 使用工作账号
CLAUDE_CONFIG_DIR=~/.claude-work claude

# 使用个人账号
CLAUDE_CONFIG_DIR=~/.claude-personal claude

第一次用某个目录启动时,Claude Code 会自动创建该目录并引导你登录,之后该目录就保存了那个账号的认证信息。这种方式零依赖,但每次都要手动输入变量名,比较麻烦。

Shell 函数封装(推荐的手动方案)

把环境变量封装进 Shell 函数,添加到 ~/.zshrc~/.bashrc 里,就能用简短命令切换:

claude() {
  local profile="personal"
  local claude_args=()

  while [[ $# -gt 0 ]]; do
    case $1 in
      -p|--profile)
        if [[ -n "$2" && "$2" != -* ]]; then
          profile="$2"
          shift 2
        else
          echo "Error: -p requires a profile name" >&2
          return 1
        fi
        ;;
      *)
        claude_args+=("$1")
        shift
        ;;
    esac
  done

  echo "Claude Code profile: $profile"
  CLAUDE_CONFIG_DIR="$HOME/.claude-$profile" command claude "${claude_args[@]}"
}

这样就可以用 claude -p work 启动工作账号,claude 不带参数则用个人账号(默认值 personal)。这个方案来自社区,简洁有效,缺点是第一次设置需要手动登录每个 profile。

这里有一个注意点:CLAUDE_CONFIG_DIR 需要绝对路径,写 ~/.claude-work 在某些上下文下可能无法展开,用 $HOME 更安全。

claude-switch 工具(功能最完整)

claude-switch(GitHub: Abhishek21k/claude-switch)是一个专门为 Claude Code 多账号设计的工具,核心命令是 cswitch

# 安装(npm 或 brew)
npm install -g claude-switch

# 把当前已登录的账号保存为 work profile
cswitch add work

# 登录一个新账号并保存为 personal profile
cswitch login personal

# 使用某个 profile 启动 Claude
cswitch use work
cswitch use personal

# 查看所有 profiles
cswitch list

# 打开交互式 TUI 菜单
cswitch

它的机制和上面的 Shell 函数一样,本质上都是把 profiles 存在独立目录(~/.claude-switch/profiles/<name>/),切换时通过 CLAUDE_CONFIG_DIR 告诉 Claude Code 用哪个。工具的亮点在于:第一次运行时会检测你当前已登录的 session,可以选择直接复制而无需重新登录;支持同时在不同终端窗口运行不同账号;支持把常用 profiles 设置为 Shell alias(比如 claude-workclaude-personal)。

macOS 上认证 token 存储在 Keychain 里,每个 profile 完全隔离。

direnv 按目录自动切换(最适合多客户场景)

如果你同时服务多个客户或多个团队,每个客户的项目放在不同目录下,direnv 方案可以做到进入目录就自动切换账号,无需任何手动操作:

~/personal/.envrc           ← 个人项目父目录
~/personal/blog/
~/personal/open-source/
~/work/company/.envrc       ← 公司项目父目录
~/work/company/webapp/
~/clients/acme/.envrc       ← 客户 Acme 项目父目录
~/clients/acme/api/

每个 .envrc 文件只需一行:

# ~/personal/.envrc
export CLAUDE_CONFIG_DIR="$HOME/.claude-profiles/personal"

# ~/work/company/.envrc
export CLAUDE_CONFIG_DIR="$HOME/.claude-profiles/org/company"

# ~/clients/acme/.envrc
export CLAUDE_CONFIG_DIR="$HOME/.claude-profiles/clients/acme"

安装 direnv 并允许这些 .envrc 文件后(direnv allow),每次 cd 进某个目录,对应的 CLAUDE_CONFIG_DIR 就会自动生效,离开目录时自动还原。这个方案还有一个额外的好处:MCP 服务器的认证信息也跟着隔离了,不同客户的 GitHub、Slack、Linear 凭证不会互相混淆。

Codex CLI 的账号存储机制

[[Codex]] CLI 的认证存储比 Claude Code 更直接:~/.codex/auth.json 这个文件就是当前账号的全部认证数据,包含 OAuth token 或 API key。~/.codex/config.toml 是配置文件,支持 profiles 功能(通过 -p 参数选择)。

~/.codex/
├── auth.json              # 当前认证(权限 600)
├── backup_auth.json       # 认证备份
├── config.toml            # 配置文件
└── sessions/              # 会话历史

理解了这个结构,切换方案就很清晰了:只要把不同账号的 auth.json 保存起来,需要时替换,就完成了切换。

Codex CLI 切换方案

codex-profiles 工具

codex-profiles 是一个专门管理 Codex CLI 账号的工具,把切换 auth.json 的操作封装成简洁命令:

# 安装
npm install -g codex-profiles

# 保存当前账号为 work
codex-profiles save --label work

# 保存当前账号为 personal
codex-profiles save --label personal

# 查看所有 profiles
codex-profiles list

# 加载 work 账号
codex-profiles load --label work --force

Profiles 存储在 ~/.codex/profiles/ 目录下,每个 profile 就是一份 auth.json 的副本。切换时 load 命令把对应的 auth.json 复制覆盖到 ~/.codex/auth.json,下次启动 codex 就会使用那个账号。数据完全本地,不会上传到任何地方。

内置 –auth-profile 参数

Codex CLI 在较新版本(commit 2ac14d1)添加了内置的 --auth-profile 参数,专门为 multi-account 场景设计:

# 用指定 auth profile 启动
codex --auth-profile work

# 登录并保存为指定 profile
codex login --auth-profile personal

这是官方原生方案,如果你的 Codex CLI 版本足够新,优先使用这个。用 codex --version 确认版本,然后 codex --help 看看 --auth-profile 是否出现在参数列表里。

环境变量方案

对于使用 API key 认证的场景(推荐用于 CI/CD 或脚本化工作流),最简洁的方式是直接通过环境变量切换:

# 个人账号
export OPENAI_API_KEY="sk-personal-xxxx"
codex

# 工作账号
export OPENAI_API_KEY="sk-work-xxxx"
codex

结合 direnv 同样可以实现进入项目目录自动切换 API key,适合多项目环境。

限制与注意事项

几个使用时需要留意的地方:

对于 Claude Code,CLAUDE_CONFIG_DIR 的隔离并不是百分之百完整。~/.claude/CLAUDE.md 这个全局指令文件,无论 CLAUDE_CONFIG_DIR 指向哪里,都会被加载。此外 ~/.local/state/claude/ 这个状态目录在所有 profiles 间共享,IDE 插件(如 JetBrains)可能也存在兼容性问题。但最关键的认证数据和会话历史是完全隔离的,日常切换已经够用。

对于 Codex,codex-profiles 导出的 bundle 文件包含认证 token,妥善保管,不要提交到 Git 或存放在共享位置。

最后

Claude Code 目前最成熟的方案是 cswitch 工具加上 Shell 函数封装,两者都基于 CLAUDE_CONFIG_DIR 环境变量,原理清晰、易于理解和排障。如果你经常在多个客户项目之间切换,direnv 方案可以彻底解放双手,进目录即自动切换,离开即还原。Codex CLI 则优先看你的版本是否支持内置的 --auth-profile 参数,不支持的话 codex-profiles 是很好的替代选择。

这些方案的共同思路都是:不修改官方工具本身,而是通过环境变量或配置目录隔离来实现多账号共存。一旦理解了这个核心机制,遇到其他 CLI 工具需要多账号切换时,也可以举一反三地应用。

socat:比 netcat 更强大的网络瑞士军刀

2026-05-12 13:00:00

socat 网络数据流示意图

在 Linux 网络工具箱里,大多数人都知道 [[netcat]](nc),遇到要临时监听端口、传文件、测连通性,第一反应就是 nc。但用了一段时间之后我发现,[[socat]] 才是那个被严重低估的工具——它不仅能做 netcat 的一切,还能做很多 netcat 根本做不到的事,比如 SSL 加密通信、Unix socket 代理、串口转 TCP,以及真正灵活的双向数据流转发。

这篇文章我想把自己用 socat 的经验好好梳理一遍,从基础概念到实战场景,争取让你看完之后不再只会用 netcat 了。

socat 是什么

socat 的全称是 SOcket CAT,名字直接说明了它的设计思路——把各种类型的数据流(socket)像 cat 一样连接起来。官方的描述是”建立两个双向字节流并在它们之间传输数据”,听起来有点抽象,但换个说法就清楚了:socat 可以把任意两个”地址”连接起来,数据在两端之间双向流动。

这里的”地址”可以是 TCP 端口、UDP 端口、Unix socket、文件、管道、设备(比如串口 /dev/ttyS0)、甚至标准输入输出。这种设计让 socat 的应用场景非常广泛,而不像 netcat 那样主要局限在 TCP/UDP 的范畴内。

安装也很简单:

# Debian/Ubuntu
sudo apt install socat

# macOS
brew install socat

# CentOS/RHEL
sudo yum install socat

核心语法与基本概念

socat 的命令格式很固定:

socat [options] <address1> <address2>

两个地址之间会建立双向数据流。地址的格式通常是 TYPE:parameters,比如 TCP:127.0.0.1:8080UDP-LISTEN:9000STDINFILE:/tmp/data.txt 等。

几个最常用的地址类型:

  • TCP:<host>:<port> — 连接到某个 TCP 地址
  • TCP-LISTEN:<port> — 监听某个 TCP 端口
  • UDP:<host>:<port> / UDP-LISTEN:<port> — UDP 版本
  • STDIN / STDOUT — 标准输入输出
  • FILE:<path> — 读写文件
  • UNIX-CONNECT:<path> / UNIX-LISTEN:<path> — Unix domain socket
  • OPENSSL:<host>:<port> — SSL/TLS 连接
  • EXEC:<command> — 执行命令并连接其 stdin/stdout

端口转发:最高频的使用场景

端口转发大概是我用 socat 最多的场景。比如你在内网有一台机器,只有 22 端口对外开放,但你想在本地直接访问那台机器上的 Web 服务(假设跑在 8080)。用 socat 一行搞定:

# 在跳板机上运行:将本地 8888 转发到目标机器的 8080
socat TCP-LISTEN:8888,fork TCP:target-host:8080

这里的 fork 参数很重要,它让 socat 在接受一个连接后继续监听,而不是只处理一次就退出。没有 fork 的话,socat 接受第一个连接处理完就会停止,这显然不是我们想要的行为。

如果要把本地的 UDP 端口转发出去:

socat UDP-LISTEN:5353,fork UDP:8.8.8.8:53

还有一个我经常用到的场景:把 IPv6 地址桥接给只支持 IPv4 的程序访问。比如本地服务只绑定在 IPv4,但你想从 IPv6 客户端访问:

socat TCP6-LISTEN:8080,fork TCP4:127.0.0.1:8080

替代 netcat 做简单通信

用 socat 做简单的 TCP 监听和连接,和 netcat 几乎一样直观。

在服务端监听:

socat TCP-LISTEN:12345 STDOUT

在客户端连接发送数据:

echo "hello from socat" | socat - TCP:server-ip:12345

传文件也很方便,接收端先开好监听:

socat TCP-LISTEN:12345 > received_file.tar.gz

发送端:

socat - TCP:server-ip:12345 < local_file.tar.gz

比起 netcat,socat 的好处是行为更可预测,不同平台的 netcat 实现差异很大(BSD 版和 GNU 版语法有不少差异),而 socat 的行为跨平台高度一致。

Unix Socket 代理:解决权限问题的妙用

这个场景在容器和 CI/CD 环境里特别实用。Docker daemon 的 socket 默认在 /var/run/docker.sock,只有 root 或 docker 组的用户才能访问。如果你在某个受限环境里需要让普通用户或某个进程访问 Docker API,可以用 socat 在 TCP 端口上暴露一个代理:

socat TCP-LISTEN:2375,fork UNIX-CONNECT:/var/run/docker.sock

之后就可以通过 DOCKER_HOST=tcp://127.0.0.1:2375 来使用 Docker 客户端,不再受 socket 权限限制。当然,这样做要注意安全问题,仅在受控环境中使用。

反过来,如果某个工具只支持 Unix socket,但你的服务暴露的是 TCP 端口,也可以反向代理:

socat UNIX-LISTEN:/tmp/myapp.sock,fork TCP:127.0.0.1:3000

SSL/TLS 加密通道

这是 socat 相对于 netcat 最大的优势之一。你可以用 socat 快速建立一个加密通道,不需要额外配置 nginx 或 stunnel。

先生成自签证书:

openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 365 -out server.crt
cat server.key server.crt > server.pem

服务端启动加密监听:

socat OPENSSL-LISTEN:443,cert=server.pem,verify=0 TCP:127.0.0.1:8080

客户端连接:

socat TCP-LISTEN:8080,fork OPENSSL:server-host:443,verify=0

verify=0 表示不验证证书(适合自签证书的测试场景),生产环境应该正确配置 CA 证书验证。

串口通信转 TCP

这个功能是 socat 独有的,netcat 完全做不到。在嵌入式开发或者工业设备调试中,经常需要把串口数据转发到网络上,让远程的机器能够访问本地的串口设备:

# 把本地串口 /dev/ttyUSB0 转发到 TCP 9600 端口
socat TCP-LISTEN:9600,fork /dev/ttyUSB0,raw,echo=0,b115200

b115200 是波特率设置,raw 表示原始模式,echo=0 关闭回显。另一端可以用 socat 连接这个 TCP 端口,就像直接操作本地串口一样。

在脚本里动态测试端口连通性

socat 可以用来替代 telnet 做端口连通性测试,而且更适合在脚本里使用:

# 测试 TCP 端口是否可达,超时 5 秒
socat /dev/null TCP:target-host:8080,connect-timeout=5
echo $?  # 0 表示成功,非0 表示失败

比 telnet 好的地方在于 socat 的退出码很规范,适合脚本判断,而 telnet 在不同系统上行为不一致。

几个实用的小技巧

在使用 socat 的过程中,我积累了一些提升体验的习惯:

加上 -d -d 可以开启详细日志,排查问题时非常有用:

socat -d -d TCP-LISTEN:8080,fork TCP:backend:8080

对于需要长期稳定运行的转发,可以配合 systemd 或者 supervisor 来管理进程,而不是直接跑在 shell 会话里,避免断开 SSH 后转发失效。

reuseaddr 选项可以避免”地址已在使用”的错误,在频繁重启的开发场景下很实用:

socat TCP-LISTEN:8080,reuseaddr,fork TCP:backend:8080

对于需要多个并发连接的场景,默认的 fork 模式已经够用;但如果担心 fork 带来的开销,可以用 TCP-LISTEN:port,fork,max-children=50 限制最大子进程数。

最后

socat 是那种乍看文档有点发怵、但真正上手之后会让你爱不释手的工具。它的地址格式设计非常正交——理解了”两个地址之间建立双向流”这个核心模型,几乎所有用法都能举一反三。端口转发、协议转换、加密隧道、串口桥接,这些场景在日常运维和开发调试中比你想象的出现得更频繁。

我现在遇到网络调试的需求,第一反应已经从 nc 变成了 socat,主要因为它的行为更一致、功能更全面,而且在 SSL 和 Unix socket 这些场景上完全没有替代品。如果你还没把它放进自己的工具箱,值得花半个小时好好熟悉一下。

cc-switch:在多个 AI 编码工具之间优雅切换

2026-05-04 13:00:00

最近这一年,AI 编码工具的竞争进入了白热化阶段。[[Claude Code]]、[[Gemini CLI]]、[[OpenAI Codex]],每家都在拼命迭代,功能差距越来越小,价格战也越打越猛。于是我开始同时订阅好几个服务,针对不同的任务选用不同的工具——写复杂逻辑用 Claude,快速查文档用 Gemini,处理 Python 脚本用 Codex。

但问题随之而来:每次切换,我都要打开 ~/.config/ 下的各种配置文件,手动修改 API Key,重新指定默认命令,还要把 MCP 服务器的配置从一个工具迁移到另一个工具。这套操作做了几十次之后,我开始觉得这不是”使用多个工具”,而是”在维护多套配置文件”。

这就是 cc-switch 出现的原因。

在日常开发中,或多或少的可能遇到如下的痛点

  • 频繁切换多个 API 供应商,官方,中转服务,每次都需要手动修改文件
  • 配置分散,难以管理,Claude,Codex,Gemini,OpenCode,OpenClaw 各有独立的配置文件
  • 无法监控使用量,不知道 API 调用的次数和数量

cc-switch 统一管理多个 AI 编码工具

多工具并用的真实痛点

在聊 cc-switch 能做什么之前,我想先把痛点说清楚,因为只有真正踩过这些坑的人才会觉得它有价值。

第一个痛点是 API Key 管理混乱。每个工具都有自己存储 Key 的地方,有些放在环境变量里,有些放在 TOML 配置文件里,有些藏在工具自己的 config 目录下。一旦需要切换账号(比如从个人账号切到公司账号,或者切换到第三方代理),这些地方都要改一遍,漏改一处就会出现莫名其妙的认证错误。

第二个痛点是 [[MCP]] 服务器的重复配置。[[Model Context Protocol]] 是目前主流 AI 工具扩展能力的标准方式,我在 Claude Code 里配置了一堆 MCP 服务器之后,发现切换到 Gemini CLI 又要重新配置一遍,而且两边的配置格式还不完全一样。久而久之,两边的配置开始出现不一致,某些工具能用某个 MCP 服务,另一个工具却找不到。

第三个痛点是余额不透明。当你同时订阅了好几个 AI 服务,又对接了第三方代理,每个服务的用量和余额分散在不同的控制台里,根本无法一眼看出今天用了多少、还剩多少。

cc-switch 针对这三个痛点都给出了答案。

cc-switch 是什么

cc-switch 是一款面向开发者的 AI 编码 CLI 工具管理器,支持在 [[Claude Code]]、[[Gemini CLI]]、[[OpenAI Codex]]、[[OpenCode]] 等主流工具之间一键切换。它提供桌面端 GUI 版本和纯命令行版本(cc-switch-cli)两个选择,功能基本对等。

它的定位不是替代任何一个 AI 编码工具,而是作为这些工具上面的一层管理层,把散落各处的配置、密钥、模型选择和 MCP 服务器统一集中到一个地方。

核心功能解析

cc-switch 的功能设计非常务实,每一项都直接对应一个具体的痛点。

一键切换 AI 提供商是最核心的能力。打开 cc-switch,主界面会列出所有已安装的 AI CLI 工具,选择目标工具后,cc-switch 会自动完成背后的切换操作——修改系统默认命令指向、切换活跃的配置文件、更新环境变量。这个过程原本需要手动操作好几个地方,现在变成了一次点击。

统一的 MCP 服务器管理是我个人最看重的功能。通过 cc-switch,我只需要配置一次 MCP 服务器列表,它会负责把这份配置同步到所有已安装的 AI 工具中。这样不管我当前切换到哪个工具,都能使用同一套 MCP 扩展能力。

余额与额度的可视化展示也解决了我日常的困扰。cc-switch 支持直接读取官方 Claude、Gemini、Codex 的余额信息,同时也支持 Token Plan、[[Copilot]] 以及各类第三方代理 API 的余额查询,集中展示在一个界面里,省去了逐一登录控制台的麻烦。

此外,cc-switch 还内置了连接诊断工具,可以针对每个提供商做速度测试和流式响应健康检查,帮助快速定位”为什么这个工具今天特别慢”这类问题。对于 [[Claude Code]] 用户,它还支持管理 Skills 扩展插件,省去了手动维护 .claude/skills/ 目录的操作。

安装与使用

桌面版从 GitHub Releases 下载对应平台的安装包,双击安装即可,没有特别的前置依赖。

CLI 版本的安装方式:

npm install -g cc-switch-cli

或者直接用 npx 运行,不需要全局安装:

npx cc-switch-cli

启动后进入交互式界面,用方向键选择目标工具,回车确认即完成切换。第一次使用时会引导你添加各个工具的 API Key 和配置信息,之后就不需要再手动操作了。

MCP 服务器的配置也在同一个界面完成,添加一次之后 cc-switch 会自动同步到所有已注册的工具。

适合哪类开发者

cc-switch 对以下几类人最有价值:同时订阅了多个 AI 编码服务、需要根据任务特点选用不同工具的开发者;使用第三方代理(如 [[OpenRouter]]、各类国内中转 API)并且需要频繁切换 endpoint 的用户;以及对 AI 工具使用成本比较敏感、需要实时监控余额的场景。

如果你只用一个 AI 工具,并且没有多账号切换的需求,cc-switch 对你的价值就很有限了,这点需要说清楚。

潜在风险与注意事项

cc-switch 集中管理了所有 AI 工具的 API Key,这在带来便利的同时也意味着需要信任这个工具的安全实现。建议在使用前看一下它的源码,确认 Key 是本地存储而不是上传到任何服务器。

另一个需要关注的点是版本兼容性。cc-switch 依赖对各个 AI 工具配置文件格式的理解,一旦 Claude Code 或 Gemini CLI 更新了配置结构,cc-switch 可能会出现短暂的滞后期,这段时间内某些功能可能不可用。关注项目的 issue 和 release 页面是个好习惯。

Tangled:基于 AT Protocol 的去中心化代码托管平台

2026-05-01 13:00:00

最近一段时间,我对去中心化互联网的兴趣越来越浓。[[Bluesky]] 的崛起让我第一次真正感受到 [[AT Protocol]] 的魅力——不是从概念上,而是实际体会到”带着自己的身份换平台”是什么感觉。然后,我发现了 [[Tangled]]。

Tangled 是一个建立在 AT Protocol 上的代码托管与协作平台,定位是 [[GitHub]] 的去中心化替代。第一次打开 tangled.org,界面整洁得出乎意料,仓库列表、Issue、Pull Request,一切都那么熟悉,但背后的逻辑已经完全不一样了。

Tangled 去中心化代码托管平台

Tangled 是什么

Tangled 是由芬兰创业公司 Tangled Labs Oy 开发的去中心化代码托管平台。2025 年初正式向公众开放,2026 年 3 月完成了 450 万美元的融资。目前平台已有超过 7000 名用户和 5000 个仓库,发展速度相当不错。

它的核心理念是:代码托管不应该绑定在某一家公司的服务器上。 开发者应该真正拥有自己的数据,社区应该能够自我治理,而不是被平台规则左右。这不是一句空话——Tangled 的整个架构都是围绕这个目标设计的。

AT Protocol 带来的身份革命

理解 Tangled 之前,需要先了解 [[AT Protocol]](Authenticated Transfer Protocol),也就是 Bluesky 背后的协议。

AT Protocol 的精髓在于将用户身份从应用层剥离出来。你的账号属于你选择的 PDS(Personal Data Service,个人数据服务),而不是某个具体的 App。就像你的手机号码可以携号转网一样,你的 AT Protocol 账号可以迁移到不同的应用和服务商,而你的社交关系和数据跟着走。

这对代码托管意味着什么?你在 Tangled 上积累的 Star、Follow、Issue 评论记录,都存储在 AT Protocol 网络中,而不是 Tangled 公司的数据库里。如果 Tangled 哪天关门了,数据不会消失。如果你不满意 Tangled 的服务,你可以带着身份和数据切换到另一个兼容 AT Protocol 的代码托管服务。

如果你已经有了 Bluesky 账号,直接用同一个 handle 就能登录 Tangled。没有账号也没关系,注册时选择 Tangled 自己运营的 PDS(tngl.sh),会分配一个 user.tngl.sh 格式的 handle。

Knots:分布式仓库存储的核心

Tangled 架构里最有意思的概念是”Knot”(结节)。

每个 Knot 都是一个轻量级的、无状态的 Git 服务器。你的代码仓库实际存储在 Knot 上,而不是 Tangled 的中央服务器上。Tangled 的 appview(应用视图)相当于一个聚合器,它把散落在不同 Knot 上的仓库统一呈现出来,让用户可以无缝地访问、克隆和贡献代码,而不用关心这些代码物理上存储在哪里。

这个设计有几个实际好处。首先,你可以在自己的服务器上自托管 Knot,代码从不离开你的机器。其次,Knot 支持单用户和多用户两种模式,既适合在家里的树莓派上单独运行,也适合作为社区服务器使用。默认情况下,Tangled 提供免费的托管 Knot,普通用户不需要自己折腾服务器。

仓库的”地址”绑定在所有者的 DID(去中心化标识符)上,而不是某台服务器的域名上。这意味着即使仓库从一台服务器迁移到另一台,链接依然有效,类似 DOI 之于学术论文的作用。

功能概览

Tangled 的功能集已经相当完整,并且在一些地方做出了有趣的创新。

Pull Request 与 Jujutsu 支持

Tangled 的 Pull Request 系统采用了”轮次(round)”的提交与审查模式,而非传统的单一线性流程。每次修改都作为一个新的轮次提交,使得审查历史更清晰,reviewer 能更好地跟踪每一轮的变化。

更值得关注的是,Tangled 是目前已知第一个代码托管平台支持 [[Jujutsu]](jj)的 stacked pull request 工作流。Jujutsu 是一个新兴的版本控制系统,在处理一系列相互依赖的变更时比 Git 更直观。Tangled 团队自己也在日常开发中使用 Jujutsu,因此支持得很到位。

Spindle:自研 CI 系统

CI 是 Tangled 用户呼声最高的功能需求,团队考虑过接入第三方平台,但最终选择自研——于是有了 Spindle。

Spindle 基于 Nix 和 Nixery 构建 CI 镜像,支持按需动态创建环境,并带有缓存机制。目前还处于早期阶段,使用 Docker/Nixery 引擎,后续计划迁移到微型虚拟机以支持完整的 NixOS 和其他系统镜像。Spindle 也是 AT Protocol 原生的,这意味着 CI 的触发和结果都能整合进去中心化的数据流中。

Issues 与标签系统

Issues 经过了一次完整的重设计,现在支持线程式讨论——顶层评论下可以有回复,更适合有深度的技术讨论。

标签系统也做得比较灵活。除了普通标签,还支持 key-value 格式的标签(如 priority/high),以及约束了取值范围的标签(如 priority: [high medium low])。多个相同类型的标签也可以同时存在,比如同一个 Issue 可以有多个 reviewed-by 标签。

静态网站托管

每个 Tangled 用户都有一个专属的子域名,可以直接从 Git 仓库部署静态网站,类似 [[GitHub Pages]] 的功能。注册 tngl.sh 账号的用户,网站域名是 username.tngl.sh;使用其他 PDS 的用户则可以申请一个 username.tngl.io 域名。

通知系统

应用内通知现已覆盖主要事件:有人在你的仓库开 Issue 或 PR、有人评论了你参与的 Issue/PR、Issues 被关闭或合并、有人给你的仓库 Star 或关注了你。这些通知都可以在设置中精细调整。

AI 代理支持

Tangled 明确将 AI 纳入了产品规划。通过完整的 XRPC API,AI 代理可以作为代码贡献者参与项目——创建仓库、提交 Pull Request、执行代码审查。对于想要在工作流中集成 AI 助手的团队来说,这是一个很实用的接口。

如何开始使用

上手非常简单,直接访问 tangled.org

如果有 Bluesky 账号,用现有的 handle 登录即可,两个平台共享同一套身份体系。如果没有,注册新账号时会在 tngl.sh 上创建 PDS,整个过程就像普通的网站注册。

登录后,界面和 GitHub 非常相似:创建仓库、设置说明、选择初始化选项,然后用标准的 Git 命令推送代码就行了。SSH 密钥的配置方式也和 GitHub 一致。

克隆仓库时,地址格式是 [email protected]:username/repo-name.git,不需要额外学习新的工具链。

自托管 Knot:真正的数据自主

对于有服务器的人来说,自托管 Knot 是一个很有吸引力的选择。你的代码完全存储在自己的机器上,只是通过 AT Protocol 的身份和数据流接入 Tangled 的生态。

官方提供了 Docker 镜像,配置主要包括设置所有者的 DID 和对外暴露服务端口。部署完成后,你的私有 Knot 会出现在 Tangled 的网络中,其他用户可以访问你的公开仓库,你也可以用 SSH 直接推送代码。如果哪天你不想用 Tangled 了,代码还在你自己的服务器上,Git 仓库可以随时镜像到其他地方。

最后

Tangled 解决的本质问题是:为什么代码托管必须是中心化的?

GitHub 目前拥有大约 88% 的市场份额,这种集中程度对整个开源生态其实是一种隐患。Tangled 不是要颠覆 GitHub,而是在探索另一种可能——一个开发者真正拥有数据所有权的代码协作世界。

目前 Tangled 还处于早期,功能还在快速迭代。但 AT Protocol 的身份基础、Knot 的分布式存储、以及团队对 Jujutsu 等新工具的拥抱,都让我觉得这个方向是对的。至少,现在是个参与进来的好时机——在它还小的时候,你的反馈更容易被听到,社区也更有可能因你的参与而变得更好。

如果你已经有了 Bluesky 账号,不妨今天就去 tangled.org 看一看。