【转载】Coding Agent的组成

原文地址:Components of A Coding Agent,by Sebastian Raschka, on 2026-04-04

Coding Agent的组成:Coding Agent如何借助工具、记忆与 repo 上下文,让 LLM 在实际应用中发挥更优效果

在本文中,我将全面讲解 coding agents 与 agent harnesses 的设计体系:它们的定义、运行机制,以及各个模块在实践中的协作逻辑。读过我《Build a Large Language Model (From Scratch)》和《Build a Large Reasoning Model (From Scratch)》的读者经常问及代理相关的问题,因此我打算写一篇可供查阅的系统参考文章。

更宽泛地说,代理已经成为 LLM 领域的核心议题之一:近期 LLM 系统的实用化突破,往往不只是模型本身的迭代,更多在于应用方式的升级。在绝大多数真实业务场景中,外围系统(工具调用、上下文管理、记忆机制等)的价值,和模型本身同等重要。这也解释了为什么 Claude Code、Codex 这类产品,比起在普通聊天界面中使用同款模型,实际体验会明显更强。

本文会拆解 coding agent 的六大核心构建模块。

Claude Code、Codex CLI 与其他Coding Agent

你或许已经熟悉 Claude Code 或者 Codex CLI。简单来说,它们本质上是具备代理能力的编码工具:在 LLM 之外包裹了一层应用层,也就是所谓的 agentic harness(代理式框架),从而让编码任务更高效、体验更顺滑。

figure01

图 1:Claude Code CLI、Codex CLI,以及我开发的 mini-coding-agent(https://github.com/rasbt/mini-coding-agent

coding agents 是面向软件开发场景定制的系统,其核心竞争力不止来自模型选型,更来自外围系统的能力,包括 repo 上下文感知、工具设计、prompt 缓存稳定性、记忆机制,以及长会话连续性。

这个区分非常关键:当我们谈论 LLM 的编码能力时,人们常常把模型本身、推理行为和代理产品混为一谈。在深入讲解 coding agent 的技术细节之前,我先简单梳理 LLM、推理模型(reasoning model)和代理(agent)这几个概念的差异。

LLM、推理模型与代理的关系

LLM 是核心的下一词元预测模型。推理模型本质上仍属于 LLM,但它通常经过专项训练或 prompt 优化,会在生成过程中投入更多算力做中间推导、自我校验,或是对候选答案进行检索。

代理(Agent) 则是叠加在模型之上的一层系统,可以理解为围绕模型的控制循环。给定目标后,代理层(或框架)会自主决定下一步检查什么、调用哪些工具、如何更新状态,以及何时终止任务。

我们可以用一个粗略的类比来理解三者关系:LLM 是发动机,推理模型是升级后的高性能发动机(动力更强,但运行成本也更高),而 agent harness 则是让发动机真正发挥作用的整车系统。这个类比并不完全严谨 —— 常规 LLM 和推理 LLM 本身也可以独立使用(在聊天界面或 Python 会话中),但希望能帮你理解核心逻辑。

figure02

图 2:常规 LLM、推理 LLM(或推理模型),以及包裹在 agent harness 中的 LLM 三者的关系

换句话说,代理是在特定环境中反复调用模型的闭环系统。

简言之,我们可以这样总结几个概念:

  • LLM:原始模型本体

  • Reasoning model(推理模型):经过优化的 LLM,擅长输出中间推理链路,并且具备更强的自我校验能力

  • Agent(代理):结合模型、工具、记忆和环境反馈来完成任务的循环系统

  • Agent harness(代理框架):代理外围的软件支架,负责管理上下文、工具调用、prompt、状态和控制流

  • Coding harness(编码框架):agent harness 的一个特例,是面向软件工程任务的专项框架,负责管理代码上下文、工具、执行过程和迭代反馈

如上文所述,在代理和编码工具领域,agent harness 和(agentic)coding harness 是两个常用术语。coding harness 是围绕模型的软件支架,帮助模型高效地编写和修改代码;而 agent harness 范围更广,不局限于编码场景(比如 OpenClaw 就属于这类)。Codex 和 Claude Code 都可以归为 coding harness。

当然,能力更强的 LLM 能为推理模型(需要额外训练)提供更好的基础,而 harness 则能进一步释放推理模型的潜力。

诚然,LLM 和推理模型本身也能独立完成编码任务(不需要 harness),但编码工作不只是下一词元生成。很大一部分工作在于 repo 导航、代码搜索、函数查找、diff 应用、测试执行、错误排查,以及把所有相关信息维持在上下文中。(程序员都知道这是很费脑力的工作,这也是为什么我们编码时不喜欢被打断的原因 :))

