AI Coding Agent:从需求到代码修改的完整过程
这篇笔记用一个具体例子说明:
用户提出需求 -> AI coding 工具接收 -> Agent 检索项目上下文 -> 模型基于上下文推理 -> 定位文件、变量、行号 -> 生成 patch -> 修改代码 -> 运行验证 -> 输出结论先强调一个关键点:
当前项目上下文不是在一次任务中“后训练进模型权重”的。它是在推理阶段由 Agent 检索、筛选、压缩后放进模型上下文窗口的。
更准确地说:
预训练/后训练:让模型学会如何理解代码、如何使用上下文、如何按工具反馈工作。 推理时上下文注入:把当前项目的真实文件片段、搜索结果、报错、diff 放进 prompt,让模型基于这些证据推理。所以在 AI coding 中:
模型权重通常不变。 变化的是每一轮 prompt 里的上下文。1. 总览图
这个流程有效,不是因为模型一次性知道整个项目,而是因为 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 文本 patch7. 修改前后代码
修改前
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 会运行测试:
npmtestLoginForm如果测试失败,比如:
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
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. 最小伪代码
defai_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)whilenotresult.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)returnsummarize_changes_and_verification()这个伪代码就是 AI coding agent 的核心:
检索真实上下文 -> 模型推理 -> 修改 -> 验证 -> 失败再循环。