在 LLM 应用领域,一个常被忽视的事实是:模型本身只是引擎,真正的工程价值往往体现在围绕模型构建的完整控制系统上。Sebastian Raschka 在其最新文章中系统性地拆解了编码智能体的六大核心组件,为开发者提供了一份可操作的工程实现参考。

从模型到控制系统:重新理解 Agent 架构

在深入具体组件之前,有必要厘清几个容易混淆的概念。Sebastian Raschka 提出了一个直观的类比:LLM 是引擎,推理模型是增强版引擎(更强大但也更昂贵),而 Agent Harness 则是帮助引擎工作的控制系统。这个类比虽然不完美,但准确传达了核心要点。

具体到编码场景,一个完整的 Coding Harness 由三层构成:模型家族提供「引擎」,Agent Loop 驱动迭代式问题解决,Runtime Supports 则负责「管道连接」。在 Agent Loop 内部,「Observe」收集环境信息,「Inspect」分析这些信息,「Choose」选择下一步行动,「Act」执行行动。这种循环机制正是编码智能体与普通对话界面的本质区别。

值得开发者注意的是,当前的 LLM Vanilla 版本之间能力已经非常接近。在这种情况下,Harness 往往成为区分不同产品表现的关键因素。Sebastian Raschka 推测,如果将最新的开源大模型放入类似的 Harness 中,其表现很可能与闭源模型在专用产品中的表现相当。这一洞察对架构选型具有重要参考意义。

组件一:实时仓库上下文(Live Repo Context)

实时仓库上下文是最直观但也最关键的组件。当用户发出「修复测试」或「实现功能」这样的指令时,模型需要知道当前是否在 Git 仓库中、处于哪个分支、项目文档中是否包含相关说明。这些细节直接影响正确操作的判断。

工程实现上,Harness 应该在开始任何工作之前,先行收集「稳定事实」作为工作区摘要。这包括:当前 Git 分支和状态、项目根目录路径、关键配置文件位置(如 AGENTS.md、README.md、pytest.ini 等)、以及项目结构概览。收集这些信息的目的是让 Agent 不是每次都从零开始,而是带着项目上下文工作。

一个可行的实现参数是:工作区摘要应该在前三次交互中保持完整,之后根据项目复杂度动态调整更新频率。对于小型项目(文件数少于 100),可以在每次重要文件操作后更新;对于大型项目,建议采用增量更新策略,只在目录结构发生显著变化时重新生成完整摘要。

组件二:提示塑形与缓存复用(Prompt Shape And Cache Reuse)

编码会话具有高度重复性的特点:Agent 规则通常保持不变,工具描述通常保持不变,甚至工作区摘要也基本保持不变。唯一频繁变化的是最新的用户请求、近期会话记录和短期记忆。

基于这一观察,Smart Runtime 不应该在每次交互时都将所有内容重新组合成一个巨大的无差异提示。正确的做法是构建一个稳定的「Prompt Prefix」,其中包含通用指令、工具描述和工作区摘要。这个 Prefix 在每次交互中被复用,只有会话状态部分需要更新。

工程实现的关键参数包括:Prompt Prefix 的缓存有效期建议设置为 5-10 分钟或 20-30 次模型调用,具体取决于项目规模和代码变更频率。当工作区发生显著变化(如切换分支、修改配置文件)时,应该主动失效缓存而不是依赖被动过期机制。

这种分离式缓存架构的优势在于:它将静态信息(系统指令、工具定义)与动态信息(用户请求、会话历史)解耦,使得模型可以在保持一致上下文的同时,高效处理多轮交互。

组件三:结构化工具、验证与权限(Structured Tools, Validation, And Permissions)

工具使用是让 Agent 感觉不像聊天而更像 Agent 的关键点。一个普通的模型可以用散文形式建议命令,但编码 Harness 中的 LLM 应该能够实际执行命令并获取结果,而不是让用户手动调用命令并粘贴结果。

实现层面,Harness 应该提供预定义的允许工具列表,每个工具具有清晰的输入格式和明确的边界。这些工具通常包括:文件列表、文件读取、代码搜索、Shell 命令执行、文件写入等。工具描述应该足够详细,使模型能够理解何时以及如何使用每个工具。

安全验证是这一组件的核心。Sebastian Raschka 强调,Harness 应该在执行任何工具之前进行以下程序化检查:工具是否已知、参数是否有效、是否需要用户审批、请求的路径是否在工作区内。这些检查不仅降低了风险,还提高了可靠性,因为模型不会执行完全任意的命令。

针对生产环境,建议的权限模型参数包括:默认情况下,文件写入操作需要用户确认;Shell 命令执行根据危险级别分类,低风险命令(如 git statusls)自动执行,中风险命令(如 pip install)需要确认,高风险命令(如 rm -rf)默认拒绝;所有文件访问必须限制在工作区目录内,禁止跨目录操作。

组件四:上下文缩减与输出管理(Context Reduction And Output Management)

上下文膨胀是 LLM 的普遍问题,但编码智能体尤其容易受到影响,原因在于多轮交互中会产生大量重复的文件读取、冗长的工具输出和日志信息。如果 Runtime 保持所有内容的完整 fidelity,会很快耗尽可用的上下文令牌。

