AI Coding Agent:从需求到代码修改的完整过程

这篇笔记用一个具体例子说明:

用户提出需求
-> AI coding 工具接收
-> Agent 检索项目上下文
-> 模型基于上下文推理
-> 定位文件、变量、行号
-> 生成 patch
-> 修改代码
-> 运行验证
-> 输出结论

先强调一个关键点:

当前项目上下文不是在一次任务中“后训练进模型权重”的。它是在推理阶段由 Agent 检索、筛选、压缩后放进模型上下文窗口的。

更准确地说:

预训练/后训练:让模型学会如何理解代码、如何使用上下文、如何按工具反馈工作。
推理时上下文注入:把当前项目的真实文件片段、搜索结果、报错、diff 放进 prompt,让模型基于这些证据推理。

所以在 AI coding 中:

模型权重通常不变。
变化的是每一轮 prompt 里的上下文。

1. 总览图

否

是

用户需求 Prompt

AI Coding Agent 接收任务

任务理解与拆解

生成检索计划

工具检索项目上下文

rg 搜索关键词/符号

读取相关文件片段

查看测试/类型/调用链

上下文打包 Context Pack

模型推理

形成工程假设

定位修改点

文件路径

函数/组件

变量/状态

具体行号或 anchor 文本

生成最小 patch

Agent 应用修改

运行测试/类型检查/lint

验证通过?

读取报错并补充上下文

总结修改和证据

这个流程有效,不是因为模型一次性知道整个项目,而是因为 Agent 不断把“与当前任务最相关的证据”放进模型上下文。

2. 示例需求

用户输入:

登录失败时页面没有错误提示,请修复。

这个 prompt 进入 AI coding 工具后,会被转成一个工程任务:

目标:登录失败时展示用户可见的错误信息。
需要找:
1. 登录表单组件
2. 提交处理函数
3. API 调用和错误分支
4. UI 中是否已有 error state
5. 相关测试是否存在

3. Agent 如何把需求转成检索动作

模型不会凭空知道代码在哪里。Agent 会先用工具查证。

可能的检索动作:

rg "login|Login|signIn|auth" src tests
rg "setError|errorMessage|toast|role=\"alert\"" src tests
rg "useLogin|loginUser|authApi" src

假设搜索结果返回:

src/components/LoginForm.tsx:12:function LoginForm()
src/components/LoginForm.tsx:28:const [errorMessage, setErrorMessage] = useState("")
src/components/LoginForm.tsx:41:await authApi.login(email, password)
src/api/auth.ts:8:export async function login(email, password)
tests/LoginForm.test.tsx:15:it("submits credentials")

这一步的关键是:

行号不是模型猜出来的。
行号来自工具对真实文件的搜索和读取结果。

4. 上下文如何进入模型

Agent 会读取相关文件片段,并组装成模型可读的上下文包。

例如:

用户需求:
登录失败时页面没有错误提示,请修复。

相关搜索结果:
- src/components/LoginForm.tsx:28 errorMessage state
- src/components/LoginForm.tsx:41 authApi.login
- tests/LoginForm.test.tsx 登录测试

