一、Claude Code整体概述
Claude Code是Anthropic开发的终端AI编程工具,直接集成在开发者终端环境中,无需额外服务器或复杂配置。与Cursor相比,它更像是一个熟悉整个项目的高级程序员,输出代码更简练。
二、Claude Code系统架构深度拆解
2.1 系统架构三层核心
- 交互层:用户与Claude Code的接触点
- 核心引擎:负责协调各组件工作的"大脑"
- 工具系统:Claude Code的"手脚",用于与外部环境交互
2.2 执行流程
从用户提交命令到渲染结果的完整流程:
- 用户输入 → 输入处理 → 核心引擎 → 工具调度 → 结果渲染
2.3 交互层实现细节
主要由REPL.tsx和PromptInput.tsx等组件实现,包含三个关键模块:
2.3.1 输入逻辑处理
function processUserInput(input: string, mode: InputMode): UserMessage {if (input.startsWith('/')) {return handleSlashCommand(input); // 处理斜杠命令} else if (input.startsWith('!')) {return handleBashCommand(input.slice(1)); // 处理bash命令} else {return createUserMessage(input); // 创建普通用户消息}
}
输入模式分类:
/开头:斜杠命令!开头:Bash命令- 其他:自然语言输入
2.3.2 渲染系统
渲染分为两个阶段:
- 工具调用阶段(Assistant侧):显示工具名称、参数和执行状态
- 工具结果阶段(User侧):显示执行结果
核心组件:
AssistantToolUseMessage:渲染助手调用工具时的消息- 显示工具名称(通过
tool.userFacingName()) - 显示参数(通过
tool.renderToolUseMessage()) - 使用
ToolUseLoader显示执行状态动画
- 显示工具名称(通过
UserToolSuccessMessage:渲染工具执行成功后的结果- 调用
tool.renderToolResultMessage()渲染具体内容
- 调用
工具接口定义规范:
userFacingName():显示给用户的工具名称renderToolUseMessage(input, options):渲染工具参数renderToolResultMessage(output, options):渲染工具结果renderToolUseRejectedMessage():渲染拒绝消息
UI渲染特性:
- 使用Ink框架的Box和Text组件构建终端UI
- 支持主题系统(通过
getTheme()) - 响应式布局(flexDirection, justifyContent)
- 详细/简洁模式切换(verbose参数)
- 执行成本和时间显示(Cost组件)
2.4 核心引擎(Core Engine)
核心引擎是Claude Code的"大脑",负责:
- 消息系统:管理用户输入、AI响应和工具结果的消息流
- 查询引擎:与AI模型交互,发送请求并处理响应
- 工具调度器:协调工具的调用和结果处理
关键组件query.ts实现逻辑:
async function* query(messages: Message[],systemPrompt: string,context: Context,canUseTool: CanUseToolFn,toolUseContext: ToolUseContext,
): AsyncGenerator<Message> {// 1. 初始化大模型promptconst fullSystemPrompt = formatSystemPromptWithContext(systemPrompt, context)// 2. 获取大模型返回const result = await queryWithBinaryFeedback(toolUseContext,getAssistantResponse,getBinaryFeedbackResponse,)// 3. 处理模型返回的工具请求const toolUseMessages = assistantMessage.message.content.filter(_ => _.type === 'tool_use',)// 4. 并行/串行执行工具if (toolUseMessages.every(msg =>toolUseContext.options.tools.find(t => t.name === msg.name)?.isReadOnly(),)) {for await (const message of runToolsConcurrently) // 并行执行} else {for await (const message of runToolsSerially) // 串行执行}// 5. 处理后续交互yield* await query()
}
执行策略智能判断:
- 并行执行:当所有工具都是只读操作(
isReadOnly())时,可以并发执行 - 串行执行:当包含写操作时,必须串行执行以保证安全
2.5 工具系统
工具系统使Claude Code能够与外部环境交互,包含四类工具:
- 文件工具:读取、写入、搜索文件
- 执行工具:运行shell命令、执行代码
- 分析工具:代码分析、依赖检查等
- 元工具:复合工具,可执行更复杂的任务
工具接口定义:
interface Tool {name: string;description: string;inputSchema: z.ZodType;execute(params: any): Promise<ToolResult>;
}
技术亮点:
- 每个工具遵循统一接口,包含名称、描述、参数模式和执行逻辑
- Claude Code内置15个工具,实现和提示词都值得学习
- 特别强大的bash工具可调用shell所有命令
- 包含agent tool,可发挥更强大的能力
2.6 上下文管理
上下文管理是Claude Code的"记忆",负责收集和组织代码相关信息:
- 项目结构:目录和文件结构
- 代码内容:关键文件的内容
- 版本控制:Git历史和状态
- 配置信息:项目配置和依赖
核心挑战:在有限的上下文窗口内提供最相关的信息
2.6.1 LRU缓存机制
const fileEncodingCache = new LRUCache<string, BufferEncoding>({fetchMethod: path => detectFileEncodingDirect(path),ttl: 5 * 60 * 1000, // 5分钟过期ttlAutopurge: false,max: 1000, // 最大缓存1000个文件
})const lineEndingCache = new LRUCache<string, LineEndingType>({fetchMethod: path => detectLineEndingsDirect(path),ttl: 5 * 60 * 1000,ttlAutopurge: false,max: 1000,
})
缓存策略:对文件编码、行尾类型等信息实现缓存,减少重复操作
2.6.2 按需加载策略
不会一次性加载整个代码库,而是根据查询需要智能加载相关文件:
async *call({ pattern, path }, { abortController }){const start = Date.now()const { files, truncated } = await glob(pattern,path ?? getCwd(),{ limit: 100, offset: 0 },abortController.signal,)const output: Output = {filenames: files,durationMs: Date.now() - start,numFiles: files.length,truncated,}yield {type: 'result',resultForAssistant: this.renderResultForAssistant(output),data: output,}
}
- 搜索结果限制100个,避免上下文溢出
- 提供截断提示(truncated)
2.6.3 结果截断处理
const MAX_LINES = 4
const MAX_FILES = 1000
const TRUNCATED_MESSAGE = `There are more than ${MAX_FILES} files in the repository. Use the LS tool (passing a specific path), Bash tool, and other tools to explore nested directories. The first ${MAX_FILES} files and directories are included below:\n\n`
- 对大量搜索结果实现智能截断
- 提供清晰的截断提示和操作引导
2.6.4 上下文拼装
async function getContext(): Context {return {directoryStructure: await getDirectoryStructure(),gitStatus: await getGitStatus(),codeStyle: await getCodeStyle(),// 其他上下文...};
}
2.7 安全机制
安全与权限是Claude Code的"护栏",确保工具使用的安全性:
- 权限验证:工具执行前的权限检查
- 用户确认:关键操作的用户确认机制
- 最小权限原则:只向用户索要完成任务的最小权限
- 安全边界:文件操作和命令执行的限制
权限检查实现:
export const hasPermissionsToUseTool// 跳过if (context.options.dangerouslySkipPermissions) {return { result: true }}if (context.abortController.signal.aborted) {throw new AbortError()}// 允许每个工具单独配置,由工具声明安全性try {if (!tool.needsPermissions(input as never)) {return { result: true }}} catch (e) {logError(`Error checking permissions: ${e}`)return { result: false, message: 'Error checking permissions' }}
三、关键技术启发
3.1 Binary Feedback机制
用于程序员测试prompt质量的核心机制:
async function queryWithBinaryFeedback(toolUseContext: ToolUseContext,getAssistantResponse: () => Promise<AssistantMessage>,getBinaryFeedbackResponse?: (m1: AssistantMessage,m2: AssistantMessage,) => Promise<BinaryFeedbackResult>,
): Promise<BinaryFeedbackResult> {if (process.env.USER_TYPE !== 'ant' ||!getBinaryFeedbackResponse ||!(await shouldUseBinaryFeedback()))const [m1, m2] = await Promise.all([getAssistantResponse(),getAssistantResponse(),])
}
机制原理:
- 使用完全相同的请求调用两次,观察模型是否给出不同输出
- 如果AI返回两个不同答案,说明模型对此次请求是犹豫的、考虑不清楚的,需要让用户做选择
- 检测对象不是文本,而是生成的tool use是否相同(结构化数据输出的稳定性远大于文本)
- 仅在程序员自己测试时生效,说明这种测试逻辑对开发自己的Agent很有用
- 出现差异说明需要提高prompt质量
3.2 MCP工具分层管理
Claude Code自身只维护一个tengu_mcp_server,同时支持用户添加MCP Server,通过三级分层结构管理:
三层结构:
- Global:全局配置的通用MCP
- Mcprc:配置文件,可以共享(
.mcprc文件) - Project:项目级别,当前代码库可单独配置
优先级规则:下层结构的MCP配置可以覆盖上层配置
添加MCP Server实现:
export function addMcpServer(name: McpName,server: McpServerConfig,scope: ConfigScope = 'project',
): void {if (scope === 'mcprc') {// 写入.mcprc配置文件const mcprcPath = join(getCwd(), '.mcprc')// ... 读取现有配置,添加新server,写回文件} else if (scope === 'global') {// 写入全局配置const config = getGlobalConfig()config.mcpServers[name] = serversaveGlobalConfig(config)} else {// 写入项目配置const config = getCurrentProjectConfig()config.mcpServers[name] = serversaveCurrentProjectConfig(config)}
}
工具聚合逻辑:
- 请求所有MCP Server,获取所有tools
- 将tools聚合后发送给大模型
3.3 通过AI检测安全
利用AI做安全辅助,例如判断命令是否有被注入的可能性:
export const getCommandSubcommandPrefix = memoize(async (command: string,abortSignal: AbortSignal,): Promise<CommandSubcommandPrefixResult | null> => {const subcommands = splitCommand(command)// 获取命令前缀观察是否在安全执行列表const [fullCommandPrefix, ...subcommandPrefixesResults] = await Promise.all([getCommandPrefix(command, abortSignal),...subcommands.map(async subcommand => ({subcommand,prefix: await getCommandPrefix(subcommand, abortSignal),})),])},command => command,
)
3.4 上下文压缩处理
核心功能:清空对话历史但保留上下文摘要,解决长对话导致的上下文窗口问题
技术亮点:
- 智能摘要生成:使用Sonnet模型生成对话摘要,保留关键信息供后续使用
- Fork机制应用:利用
setForkConvoWithMessagesOnTheNextRender创建新的对话分支,摘要作为新对话起点 - Token使用优化:将摘要的token使用量设为0,避免触发上下文窗口警告
- 缓存清理:清理
getContext和getCodeStyle缓存,确保新对话环境干净
核心代码流程:
- 获取当前对话历史
- 构造摘要请求并调用Sonnet模型
- 提取并验证摘要内容
- 清屏、清空消息历史
- 创建包含摘要的新对话分支
3.5 简单任务交给小模型
Claude内部有多个模型实例,对于只判断对错或简单任务,会交给Haiku模型:
示例1:创建标题任务
async function generateTitle(description: string): Promise<string> {const response = await queryHaiku({systemPrompt: ['Generate a concise issue title (max 80 chars)...'],userPrompt: description,})// ... 处理响应
}
示例2:确认前缀任务
const getCommandPrefix = memoize(async (command: string, abortSignal: AbortSignal): Promise<CommandPrefixResult | null> => {const response = await queryHaiku({systemPrompt: [`Your task is to process Bash commands...`],// ... 包含大量示例})},
)
优势:节省成本、提升速度、分工明确
3.6 高效的文件系统策略
- 分层拉取:先获取高层次项目结构,再根据需要深入特定目录,避免一次性加载过多内容
- Ripgrep集成:利用Rust编写的高性能搜索工具,实现毫秒级代码库搜索
- 内置二进制支持:包含预编译的ripgrep二进制文件,确保跨平台一致性和性能
- 智能结果排序:搜索结果按修改时间排序,优先展示最近更改的文件
- 并发搜索能力:支持同时发起多个搜索请求,提高大型代码库分析效率
- LRU缓存机制:对文件编码、行尾类型等信息实现缓存,减少重复操作
3.7 精妙的工具设计
Claude Code中内置的15个工具的实现和提示词都值得学习,正是这些极致的工具才保证了任务执行的高效性。
总结要点
- Claude Code的核心优势:系统架构清晰、工具系统极致、上下文管理智能、安全机制完善
- 关键启发:Binary Feedback机制、MCP分层管理、AI安全检测、上下文压缩、模型分级使用
- 应用场景:从日常开发到复杂任务(DeepResearch),CLI+AI模式展现出强大潜力
- 技术趋势:MCP协议正在成为AI工具标准接口,构建自主可控的AI编程基础设施是重要方向