figure03

图 3:一个 coding harness 包含三层:模型家族、代理循环和运行时支撑。模型提供 “引擎”,代理循环驱动迭代式问题求解,运行时支撑提供底层设施。在循环内部,“observe(观察)” 从环境收集信息,“inspect(检视)” 分析信息,“choose(决策)” 选择下一步行动,“act(执行)” 落地操作。

这里的核心结论是:优秀的 coding harness 能让推理模型和非推理模型的表现,都远胜于在普通聊天框中的表现,核心原因就是它能高效地管理上下文等关键要素。

编码框架(Coding Harness)

上一节提到,我们所说的 harness,通常指模型外围的软件层,负责组装 prompt、开放工具能力、追踪文件状态、应用代码修改、运行命令、管理权限、缓存稳定前缀、存储记忆等等。

如今,相比直接给模型发 prompt 或是使用网页聊天界面(更接近 “上传文件聊天” 的模式),这一层软件在很大程度上决定了用户体验。

在我看来,如今主流 LLM 的基础版本能力都很接近(比如 GPT-5.4、Opus 4.6、GLM-5 这些模型的原生版本),harness 往往成为区分不同 LLM 实际表现的关键因素。

这是我的推测:如果把最新、能力最强的开源 LLM(比如 GLM-5)放进一套成熟的 harness 中,它的表现很可能和 Codex 中的 GPT-5.4、Claude Code 中的 Claude Opus 4.6 不相上下。当然,针对 harness 的专项后训练通常会带来额外提升。比如 OpenAI 过去就一直维护单独的 GPT-5.3 和 GPT-5.3-Codex 版本。

