【斯坦福 AI 编程课 02】从”会话”到”会做”——Coding Agent 解剖

【斯坦福 AI 编程课 02】从"会话"到"会做"——Coding Agent 解剖

CS146S: 现代软件开发(The Modern Software Developer) 是斯坦福大学 2025 年秋季开设的一门前沿课程,由 Mihail Eric 教授主讲。课程聚焦 AI 时代的软件开发新范式——从 Coding Agent、AI IDE 到自动化运维,邀请了 Claude Code 创建者、Devin 团队、Warp CEO、a16z 合伙人等行业顶尖嘉宾分享实战经验。这是学习笔记系列的第二篇。


AI Agent Architecture

上一篇我们讲了 LLM 如何"思考"——通过预测下一个词来生成回答。但只会"说"还不够,真正的 AI 助手得会"做"。

这就引出了今天的主角:Coding Agent

它不只是会写代码,还会读文件、运行命令、调试错误、甚至部署应用。它是怎么做到的?让我们来解剖一下。

从"聊天机器人"到"工作伙伴"

普通的 LLM 只能和你对话:

你:帮我写一个 Python 脚本,读取 CSV 文件并计算平均值
AI:好的,这是代码...

(你复制代码 → 保存文件 → 运行 → 报错 → 修改 → 再运行...)

Coding Agent 不一样,它会:

你:帮我处理一下 data.csv
AI:我来读取这个文件... (执行 read_file)
AI:我看到里面有销售数据,我来计算平均值... (执行 calculate)
AI:结果保存到 result.csv 了... (执行 write_file)
AI:顺便帮你画了个图表... (执行 plot)

看出区别了吗?Agent 有"手"

这双手就是:工具(Tools)

Agent 的四大组件

一个完整的 Coding Agent 由四个核心组件构成:

1. LLM 核心——大脑

还是我们上一篇讲的那个 LLM,但角色变了。

在普通聊天中,LLM 是"答题者"。在 Agent 中,LLM 是"决策者"。

它会思考:

  • 用户想要什么?
  • 我应该用哪个工具?
  • 工具返回的结果意味着什么?
  • 下一步该做什么?

2. 工具箱——双手

Agent 能执行的各种操作,就是工具。

常见的工具类型:

工具类型 示例 用途
文件操作 read_file, write_file 读写代码文件
代码执行 run_python, run_bash 执行代码和命令
搜索 search_code, grep 查找代码片段
调试 debug, test 运行测试和调试
网络 http_request, fetch API 调用

Claude Code 有几十个工具,Devin 有上百个。工具越多,Agent 能做的事就越多。

3. 上下文管理器——记忆

这是 Agent 的"工作记忆"。

它会记住:

  • 项目结构是什么样的
  • 哪些文件已经改过了
  • 上一步做了什么
  • 错误信息是什么

没有上下文管理,Agent 就会像金鱼一样,7秒就忘。

4. 函数调用机制——神经

LLM 怎么"指挥"工具?靠 Function Calling

流程是这样的:

1. LLM 思考:"我需要读取 data.csv"
2. LLM 输出:调用 read_file("data.csv")
3. 系统执行:读取文件内容
4. 系统返回:"文件内容是..."
5. LLM 继续:根据内容思考下一步

这个过程会循环往复,直到任务完成。

工具调用的本质

Function Calling 看起来很神奇,其实原理很简单。

传统对话

用户:今天天气怎么样?
LLM:今天天气晴朗,温度25度...
(纯文本生成)

工具调用

用户:今天北京天气怎么样?
LLM:{
  "function": "get_weather",
  "parameters": {
    "city": "北京"
  }
}
系统:(执行函数,返回真实数据)
LLM:根据数据,北京今天晴,25度...

关键在于:LLM 不直接回答,而是先生成"函数调用指令"

训练 LLM 使用工具

LLM 怎么知道有哪些工具可用?

这需要在系统提示(System Prompt)中告诉它:

你是一个 Coding Agent,可以使用以下工具:

