Skip to content

Cursor 实现深度分析 🖥️

"Cursor 是目前最成功的 AI 编程助手之一,其设计思路值得深入学习。"

1. Cursor 架构概述

1.1 核心组件

┌─────────────────────────────────────────────────────────────────┐
│                        Cursor IDE                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────────┐   │
│  │    Editor    │  │   Terminal   │  │    File Explorer     │   │
│  └──────────────┘  └──────────────┘  └──────────────────────┘   │
│          │                 │                    │                │
│          └─────────────────┼────────────────────┘                │
│                            ▼                                     │
│                   ┌──────────────────┐                          │
│                   │  Context Engine  │  ← 上下文收集             │
│                   └────────┬─────────┘                          │
│                            │                                     │
│                   ┌────────┴─────────┐                          │
│                   │   Agent System   │  ← AI 对话与工具调用       │
│                   └────────┬─────────┘                          │
│                            │                                     │
│                   ┌────────┴─────────┐                          │
│                   │   Tool Executor  │  ← 工具执行               │
│                   └──────────────────┘                          │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

1.2 交互模式

模式触发方式用途
Tab 补全自动触发代码自动完成
Cmd+K快捷键编辑选中代码
Chat侧边栏对话式问答
ComposerCmd+I多文件编辑
Agent@agent自主任务执行

2. System Prompt 分析

2.1 Cursor 的核心 System Prompt 结构

基于泄露和逆向分析,Cursor 的 System Prompt 大致结构如下:

markdown
You are a powerful agentic AI coding assistant, powered by Claude 3.5 Sonnet. You operate in Cursor.

You are pair programming with a USER to solve their coding task.Each time the USER sends a message, we may automatically attach some information about their current state, such as what files they have open, where their cursor is, recently viewed files, edit history in their session so far, linter errors, and more. This information may or may not be relevant to the coding task, it is up for you to decide.

Your main goal is to follow the USER's instructions at each message.

<communication>
1. Be conversational but not too verbose.
2. Be concise, brief, and to the point.
3. Use markdown formatting when appropriate.
4. When citing code, use markdown code blocks with the correct language.
</communication>

<tool_calling>
You have tools at your disposal to solve the coding task. Follow these rules:
1. ALWAYS follow the tool call schema exactly.
2. Only call tools when necessary.
3. Never refer to tool names in user-facing messages.
</tool_calling>

<making_code_changes>
1. Prefer editing existing files over creating new ones.
2. Never output extremely long code blocks.
3. Always apply changes using the edit tools, never just show the code.
4. If you've introduced linter errors, fix them.
</making_code_changes>

<searching_codebase>
1. Use semantic search for conceptual queries.
2. Use grep for exact matches.
3. Be thorough - search multiple times if needed.
</searching_codebase>

2.2 关键设计原则

  1. 上下文注入: 自动附加文件、光标位置、最近编辑等上下文
  2. 工具优先: 要求使用工具而非仅展示代码
  3. 简洁沟通: 强调简洁,避免冗长解释
  4. 自我修正: 发现 linter 错误要主动修复

3. 工具系统设计

3.1 核心工具集

typescript
// Cursor 的主要工具

interface CursorTools {
  // 文件操作
  read_file: {
    path: string;
    start_line?: number;
    end_line?: number;
  };
  
  write_file: {
    path: string;
    content: string;
  };
  
  edit_file: {
    path: string;
    old_content: string;  // 要替换的内容
    new_content: string;  // 新内容
  };
  
  // 搜索
  codebase_search: {
    query: string;  // 语义搜索
    target_directory?: string;
  };
  
  grep: {
    pattern: string;  // 正则表达式
    path?: string;
    include?: string;  // 文件类型过滤
  };
  
  file_search: {
    query: string;  // 文件名搜索
  };
  
  // 终端
  run_terminal_cmd: {
    command: string;
    cwd?: string;
  };
  
  // 浏览器
  browser_action: {
    action: 'launch' | 'click' | 'type' | 'scroll' | 'screenshot';
    // ...其他参数
  };
}

3.2 工具描述最佳实践

Cursor 的工具描述非常详细,包含:

typescript
{
  name: "codebase_search",
  description: `Semantic search that finds code by meaning, not exact text.
  
When to Use:
- Explore unfamiliar codebases
- Find code by meaning rather than exact text
- Ask "how/where/what" questions

When NOT to Use:
- Exact text matches (use grep)
- Simple symbol lookups (use grep)

Examples:
- Good: "Where is user authentication handled?"
- Bad: "AuthService" (use grep for this)

Strategy:
1. Start broad with []
2. If results point to a directory, rerun focused on that directory
3. Break large questions into smaller ones`,
  
  input_schema: {
    type: "object",
    properties: {
      query: {
        type: "string",
        description: "A complete question about what you want to understand"
      },
      target_directories: {
        type: "array",
        items: { type: "string" },
        description: "Single directory path to limit search scope"
      }
    },
    required: ["query"]
  }
}