文件片段:
src/components/LoginForm.tsx:24-48
24  export function LoginForm() {
25    const [email, setEmail] = useState("")
26    const [password, setPassword] = useState("")
27    const [loading, setLoading] = useState(false)
28    const [errorMessage, setErrorMessage] = useState("")
29
30    async function handleSubmit(event) {
31      event.preventDefault()
32      setLoading(true)
33
34      try {
35        await authApi.login(email, password)
36        navigate("/dashboard")
37      } catch (error) {
38        console.error(error)
39      } finally {
40        setLoading(false)
41      }
42    }
43
44    return (
45      <form onSubmit={handleSubmit}>
46        {errorMessage && <p className="error">{errorMessage}</p>}
47        ...
48      </form>

注意:这些内容是推理时 prompt 的一部分,不是训练数据写进权重。

模型此时看到的是:

需求 + 搜索结果 + 文件路径 + 行号 + 真实代码片段

然后才开始推理。

5. 模型如何推理

模型基于上下文会形成因果链:

1. LoginForm 已经有 errorMessage 状态。
2. UI 第 46 行已经会展示 errorMessage。
3. 但 catch 分支第 37-39 行只 console.error,没有 setErrorMessage。
4. 因此登录失败时 UI 状态没有变化。
5. 最小修复是在 catch 分支设置 errorMessage。

这不是模型“记住项目”,而是模型对上下文片段做局部推理。

6. 如何定位到哪一行、哪些变量

定位通常靠三类信息共同完成。

1. 工具给出的行号

搜索和读取文件会返回路径和行号:

src/components/LoginForm.tsx:28
src/components/LoginForm.tsx:37
src/components/LoginForm.tsx:46

模型把这些行号作为证据引用。

2. 代码结构和变量关系

模型看到:

const [errorMessage, setErrorMessage] = useState("")

它会推断:

errorMessage 是 UI 显示状态。
setErrorMessage 是更新错误信息的 setter。

看到:

catch (error) {
  console.error(error)
}

它会推断:

错误发生时没有调用 setErrorMessage。

看到:

{errorMessage && <p className="error">{errorMessage}</p>}

它会推断:

只要设置 errorMessage,页面就会显示错误。

3. 修改 anchor

真正应用 patch 时,Agent 不应只依赖“第 37 行”。因为文件可能变化,行号会漂移。

更稳的方式是用 anchor 文本:

} catch (error) {
  console.error(error)
} finally {

然后替换成:

} catch (error) {
  console.error(error)
  setErrorMessage("登录失败,请检查邮箱和密码。")
} finally {

所以精确定位不是单点能力,而是:

工具行号 + 代码结构理解 + anchor 文本 patch

7. 修改前后代码

修改前

async function handleSubmit(event) {
  event.preventDefault()
  setLoading(true)

  try {
    await authApi.login(email, password)
    navigate("/dashboard")
  } catch (error) {
    console.error(error)
  } finally {
    setLoading(false)
  }
}

修改后

async function handleSubmit(event) {
  event.preventDefault()
  setLoading(true)
  setErrorMessage("")

  try {
    await authApi.login(email, password)
    navigate("/dashboard")
  } catch (error) {
    console.error(error)
    setErrorMessage("登录失败,请检查邮箱和密码。")
  } finally {
    setLoading(false)
  }
}

这里有两个修改点:

1. 提交开始时清空旧错误:setErrorMessage("")
2. 登录失败时设置新错误:setErrorMessage("登录失败,请检查邮箱和密码。")

为什么要清空旧错误?

如果用户第一次失败,页面显示错误;第二次重新提交时,旧错误不应一直残留。

8. 这个 patch 是如何生成的

模型生成的不是“随便写一段代码”,而是基于上下文做最小编辑:

目标变量:errorMessage / setErrorMessage
目标函数:handleSubmit
目标分支:catch
辅助位置:try 前清空旧错误
不改动:authApi.login、navigate、form 结构

伪代码:

context = retrieve_relevant_context(user_request)

analysis = model.reason(
    request=user_request,
    files=context.files,
    search_results=context.search_results,
)

edit_plan = {
    "file": "src/components/LoginForm.tsx",
    "anchors": [
        "setLoading(true)",
        "} catch (error) {\n    console.error(error)\n  } finally {",
    ],
    "changes": [
        "insert setErrorMessage(\"\") after setLoading(true)",
        "insert setErrorMessage(\"登录失败,请检查邮箱和密码。\") after console.error(error)",
    ],
}

patch = model.generate_patch(edit_plan, context)
agent.apply_patch(patch)

9. 验证过程

修改后 Agent 会运行测试:

npm test LoginForm

如果测试失败,比如:

TestingLibraryElementError: Unable to find role="alert"

Agent 会再次读取 UI 片段:

{errorMessage && <p className="error">{errorMessage}</p>}

模型会推断:

测试希望错误提示具备 role="alert"。
当前 p 标签只有 className,没有 role。

于是二次修改:

{errorMessage && (
  <p className="error" role="alert">
    {errorMessage}
  </p>
)}

这就是闭环:

修改 -> 测试 -> 报错 -> 补上下文 -> 再推理 -> 再修改

10. Sequence Diagram

测试/类型检查文件系统大模型工具层AI Coding Agent用户测试/类型检查文件系统大模型工具层AI Coding Agent用户alt[测试失败][测试通过]登录失败时没有错误提示,请修复解析需求,生成检索计划搜索 login/auth/error/setErrorrg 搜索关键词读取文件索引和内容返回路径、行号、片段搜索结果读取 LoginForm.tsx 相关行read file代码片段 24-48 行注入需求 + 搜索结果 + 文件片段推理出 catch 分支未设置 errorMessage请求生成最小 patchpatch: 在 handleSubmit 中设置 setErrorMessage应用 patch修改 LoginForm.tsx运行 LoginForm 测试通过或返回报错注入报错 + 相关代码生成修正 patch再次应用 patch再次验证汇报修改内容和验证结果

11. 大模型和 Agent 分别负责什么

大模型负责

理解自然语言需求
解释代码片段
建立因果链
识别变量和函数关系
判断最小修改点
生成 patch
阅读测试失败信息
总结结果

Agent 负责

搜索文件
读取文件
管理上下文窗口
提供路径和行号
应用 patch
运行命令
收集报错
循环验证
控制任务状态

一句话:

模型负责推理。
Agent 负责取证、执行和验证。

12. 为什么它能很好地工作

它能工作,不是因为模型一次性知道全部代码,而是因为形成了工程闭环:

真实代码上下文
+ 模型代码推理能力
+ 工具精确定位
+ patch 小步修改
+ 测试硬反馈
= 相对可靠的 AI coding 过程

其中最关键的是上下文注入:

没有上下文,模型只能猜。
有上下文,模型可以基于真实代码推理。
有测试反馈,模型可以从错误中修正。

13. 再次澄清:上下文和后训练的关系

要区分两个概念:

后训练阶段

后训练发生在模型发布或使用前:

SFT / DPO / RLHF / GRPO / agent trajectory training

它改变模型参数,让模型学会:

如何听指令
如何看代码
如何调用工具
如何根据报错修复
如何输出 patch

推理阶段上下文

AI coding 时,当前项目文件片段是推理输入:

用户需求 + 文件片段 + 搜索结果 + 报错 + diff

它不改变模型参数,只改变当前这一次回答的依据。

所以正确理解是:

后训练教会模型“如何使用上下文”。
Agent 在推理时把“当前项目上下文”放进去。
模型基于这些上下文进行代码推理和 patch 生成。

14. 最小伪代码

def ai_coding_task(user_prompt):
    task = model.parse_task(user_prompt)

    search_queries = model.plan_search(task)
    search_results = tools.rg(search_queries)

    files = tools.read_relevant_files(search_results)
    context_pack = build_context_pack(
        user_prompt=user_prompt,
        search_results=search_results,
        files=files,
    )

    diagnosis = model.reason(context_pack)
    edit_plan = model.plan_edit(diagnosis)

    patch = model.generate_patch(edit_plan, context_pack)
    tools.apply_patch(patch)

    result = tools.run_tests(edit_plan.related_tests)

    while not result.ok:
        failure_context = build_context_pack(
            user_prompt=user_prompt,
            previous_patch=patch,
            test_output=result.output,
            files=tools.read_relevant_files(result.related_files),
        )

        diagnosis = model.reason(failure_context)
        patch = model.generate_patch(diagnosis, failure_context)
        tools.apply_patch(patch)
        result = tools.run_tests(edit_plan.related_tests)

    return summarize_changes_and_verification()

这个伪代码就是 AI coding agent 的核心:

检索真实上下文 -> 模型推理 -> 修改 -> 验证 -> 失败再循环。
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