Agent 系统里有多个模块都需要访问 LLM 客户端(如 openai.AsyncOpenAI),如何设计才能避免重复创建连接池,同时保证可测试性?
这个问题本质上是两个需求的平衡:
既要全局共享一个连接池避免重复创建,又要方便替换以便测试。
我会用依赖注入 + 模块级单例来解决。”
❌ 先看坏味道¶
多个模块各自实例化客户端:
🔴 问题:
-
连接池被复制多份,资源浪费;
-
测试时你没法统一 mock,得去改每个模块的源码或者做猴子补丁,非常难看。
✅ 正确设计:单例创建,依赖注入¶
把客户端的创建和使用分开:
# llm_client.py —— 全局只建一次
import openai
from functools import lru_cache
@lru_cache(maxsize=1)
def get_llm_client() -> openai.AsyncOpenAI:
return openai.AsyncOpenAI()
然后每个模块不自己创建,而是通过参数接收:
组装时注入同一个实例:
📊 直观示意图:

🧪 可测试性怎么来的?¶
测试时,你根本不用走真实网络:
from unittest.mock import AsyncMock
mock_client = AsyncMock()
agent = AgentA(mock_client)
# 直接断言行为,完全隔离
因为模块依赖于接口(AsyncOpenAI 本身就是个协议),而非具体创建方式,替换起来没有任何负担。
🎯 如果需要更复杂的生命周期管理¶
可以用上下文管理器或依赖注入容器,但核心原则不变:
-
✅ 创建集中:单例或工厂负责生成客户端。
-
✅ 使用注入:模块只声明“我需要一个 LLM 客户端”,不关心它从哪来。
-
✅ 测试替换:注入 mock 即可,框架完全不受影响。
📌 一句话总结
“单例保连接池,注入保可测性。创建归创建,使用归使用,边界划清楚,两端都舒服。”