找回密码
立即注册
搜索
发回帖 发新帖

5040

积分

0

好友

642

主题
发表于 1 小时前 | 查看: 8| 回复: 0

面试官这个连环问,说穿了是一道送分题,同时也是一道送命题。第一问大部分人能答上来,真正容易卡住的是第二问。今天就把这道题的完整逻辑捋一遍,下次再碰到,可以直接秒答。

一、主流范式:ReAct 循环

把这些 code agent 的“引擎盖”拆开看,会发现一个共同点:它们几乎都基于同一个核心模式——ReAct 循环,也就是 Reasoning 加上 Acting。

简单说,就是一个“思考、行动、观察”的循环。模型先推理下一步该做什么,然后调用工具去执行,拿到结果之后再继续推理,如此往复,直到任务完成。

举个例子:用户说“帮我修一下登录接口报 500 的 bug”,这个 agent 的循环大概是这样:

  1. 思考:这个报错可能跟登录逻辑有关,先看看相关代码
  2. 行动:调用 grep 工具搜索 "login" 相关的文件
  3. 观察:找到了 auth.py,把内容读出来
  4. 思考:发现某处调用了一个可能为空的字段,得看看调用方传的是什么参数
  5. 行动:搜索这个函数的调用点
  6. 观察:确认问题出在参数校验缺失上
  7. 思考:修复方案确定了,写代码,跑测试,看结果

ReAct循环示意图:思考、行动、观察三个环节循环连接,每一步取决于上一步看到什么

注意,这里没有一步是提前写死的。每一步都取决于上一步“看到”了什么,这就是 ReAct 循环最直观的体现。

围绕这个循环,有几个关键的设计要素,逐个来看。

第一个是工具化操作,也就是 Tool Use 或者说 Function Calling。

读文件、写文件、执行命令、搜索代码,这些操作全都被封装成结构化的工具调用,而不是让模型直接“生成代码去跑”。好处很明显:既安全,又可控。

比如 Claude Code 里面有 bash、str_replace、create_file、view 这些工具。模型要改一行代码,会调用类似 str_replace(path="auth.py", old_str="if user:", new_str="if user is not None:") 这样的结构化指令,而不是直接吐出一整段代码让系统自己去猜怎么应用。

结构化工具调用与直接生成整段代码的对比:左侧安全可控,右侧系统靠猜

第二个是上下文管理。

真实的代码库往往大到装不进上下文窗口。所以 agent 不会试图一次性把整个项目“读完”,而是靠 grep、向量检索、文件树导航这些方式按需获取信息。

比如一个几十万行代码的单体仓库,agent 不会尝试全部塞进上下文。它会先用 grep "class UserService" 定位目标文件,再针对性地读那几百行,用完就丢,需要的时候再检索。这种看代码的方式,其实跟人类工程师很像。

几十万行单体仓库中通过grep定位目标文件,只读需要的几百行

第三个是轻量级的计划与分解。

复杂任务会先拆成子任务,比如维护一份可以随时更新的 TODO 列表,而不是一次性把所有步骤写死。

拿“给项目加一个用户注册的邮箱验证功能”来说,agent 可能会先列出:加数据库字段、写发送验证邮件的逻辑、加验证接口、更新前端提示、补测试。但执行过程中如果发现数据库层已经有类似字段了,它就会动态调整列表,把第一步改掉,或者干脆删掉,而不是死板地按原计划走完。

任务清单因发现已有字段而动态调整,计划赶不上变化

第四个是验证闭环。

代码任务有个天然优势:可以被验证。跑测试、跑编译,看看报错,再回头修正。这个反馈闭环让 agent 的每一步都有真实依据,而不是靠“脑补”。

比如改完代码跑 pytest,如果报了 TypeError: NoneType has no attribute 'id',agent 能直接拿到具体的报错信息,定位到出问题的那一行,而不是凭感觉猜“应该改好了”。这种确定性的反馈,是写文案、做设计这类任务不具备的。

纯靠脑补与pytest真实反馈的对比:右侧直接定位到出错行

第五个是人在回路,也就是 Human-in-the-loop。

关键操作,比如执行命令、写文件,通常需要用户确认。这是安全性设计里很重要的一环。agent 想执行 rm -rf 或者 git push --force 这种有风险的命令,通常会先弹出确认框,等用户点了“允许”才真正执行,而不是“先斩后奏”。

rm -rf命令需要用户点击允许才会真正执行的幽默示意

