大数跨境

测试智能体平台化:让 Agent 从硬编码走向配置驱动

测试智能体平台化:让 Agent 从硬编码走向配置驱动 智测AI
2026-06-06
2
导读:每次新增一个 Agent 都要改代码、走流程、发版等窗口——这个问题我们忍了很久。

每次新增一个 Agent 都要改代码、走流程、发版等窗口——这个问题我们忍了很久。这篇文章讲的是我们怎么用一套配置驱动的架构彻底解决掉这件事,以及这个架构背后真正重要的设计决策。


先说我们遇到了什么问题

做 Cogent 平台最早的时候,每个智能体都是一个独立的 Python 文件。角色定义、工具列表、中间件配置,全部硬编码在里面。想新增一个 Agent?流程是这样的:提需求 → 找后端 → 写代码 → 测试联调 → 走发版流程。快的话两天,碰上版本窗口不对,一周都是正常的。

内部小团队用的时候这还能接受,大家凑一凑也就过去了。但当我们想把平台开放出来,让业务侧的同学、测试工程师甚至非开发人员都能自己在上面创建 Agent 的时候,这套方式就完全撑不住了。用户的需求是即时的,他们等不了发版窗口,也不应该需要等。

更让人想不通的是:仔细看这些硬编码的 Agent 文件,会发现它们结构上高度雷同。无论是代码审查 Agent、接口分析 Agent 还是测试用例生成 Agent,本质上都是一个 LLM + 一组工具 + 一段 system prompt + 一套中间件配置。真正不同的只是这些配置的具体内容,骨架是完全稳定的。既然骨架稳定,为什么要一次次重复写代码?

这个问题推着我们走向了一个方向:把 Agent 的「描述」和 Agent 的「运行」彻底分离。 用数据库存描述,用代码执行描述,中间放一个工厂负责把描述变成可运行的东西。这个思路不算新鲜,但在 LangGraph 体系下怎么落地,有几个地方还挺有意思的。


核心设计思路:AgentConfig 驱动一切

整个设计可以用一句话概括:AgentConfig 驱动,工厂函数组装,LangGraph callable 入口。

我们在数据库里设计了一张 AgentConfig 表,把一个 Agent 运行所需的全部信息拆成五个维度存进去。用户在前端完成配置后,系统把这张表的一行记录拿出来,交给工厂函数,工厂函数按这份「图纸」组装出一个可运行的 Agent 实例。

这套结构的本质是:前端只需要提交一个 JSON,后端不用改任何业务逻辑,Agent 就能按新配置运行。从「改代码发版」变成了「存一行数据库记录」——交付周期从天级降到了秒级。


LangGraph 的一个关键机制:callable 注册

实现这套设计,有一个 LangGraph 的机制是绕不开的,也是整个方案能跑起来的技术基础。

LangGraph 支持两种方式向服务注册一个 Agent:第一种是注册一个已编译好的图对象(CompiledStateGraph),这是最常见的静态用法;第二种是注册一个可调用函数(callable),这是我们用到的核心能力。

这一点非常重要。它意味着我们可以把「拿哪套配置构建 Agent」这件事延迟到请求时再决定,而不是在服务启动时就固定下来。利用这个机制,我们注册了一个 dynamic_agent_graph 工厂函数作为所有动态 Agent 的统一入口。请求里只需要带上 agent_config_id,工厂函数就知道该去数据库拉哪条配置、组装哪个 Agent:

dynamic_agent.py

def dynamic_agent_graph(config: dict):
    """
    LangGraph callable 入口。
    平台内所有用户创建的 Agent 共用此函数,
    通过 configurable.agent_config_id 路由到对应配置。
    """

    configurable = (config or {}).get("configurable", {})
    agent_config_id = configurable.get("agent_config_id")

    if not agent_config_id:
        raise ValueError("缺少 agent_config_id,动态智能体必须通过配置指定")

    return _build_dynamic_graph(int(agent_config_id))

调用方的请求格式也随之固定下来,agent_config_id 通过 configurable 字段传入,其他部分和普通 LangGraph 请求没有区别。这意味着前端只需要知道当前 Agent 的 ID,就可以和任何一个动态 Agent 对话:

{
  "input": {
    "messages": [{ "role": "user", "content": "帮我分析一下这个接口的调用链路" }]
  },
  "config": {
    "configurable": {
      "thread_id": "session-abc123",
      "agent_config_id": 42   // 这个 42 决定了用哪套 Agent 配置
    }
  }
}


工厂内部:五步组装出一个可运行的 Agent

拿到 agent_config_id,从数据库取出 AgentConfig 对象之后,build_agent_from_config 函数按照固定的顺序完成组装。这五步的设计顺序不是随意的,每步都依赖上一步的输出,最终全部汇入 create_deep_agent


缓存设计:性能和一致性不能只顾一头

每次请求都从零组装一个 Agent 是不现实的。工具加载、Backend 构建、图编译,这些操作加在一起在工具较多的 Agent 上可能需要几百毫秒甚至更长。高并发场景下这个开销是不可接受的。但另一个极端同样危险:如果缓存太激进,用户在前端修改了 Agent 配置,却仍然在跑旧版本,这种隐形的不一致比性能问题更麻烦,因为它不会报错。

我们的解法是把 config_id 和 updated_at 两个字段一起参与缓存 key 的生成:

配置未变更时,key 不变,直接命中缓存,复用已编译的图,零组装开销。配置一旦更新(updated_at 变化),key 跟着变化,旧缓存自动失效,下次请求触发重新构建。这样既不会跑旧配置,也不会频繁重建。

除了 key 生成逻辑,我们还维护了一个反向索引 _cache_key_mapconfig_id → set of cache_keys)。这个结构的用途是支持精准缓存清除:当某个 Agent 被删除,或者管理员需要强制刷新时,通过 invalidate_cache(config_id) 就能把这个 Agent 所有历史版本的缓存一并清掉,而完全不影响其他 Agent 的缓存状态。

agent_factory.py

# 实例缓存:cache_key -> compiled graph
_agent_cache: dict[str, object] = {}
# 反向索引:config_id -> set of cache_keys(精准清除用)
_cache_key_map: dict[int, set] = {}

def _make_cache_key(config_id: int, updated_at) -> str:
    raw = f"{config_id}:{updated_at}"
    key = hashlib.md5(raw.encode()).hexdigest()
    _cache_key_map.setdefault(config_id, set()).add(key)
    return key

def invalidate_cache(config_id: int):
    """精准清除指定 config_id 的所有历史版本缓存"""
    for key in _cache_key_map.pop(config_id, set()):
        _agent_cache.pop(key, None)


整体架构图

把上面所有的模块连起来,一次用户请求从发出到拿到响应,完整路径如下:

工厂内部的加载逻辑可以看作四条并行的加载链,各自独立,最终汇入 create_deep_agent


这套方案到底改变了什么

说完技术细节,回过头来看这套方案真正解决的问题。对比「每个 Agent 独立硬编码」的旧方式,变化发生在每个值得在意的维度上:

当然这套方案也有它没解决的问题:首次构建一个新 Agent 会有冷启动延迟工具越多、Skills 越多,组装时间越长,通常在几百毫秒到几秒之间。这在高频使用场景下是可以接受的,因为后续请求都命中缓存,但第一次确实会慢一下。我们后续会通过预热机制缓解,但那是另一个话题了。


这篇文章讲的是整体的架构骨架:为什么要这样设计,LangGraph callable 的机制是什么,工厂怎么工作,缓存怎么做。

真正让这套架构站得住脚的,是每个模块的具体实现细节——四类工具各有各的加载逻辑,Python 工具在沙箱里跑是怎么隔离的,Skills 的 CompositeBackend 路由是怎么实现的,MCP 工具为什么不能走普通加载流程、得用中间件注入绕开 configurable 的限制。这些放到第二篇展开。

【声明】内容源于网络
0
0
智测AI
专注AI与软件测试融合,探索智能测试前沿技术与实践。
内容 149
粉丝 0
智测AI 专注AI与软件测试融合,探索智能测试前沿技术与实践。
总阅读734
粉丝0
内容149