1. read_file(path) - 读取文件
   参数:path(文件路径)
   返回:文件内容

2. write_file(path, content) - 写入文件
   参数:path(路径), content(内容)
   返回:成功/失败

3. run_bash(command) - 执行命令
   参数:command(bash 命令)
   返回:执行结果

使用规则:
- 必须先读取文件,才能修改
- 修改后必须测试
- 遇到错误要调试

有了这个说明,LLM 就知道什么时候该用什么工具了。

MCP:工具的统一语言

现在有个问题:每个 Agent 都有自己的工具格式。

Claude Code 的工具调用:

{
  "name": "read_file",
  "arguments": {"path": "data.csv"}
}

Devin 的工具调用:

{
  "tool": "file_reader",
  "params": {"file": "data.csv"}
}

这不乱套了吗?

MCP(Model Context Protocol) 就是为了解决这个问题而生的。

什么是 MCP?

MCP 是一个开放协议,定义了:

  • 如何描述工具
  • 如何调用工具
  • 如何返回结果

就像 USB 接口一样——不管什么设备,插上就能用。

MCP 的三个角色

┌─────────────┐
│  MCP Client │  ← Agent(Claude Code, Cursor)
└──────┬──────┘
       │ MCP 协议
┌──────▼──────┐
│  MCP Server │  ← 工具提供者
└──────┬──────┘
       │
┌──────▼──────┐
│   本地资源   │  ← 文件系统、数据库、API
└─────────────┘

Client:Agent 本身(比如 Claude Code)

Server:提供工具的服务(比如文件系统服务、GitHub 服务)

资源:Server 能访问的东西(文件、数据库、API)

一个简单的 MCP Server

假设我们要让 Agent 访问天气 API:

from mcp.server import Server

# 创建 MCP Server
server = Server("weather-service")

# 定义工具
@server.tool()
async def get_weather(city: str) -> str:
    """获取城市天气"""
    # 调用天气 API
    weather = await fetch_weather(city)
    return f"{city} 天气:{weather}"

# 启动服务
server.run()

现在,任何支持 MCP 的 Agent 都能使用这个工具了。

为什么 MCP 很重要?

  1. 标准化:一次开发,到处使用
  2. 可组合:不同服务可以组合使用
  3. 安全:权限控制更清晰
  4. 生态:社区可以贡献工具

目前已经有:

  • GitHub MCP Server(代码仓库)
  • Google Drive MCP Server(云存储)
  • PostgreSQL MCP Server(数据库)
  • Puppeteer MCP Server(浏览器自动化)

你可以像搭积木一样,组合这些服务。

Agent 的"思考循环"

现在我们把所有组件串起来,看看 Agent 是怎么工作的。

ReAct 模式

最常用的模式是 ReAct(Reasoning + Acting)

循环开始:
  1. Thought(思考):分析当前状态,决定下一步
  2. Action(行动):调用工具
  3. Observation(观察):获取工具返回结果
  4. 重复...

直到任务完成

实际案例

任务:修复一个 bug

第1轮:
Thought: 用户说有个 bug,我需要先找到错误日志
Action: run_bash("tail -100 error.log")
Observation: TypeError: 'NoneType' object is not callable

第2轮:
Thought: 看到了 TypeError,我需要找到出错的代码位置
Action: search_code("TypeError")
Observation: 找到 3 个可能的位置

第3轮:
Thought: 第一个位置在 app.py 第 42 行,我去看看
Action: read_file("app.py", line=40, context=5)
Observation: user = get_user(id) 然后调用 user()

第4轮:
Thought: 问题找到了!get_user 可能返回 None,但代码没检查
Action: write_file("app.py", fixed_code)
Observation: 文件已更新

第5轮:
Thought: 修复完成,我运行测试验证一下
Action: run_bash("pytest tests/")
Observation: 所有测试通过

第6轮:
Thought: 任务完成!
Final Answer: 已修复 bug,原因是 get_user 可能返回 None...

这就是 Agent 的"思考过程"——不断循环,直到目标达成。