一个成熟的 Coding Harness 需要采用两类压缩策略。第一是 Clipping(截断),用于缩短长文档片段、大型工具输出、记忆笔记和会话条目。核心原则是防止任何单段文本因为冗长而占据整个提示预算。第二是 Transcript Reduction(会话压缩),将完整的会话历史转化为更小的可提示摘要。

实现细节上,关键技巧是保持近期事件更加丰富完整,因为它们更可能与当前步骤相关;对较旧的事件进行更激进的压缩,因为它们可能不太相关。同时,对较早的文件读取进行去重,避免模型反复看到相同的文件内容,只是因为在会话早期读取过多次。

推荐的实现参数是:单个工具输出的最大 token 数设置为 2000;会话历史保留最近 10 轮完整记录,超过部分进行摘要压缩,摘要长度控制在 500 token 以内;文件读取历史采用 LRU 缓存策略,保留最近 20 个文件的读取状态。

组件五:会话记录、记忆与恢复(Transcripts, Memory, And Resumption)

这里需要区分两个相关但不同的概念。上一节讨论的是提示时如何使用历史,核心问题是:过去有多少内容应该回到模型的下一轮?重点是压缩、去重和时效性。

本节讨论的是存储时的历史结构,核心问题是:Agent 长期保留什么作为持久记录?重点是 Agent 维护一个更完整的会话记录作为持久状态,以及一个更轻量的记忆层用于跨轮传递。

具体实现上,编码智能体将状态分为至少两层:工作记忆(Working Memory)是小型、精炼的状态,Agent 明确保留;完整记录(Full Transcript)存储所有用户请求、工具输出和 LLM 响应。两者通常以 JSON 文件形式持久化到磁盘。

这种双层架构的设计考量是:完整记录确保会话可恢复(即使 Agent 意外退出),工作记忆则保持当前任务的关键信息。值得注意的是,压缩后的会话记录和工作记忆有轻微不同的职责 —— 前者用于提示重建,提供模型最近历史的压缩视图;后者更注重任务连续性,保持跨轮次最重要信息的显式维护。

推荐的实现参数:完整会话记录使用 JSONL 格式,每个事件作为一行,便于流式读取;工作记忆使用 JSON 格式,最大尺寸控制在 4KB 以内;自动保存触发条件为每完成 5 次工具调用或距离上次保存超过 2 分钟。

组件六:委托与受限子代理(Delegation And Bounded Subagents)

当 Agent 具备工具和状态后,下一个有用的能力是委托。委托允许我们通过子代理并行化某些工作并加速主任务。例如,主 Agent 可能在执行一个任务的同时,还需要一个辅助答案 —— 比如某个文件在哪里定义了一个符号、配置文件的内容是什么、为什么某个测试失败。将这些辅助任务拆分出来而不是强制单个循环处理所有工作线程,会更加高效。

然而,子代理只有在继承足够上下文的情况下才有用。如果不加以限制,现在我们有了多个代理复制工作、接触相同文件或生成更多子代理的问题。因此,棘手的设计问题不仅是「如何生成子代理」,还有「如何绑定子代理」。

Sebastian Raschka 提出的解决方案是:子代理继承足够的上下文来执行实际工作,但同时受到更严格的约束。例如,子代理默认以只读模式运行,递归深度受限,只能访问特定目录。不同的产品有不同的边界策略:Claude Code 长期支持子代理,Codex 则通常不强制子代理进入只读模式,而是继承主代理的沙箱和审批设置,边界更多体现在任务范围、上下文和深度上。

推荐的实现参数:子代理的默认权限设置为只读;最大递归深度限制为 2 层(即子代理不能再生成子代理);上下文继承策略是传递主代理工作记忆的子集(约 60%),同时附加当前任务的简要描述;子代理执行超时设置为 60 秒。

工程实践建议

基于上述分析,对于计划构建或优化编码智能体系统的团队,以下是可落地的工程参数建议:

首先,在架构层面,建议采用模块化设计,将六大组件作为独立模块实现,通过标准接口通信。这种设计允许单独升级或替换某个组件而不影响整体系统。

其次,在上下文管理上,应该建立统一的上下文预算机制,动态分配 token 给不同组件。合理的预算分配是:Prompt Prefix 占用 40%,会话历史占用 35%,当前请求和响应占用 25%。

第三,在安全性方面,所有工具调用必须经过验证层,文件操作限制在项目目录内,敏感操作需要用户确认。建议日志记录所有工具调用的请求和响应,便于审计和问题排查。

第四,在持久化设计上,会话状态应该支持中断恢复。实现定期快照机制,确保在系统异常时能够恢复到最近的有效状态。

最后,在性能优化上,利用 KV Cache 加速 Prompt Prefix 的处理;对于频繁访问的项目信息,建立专门的索引结构;对长时间运行的会话,实施上下文压缩的渐进式策略。

Sebastian Raschka 的六大组件框架为编码智能体的工程实现提供了清晰的指导。理解这些组件及其相互关系,是构建可靠、高效编码 Agent 的基础。在实际开发中,应该根据具体场景权衡各组件的实现深度,避免过度工程化同时确保关键路径的完整性。


参考资料