下一节,我将结合自己的 Mini Coding Agent(https://github.com/rasbt/mini-coding-agent),更具体地讲解 coding harness 的核心组件。

figure04

图 4:下文将讨论的 coding agent /coding harness 的主要框架特性

顺便一提,为了简化表述,本文中 “coding agent” 和 “coding harness” 两个术语会交替使用。(严格来说,agent 是模型驱动的决策循环,而 harness 是外围的软件支架,提供上下文、工具和执行支撑。)

figure05

图 5:极简但完整可运行、从零实现的 Mini Coding Agent(https://github.com/rasbt/mini-coding-agent)(纯 Python 实现)

以下就是 coding agent 的六大核心组件。你可以查看我那个极简但完整可运行的从零实现项目源码(https://github.com/rasbt/mini-coding-agent/blob/main/mini_coding_agent.py,纯 Python 实现)来获取更具体的代码示例。代码中通过注释标注了下面要讲的六大组件:

##############################
#### Six Agent Components ####
##############################
# 1) Live Repo Context -> WorkspaceContext
# 2) Prompt Shape And Cache Reuse -> build_prefix, memory_text, prompt
# 3) Structured Tools, Validation, And Permissions -> build_tools, run_tool, validate_tool, approve, parse, path, tool_*
# 4) Context Reduction And Output Management -> clip, history_text
# 5) Transcripts, Memory, And Resumption -> SessionStore, record, note_tool, ask, reset
# 6) Delegation And Bounded Subagents -> tool_delegate

1. 实时代码仓库上下文(Live Repo Context)

这可能是最显而易见的组件,但也是最重要的组件之一。

当用户说 “修复测试用例” 或者 “实现某某功能” 时,模型需要知道自己是否在一个 Git repo 中、当前在哪个分支、哪些项目文档可能包含说明信息等等。

因为这些细节往往会决定或影响正确的操作是什么。比如,“修复测试用例” 本身不是一个完整的指令。如果代理能看到 AGENTS.md 或者项目 README,就能知道该运行哪个测试命令;如果它知道 repo 的根目录和结构,就能去正确的位置查找,而不是靠猜测。

此外,git 分支、状态和提交记录也能提供更多上下文,帮助判断当前正在进行哪些改动、应该聚焦在哪里。

figure06

图 6:agent harness 首先会生成一份精简的工作区摘要,和用户请求结合在一起,为模型提供额外的项目上下文。

核心要点是:coding agent 在开始工作前,会预先收集信息(作为工作区摘要的 “稳定事实”),这样它不会每次响应 prompt 都从零开始、毫无上下文。

2. Prompt 结构与缓存复用

当代理获取了 repo 视图后,下一个问题就是如何把这些信息喂给模型。上一张图展示了简化的形式(“组合 prompt:前缀 + 请求”),但实际上,如果每次用户查询都重新拼接、重新处理工作区摘要,会相当浪费算力。

也就是说,编码会话是重复性的:代理规则通常保持不变,工具描述通常也不变,甚至连工作区摘要大部分时候也基本一致。真正变化的通常是最新的用户请求、近期的对话记录,可能还有短期记忆。

“智能” 的运行时不会每一轮都把所有内容重建成一个庞大的、无差别的 prompt,如下图所示。

figure07

图 7:agent harness 构建一个稳定的 prompt 前缀,加入变化的会话状态,再把组合后的 prompt 喂给模型。

这一部分和第 1 点的主要区别是:第 1 点侧重收集 repo 事实,而这里关注的是如何高效地打包和缓存这些事实,供多次模型调用使用。

“稳定 prompt 前缀” 的意思是,其中包含的信息不会频繁变动,通常包括通用指令、工具描述和工作区摘要。如果没有重要变化,我们没必要每次交互都从头重建它,浪费算力。

其他组件则更新得更频繁(通常每轮都更新),包括短期记忆、近期对话记录和最新的用户请求。

简而言之,“稳定 prompt 前缀” 的缓存逻辑就是:智能运行时会尽量复用这部分内容。

3. 工具访问与调用

到了工具访问与调用这一步,体验就开始不像聊天,而更像真正的代理了。

普通的模型可以用自然语言建议命令,但处在 coding harness 中的 LLM,应该做更精准、更有用的事 —— 真正执行命令并获取结果(而不是我们手动敲命令再把结果粘贴回聊天框)。

但框架通常不会让模型随意自创语法,而是提供一份预定义的、有名称的工具列表,包含明确的输入和边界。(当然,类似 Python subprocess.call 这样的能力也可以包含在内,这样代理也能执行各种 shell 命令。)

工具调用的流程如下图所示。

figure08

图 8:模型输出结构化动作,harness 校验动作,按需请求用户批准,执行操作,再把受限的结果反馈回循环中。

为了说明这一点,下面是我的 Mini Coding Agent 中用户看到的工具调用示例。(它不像 Claude Code 或 Codex 那么美观,因为它非常极简,只用纯 Python 实现,没有外部依赖。)

figure09

图 9:Mini Coding Agent 中工具调用审批请求的示例

在这里,模型必须选择 harness 能识别的动作,比如列出文件、读取文件、搜索、运行 shell 命令、写入文件等等。同时,它提供的参数格式必须能被 harness 校验通过。

因此当模型请求执行某个操作时,运行时可以介入并做程序化检查,比如:

  • “这是已知的工具吗?”

  • “参数合法吗?”

  • “这个操作需要用户批准吗?”

  • “请求的路径是否在工作区范围内?”

只有这些检查都通过后,才会真正执行操作。

虽然运行 coding agents 本身存在一定风险,但 harness 的校验机制也提升了可靠性,因为模型不会执行完全任意的命令。

此外,除了拒绝格式错误的操作和设置审批门控,还可以通过校验文件路径,把文件访问限制在 repo 内部。

从某种意义上说,harness 限制了模型的自由度,但同时也提升了实用性。

4. 最小化上下文膨胀

上下文膨胀(context bloat)不是 coding agents 独有的问题,而是所有 LLM 都面临的共性问题。诚然,如今 LLM 支持的上下文长度越来越长(我最近也写过一篇文章,讲解让长上下文在算力上更可行的注意力变体:https://magazine.sebastianraschka.com/p/visual-attention-variants),但长上下文依然成本高昂,而且如果包含大量无关信息,还会引入额外噪声。

coding agents 在多轮对话中比普通 LLM 更容易出现上下文膨胀,因为会反复读取文件、产生冗长的工具输出、日志等等。

如果运行时把所有内容都完整保留,很快就会耗尽可用的上下文 token。因此,优秀的 coding harness 通常在处理上下文膨胀方面做得很精细,不止是像普通聊天界面那样简单截断或概括信息。

从概念上讲,coding agents 中的上下文压缩机制大致如下图所示。具体来说,我们把视角放大到上一节图 8 中的 clip(截断)环节。

figure10

图 10:长输出会被截断,重复的旧文件读取会被去重,对话记录在放回 prompt 前会被压缩。

一个极简的 harness 至少会采用两种压缩策略来应对这个问题。

第一种是截断(clipping):缩短长文档片段、大型工具输出、记忆笔记和对话条目。换句话说,防止单条文本因为本身冗长就占用过多的 prompt 配额。

第二种策略是对话精简或摘要:把完整的会话历史压缩成更短的、可放入 prompt 的摘要。

这里的一个关键技巧是:近期事件保留更完整的信息,因为它们对当前步骤更重要;而更早的事件则更大力度地压缩,因为它们相关性更低。

此外,我们还会对较早的文件读取结果去重,避免模型因为会话中多次读取同一个文件,就反复看到相同的文件内容。

总的来说,我认为这是优秀 coding agent 设计中最被低估、也最枯燥的部分之一。很多表面上的 “模型质量” 差异,本质上其实是上下文质量的差异。

5. 结构化会话记忆

实际上,这里讲的六大核心概念是高度交织的,不同章节和图表从不同侧重点或粒度对它们进行了讲解。上一节我们讲了 prompt 阶段的历史使用,以及如何构建精简的对话记录,核心问题是:下一轮调用模型时,应该把多少历史信息放回去?因此重点在于压缩、截断、去重和时效性。

而本节的结构化会话记忆,关注的是历史信息在存储层面的结构。核心问题是:代理会长期保存哪些内容作为永久记录?因此重点在于:运行时会保存一份完整的对话记录(full transcript)作为持久化状态,同时还有一个更轻量的记忆层 —— 体量更小,会被修改和压缩,而不是简单追加内容。

总结来说,coding agent 至少把状态分成两层:

  • 工作记忆(working memory):代理显式维护的精简状态

  • 完整对话记录(full transcript):涵盖所有用户请求、工具输出和 LLM 响应

figure11

图 11:新事件会追加到完整对话记录中,同时也会被摘要更新到工作记忆里。磁盘上的会话文件通常以 JSON 格式存储。

上图展示了两类主要的会话文件:完整对话记录和工作记忆,它们通常以 JSON 文件形式存在磁盘上。如前所述,完整对话记录存储全部历史,关闭代理后可以恢复会话;工作记忆则更像是提炼后的版本,保存当前最重要的信息,和精简对话记录有一定关联。

但精简对话记录和工作记忆的作用略有不同。精简对话记录用于重建 prompt,目的是给模型提供近期历史的压缩视图,让它不用每轮都看完整对话就能继续交流;工作记忆则更偏向任务连续性,目的是跨轮次维护一小份显式的关键信息摘要,比如当前任务、重要文件和近期记录。

按照上图的步骤 4,最新的用户请求,加上 LLM 响应和工具输出,会作为 “新事件” 同时记录到完整对话记录和工作记忆中,进入下一轮循环(图中没有画出,以避免画面杂乱)。

6. 基于受限子代理的任务委派

当代理具备了工具和状态之后,下一个实用的能力就是任务委派(delegation)。

原因在于,它可以把部分工作拆分成子任务,通过 subagents 并行处理,加快主任务的进度。比如,主代理可能正在处理某项任务,但同时还需要解答一个侧边问题 —— 比如某个符号在哪个文件中定义、配置项是什么意思、或者某个测试为什么失败。把这类问题拆成一个受限的子任务会更高效,而不是让一个循环同时处理所有工作。

(在我的 mini coding agent 中,实现方式更简单,子代理仍然同步运行,但核心思路是一致的。)

子代理只有继承了足够的上下文才能真正发挥作用。但如果不加限制,就会出现多个代理重复工作、操作同一个文件,或者不断衍生更多子代理等问题。

因此,设计的难点不只是如何生成子代理,还有如何约束它。

figure12

图 12:子代理继承足够的上下文以保证可用性,但运行在比主代理更严格的边界内。

这里的诀窍是:子代理继承足够的上下文来完成工作,但同时受到约束(比如只读模式、递归深度限制)。

Claude Code 很早就支持 subagents,Codex 近期也加入了该功能。Codex 一般不会把子代理强制设为只读模式,它们通常会继承主代理的大部分沙箱权限和审批设置。因此,边界更多体现在任务范围、上下文和深度上。

组件总结

上文讲解了 coding agent 的核心组件。如前所述,它们在实现中或多或少是深度交织的。但我希望逐一拆解的方式,能帮助大家建立对 coding harness 工作原理的整体认知,理解为什么相比简单的多轮聊天,它们能让 LLM 变得更实用。

figure13

图 13:前文讨论的 coding harness 的六大核心特性

如果你想看到这些组件用简洁、极简的 Python 代码实现,可以看看我的项目:https://github.com/rasbt/mini-coding-agent

和 OpenClaw 相比有什么不同?

OpenClaw 是一个很有意思的参照对象,但它和 coding agent 不属于完全同类的系统。

OpenClaw 更偏向一个本地通用代理平台,也具备编码能力,而不是专门的(终端型)编码助手。

它和 coding harness 仍有不少重合之处:

  • 它会使用工作区中的 prompt 和指令文件,比如 AGENTS.mdSOUL.mdTOOLS.md

  • 它保存 JSONL 格式的会话文件,包含对话压缩和会话管理能力

  • 它可以生成助手会话和 subagents

  • 等等

不过如前所述,两者的侧重点不同。coding agents 是为在仓库中工作的用户优化的,让编码助手可以高效地检查文件、修改代码、运行本地工具。而 OpenClaw 更优化于跨聊天、频道和工作区运行多个长生命周期的本地代理,编码只是其中一项重要的工作负载。


最后,我很高兴地告诉大家,《Build A Reasoning Model (From Scratch)》已经完成撰写,所有章节都已进入早期访问阶段。出版社目前正在排版,预计今年夏天正式面世。

这大概是我迄今为止最有野心的一本书。我花了大约一年半时间撰写,其中包含了大量实验。无论是投入的时间、精力还是打磨的精细度,它都算得上是我最用心的一本书,希望你们会喜欢。

《Build a Reasoning Model (From Scratch)》购买链接:https://mng.bz/Nwr7https://amzn.to/4aAKiFY

本书核心主题包括:

  • 推理模型评估

  • 推理时算力扩展

  • 自我优化

  • 强化学习

  • 模型蒸馏

如今关于 LLM 中的 “推理” 有很多讨论,而我认为理解其真正含义的最佳方式,就是从零开始实现一个推理模型!

https://amzn.to/4aAKiFY(预售)
https://mng.bz/Nwr7(全书电子版,排版前版本,共 528 页)

Leave a Reply

Your email address will not be published. Required fields are marked *

*