Agent 的自主级别

不是所有 Agent 都一样"聪明"。根据自主程度,可以分为三个级别:

Level 1:建议模式

Agent: 我建议修改这行代码...
人类: 好的,执行吧
Agent: (执行修改)

特点:Agent 只建议,人类批准后才执行。

适用场景:高风险操作(删除文件、部署上线)

Level 2:协作模式

Agent: 我来修改这个文件... (自动执行)
Agent: 修改完成,请检查
人类: 看起来不错

特点:Agent 自主执行,但人类会审核结果。

适用场景:日常开发(写代码、重构)

Level 3:自主模式

人类: 帮我完成这个功能
Agent: (自己规划、执行、测试、调试)
Agent: 搞定了!

特点:Agent 独立完成整个任务。

适用场景:简单重复性任务(写单元测试、更新文档)

目前的 Claude Code 主要在 Level 2,Devin 尝试达到 Level 3

实战:构建你的第一个 MCP Server

理论讲完了,来动手试试!

目标

创建一个简单的 MCP Server,让 Agent 能:

  1. 读取 TODO 列表
  2. 添加 TODO 项
  3. 标记完成

代码

# todo_mcp_server.py
from mcp.server import Server
import json

# 创建 Server
server = Server("todo-manager")

# 数据存储(简单起见用文件)
TODO_FILE = "todos.json"

def load_todos():
    try:
        with open(TODO_FILE, 'r') as f:
            return json.load(f)
    except:
        return []

def save_todos(todos):
    with open(TODO_FILE, 'w') as f:
        json.dump(todos, f)

# 定义工具

@server.tool()
async def list_todos() -> str:
    """列出所有待办事项"""
    todos = load_todos()
    if not todos:
        return "暂无待办事项"
    result = "待办列表:\n"
    for i, todo in enumerate(todos, 1):
        status = "✓" if todo['done'] else "○"
        result += f"{i}. {status} {todo['text']}\n"
    return result

@server.tool()
async def add_todo(text: str) -> str:
    """添加新的待办事项"""
    todos = load_todos()
    todos.append({
        'text': text,
        'done': False,
        'created_at': datetime.now().isoformat()
    })
    save_todos(todos)
    return f"已添加:{text}"

@server.tool()
async def complete_todo(index: int) -> str:
    """标记待办事项为完成"""
    todos = load_todos()
    if 1 <= index <= len(todos):
        todos[index-1]['done'] = True
        save_todos(todos)
        return f"已完成:{todos[index-1]['text']}"
    return "无效的序号"

# 启动 Server
if __name__ == "__main__":
    server.run()

测试

# 安装 MCP SDK
pip install mcp

# 启动 Server
python todo_mcp_server.py

# 在 Claude Code 中使用
# Agent 会自动发现这些工具

现在,你就可以对 Agent 说:"帮我看看有什么待办事项",它会调用你的 MCP Server 来获取数据。

小结:从"会话"到"会做"

这一讲我们拆解了 Coding Agent 的内部构造:

  1. LLM 是大脑:负责思考和决策
  2. 工具是双手:负责执行操作
  3. 上下文是记忆:记住做过什么
  4. 函数调用是神经:连接大脑和双手
  5. MCP 是协议:让工具可以通用

理解了这些,你就能:

  • 更好地使用 Agent(知道它能做什么、不能做什么)
  • 调试 Agent(知道哪里出了问题)
  • 扩展 Agent(给它添加新能力)

下一讲,我们会深入 AI IDE——看看 Claude Code、Cursor 这些工具是如何把 Agent 集成到开发环境中的。


思考题

  1. 如果让你设计一个 Agent 来帮你写作业,它需要哪些工具?
  2. Level 3 的自主 Agent 有什么风险?如何控制?
  3. MCP 和传统的 API 有什么区别?

延伸阅读


系列导航:第01篇:LLM 原理揭秘 | 第02篇:Coding Agent 解剖 | 第03篇:AI IDE(待发布)

Views: 0