V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
cexll
V2EX  ›  程序员

Claude Code 实现完全揭秘 - 抓包与逆向

  •  
  •   cexll ·
    cexll · 7 小时 44 分钟前 · 1251 次点击

    Claude Code 实现完全揭秘 - 抓包与逆向

    作者: stellarlink 地址 https://mp.weixin.qq.com/s/Wakz1aWfCygl8xskdfg1Pw


    Claude Code 代码与接口完全揭秘

    通过抓包与逆向打开黑盒

    通过接口抓包代码逆向,我们可以完整了解 Claude Code 的全貌,并学习其实现来打造自己的 Agent 。

    抓包工具 claude-trace^[1]^

    本文基于以下关键材料:

    代码实现层 (request):

    • Go 实现 (agent.go) - 核心 Agent 循环
    • 完整系统提示词 (system-prompt) - 行为约束与工具策略
    • 工具定义 (tools.json) - 15+ 工具的 JSON Schema

    接口设计层 (response):

    • 真实 API 请求体 - 完整的消息结构、工具数组、缓存策略
    • SSE 流式响应 - model 选择、token 计数、流式输出协议

    通过对比 request(代码如何组装请求)与 response(Anthropic 如何设计接口与选择模型),我们将揭秘:

    • Agent 核心循环代码
    • 系统提示词如何塑造行为
    • 工具定义即能力边界
    • MCP 与 Skills 的本质区别(80% 上下文节省)
    • Prompt Caching 如何节省 90% 成本

    让我们从最简单的代码开始,一步步看透 Claude Code 的全部技术细节。


    第一部分:核心循环

    1.1 主循环

    打开 agent.go,第 374-432 行是整个 Agent 的核心:

    func query(cfg Config, messages []Message) ([]Message, error) {
        sysPrompt := fmt.Sprintf(systemPrompt, cfg.WorkDir)
    
        for idx := 0; idx < maxAgentIterations; idx++ {
            spin := newSpinner("Waiting for model")
            spin.Start()
            resp, err := callOpenAI(cfg, fullMessages)
            spin.Stop()
    
            if err != nil {
                return messages, err
            }
    
            // 打印文本内容
            if assistantMsg.Content != "" {
                fmt.Println(assistantMsg.Content)
            }
    
            // 检查是否有 tool calls
            if choice.FinishReason == "tool_calls" && len(assistantMsg.ToolCalls) > 0 {
                // 执行所有工具
                for _, tc := range assistantMsg.ToolCalls {
                    result := dispatchToolCall(cfg, tc)
                    messages = append(messages, result)
                    fullMessages = append(messages, result)
                }
                continue
            }
    
            // 跟踪没有使用 todo 的轮次
            agentState.mu.Lock()
            agentState.roundsWithoutTodo++
            if agentState.roundsWithoutTodo > 10 {
                ensureContextBlock(nagReminder)
            }
            agentState.mu.Unlock()
    
            return messages, nil
        }
    
        return messages, errors.New("agent max iterations reached")
    }
    

    核心逻辑可以总结为三步:

    1. 调用模型 - 等待 LLM 响应
    2. 执行工具 - 如果模型请求工具调用,执行并返回结果
    3. 循环 - 重复直到模型返回最终答案或达到最大迭代次数

    对比传统 Agent 框架动辄几千行的状态管理代码,这种极简设计令人震撼。

    1.2 工具分发:Unix 哲学的体现

    第 515-567 行的 dispatchToolCall 函数展示了工具调用的处理方式:

    func dispatchToolCall(cfg Config, tc ToolCall) Message {
        // 解析参数
        var input map[string]interface{}
        json.Unmarshal([]byte(tc.Function.Arguments), &input)
    
        // 显示工具调用
        var displayText string
        switch tc.Function.Name {
        case "TodoWrite":
            displayText = "updating todos"
        default:
            displayText = fmt.Sprintf("%v", input)
        }
        prettyToolLine(tc.Function.Name, displayText)
    
        var result string
        var err error
    
        // 分发到具体工具
        switch tc.Function.Name {
        case "Bash":
            result, err = runBash(cfg, input)
        case "Read":
            result, err = runRead(cfg, input)
        case "Write":
            result, err = runWrite(cfg, input)
        case "Edit":
            result, err = runEdit(cfg, input)
        case "TodoWrite":
            result, err = runTodoUpdate(cfg, input)
        default:
            err = fmt.Errorf("unknown tool: %s", tc.Function.Name)
        }
    
        if err != nil {
            result = err.Error()
        }
    
        prettySubLine(clampText(result, 2000))
    
        return Message{
            Role:       "tool",
            ToolCallID: tc.ID,
            Name:       tc.Function.Name,
            Content:    clampText(result, cfg.MaxResult),
        }
    }
    

    每个工具都是独立的纯函数,输入参数,输出结果,不维护任何状态。这正是 Unix 哲学 "Do one thing and do it well" 的代码体现。

    1.3 Todo 管理:模型的自我追踪

    第 757-818 行实现了一个巧妙的 Todo 系统:

    func runTodoUpdate(cfg Config, input map[string]interface{}) (string, error) {
        itemsList, ok := input["items"].([]interface{})
        if !ok {
            return "", errors.New("items must be an array")
        }
    
        items := make([]TodoItem, 0, len(itemsList))
        for i, rawItem := range itemsList {
            itemMap, ok := rawItem.(map[string]interface{})
            if !ok {
                return "", fmt.Errorf("item %d is not an object", i)
            }
    
            items = append(items, TodoItem{
                ID:         getString(itemMap, "id"),
                Content:    getString(itemMap, "content"),
                Status:     getString(itemMap, "status"),
                ActiveForm: getString(itemMap, "activeForm"),
            })
        }
    
        boardView, err := todoBoard.Update(items)
        if err != nil {
            return "", err
        }
    
        // 重置轮次计数器
        agentState.mu.Lock()
        agentState.roundsWithoutTodo = 0
        agentState.mu.Unlock()
    
        stats := todoBoard.Stats()
        summary := fmt.Sprintf("Status updated: %d completed, %d in progress.",
            stats["completed"], stats["in_progress"])
    
        return boardView + "\n\n" + summary, nil
    }
    

    这不是给用户看的任务列表,而是模型的自我管理工具。模型通过 TodoWrite 工具:

    • 规划多步任务
    • 跟踪执行进度
    • 自我提醒下一步

    更妙的是第 421-427 行的监控逻辑:如果连续 10 轮没使用 Todo,系统会自动注入提醒。这是一种软性约束,不强制,但引导模型养成良好习惯。

    1.4 上下文注入:隐形的引导

    第 879-900 行展示了上下文注入机制:

    func injectReminders(userText string) interface{} {
        if len(pendingContextBlocks) == 0 {
            return userText // 简单字符串
        }
        blocks := make([]ContentBlock, len(pendingContextBlocks))
        copy(blocks, pendingContextBlocks)
        blocks = append(blocks, ContentBlock{Type: "text", Text: userText})
        pendingContextBlocks = nil
        return blocks
    }
    
    func ensureContextBlock(text string) {
        for _, block := range pendingContextBlocks {
            if block.Text == text {
                return
            }
        }
        pendingContextBlocks = append(pendingContextBlocks, ContentBlock{
            Type: "text",
            Text: text,
        })
    }
    

    系统可以在用户消息前静默插入提示,比如:

    • 第 53 行定义的 initialReminder - 提醒使用 Todo 工具
    • 第 54 行的 nagReminder - 超过 10 轮的警告

    这些提醒对用户不可见,但会影响模型行为。这是一种精妙的行为塑造技术 —— 通过上下文微调而非硬编码规则来引导模型。


    第二部分:系统提示词 - 行为塑造的艺术

    2.1 提示词结构:从宏观到微观的层次设计

    抓包得到 system-prompt,你会发现一个精心组织的 200+ 行提示词,分为以下层次:

    第 1 层:身份与约束

    You are Claude Code, Anthropic's official CLI for Claude.
    You are an interactive CLI tool that helps users with software engineering tasks.
    
    IMPORTANT: Assist with authorized security testing...
    IMPORTANT: You must NEVER generate or guess URLs...
    

    开门见山定义身份,然后立即设置安全边界

    第 2 层:沟通风格

    # Tone and style
    - Only use emojis if the user explicitly requests it.
    - Your output will be displayed on a command line interface.
      Your responses should be short and concise.
    - Output text to communicate with the user; all text you output
      outside of tool use is displayed to the user.
    

    强调 CLI 环境的特殊性 —— 简洁、直接、避免表情符号。这与 Web 聊天界面的提示完全不同。

    第 3 层:专业客观性

    # Professional objectivity
    Prioritize technical accuracy and truthfulness over validating
    the user's beliefs. Focus on facts and problem-solving...
    Avoid using over-the-top validation or excessive praise when
    responding to users such as "You're absolutely right"...
    

    这是 Anti-RLHF 的体现。传统聊天模型被训练成"讨好用户",但 Agent 需要说真话,即使用户不爱听

    第 4 层:任务管理策略

    # Task Management
    You have access to the TodoWrite tools to help you manage and
    plan tasks. Use these tools VERY frequently...
    
    It is critical that you mark todos as completed as soon as you
    are done with a task. Do not batch up multiple tasks before
    marking them as completed.
    

    详细定义了何时使用 Todo 、如何拆分任务、什么时候标记完成。这些规则配合代码中的监控机制,形成了完整的任务管理体系。

    2.2 工具使用策略:优先级与禁忌

    提示词中最长的部分是工具使用指南,包含大量实战智慧:

    并行执行规则

    You can call multiple tools in a single response. If you intend
    to call multiple tools and there are no dependencies between them,
    make all independent tool calls in parallel. Maximize use of
    parallel tool calls where possible to increase efficiency.
    

    模型被明确告知:能并行就并行。这直接影响执行效率。

    工具选择层次

    Use specialized tools instead of bash commands when possible:
    - File search: Use Glob (NOT find or ls)
    - Content search: Use Grep (NOT grep or rg)
    - Read files: Use Read (NOT cat/head/tail)
    - Edit files: Use Edit (NOT sed/awk)
    - Write files: Use Write (NOT echo >/cat <<EOF)
    

    建立了清晰的工具优先级。虽然 Bash 能做所有事,但专用工具更可靠、更好追踪。

    探索式搜索委托

    VERY IMPORTANT: When exploring the codebase to gather context
    or to answer a question that is not a needle query for a specific
    file/class/function, it is CRITICAL that you use the Task tool
    with subagent_type=Explore instead of running search commands
    directly.
    

    这解决了一个关键问题:复杂搜索任务应该委托给子 Agent,而不是自己循环搜索。避免主 Agent 陷入"搜索地狱"。

    2.3 Git 操作规范:细节中的工程智慧

    Git 相关的提示词占了 100+ 行,包含大量实战经验:

    Commit 流程 - 并行+串行的混合策略

    1. Run multiple bash commands in parallel:
       - Run a git status command
       - Run a git diff command
       - Run a git log command
    
    2. Analyze all staged changes and draft a commit message
    
    3. Run the following commands:
       - Add relevant untracked files to the staging area
       - Create the commit with a message ending with:
         🤖 Generated with [Claude Code]( https://claude.com/claude-code "Claude Code")
         Co-Authored-By: Claude <[email protected]>
       - Run git status after the commit completes to verify success
         Note: git status depends on the commit completing,
         so run it sequentially after the commit.
    

    注意这里的策略:信息收集并行,操作执行串行。这是实践中总结出的最优模式。

    安全协议 - 永远不要做的事

    Git Safety Protocol:
    - NEVER update the git config
    - NEVER run destructive/irreversible git commands unless explicitly requested
    - NEVER skip hooks (--no-verify, --no-gpg-sign, etc)
    - NEVER run force push to main/master
    - NEVER commit changes unless the user explicitly asks you to
    

    这些硬约束是从血泪教训中学来的。Agent 的自主性很强,必须有明确的禁区

    2.4 上下文工程:CLAUDE.md 的巧妙设计

    提示词最后引用了项目级配置:

    <system-reminder>
    As you answer the user's questions, you can use the following context:
    # claudeMd
    Codebase and user instructions are shown below. Be sure to adhere
    to these instructions. IMPORTANT: These instructions OVERRIDE any
    default behavior and you MUST follow them exactly as written.
    
    Contents of /Users/xxxxxx/.claude/CLAUDE.md (user's private
    global instructions for all projects):
    ...
    
    Contents of /Users/xxxxxx/CLAUDE.md (project
    instructions, checked into the codebase):
    ...
    </system-reminder>
    

    这里引入了三层配置体系:

    1. 全局配置 (~/.claude/CLAUDE.md) - 用户偏好,跨项目生效
    2. 项目配置 (project/CLAUDE.md) - 团队约定,纳入版本控制
    3. 系统默认 - Anthropic 内置的基础提示

    优先级明确:项目配置 > 全局配置 > 系统默认

    这相当于给了用户修改系统提示的能力,同时保证了团队协作的一致性。非常巧妙的设计。


    第三部分:工具定义 - API 即能力边界

    3.1 工具 Schema 的设计哲学

    tools.json 定义了 15+ 个工具,每个工具都遵循 OpenAI Function Calling 规范:

    {
      "name": "Bash",
      "description": "Executes a given bash command...",
      "input_schema": {
        "type": "object",
        "properties": {
          "command": {"type": "string", "description": "The command to execute"},
          "timeout": {"type": "number", "description": "Optional timeout in milliseconds"},
          "description": {"type": "string", "description": "Clear, concise description..."}
        },
        "required": ["command"],
        "additionalProperties": false
      }
    }
    

    关键设计原则:

    1. Description 即 Prompt

    工具的 description 字段其实是给模型看的文档。比如 Bash 工具的描述长达 300+ 行,包含:

    • 使用场景定义
    • 参数说明
    • 使用禁忌
    • 最佳实践
    • 错误案例

    这些信息直接影响模型的工具使用行为。工具定义本身就是一种提示工程

    2. 严格的 Schema 验证

    每个工具都设置了 "additionalProperties": false",拒绝模型传入未定义的参数。这是一种接口防御,避免模型"创造性"地使用工具。

    3. 可选参数的默认值策略

    以 Grep 工具为例:

    {
      "name": "Grep",
      "properties": {
        "pattern": {"type": "string", "description": "The regular expression pattern..."},
        "output_mode": {
          "type": "string",
          "enum": ["content", "files_with_matches", "count"],
          "description": "Output mode... Defaults to 'files_with_matches'."
        },
        "head_limit": {
          "type": "number",
          "description": "Limit output to first N lines... Defaults based on 'cap' experiment value: 0 (unlimited), 20, or 100."
        }
      },
      "required": ["pattern"]
    }
    

    只有 pattern 是必需的,其他参数都有智能默认值。这降低了模型的使用门槛,同时保留了高级控制能力。

    3.2 核心工具解析

    Task - Agent 套 Agent

    {
      "name": "Task",
      "description": "Launch a new agent to handle complex, multi-step tasks autonomously...",
      "properties": {
        "subagent_type": {
          "type": "string",
          "description": "The type of specialized agent to use for this task"
        },
        "prompt": {"type": "string"},
        "model": {
          "type": "string",
          "enum": ["sonnet", "opus", "haiku"],
          "description": "Optional model to use. Prefer haiku for quick tasks..."
        }
      }
    }
    

    这是 Claude Code 的多层 Agent 架构关键。主 Agent 可以启动子 Agent 处理特定任务,每个子 Agent 可以:

    • 使用不同模型 (降低成本)
    • 独立的上下文 (隔离复杂度)
    • 失败不影响主流程 (容错)

    描述中明确说 "Prefer haiku for quick tasks",这是在提示模型成本意识

    TodoWrite - 自我管理的接口

    注意 activeForm 字段 —— 要求提供"进行时"的表述 (如 "Running tests")。这让 UI 可以显示更友好的进度提示,同时强制模型用动词而非名词描述任务。

    Read - 增量加载设计

    支持分块读取大文件。模型可以先读前 100 行,如果需要再读接下来的部分。避免一次性加载巨型文件炸掉上下文窗口。

    3.3 MCP 工具集成:扩展性的体现

    tools.json 最后包含了 MCP (Model Context Protocol) 工具:

    {
      "name": "mcp__fetch__fetch",
      "description": "Fetches a URL from the internet and optionally extracts its contents as markdown..."
    },
    {
      "name": "mcp__ide__getDiagnostics",
      "description": "Get language diagnostics from VS Code"
    },
    {
      "name": "mcp__ide__executeCode",
      "description": "Execute python code in the Jupyter kernel..."
    }
    

    这些以 mcp__ 前缀的工具来自外部 MCP 服务器。Claude Code 本身只提供核心工具,复杂能力通过 MCP 协议接入。

    这是一种插件化架构:

    • 核心保持简洁
    • 能力可无限扩展
    • 第三方可贡献工具

    第四部分:实际请求 - 理论到实践的最后一环

    4.1 请求结构剖析

    打开 request 文件,看到一个完整的 API 请求:

    {
      "model": "claude-sonnet-4-5-20250929",
      "messages": [
        {
          "role": "user",
          "content": [
            {
              "type": "text",
              "text": "<system-reminder>\n 这是系统提示...\n</system-reminder>"
            },
            {
              "type": "text",
              "text": "基于 docs/refactor-simple-agent-design.md 开发文档进行 code review"
            }
          ]
        },
        {
          "role": "assistant",
          "content": [
            {"type": "text", "text": "我来对基于这两份设计文档的代码实现进行全面审查。"},
            {
              "type": "tool_use",
              "id": "toolu_017EWM5QoGex4Y8GPLyGZkc1",
              "name": "Read",
              "input": {"file_path": "/Users/.../refactor-simple-agent-design.md"}
            },
            {
              "type": "tool_use",
              "id": "toolu_01HWzrYBbM3EiPwUtxFGraeA",
              "name": "Read",
              "input": {"file_path": "/Users/.../simple_agent_optimization.md"},
              "cache_control": {"type": "ephemeral"}
            }
          ]
        },
        {
          "role": "user",
          "content": [
            {
              "tool_use_id": "toolu_01HWzrYBbM3EiPwUtxFGraeA",
              "type": "tool_result",
              "content": "     1→# Simple Agent 优化开发文档\n...",
              "cache_control": {"type": "ephemeral"}
            }
          ]
        }
      ],
      "system": [
        {
          "type": "text",
          "text": "You are Claude Code, Anthropic's official CLI for Claude.",
          "cache_control": {"type": "ephemeral"}
        },
        {
          "type": "text",
          "text": "完整的系统提示词...",
          "cache_control": {"type": "ephemeral"}
        }
      ],
      "tools": [...],
      "max_tokens": 32000,
      "stream": true
    }
    

    几个关键发现:

    4.2 Prompt Caching 策略

    注意到多处 "cache_control": {"type": "ephemeral"}"。这是 Anthropic 的 Prompt Caching 特性:

    • System 消息缓存 - 系统提示词几乎不变,每次请求复用缓存
    • Tool 定义缓存 - 工具 Schema 很大但固定,缓存后省 90% token
    • 长文档缓存 - 读取的文件内容标记为可缓存

    这大幅降低了成本。据 Anthropic 披露,Prompt Caching 可节省 90% 的输入 token 费用

    4.3 上下文注入的实际形态

    User 消息的第一个 content block 是:

    <system-reminder>
    This is a reminder that your todo list is currently empty.
    DO NOT mention this to the user explicitly...
    </system-reminder>
    

    这就是前面代码中 ensureContextBlock 函数注入的内容。它被包装在 <system-reminder> 标签里,并明确告诉模型不要提及这个提醒

    这是一种隐形引导 —— 影响模型行为但对用户透明。

    4.4 多模态内容的组织

    User 消息可以包含多个 content blocks:

    {
      "role": "user",
      "content": [
        {"type": "text", "text": "<system-reminder>...</system-reminder>"},
        {"type": "text", "text": "IDE 打开文件的提醒"},
        {"type": "text", "text": "CLAUDE.md 的内容"},
        {"type": "text", "text": "用户的实际输入"}
      ]
    }
    

    这种结构让系统可以在用户输入前后插入任意数量的上下文,且保持清晰的分隔。

    4.5 工具调用的完整流程

    从请求中可以看到一个完整的工具使用循环:

    第 1 轮 (Assistant 主动):

    {
      "role": "assistant",
      "content": [
        {"type": "text", "text": "我来审查代码"},
        {"type": "tool_use", "name": "Read", "input": {...}},
        {"type": "tool_use", "name": "Read", "input": {...}}
      ]
    }
    

    第 2 轮 (User 返回结果):

    {
      "role": "user",
      "content": [
        {"type": "tool_result", "tool_use_id": "...", "content": "文件内容..."}
      ]
    }
    

    第 3 轮 (Assistant 继续):

    {
      "role": "assistant",
      "content": [
        {"type": "text", "text": "根据文档分析..."}
      ]
    }
    

    这是标准的 OpenAI Function Calling 协议,但 Anthropic 的实现更灵活:允许在一轮中同时调用多个工具


    因为只能上传 20000 个字符 所以无法展示全部内容

    6 条回复    2025-11-25 14:34:57 +08:00
    skyemin
        1
    skyemin  
       7 小时 32 分钟前
    有博客吗
    giveupAK47
        2
    giveupAK47  
       6 小时 22 分钟前 via Android
    佬,完整版在哪
    gaogao321
        3
    gaogao321  
       5 小时 13 分钟前
    佬,完整版在哪
    yanchao7511461
        4
    yanchao7511461  
       5 小时 5 分钟前
    牛的
    gt2ming
        5
    gt2ming  
       4 小时 44 分钟前
    好强,值得学习
    mightybruce
        6
    mightybruce  
       4 小时 40 分钟前
    别蹭热度, 这 claude code 逆向几个月前就有好几个人专门做研究和分析,甚至还造了一个简化版的, 没你写的这么简单。
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   3277 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 11:15 · PVG 19:15 · LAX 03:15 · JFK 06:15
    ♥ Do have faith in what you're doing.