3.3 Edit 工具的精确匹配

Cursor 使用 old_content / new_content 模式进行编辑:

typescript
// 编辑工具要求精确匹配
{
  name: "edit_file",
  description: `Edit a file by replacing old_content with new_content.
  
CRITICAL:
- old_content must match EXACTLY (including whitespace)
- Include enough context to make the match unique
- If matching fails, read the file first to get exact content`,
  
  input_schema: {
    properties: {
      path: { type: "string" },
      old_content: { 
        type: "string",
        description: "Exact text to replace (must be unique in file)"
      },
      new_content: { 
        type: "string",
        description: "Replacement text"
      }
    }
  }
}

4. 上下文管理策略

4.1 自动上下文收集

Cursor 自动收集并注入的上下文:

typescript
interface AutoContext {
  // 当前文件状态
  currentFile: {
    path: string;
    content: string;
    cursorPosition: { line: number; column: number };
    selection?: { start: Position; end: Position; text: string };
  };
  
  // 最近查看的文件
  recentFiles: Array<{
    path: string;
    lastViewed: Date;
  }>;
  
  // 编辑历史
  editHistory: Array<{
    path: string;
    before: string;
    after: string;
    timestamp: Date;
  }>;
  
  // Linter 错误
  diagnostics: Array<{
    path: string;
    line: number;
    message: string;
    severity: 'error' | 'warning';
  }>;
  
  // 终端状态
  terminals: Array<{
    id: string;
    cwd: string;
    recentCommands: string[];
    lastOutput?: string;
  }>;
  
  // 项目信息
  project: {
    rootPath: string;
    gitStatus?: string;
    packageJson?: object;
  };
}

4.2 上下文优先级

typescript
class ContextManager {
  // 上下文优先级排序
  prioritize(contexts: AutoContext): string {
    const sections = [];
    
    // 1. 系统指令 (最高优先级)
    sections.push(this.systemPrompt);
    
    // 2. 当前选中的代码 (用户正在看的)
    if (contexts.currentFile.selection) {
      sections.push(`
<current_selection>
File: ${contexts.currentFile.path}
Selected code:
${contexts.currentFile.selection.text}
</current_selection>`);
    }
    
    // 3. Linter 错误 (需要立即处理)
    if (contexts.diagnostics.length > 0) {
      sections.push(`
<diagnostics>
${contexts.diagnostics.map(d => 
  `${d.path}:${d.line}: ${d.severity} - ${d.message}`
).join('\n')}
</diagnostics>`);
    }
    
    // 4. 编辑历史 (理解用户意图)
    if (contexts.editHistory.length > 0) {
      sections.push(`
<recent_edits>
${contexts.editHistory.slice(-3).map(e =>
  `${e.path}: Changed from ... to ...`
).join('\n')}
</recent_edits>`);
    }
    
    // 5. 打开的文件 (可能相关)
    sections.push(`
<open_files>
${contexts.recentFiles.map(f => f.path).join('\n')}
</open_files>`);
    
    return sections.join('\n\n');
  }
}

4.3 @ Mentions 系统

typescript
// @ 符号引用系统
const mentionHandlers = {
  '@file': async (path: string) => {
    return await readFile(path);
  },
  
  '@folder': async (path: string) => {
    const files = await listFiles(path, { recursive: true });
    return files.map(f => f.path).join('\n');
  },
  
  '@codebase': async (query: string) => {
    return await semanticSearch(query);
  },
  
  '@docs': async (url: string) => {
    return await fetchAndParseDocs(url);
  },
  
  '@git': async (command: string) => {
    // git diff, git log 等
    return await execGitCommand(command);
  },
  
  '@web': async (query: string) => {
    return await webSearch(query);
  }
};

5. Composer 多文件编辑

5.1 Composer 工作流

用户: "添加用户认证功能"


    ┌──────────────┐
    │   分析需求    │
    └──────┬───────┘


    ┌──────────────┐
    │   生成计划    │ ← 列出需要修改的文件
    └──────┬───────┘


    ┌──────────────┐
    │   逐文件编辑  │ ← 每个文件单独处理
    └──────┬───────┘


    ┌──────────────┐
    │   应用 Diff   │ ← 展示变更供确认
    └──────┬───────┘


    ┌──────────────┐
    │   验证结果    │ ← 检查 linter 错误
    └──────────────┘

5.2 多文件变更表示

