通过接口抓包和代码逆向,我们可以完整了解Claude Code的全貌,并学习其实现来打造自己的Agent。本文基于Go实现的核心代码、完整系统提示词、工具定义及真实API请求,揭秘Agent核心循环、工具分发机制、Prompt Caching策略等关键技术细节。
打开 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")
}
核心逻辑可以总结为三步:
对比传统Agent框架动辄几千行的状态管理代码,Claude Code这种极简设计令人震撼。没有复杂的状态机,没有繁琐的调度器,只有最纯粹的"思考-行动-观察"循环。
第515-567行的 dispatchToolCall 函数展示了工具调用的处理方式:
func dispatchToolCall(cfg Config, tc ToolCall) Message {
// 解析参数
var input map[string]interface{}
json.Unmarshal([]byte(tc.Function.Arguments), &input)
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()
}
return Message{
Role: "tool",
ToolCallID: tc.ID,
Name: tc.Function.Name,
Content: clampText(result, cfg.MaxResult),
}
}
每个工具都是独立的纯函数,输入参数,输出结果,不维护任何状态。这正是Unix哲学"Do one thing and do it well"的代码体现。
Claude Code实现了一个巧妙的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 := renderTodoBoard(items)
return boardView, err
}
当模型超过10轮没有使用Todo工具时,系统会自动注入提醒:
if agentState.roundsWithoutTodo > 10 {
ensureContextBlock(nagReminder)
}
这个提醒被包装在 <system-reminder> 标签里,并明确告诉模型不要提及这个提醒,这是一种"隐形引导"——影响模型行为但对用户透明。
系统提示词定义了Claude Code的核心行为准则,包含以下关键部分:
系统提示词是Agent能力的边界。Claude Code通过精心设计的提示词,让模型在没有复杂状态管理的情况下,依然能够处理复杂的多步骤任务。
Claude Code提供了15+核心工具,每个工具都有完整的JSON Schema定义:
除了核心工具,Claude Code还支持通过MCP(Model Context Protocol)协议接入外部工具:
{
"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服务器。这是一种插件化架构:核心保持简洁,能力可无限扩展,第三方可贡献工具。
从实际API请求中可以看到多处 "cache_control": {"type": "ephemeral"},这是Anthropic的Prompt Caching特性:
{
"model": "claude-sonnet-4-5-20250929",
"system": [
{
"type": "text",
"text": "You are Claude Code, Anthropic's official CLI...",
"cache_control": {"type": "ephemeral"}
}
],
"tools": [...], // 工具定义也被缓存
"max_tokens": 32000,
"stream": true
}
据Anthropic披露,Prompt Caching可节省90%的输入token费用。这使得Claude Code能够在每次请求中携带完整的系统提示词和工具定义,而不会产生高昂的成本。
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": "用户的实际输入"}
]
}
这种结构让系统可以灵活地注入各种上下文信息,且保持清晰的分隔。
从请求中可以看到一个完整的工具使用循环:
{
"role": "assistant",
"content": [
{"type": "text", "text": "我来审查代码"},
{"type": "tool_use", "name": "Read", "input": {...}},
{"type": "tool_use", "name": "Read", "input": {...}}
]
}
{
"role": "user",
"content": [
{"type": "tool_result", "tool_use_id": "...", "content": "文件内容..."}
]
}
{
"role": "assistant",
"content": [
{"type": "text", "text": "根据文档分析..."}
]
}
这是标准的OpenAI Function Calling协议,但Anthropic的实现更灵活:允许在一轮中同时调用多个工具。
通过对Claude Code的完整解析,我们可以提炼出以下关键技术点:
Claude Code的实现为我们提供了一个优秀的Agent设计范本。它证明了:简单的设计往往比复杂的框架更有效。通过精心设计的提示词和工具定义,配合智能的缓存策略,就能打造出强大而高效的AI Agent。
cache_control: {type: "ephemeral"} 标记即可。