Skip to content

AI Coding 原理详解

更新: 5/15/2026 字数: 0 字 时长: 0 分钟

1. AI Coding 的三种形态

形态 1:代码补全(Autocomplete)
  你打字 → 模型预测你接下来要写什么 → 显示灰色建议
  例:GitHub Copilot 的 Tab 补全

形态 2:对话式编程(Chat)
  你用自然语言描述需求 → 模型生成代码
  例:ChatGPT、Claude 的代码对话

形态 3:AI Agent(自主编程)
  你描述目标 → Agent 自主规划、搜索代码、编辑文件、运行测试
  例:Claude Code、Cursor Agent、Devin

2. 代码补全的原理

2.1 基本流程

你在编辑器中输入:
  fun calculateTotal(items: List<Item>): Double {
      return items.

光标在 "items." 后面

IDE 插件做的事:
  1. 收集上下文
     → 当前文件的内容(光标前后)
     → 打开的其他文件
     → 项目的语言、框架信息

  2. 构建 Prompt
     → <prefix>fun calculateTotal(items: List<Item>): Double {\n    return items.</prefix>
     → <suffix>\n}</suffix>
     → 加上相关文件片段作为上下文

  3. 发送给模型(Fill-in-the-Middle)
     → 模型看到前缀和后缀,预测中间应该填什么

  4. 模型返回
     → "sumOf { it.price }"

  5. IDE 显示灰色建议
     → 你按 Tab 接受

2.2 Fill-in-the-Middle(FIM)

代码补全不是简单的"预测下一个 Token",而是"根据前后文填空":

普通的自回归生成(只看前面):
  输入: "fun add(a: Int, b: Int): Int {"
  生成: "\n    return a + b\n}"

FIM(看前面和后面):
  前缀: "fun add(a: Int, b: Int): Int {\n    "
  后缀: "\n}"
  填空: "return a + b"
  → 生成的代码能和后面的 "}" 完美衔接

训练时的数据格式:
  <PRE>前缀内容<SUF>后缀内容<MID>中间内容
  模型学会了根据前后文生成中间部分

2.3 上下文收集策略

代码补全的质量取决于给模型多少有用的上下文:

1. 当前文件(最重要)
   → 光标前的代码(前缀)
   → 光标后的代码(后缀)

2. 相关文件
   → 当前文件 import 的文件
   → 最近编辑过的文件
   → 同目录下的文件

3. 项目信息
   → 语言、框架(Kotlin + Android + Compose)
   → 代码风格(命名规范、缩进)

4. LSP 信息
   → 类型信息(items 是 List<Item>,Item 有 price 字段)
   → 函数签名
   → 编译错误

上下文窗口有限,需要智能选择最相关的内容
→ 这就是不同 AI Coding 工具效果差异的关键

3. 对话式编程的原理

3.1 System Prompt

每个 AI Coding 工具都有一个 System Prompt,定义模型的行为:

System: """
你是一个 Android 开发助手。
- 使用 Kotlin 语言
- 遵循 Android 最佳实践
- 代码要有适当的错误处理
- 优先使用 Jetpack 组件
"""

User: "帮我写一个网络请求的 Repository"

模型根据 System Prompt 的约束生成代码
不同工具的 System Prompt 不同 → 生成风格不同

3.2 多轮对话的上下文管理

对话历史会占用 Context Window:

Turn 1: User: "写一个 UserRepository"
        Assistant: "```kotlin\nclass UserRepository...\n```"  ← 500 Token

Turn 2: User: "加上缓存功能"
        Assistant: "```kotlin\nclass UserRepository...\n```"  ← 800 Token

Turn 3: User: "加上错误处理"
        → 此时模型的输入 = System Prompt + Turn1 + Turn2 + Turn3
        → 可能已经用了 5000 Token

对话越长,可用的 Context Window 越少
工具需要策略来管理:
  → 压缩早期对话
  → 只保留关键代码片段
  → 滑动窗口(丢弃最早的对话)

4. AI Agent 的原理

4.1 Agent 的核心循环

Agent 不是一次性生成代码,而是循环执行:

while (任务未完成) {
    1. 观察(Observe)
       → 读取文件、查看错误、检查测试结果

    2. 思考(Think)
       → 分析当前状态,决定下一步做什么

    3. 行动(Act)
       → 编辑文件、运行命令、搜索代码

    4. 反馈(Feedback)
       → 检查行动的结果,决定是否继续
}
实际例子:Claude Code 修复一个 Bug

用户: "RecyclerView 滑动时崩溃,修复一下"

Agent 循环:
  Round 1:
    观察: 读取崩溃日志 → IndexOutOfBoundsException in onBindViewHolder
    思考: 可能是数据源和 Adapter 不同步
    行动: 搜索项目中的 Adapter 代码
    反馈: 找到 UserAdapter.kt

  Round 2:
    观察: 读取 UserAdapter.kt
    思考: notifyDataSetChanged 在子线程调用,和 RecyclerView 的布局冲突
    行动: 修改代码,用 DiffUtil + submitList 替代
    反馈: 文件已修改

  Round 3:
    观察: 运行测试
    思考: 测试通过
    行动: 完成,向用户报告修复内容

4.2 Function Calling(函数调用)

Agent 能使用工具,靠的是 Function Calling:

模型不能直接读文件、运行命令
但它可以输出结构化的"工具调用请求"

模型的输出:
{
  "tool": "read_file",
  "arguments": {
    "path": "app/src/main/java/com/example/UserAdapter.kt"
  }
}

系统(IDE/CLI)执行这个调用,把结果返回给模型:
{
  "result": "class UserAdapter : RecyclerView.Adapter<...> {\n    ..."
}

模型看到文件内容后,决定下一步操作:
{
  "tool": "edit_file",
  "arguments": {
    "path": "app/src/main/java/com/example/UserAdapter.kt",
    "old_string": "notifyDataSetChanged()",
    "new_string": "submitList(newList)"
  }
}
Function Calling 的实现原理:

模型在训练时学会了一种特殊的输出格式:
  当需要使用工具时,输出 JSON 格式的工具调用
  而不是直接输出文本

System Prompt 中定义了可用的工具:
  tools: [
    {
      name: "read_file",
      description: "读取文件内容",
      parameters: { path: string }
    },
    {
      name: "edit_file",
      description: "编辑文件",
      parameters: { path: string, old_string: string, new_string: string }
    },
    {
      name: "run_command",
      description: "运行 shell 命令",
      parameters: { command: string }
    }
  ]

模型根据当前任务,选择合适的工具调用

4.3 MCP(Model Context Protocol)

问题:每个 AI 工具都要自己实现和外部系统的对接
  Cursor 要自己实现 Git 集成
  Claude Code 要自己实现文件系统操作
  每个工具都重复造轮子

MCP 的解决方案:标准化的协议

AI 模型 ←→ MCP 协议 ←→ MCP Server(工具提供者)

MCP Server 示例:
  Git MCP Server:提供 git_log、git_diff、git_commit 等工具
  Database MCP Server:提供 query、insert、update 等工具
  Jira MCP Server:提供 create_issue、update_status 等工具

任何 AI 工具只要支持 MCP 协议,就能使用所有 MCP Server
任何工具提供者只要实现 MCP Server,就能被所有 AI 工具使用
MCP 的通信流程:

1. AI 工具启动时,连接 MCP Server
   → Server 返回可用工具列表

2. 模型需要使用工具时
   → AI 工具通过 MCP 协议调用 Server
   → Server 执行操作,返回结果
   → 结果传回给模型

3. 协议格式(JSON-RPC):
   请求: {"method": "tools/call", "params": {"name": "git_diff", "arguments": {}}}
   响应: {"result": {"content": [{"type": "text", "text": "diff --git a/..."}]}}

5. RAG(检索增强生成)在代码中的应用

5.1 为什么需要 RAG

问题:模型的训练数据有截止日期,不知道你的项目代码

用户: "UserRepository 的 getUser 方法有什么问题?"
模型: "我不知道你的 UserRepository 长什么样..."

RAG 的解决方案:先检索相关代码,再让模型回答

1. 检索:在你的代码库中搜索 "UserRepository" 相关的文件
2. 注入:把找到的代码片段放入 Prompt
3. 生成:模型基于这些代码片段回答问题

5.2 代码检索的实现

代码库索引(离线建立):

1. 遍历项目所有代码文件
2. 把每个文件/函数/类切分为代码片段(Chunk)
3. 用 Embedding 模型把每个片段转为向量
4. 存入向量数据库

代码片段:                          向量:
"class UserRepository {"     →    [0.12, -0.34, 0.56, ...]
"fun getUser(id: Int)"       →    [0.45, 0.23, -0.12, ...]
"suspend fun fetchData()"    →    [-0.08, 0.67, 0.34, ...]

查询时:
  用户问题 "UserRepository 的缓存策略" → 转为向量 → 在向量数据库中找最相似的片段
  → 返回 UserRepository 相关的代码片段
  → 注入到 Prompt 中

5.3 Embedding(嵌入向量)

Embedding 模型把文本/代码转为固定长度的向量
语义相似的内容,向量也相似(余弦相似度高)

"fun getUser(id: Int): User"  → [0.45, 0.23, -0.12, ...]
"fun fetchUser(userId: Int)"  → [0.44, 0.25, -0.10, ...]  ← 相似!
"fun deleteAll()"             → [-0.30, 0.10, 0.80, ...]  ← 不相似

相似度计算:
  cosine_similarity(getUser, fetchUser) = 0.95(高,语义相近)
  cosine_similarity(getUser, deleteAll) = 0.12(低,语义不同)

6. Prompt Engineering 在 AI Coding 中的应用

6.1 好的 Prompt vs 差的 Prompt

❌ 差的 Prompt:
  "帮我写个网络请求"

✅ 好的 Prompt:
  "用 Kotlin + Retrofit + 协程写一个 UserRepository,
   包含 getUser(id) 和 getUsers(page) 两个方法,
   返回 Flow,有错误处理,
   参考项目中已有的 ArticleRepository 的风格"

好的 Prompt 包含:
  1. 技术栈(Kotlin + Retrofit + 协程)
  2. 具体需求(哪些方法,什么参数)
  3. 返回类型(Flow)
  4. 约束条件(错误处理)
  5. 参考示例(已有代码的风格)

6.2 Few-shot Prompting

给模型几个示例,让它学会你的代码风格:

"参考以下代码风格:

// 示例 1
class ArticleRepository @Inject constructor(
    private val api: ArticleApi,
    private val dao: ArticleDao
) {
    fun getArticles(): Flow<Result<List<Article>>> = flow {
        emit(Result.Loading)
        try {
            val articles = api.getArticles()
            dao.insertAll(articles)
            emit(Result.Success(articles))
        } catch (e: Exception) {
            emit(Result.Error(e))
        }
    }
}

现在用同样的风格写一个 UserRepository"

模型会模仿示例的:
  命名规范、错误处理方式、Flow 的使用方式、Result 封装

6.3 Chain-of-Thought(思维链)

让模型先分析再写代码:

"分析这个崩溃日志,一步步思考可能的原因,然后给出修复方案:

java.lang.IndexOutOfBoundsException: Inconsistency detected.
    at RecyclerView.Recycler.tryGetViewHolderForPositionByDeadline
    at RecyclerView.fill
    at LinearLayoutManager.onLayoutChildren

请先分析:
1. 这个异常通常是什么原因导致的?
2. 在什么场景下会触发?
3. 项目中哪些代码可能有问题?
4. 最佳的修复方案是什么?"

模型会逐步推理,而不是直接给一个可能不准确的答案

7. AI Coding 工具的架构

7.1 典型架构

┌─────────────────────────────────────────────┐
│                IDE / CLI                     │
│                                             │
│  ┌─────────┐  ┌──────────┐  ┌───────────┐  │
│  │代码补全  │  │对话面板   │  │Agent 模式 │  │
│  └────┬────┘  └────┬─────┘  └─────┬─────┘  │
│       │            │              │         │
│  ┌────┴────────────┴──────────────┴────┐    │
│  │         上下文收集引擎               │    │
│  │  ┌──────┐ ┌──────┐ ┌──────────┐    │    │
│  │  │当前文件│ │LSP   │ │代码索引   │    │    │
│  │  └──────┘ └──────┘ └──────────┘    │    │
│  └─────────────────┬───────────────────┘    │
│                    │                        │
│  ┌─────────────────┴───────────────────┐    │
│  │         Prompt 构建引擎              │    │
│  └─────────────────┬───────────────────┘    │
└────────────────────┼────────────────────────┘
                     │ API 调用

              ┌──────────────┐
              │   LLM API    │
              │ (Claude/GPT) │
              └──────────────┘

7.2 不同工具的差异

GitHub Copilot:
  强项:代码补全(FIM 模型专门优化)
  模型:Codex / GPT-4 系列
  上下文:当前文件 + 打开的 Tab

Cursor:
  强项:整个项目的上下文理解
  模型:Claude / GPT-4 可切换
  上下文:代码库索引 + RAG 检索 + 当前文件

Claude Code(CLI):
  强项:Agent 模式,自主完成复杂任务
  模型:Claude
  上下文:文件系统访问 + Shell 命令 + 工具调用
  特点:在终端中运行,直接操作文件系统

8. 端侧 AI(On-Device LLM)

8.1 为什么要在手机上跑模型

云端 API 的问题:
  → 需要网络连接
  → 有延迟(几百 ms 到几秒)
  → 隐私问题(数据发送到服务器)
  → API 调用成本

端侧模型的优势:
  → 离线可用
  → 低延迟(本地推理)
  → 数据不出设备
  → 无 API 成本

8.2 端侧模型的技术挑战

手机的限制:
  内存:8-16GB(模型 + App + 系统共享)
  算力:GPU/NPU 远弱于服务器 GPU
  功耗:不能持续高负载

解决方案:

1. 模型量化(Quantization)
   FP32(32位浮点)→ INT8(8位整数)→ INT4(4位整数)
   7B 模型:FP16 = 14GB → INT4 = 3.5GB(可以在手机上跑)
   精度损失很小,速度提升 2-4 倍

2. 小模型
   Gemma 2B、Phi-3 Mini 3.8B、LLaMA 3.2 1B/3B
   专门为端侧设计的小模型

3. 硬件加速
   Android: NNAPI → GPU / NPU / DSP
   iOS: Core ML → Neural Engine
   高通: QNN SDK → Hexagon NPU

8.3 Android 端侧 AI 集成

kotlin
// Google AI Edge(MediaPipe LLM Inference API)
val llmInference = LlmInference.createFromOptions(
    context,
    LlmInference.LlmInferenceOptions.builder()
        .setModelPath("/path/to/gemma-2b-it-q4.bin")
        .setMaxTokens(1024)
        .build()
)

// 推理
val response = llmInference.generateResponse("解释 ViewModel 的作用")

// 流式输出
llmInference.generateResponseAsync("写一个单例模式") { partialResult ->
    // 逐 Token 回调
    textView.append(partialResult)
}