Hotdry.

Article

构建十个定制子代理:Metabase 驯服 500K 行 Clojure 代码库的工程实践

解析 Metabase 如何通过十个领域专家子代理控制 50 万行 Clojure 代码重构,涵盖任务分解策略、上下文管理参数与可落地实施清单。

2026-04-29ai-systems

当一个 Clojure 代码库膨胀至五十万行规模时,即便是最强大的大语言模型也会在上下文窗口的竞争中丢失关键信息。Metabase 团队在处理这一挑战时,给出了一个极具工程参考价值的解法:构建十个定制子代理,每个子代理承载特定领域的完整上下文与决策能力。这种架构不仅解决了上下文瓶颈问题,更为大型 Lisp 方言代码库的 AI 辅助重构提供了可复用的任务分解范式。

为什么大型 Lisp 代码库需要子代理架构

Clojure 作为一种运行在 JVM 之上的 Lisp 方言,其代码组织方式与主流面向对象语言存在显著差异。Metabase 的后端代码涵盖了查询处理器、权限系统、数据库驱动、通知服务等数十个高度耦合的子系统。以查询处理管线为例,从 MBQL 解析到最终 SQL 生成需要经历超过六十八个阶段的转换层,每一层都涉及复杂的中间表示与状态管理。当开发者需要修改 HoneySQL 编译逻辑或修复 Redshift 驱动的连接问题时,AI 模型必须同时理解查询管道、SQL 方言差异、驱动接口契约等多个交叉领域,这往往导致上下文溢出或推理深度不足。

子代理架构的核心价值在于将全局上下文压力转化为多个局部深度的优化问题。每个子代理维护独立的上下文窗口、系统提示与记忆机制,主代理则负责根据任务描述将请求路由至最合适的子代理。例如,当处理「优化 MBQL 中间件执行顺序」这类需求时,主代理会识别关键词并将任务委托给 mbql-expert,而非让通用会话在权限层与查询层之间反复横跳。

十个领域专家子代理的职责划分

Metabase 团队根据代码库的模块边界与业务领域,将子代理划分为以下十个角色。每个角色都对应明确的代码路径与职责范围,这使得子代理的知识可以预先注入到 Markdown 文件的 YAML 头部,实现一次加载、多次复用的效果。

mbql-expert 负责查询处理器的所有层面,包括 MBQL 语言解析、SQL 编译流程、以及中间件管道的配置。当需要修改求值顺序或添加新的结果转换阶段时,这个子代理可以快速定位到 src/metabase/query_processor 目录下的相关文件,并提供该管道历次重构的历史上下文。permissions-expert 则聚焦于访问控制、沙箱隔离、SSO 集成与嵌入安全等权限相关功能,其知识库涵盖了权限模型的设计演进与各版本 API 的兼容性注意事项。

platform-expert 管理应用数据库、HTTP 服务器、API 框架、定时任务与数据迁移等基础设施层代码。对于需要修改 API 路由或新增数据库表结构的场景,这个子代理能够提供完整的迁移路径与回滚方案。enterprise-expert 专门处理序列化、SCIM 目录同步、多租户架构与企业级功能的依赖追踪,这类功能通常涉及多个子系统的联动修改。content-expert 覆盖集合、仪表板、卡片、数据模型与版本历史等内容管理层功能,notifications-expert 则负责订阅推送、告警渲染与图表图片生成等通知相关逻辑。

在数据层面,drivers-and-sync 子代理封装了所有数据库驱动的实现细节、元数据同步机制与类型映射规则,这是 Metabase 代码库中最为复杂的领域之一。search-expert 管理搜索索引构建、X 射线分析与语义搜索功能,ai-expert 负责 Metabot v3 与 LLM 工具链的集成,而 transforms-expert 则处理数据动作、CSV 上传与模型持久化等转换功能。

任务路由与上下文复用机制

子代理的实际效果高度依赖于任务描述的精确程度与路由算法的匹配能力。Metabase 团队在实践中总结出一条关键经验:使用自然语言描述而非文件路径来定义子代理的职责。例如,主代理的系统提示中会包含类似「当任务涉及 MBQL 解析或 SQL 生成时,调用 @mbql-expert」的指令,这样 Claude Code 在解析用户请求时能够通过关键词匹配自动选择最合适的子代理。

