如何在FastAPI中用Pickle/Dill将llm_client对象存储到Redis?
问题描述
我正在开发一个FastAPI应用,需要将Azure OpenAI的llm_client对象与会话数据一同存储到Redis中,并设置过期时间。最初尝试使用pickle序列化时遇到错误,改用dill后仍出现问题。
使用pickle的代码
import redis import pickle from openai import AzureOpenAI # Initialize Redis client redis_client = redis.Redis( host='redis-13661.c212.ap-south-1-1.ec2.redns.redis-cloud.com', port=13661, password="*******", username="default" ) # Initialize llm_client client = AzureOpenAI( azure_endpoint="https://my-openai-endpoint.azure.com/", api_key="*******", api_version="2024-02-01" ) # Store session data in Redis with an expiration time of 1 hour session_data = {"llm_client": client} session_id = "1234" redis_client.hmset(session_id, 3600, pickle.dumps(session_data))
错误信息
TypeError: cannot pickle '_thread.RLock' object
使用dill的代码
import redis import dill from openai import AzureOpenAI # Initialize Redis client redis_client = redis.Redis( host='redis-13661.c212.ap-south-1-1.ec2.redns.redis-cloud.com', port=13661, password="*******", username="default" ) # Initialize llm_client client = AzureOpenAI( azure_endpoint="https://my-openai-endpoint.azure.com/", api_key="*******", api_version="2024-02-01" ) # Store session data in Redis with an expiration time of 1 hour session_data = {"llm_client": client} session_id = "1234" redis_client.hmset(session_id, 3600, dill.dumps(session_data))
错误信息
TypeError: cannot pickle 'SSLContext' object
已尝试方案
- 使用
pickle:因llm_client中的锁对象引发_thread.RLock错误 - 使用
dill:因无法处理SSLContext对象报错
核心问题
- 能否将llm_client对象序列化后存储到Redis?
- 有没有处理Redis中非可序列化对象的替代方案,比如检索时重建对象?
解决方案与最佳实践
1. 直接序列化llm_client不可行
AzureOpenAI客户端对象内部包含_thread.RLock、SSLContext等无法被序列化的底层资源(用于线程安全、网络连接管理),不管用pickle还是dill都无法完成序列化,所以不能直接将llm_client对象存储到Redis。
2. 替代方案:存储客户端配置,按需重建对象
这是行业通用的最佳实践,具体步骤如下:
- 不存储客户端实例,而是存储创建客户端所需的配置参数(如azure_endpoint、api_key、api_version等)
- 当需要使用客户端时,从Redis中取出配置参数,重新初始化AzureOpenAI对象
修改后的代码示例
存储会话数据到Redis
import redis import json from openai import AzureOpenAI # Initialize Redis client redis_client = redis.Redis( host='redis-13661.c212.ap-south-1-1.ec2.redns.redis-cloud.com', port=13661, password="*******", username="default" ) # 存储客户端配置而非实例 client_config = { "azure_endpoint": "https://my-openai-endpoint.azure.com/", "api_key": "*******", "api_version": "2024-02-01" } # 会话数据包含配置和其他会话信息 session_data = { "llm_config": client_config, # 其他会话数据,比如对话历史等 "conversation_history": [] } session_id = "1234" # 使用json序列化(比pickle更安全,跨语言兼容),设置1小时过期 redis_client.setex(session_id, 3600, json.dumps(session_data))
从Redis中取出并重建客户端
def get_llm_client(session_id: str) -> AzureOpenAI: # 从Redis获取会话数据 session_data_str = redis_client.get(session_id) if not session_data_str: raise ValueError("Session not found or expired") session_data = json.loads(session_data_str) llm_config = session_data["llm_config"] # 重建AzureOpenAI客户端 return AzureOpenAI(**llm_config)
3. 额外优化建议
- 安全注意事项:如果api_key等敏感信息存储到Redis,确保Redis实例的访问权限严格控制(如设置强密码、限制IP访问),避免泄露。
- 会话数据分离:如果会话中有大量非配置数据(比如对话历史),可以使用Redis哈希结构存储,将配置和其他数据分开,更便于管理。
- 客户端复用:如果多个会话使用相同的客户端配置,可以在应用层面维护一个客户端池,避免重复创建实例,提升性能。
内容的提问来源于stack exchange,提问作者AYUSH BHARDWAJ
相关产品推荐
相关产品推荐

