能力市场换成数据库要改多少代码?一个接口的事 🔧

26 阅读3分钟

「Regnexe 实战系列」第 6 篇(共 10 篇),对应仓库 ExampleReadme06MarketplaceTest。上一篇:05. 插件加载的四种姿势。

🏗️ 一个容易被忽略的架构问题

前 5 篇无论用哪种方式注册能力——withTool、@Plugin、包扫描、目录加载——最终都会落到同一个对象上:Marketplace。这是所有能力的统一索引:装能力、按目标搜能力、按 id 解析能力。

默认实现是 SimpleMarketplace,纯内存 Map。能跑 demo,但企业场景里很快会遇到真实需求:插件数量上百个要按租户/权限过滤,想用 ES 做关键词检索或者向量库做语义召回,能力定义本身就存在数据库里。

如果 Marketplace 是个具体类而不是接口,这些需求基本意味着要改框架源码。Regnexe 的做法是把它设计成一个纯接口,剩下的交给你。

📦 默认实现长什么样

SimpleMarketplace marketplace = new SimpleMarketplace();
marketplace.install(PluginDescriptor.builder()
    .pluginId("weather-plugin").version("1.0")
    .name("Weather Plugin").description("Weather queries")
    .tool(weatherTool)
    .build());

CapabilitySearchResult result = marketplace.search(searchQuery);   // 给 Planner 的候选能力
CapabilityDescriptor cap = marketplace.resolveDescriptor("weather-plugin.get_weather");

install 装能力,search 给 Planner 提供候选集,resolveDescriptor 按 id 精确取出。

🔄 换成自己的实现,长这样

Marketplace 接口要求实现 install/uninstall/enable/disable/search/resolveDescriptor/listEnabled 七个方法。仓库测试里写了一个最小的"数据库版"示例(用 Map 模拟一张表,真实场景换成 JPA Repository 或 JdbcTemplate 就行):

class DbBackedMarketplace implements Marketplace {
    private final Map<String, PluginDescriptor> table = new LinkedHashMap<>();
    private final Set<String> enabledIds = new HashSet<>();

    @Override
    public void install(PluginDescriptor plugin) {
        table.put(plugin.getPluginId(), plugin);
        enabledIds.add(plugin.getPluginId());
    }

    @Override
    public CapabilitySearchResult search(SearchQuery query) {
        // 真实实现这里换成 SQL 查询 / ES 检索 / 向量召回
        ...
    }

    @Override
    public CapabilityDescriptor resolveDescriptor(String capabilityId) { ... }

    // 运维后台需要的额外查询方法,自由加,不受接口约束
    List<PluginDescriptor> findByTag(String tag) {
        return table.values().stream()
                .filter(p -> p.getTags() != null && p.getTags().contains(tag))
                .toList();
    }
}

接入只有一行:

regnexeAgentBuilder.withPluginMarket(new DbBackedMarketplace()) ...

没有改一行框架源码,Agent 主流程毫无感知,Search → Plan → Execute → Reflect 该怎么跑还怎么跑,只是这套 harness 背后查能力的实现换了。

💡 划重点:接口之外的方法你可以随便加

注意示例里的 findByTag(String tag)——这个方法不在 Marketplace 接口里,是 DbBackedMarketplace 自己额外加的。运维后台想按标签筛插件、想加个使用频率统计,直接在自己的实现类上扩展即可,完全不受接口约束。

🎯 这个设计解决了什么问题

很多框架的"可扩展点"停留在文档层面——理论上能换,实操起来发现到处都是具体类型依赖。Regnexe 这里做得比较克制:RegnexeAgentBuilder.withPluginMarket(Marketplace) 接受的就是接口类型,框架内部从 Search 节点到 Execute 节点,全部只依赖这个接口。

也就是说:从内存 Demo 跑到真实生产,能力市场这一层的迁移成本几乎为零——你需要做的只是写一个实现类,业务代码和 Agent 主循环一行都不用改。


你们项目里"看起来可扩展,实际换实现很麻烦"的设计,踩过哪些坑?评论区聊聊,点个赞 👍

📌 上一篇:05. 插件加载的四种姿势 | 下一篇:07. Agent 记忆为什么要拆三层 📌 项目地址:github.com/flower-tree…