这种路由机制的工程参数包括:描述文本长度控制在十五到三十个单词之间、包含两到三个领域专属术语、避免使用过于通用的词汇。当路由不准确时,团队建议迭代优化描述文本而非修改文件路径,因为路径会随重构而变化,但领域概念相对稳定。

上下文复用方面,每个子代理的初始化流程会加载预定义的 Markdown 文件,其中 YAML 头部包含该领域的代码位置清单、常见调查模式、已知缺陷与测试策略。正文部分则记录了关键的函数签名、协议定义与数据流走向。这种结构化知识注入方式使得子代理在首次响应时就能提供深度分析,而无需每次都从头探索代码库。

可落地的实施参数与监控要点

对于希望在自己的代码库中复制这一架构的团队,以下是关键的实施参数。子代理数量建议控制在八到十二个之间,过少会导致领域划分粗糙、上下文压力重新累积,过多则增加维护成本与路由复杂度。每个子代理应拥有独立的配置文件存储路径,推荐使用 agents/ 目录下的子目录结构,例如 agents/mbql-expert/、agents/permissions-expert/ 等。

上下文注入文件的推荐结构包含四个部分:domain 字段声明子代理的职责范围、code-paths 列举主要代码路径数组、investigation-patterns 描述常见的调试步骤、caveats 记录已知的边界情况与陷阱。文件格式使用 YAML 头部加 Markdown 正文,总行数控制在一百到两百行之间,确保加载时间在可接受范围内。

监控子代理效果的指标应聚焦于两个维度:任务完成率与上下文命中率。任务完成率衡量子代理是否能够独立完成分配的子任务,而非频繁升级至主代理处理。上下文命中率则评估子代理在单次交互中提供的答案与问题领域相关联的比例。若发现某个子代理的任务完成率持续低于百分之七十,需要重新审视其职责边界是否过于模糊或知识库是否需要补充。

REPL 驱动的工作流整合

Clojure 生态的独特优势在于 REPL 驱动的增量开发模式,这一点也被融入到子代理的工作流设计中。当 mbql-expert 需要验证某个中间件修改是否正确时,它可以在对话中生成针对该管道的求值表达式,开发者将这些表达式粘贴至正在运行的 REPL 会话中,即可实时观察中间件的输入输出变化。这种交互模式避免了传统代码修改 - 编译 - 测试循环的繁琐,使得子代理提供的重构建议能够在几分钟内得到验证。

实践中建议为每个子代理准备三到五个典型的 REPL 测试用例,作为知识库的附录存在。当子代理推荐某项修改时,这些测试用例可以作为验证步骤自动呈现给开发者。例如,permissions-expert 在建议修改沙箱逻辑时,可以附带一个预定义的测试场景:模拟普通用户访问受限数据集,预期行为是返回空结果集而非原始数据。这种可执行的验证用例大幅提升了重构建议的可信度与采纳意愿。

适用场景与局限性评估

子代理架构并非万能解,其最佳适用场景包括:代码库规模超过十万行、存在明确的功能模块边界、需要多人协同维护且领域知识高度专业化。对于小型项目或快速原型阶段,引入子代理只会增加不必要的复杂度。另一个值得注意的局限是跨领域重构的场景:当一项修改涉及权限系统与查询处理器的联动时,单个子代理可能无法提供完整的分析视角,此时需要主代理协调多个子代理并行工作,但现有的路由机制对这类协同场景的支持仍处于早期阶段。

从技术选型的角度看,如果你的项目使用的是其他 Lisp 方言如 Common Lisp 或 Scheme,或者虽使用主流语言但代码组织遵循清晰的领域划分模式,子代理架构的核心思路仍然适用。关键在于识别代码库中的自然边界,并将每个边界转化为拥有独立上下文的子代理单元。

资料来源:Metabase 官方博客介绍了其构建十个自定义子代理管理五十万行 Clojure 代码库的实践经验,详细阐述了子代理的职责划分、路由机制与 REPL 驱动的工作流整合方式。

ai-systems