当你对AI编程助手说“帮我修一下这个函数”,它通常能干净利落地完成。可一旦换成“给项目加上Postgres支持”这种全局任务,麻烦就来了——它会在六个地方同时动刀,每处都在猜你的意图,然后悄悄搞砸第七处。这问题的根源并非模型能力不足,而是代码本身从未向任何人(包括机器)清楚说明:哪些地方可以改,哪些不能碰。
六边形架构正好提供了一份这样的说明书。这个由Alistair Cockburn在2005年以“端口与适配器”命名、后来被广泛称为六边形架构的设计思路,恰好是AI编程代理最需要的边界规则:窄接口、受控的爆炸半径、以及一份代理能在动手前就读懂的规约。它告诉机器,改动只允许发生在边缘,核心区域不得越界。
六边形架构只有一条铁律:依赖必须指向内核。业务逻辑居于正中心,它定义自己需要的外部世界接口(比如存数据、发邮件),但丝毫不关心这些接口由谁实现。所有的Web框架、数据库驱动、JSON序列化这些技术细节,全都住在边缘,并且只能依赖内核,绝不能反过来。把它画成图,就是一圈圈同心环,所有箭头都直指圆心:服务器→适配器→应用层→领域层。领域层只包含业务类型和端口(Rust中就是trait),应用层针对这些端口编写用例,适配器是HTTP处理器、Postgres客户端或内存模拟实现,而服务器这个装配点负责把具体的适配器插到内核上。
在Rust里,这条规则能被编译器强制执行。大多数语言只能把依赖方向写进文档,然后祈祷团队遵守;Rust却可以把每一层拆成独立的crate,并且只允许crate的依赖列表指向更内层。这样内核根本不可能导入适配器,因为适配器的crate根本不在它的依赖图里。这条规则不再是一纸随着时间推移逐渐腐蚀的约定,而是每次构建时编译器都会核验的事实。
来看核心crate的代码:它没有引入任何axum、sqlx或serde,只有标准库和两个极小的工具。比如一个ShortCode类型,它的内部String是私有的,获取它的唯一途径是通过parse方法——如果有任何无效的字符串,系统里就根本不可能存在一个ShortCode实例。这种设计保证了无效状态不可表示,也让编程代理在修改边界代码时,根本不可能意外破坏核心契约。
同样的结构,让人读明白的边界,也让机器读明白。一份配套的仓库已经公开在llmgraph-ai/hexagonal-rust-template上,编译、测试、运行一应俱全。当你把依赖只向内指向的规则焊进编译器,代码库就成了一本任何AI代理都能逐页阅读的操作手册。
热门跟贴