乐于分享
好东西不私藏

Claude Code泄露源码深度解析:揭秘其硬核通信架构

Claude Code泄露源码深度解析:揭秘其硬核通信架构

Claude Code 

从意外开源看顶流AI编程工具的网络通信

Comm Arch

前阵子,Claude Code 意外泄露源码的“事故”在技术圈闹得沸沸扬扬。虽然对 Anthropic 来说有点尴尬,但对广大开发者而言,这简直是一场送上门的“开卷考试”——我们终于得以绕开黑盒,拿着放大镜去围观这款顶流 AI 编程工具的底层实现。借着这次意外的“开源”,今天我们不聊它的 Prompt 有多花哨,就硬核扒一扒它的网络通信机制。很多人第一次上手 Claude Code,会下意识把它当成一个“会调用模型的命令行工具”。但翻看源码后你会发现,格局小了——它的骨架远比“发一个请求、收一段回复”复杂得多。它更像是一套严密的远程协作系统。本地终端只是一个入口,真正的工作是在一个持续在线的会话里完成的。消息来回流转、权限即时确认、断线自动重连……整套机制用一句话概括就是:它不是在“请求一次 AI”,而是在“维持一个长期的会话现场”。以下是我们从源码中提炼出的核心通信架构,看看这套“顶配”的工程设计到底牛在哪里。

一、中枢神经:真正的总控 RemoteSessionManager

01

在源码中,整套网络通信的“中枢神经”是一个叫做RemoteSessionManager的模块。它负责把所有通信的线头拴在一起。

它做的事情本质上只有四件:建立连接、分发消息、处理权限请求、发送控制指令。

你可以把它想象成一个现场调度员:

服务端发来消息,它负责接住。用户要发消息,它负责送出去。远端模型需要调用本地工具的权限,它负责拦截并转给上层(用户)确认。如果连接意外断开,它负责通知并尝试恢复。

它未必是业务逻辑最复杂的代码,但绝对是通信链路最核心的枢纽。

二、读写分离:WebSocket 听令,HTTP POST 汇报

02

Claude Code 的会话通信,最核心的设计思路非常朴实:读写分离。

它并没有把所有通信都塞进一条通道里,而是根据场景拆分了协议:

读(下行):通过 WebSocket 持续接收服务端消息。适合“服务端不断推消息下来”的持续订阅场景。写(上行):通过 HTTP POST 把用户输入和事件发回去。适合“单次明确提交”的场景。

1. WebSocket:实时消息的主干道

接收远端消息走的是 WebSocket 订阅。源码中它的连接形式非常干净:

const url = `wss://…/v1/sessions/ws/

${sessionId}/subscribeorganization_uuid=…`

const headers = {

  Authorization: `Bearer ${accessToken}`,

  ‘anthropic-version’: ‘2023-06-01’,

}

这里藏着几个极具工程素养的细节:

不迷信长连接:每次重新连接前都会重新获取一次 token,默认考虑到“认证可能过期”的现实情况。精细的断线处理:遇到 4003 错误码视为永久拒绝(不再重连),遇到 4001 视为暂时不可用(允许有限重试)。它不是个无脑重试的机器,而是个懂语义的通信系统。心跳保活:定时 ping,防止被中间网络设备掐断(长连接系统里最无聊但也最救命的机制)。

2. HTTP POST:真正的写入通道

用户输入和事件提交并不走 WebSocket,而是构造成带有明确“事件语义”的数据包,通过 HTTP POST 发送到接口:

const requestBody = {

  events: [

    {

      uuid: ‘…’,

      session_id: sessionId,

      type: ‘user’,

      parent_tool_use_id: null,

      message: {

        role: ‘user’,

        content: messageContent,

      },

    },

  ],

}

这种设计的好处是发送行为清晰、失败可感知、便于重试。Claude Code 传的不是一句话,而是一整段会话中的一个“事件节点”。

三、秩序之美:内容归内容,控制归控制

03

服务端发来的消息如果像一锅粥一样混在一起,系统很快就会崩溃。Claude Code 的消息流设计了一套非常成熟的分层协议。

消息大致被分为三类:

普通消息:比如助理回复的内容、系统状态、工具执行进度。这些是用户真正看到的“正文”。control_request(控制请求):服务端向客户端发出的控制信号。比如“我需要确认这个工具能不能用”、“中断当前请求”。control_response(控制响应):客户端对控制请求的答复。

这套机制将“内容流”和“控制流”完美剥离。聊天内容绝不会和权限请求混在一起,UI 界面知道该渲染什么,服务端也清楚自己是在等用户拍板,还是在继续生成代码。

四、最精彩的一环:远端工具权限审批流

04

Claude Code 作为 AI 编程工具,最大的特点是它能操作本地文件、执行命令。这些动作伴随着高风险,因此权限请求绝对不能含糊。

当服务端发来control_request(且类型为can_use_tool)时,系统会进入一套严密的时序协议:

服务端请求权限。客户端记录该请求,并挂起等待。上层 UI 弹出确认框(允许/拒绝)。客户端将用户的决定封装成 control_response 发回服务端。服务端收到确认后,继续执行后续动作。

这不是多此一举,而是远程代理系统必须死守的安全边界。如果请求被取消,本地会清掉等待状态;如果找不到请求 ID,会直接报错。它对权限的要求是:必须明确可追踪,绝不能悬空。

五、幕后功臣:消息“同声传译”与本地调度

05

机器的语言,人不一定想看。因此在底层协议和前端 UI 之间,Claude Code 还有两层很关键的设计:

1. 消息翻译器(适配层)

服务端发来的 SDK 消息需要被转换成 UI 能理解的格式。比如:

TypeScript

if (msg.type === ‘system’ && msg.subtype === ‘status’) {

  return `Status: ${msg.status}` // 将内部状态转化为友好的前端提示

}

服务端在说“我内部状态变了”,翻译器把它变成人话:“正在压缩对话…”。

2. 本地交通枢纽(Bridge 层)

Bridge 层负责本地的消息调度。它的工作包括:

过滤噪音:把不需要送到远端的内部虚拟消息拦截下来。消息去重:利用 UUID 和时间窗口,防止重连或历史回放导致同一条消息/权限请求出现两次。极速响应:保证对控制请求的快速答复,防止服务端超时。

结语:不追求花哨,追求工程级的“稳”

如果把 Claude Code 的核心时序画出来,其实非常克制:

TypeScript

// 1. 建立长连接监听

connectWebSocket()

// 2. 接收与分发

onMessage(msg) {

  if (msg.type === ‘control_request’) handlePermissionRequest(msg)

  else renderOrDispatch(msg)

}

// 3. HTTP 提交用户输入

sendMessageToSession({ type: ‘user’, message: { … } })

// 4. 权限审批回传

sendControlResponse({ type: ‘control_response’, response: { … } })

读完这段因“意外泄露”而曝光的代码,最大的感受是:真正成熟的网络系统,往往不追求花哨的炫技,而是追求架构的清晰与可持续。

它告诉我们:一个终端工具是如何通过长连接保持活性,如何用事件接口承担写入,如何把权限请求变成严密的时序协议,最终长成了一个稳健的“轻量级远程协作平台”。

这,才是 Claude Code 藏在惊艳表现下,最硬核的技术底色。

END

本站作品均采用知识共享署名-非商业性使用-相同方式共享 4.0进行许可,资源收集于网络仅供用于学习和交流,本站一切资源不代表本站立场,我们尊重软件和教程作者的版权,如有不妥请联系本站处理!

 沪ICP备2023009708号

© 2017-2026 夜雨聆风   | sitemap | 网站地图