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、Devin2. 代码补全的原理
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 NPU8.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)
}