至于架构上的变体,目前工业界主流还是单一强模型加上好用的工具集。多智能体编排(Multi-Agent)更多用在特定场景,比如需要并行探索、需要隔离上下文的时候,它并不是用来取代主循环的。

二、为什么不用其他模式?

更有意思的问题来了:为什么大家没有走向别的路线?一个一个拆开看。

‣ 不用纯 Plan-and-Execute(先定计划再执行)

早期一些 agent,像 BabyAGI,流行的是这种模式:先让模型把任务拆成一个完整计划,然后逐步执行。

但代码任务的不确定性太高了。你读了一个文件之后,才知道下一步该读哪个;编译报错之前,根本不知道会报什么错。提前把计划定死,一旦现实跟预期不符,就要频繁推倒重来,反而不如“走一步看一步”高效。

定死计划导致反复推倒与走一步看一步更高效的对比

所以现在更常见的,是一种动态的、可以随时调整的轻量计划,而不是严格的“先规划、后执行”两阶段流程。

‣ 不用纯多智能体编排(Multi-Agent)

理论上你可以让“架构师 agent”“编码 agent”“测试 agent”分工协作,听起来挺美好,但实践中问题不少。

智能体之间传递上下文有损耗,容易“传话传歪”;协调开销大,排查“多个 agent 配合出错”比排查单个 agent 难得多。而且当单个模型的推理能力已经足够强时,人为拆分反而增加复杂度,收益有限。

多智能体传话过程信息失真,上下文损耗排查开销大的幽默示意

所以现在更流行的是“主 agent 加上按需派生的临时子任务执行者”这种轻量形态,而不是长期存在的多角色协作体系。比如 Claude Code 里的 sub-agent 机制:主 agent 遇到一个需要大量探索、但结果可以简单总结的子任务,比如“在整个仓库里找出所有用到某个废弃 API 的地方”,就会派生一个临时子 agent 专门跑搜索,拿到结果摘要后就结束,而不是让这个子 agent 长期存在、参与所有后续决策。

‣ 不用纯 Chain-of-Thought(无工具调用,纯靠“脑补”)

早期做法是让模型直接“想”出完整代码,一次性输出。但代码任务需要真实世界的反馈:当前文件到底长什么样?编译过没过?测试通没通过?纯靠模型内部推理,很容易产生幻觉——比如它以为某个函数存在,其实根本没有。

纯CoT脑补以为函数存在与工具调用查询真实文件返回undefined的对比

工具调用加上真实环境的反馈,才是解决这个问题的关键。这也是 ReAct 相对纯 CoT 的核心优势。

‣ 不用严格的工作流引擎/状态机

一些企业级系统会用预定义流程,比如“步骤一固定读代码,步骤二固定跑测试”。这在任务高度同质化的场景里很好用,固定 CI 流水线就是典型例子:“每次提交后自动跑 lint、跑单元测试、跑集成测试”,这种流程本来就该固定,不需要“智能”。

但代码任务的种类太多了:修 bug、加功能、重构、答疑。死板的流程很难覆盖这些长尾场景。同样是“修 bug”,有的只需改一行,有的需要跨多个模块排查根因。用同一套固定步骤去套,要么浪费步骤,要么覆盖不全,灵活性牺牲太多。

三、核心原因:三个约束决定了范式

说到底,代码任务有三个特别鲜明的特点:

  1. 环境是部分可观测的:代码库太大,装不进上下文。
  2. 有真实可执行的反馈:编译、测试能给出确定的信号。
  3. 路径高度依赖中间结果:下一步该做什么,往往取决于上一步“看到”了什么。

这三点共同决定了一件事:边推理、边行动、边观察的 ReAct 循环,比“提前定死计划”或“复杂角色分工”更贴合现实约束,也更容易调试和扩展。

这或许就是为什么,尽管 agent 设计的思路百花齐放,一旦落到“写代码”这个具体场景,大家最终都殊途同归了。如果你正在深入 Agent 开发,或者想系统补上从 RAG 到多智能体框架的完整链路,云栈社区上有不少实战导向的课程值得翻一翻,配合真实项目练手效果会更好。




上一篇:mKernel 跨节点 tile 级内核融合:Ring Attention 最高提速 1.88 倍
下一篇:90% 代码由 AI 写,Claude Code 团队怎么做 Code Review
您需要登录后才可以回帖 登录 | 立即注册

关闭

站长推荐上一条 /1 下一条

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-10-28 01:52 , Processed in 0.065500 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表