Skip to content

应用服务器协议 — 练习

练习 1:分析协议消息格式

阅读协议定义,分析请求和响应消息的完整格式。

参考答案

App Server Protocol 使用 JSON-RPC 2.0 格式,ClientRequest 通过宏生成 60+ 个变体,每个变体包含:

  1. 请求格式

    json
    {
      "jsonrpc": "2.0",
      "id": 1,
      "method": "submitOp",
      "params": { "thread_id": "...", "op": { "UserInput": { "content": "..." } } }
    }

    每个请求有唯一的 request_idRequestId 类型)和强类型的 params

  2. 响应格式

    json
    {
      "jsonrpc": "2.0",
      "id": 1,
      "result": { "success": true }
    }
  3. 通知格式(服务器推送):

    json
    {
      "jsonrpc": "2.0",
      "method": "turnItemUpdated",
      "params": { "thread_id": "...", "item": { ... } }
    }
  4. 序列化作用域ClientRequestSerializationScope 控制请求的并发执行。例如 Thread { thread_id } 作用域确保同一线程的请求串行执行,而不同线程可以并发。

  5. 认证AuthMode 枚举定义四种认证方式,在连接建立时协商。AgentIdentity 用于自动化场景,Chatgpt 用于交互式登录。

协议定义在 app-server-protocol/src/protocol/common.rs 中,通过 Rust 宏自动生成序列化/反序列化代码。

练习 2:追踪 Backend Client 调用

追踪一次完整的 LLM 后端调用流程,从请求构建到响应处理。

参考答案

Backend Client 的完整调用流程(core/src/client.rs):

  1. 创建 ModelClientSession

    • ModelClient::new_session() 创建 turn-scoped 的会话
    • 检查缓存的 WebSocket 连接是否可用
  2. 传输选择

    • 优先 WebSocket:prewarm_websocket() 预热连接
    • 若 WebSocket 不可用(disable_websockets = true 或连接失败),降级到 HTTP SSE
    • force_http_fallback() 方法强制使用 HTTP
  3. 请求构建

    • ModelClientSession::stream() 构建请求
    • 注入认证头(X_CODEX_INSTALLATION_ID_HEADERX_CODEX_TURN_STATE_HEADER
    • 包含上下文数据(system prompt + history + tools)
    • enable_request_compression,压缩请求体
  4. 发送请求

    • WebSocket:发送增量 delta(只发送变化部分)
    • HTTP SSE:POST 到 /responses 端点
    • 两者都使用 Responses API 格式
  5. 接收响应

    • 返回 ResponseStream(异步流)
    • WebSocket:通过 send_response_processed() 确认接收
    • SSE:通过 EventSource 解析 SSE 事件
  6. 响应处理

    • ResponseStream 产生 ResponseEvent 变体
    • Session 解析事件,提取文本输出和工具调用
    • turn_state 记录 turn 的状态

自定义 HTTP 头:

  • X_CODEX_INSTALLATION_ID_HEADER:安装 ID
  • X_CODEX_TURN_STATE_HEADER:turn 状态
  • X_CODEX_TURN_METADATA_HEADER:turn 元数据
  • X_RESPONSESAPI_INCLUDE_TIMING_METRICS_HEADER:性能指标

练习 3:分析会话生命周期

分析一个完整会话从创建到销毁的生命周期管理。

参考答案

会话生命周期在 App Server 的多个模块协同管理:

  1. 创建阶段

    • 客户端发送 ClientRequest::StartThread(或类似)
    • MessageProcessor 路由到 request_processors
    • ThreadState 创建新线程,调用 Codex::spawn(CodexSpawnArgs)
    • CodexSpawnArgs 包含完整的初始化参数(config、auth、models_manager、mcp_manager 等)
    • 返回 thread_id 给客户端
  2. 活跃阶段

    • 客户端通过 submit(Op) 提交操作
    • thread_events 处理代理事件,通过 OutgoingMessageSender 推送
    • config_manager 支持运行时配置变更
    • dynamic_tools 支持运行时添加/移除工具
    • mcp_refresh 监控 MCP 配置变更并热更新
  3. 恢复阶段

    • 客户端断开后,线程状态保存在 ThreadState
    • 重连后通过 thread_id 恢复
    • Session 通过 apply_rollout_reconstruction() 重建对话历史
  4. 终止阶段

    • 客户端请求关闭:shutdown_and_wait()
    • SessionLoopTermination 管理事件循环的优雅退出
    • 清理 ModelClient 的 WebSocket 连接
    • 释放 McpConnectionManager 的所有连接
    • RolloutRecorder 持久化最终状态
  5. 归档

    • 用户可选择归档线程
    • 归档的线程存储在 ARCHIVED_SESSIONS_SUBDIR
    • 活跃线程存储在 SESSIONS_SUBDIR

拓展挑战

  • 分析 ClientRequest 宏的生成逻辑,理解如何定义新的请求类型
  • 研究 in_process 模式如何避免序列化开销
  • 分析 TransportEvent 的所有变体和传输层状态机
  • 追踪 McpRefresh 的配置热更新流程