typescript
interface ComposerEdit {
  files: Array<{
    path: string;
    action: 'create' | 'modify' | 'delete';
    changes: Array<{
      type: 'insert' | 'replace' | 'delete';
      location: {
        startLine: number;
        endLine?: number;
      };
      oldContent?: string;
      newContent?: string;
    }>;
  }>;
  
  summary: string;  // 变更摘要
  reasoning: string;  // 为什么这样改
}

5.3 Apply 模式

Cursor 的 Apply 功能将 AI 建议应用到代码:

typescript
class ApplyManager {
  async apply(suggestion: string, targetFile: string) {
    // 1. 解析建议中的代码
    const codeBlocks = this.extractCodeBlocks(suggestion);
    
    // 2. 使用 LLM 生成精确的 diff
    const diff = await this.generateDiff(
      await readFile(targetFile),
      codeBlocks,
      suggestion
    );
    
    // 3. 应用变更
    await this.applyDiff(targetFile, diff);
    
    // 4. 验证
    const errors = await this.checkLinter(targetFile);
    if (errors.length > 0) {
      // 尝试修复
      await this.fixErrors(targetFile, errors);
    }
  }
  
  async generateDiff(original: string, newCode: string[], context: string) {
    return await llm.chat({
      messages: [{
        role: 'user',
        content: `将以下建议的代码变更转换为精确的编辑操作。

原始文件:
\`\`\`
${original}
\`\`\`

建议的变更:
${newCode.map(c => `\`\`\`\n${c}\n\`\`\``).join('\n')}

上下文: ${context}

输出 JSON 格式的编辑操作:
{
  "edits": [
    { "old": "要替换的精确文本", "new": "新文本" }
  ]
}`
      }]
    });
  }
}

6. Agent 模式

6.1 Agent 系统提示词

markdown
You are a powerful agentic AI coding assistant. When operating in agent mode:

## Capabilities
- You can autonomously plan and execute multi-step tasks
- You have access to all tools: file operations, search, terminal, browser
- You can iterate on your work based on results

## Workflow
1. Understand the task fully
2. Create a plan
3. Execute step by step
4. Verify results
5. Fix any issues
6. Report completion

## Rules
- Always verify your changes compile/lint correctly
- Run tests if they exist
- Ask for clarification if task is ambiguous
- Stop and report if something seems wrong

6.2 Agent 执行循环

typescript
class CursorAgent {
  async execute(task: string) {
    const messages: Message[] = [
      { role: 'system', content: AGENT_SYSTEM_PROMPT },
      { role: 'user', content: task }
    ];
    
    let iteration = 0;
    const maxIterations = 50;
    
    while (iteration < maxIterations) {
      const response = await this.llm.chat({
        messages,
        tools: this.tools,
        // Cursor 使用 thinking 功能
        thinking: { enabled: true }
      });
      
      messages.push({ role: 'assistant', content: response.content });
      
      // 检查是否完成
      if (this.isComplete(response)) {
        return this.extractResult(response);
      }
      
      // 执行工具调用
      if (response.toolCalls) {
        const results = await this.executeTools(response.toolCalls);
        messages.push({ role: 'tool', content: results });
      }
      
      iteration++;
    }
    
    throw new Error('Reached max iterations');
  }
  
  async executeTools(toolCalls: ToolCall[]) {
    const results = [];
    
    for (const call of toolCalls) {
      try {
        const result = await this.toolExecutor.execute(call);
        results.push({ id: call.id, result });
      } catch (error) {
        results.push({ id: call.id, error: error.message });
      }
    }
    
    return results;
  }
}

7. 性能优化

7.1 缓存策略

typescript
class CursorCache {
  // 文件内容缓存
  private fileCache = new LRUCache<string, FileContent>({
    max: 1000,
    ttl: 1000 * 60 * 5  // 5 分钟
  });
  
  // 搜索结果缓存
  private searchCache = new LRUCache<string, SearchResult[]>({
    max: 100,
    ttl: 1000 * 60 * 2  // 2 分钟
  });
  
  // Embedding 缓存 (重要:节省 API 调用)
  private embeddingCache = new LRUCache<string, number[]>({
    max: 10000,
    ttl: 1000 * 60 * 60  // 1 小时
  });
  
  async getEmbedding(text: string): Promise<number[]> {
    const hash = this.hash(text);
    
    if (this.embeddingCache.has(hash)) {
      return this.embeddingCache.get(hash)!;
    }
    
    const embedding = await this.computeEmbedding(text);
    this.embeddingCache.set(hash, embedding);
    return embedding;
  }
}

7.2 流式输出

typescript
async function* streamResponse(messages: Message[]) {
  const stream = await llm.stream({
    messages,
    tools
  });
  
  let buffer = '';
  let inToolCall = false;
  let toolBuffer = '';
  
  for await (const chunk of stream) {
    if (chunk.type === 'text') {
      buffer += chunk.text;
      
      // 实时输出文本
      yield { type: 'text', content: chunk.text };
      
    } else if (chunk.type === 'tool_call_start') {
      inToolCall = true;
      yield { type: 'tool_start', name: chunk.name };
      
    } else if (chunk.type === 'tool_call_delta') {
      toolBuffer += chunk.content;
      
    } else if (chunk.type === 'tool_call_end') {
      // 执行工具
      const input = JSON.parse(toolBuffer);
      const result = await executeToolCall(chunk.name, input);
      
      yield { type: 'tool_result', name: chunk.name, result };
      
      inToolCall = false;
      toolBuffer = '';
    }
  }
}

7.3 增量更新

typescript
class IncrementalIndexer {
  // 使用文件监听而非全量索引
  async watchAndIndex(rootPath: string) {
    const watcher = chokidar.watch(rootPath, {
      ignored: /node_modules|\.git/,
      persistent: true
    });
    
    watcher.on('add', async (path) => {
      await this.indexFile(path);
    });
    
    watcher.on('change', async (path) => {
      await this.reindexFile(path);
    });
    
    watcher.on('unlink', async (path) => {
      await this.removeFromIndex(path);
    });
  }
  
  async reindexFile(path: string) {
    // 只重新计算变更文件的 embedding
    const content = await readFile(path);
    const chunks = this.chunkCode(content);
    
    // 删除旧的
    await this.vectorDB.delete({ file: path });
    
    // 添加新的
    for (const chunk of chunks) {
      const embedding = await this.getEmbedding(chunk.content);
      await this.vectorDB.add({
        id: `${path}:${chunk.name}`,
        embedding,
        content: chunk.content,
        metadata: { file: path, ...chunk.metadata }
      });
    }
  }
}

8. 用户体验设计

8.1 渐进式披露

typescript
// 默认简洁,需要时展开详情
interface AIResponse {
  // 主要回答(总是显示)
  summary: string;
  
  // 代码变更(可折叠)
  changes?: Array<{
    file: string;
    diff: string;
    collapsed: boolean;
  }>;
  
  // 思考过程(可选展开)
  thinking?: string;
  
  // 搜索的文件(可选展开)
  searchedFiles?: string[];
}

8.2 操作可撤销

typescript
class UndoManager {
  private stack: Edit[] = [];
  
  async applyWithUndo(edit: Edit) {
    // 保存撤销信息
    const undo = await this.captureUndo(edit);
    this.stack.push(undo);
    
    // 应用编辑
    await this.apply(edit);
  }
  
  async undo() {
    const edit = this.stack.pop();
    if (edit) {
      await this.apply(edit.reverse());
    }
  }
  
  // 批量撤销整个 AI 操作
  async undoAIOperation(operationId: string) {
    const edits = this.stack.filter(e => e.operationId === operationId);
    for (const edit of edits.reverse()) {
      await this.apply(edit.reverse());
    }
  }
}

9. 关键设计启示

9.1 设计原则总结

  1. 上下文为王: 自动收集丰富的上下文减少用户输入
  2. 工具优先: 使用工具执行而非仅建议代码
  3. 精确编辑: old/new 模式保证编辑的精确性
  4. 渐进增强: 从 Tab 补全到 Agent,满足不同需求
  5. 即时反馈: 流式输出、实时预览
  6. 可撤销: 所有 AI 操作都能撤销

9.2 值得借鉴的模式

typescript
// 1. 丰富的工具描述
const toolDescription = {
  name: "xxx",
  description: `
What it does:
...

When to use:
...

When NOT to use:
...

Examples:
...

Common mistakes:
...`
};

// 2. 上下文注入模板
const contextTemplate = `
<current_state>
${JSON.stringify(currentState, null, 2)}
</current_state>

<recent_activity>
${recentActivity}
</recent_activity>
`;

// 3. 自我修正循环
async function executeWithRetry(task) {
  let result = await execute(task);
  
  const errors = await checkErrors(result);
  if (errors.length > 0) {
    result = await fix(result, errors);
  }
  
  return result;
}

10. 复刻要点

如果你想构建类似 Cursor 的工具:

  1. 构建上下文引擎: 收集 IDE 状态、文件、终端等信息
  2. 设计精确的编辑工具: 使用字符串匹配而非行号
  3. 实现语义搜索: 索引代码库,支持自然语言查询
  4. 流式交互: 实时显示 AI 输出和工具执行
  5. 可观测性: 记录所有操作,支持撤销
  6. 迭代修正: 检测错误并自动修复

延伸阅读

前端面试知识库