运行MySQL查询LangChain代码遇TypeError:无法序列化classmethod对象
问题:LangChain连接MySQL时触发pickle序列化错误
运行LangChain从MySQL取数的代码时,出现以下错误:
TypeError: cannot pickle 'classmethod' object
错误提示存在无法序列化的@classmethod对象,但用户代码中并未定义相关方法。
完整代码
from langchain.llms import GooglePalm from langchain_google_genai import ChatGoogleGenerativeAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain.sql_database import SQLDatabase from langchain_experimental.sql import SQLDatabaseSequentialChain from langchain.chains import LLMChain from langchain.utilities import SQLDatabase from langchain_experimental.sql import SQLDatabaseChain from langchain.prompts import SemanticSimilarityExampleSelector from langchain.embeddings import HuggingFaceEmbeddings from langchain.vectorstores import Chroma from langchain.prompts import FewShotPromptTemplate from langchain.chains.sql_database.prompt import PROMPT_SUFFIX,_mysql_prompt from langchain.prompts.prompt import PromptTemplate from few_shots import few_shots import os from dotenv import load_dotenv load_dotenv() # 从.env加载环境变量(尤其是API密钥) def get_few_shot_db_chain(): db_user = "root" db_password = "******" db_host = "localhost" db_name = "pras_tshirts" db = SQLDatabase.from_uri(f"mysql+pymysql://{db_user}:{db_password}@{db_host}/{db_name}",sample_rows_in_table_info=3) llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash", google_api_key=os.environ["GOOGLE_API_KEY"], temperature=0.4) Embeddings = HuggingFaceEmbeddings(model_name='sentence-transformers/all-MiniLM-L6-v2') to_vector = [" ".join(example.values()) for example in few_shots] import chromadb chromadb.api.client.SharedSystemClient.clear_system_cache() persist_directory = "./chroma_db" vectorstore = Chroma.from_texts(to_vector, embedding=Embeddings, persist_directory=persist_directory,metadatas=few_shots) example_selector = SemanticSimilarityExampleSelector( vectorstore=vectorstore, k=2, ) mysql_prompt = """You are a MySQL expert. Given an input question, first create a syntactically correct MySQL query to run, then look at the results of the query and return the answer to the input question. Unless the user specifies in the question a specific number of examples to obtain, query for at most {top_k} results using the LIMIT clause as per MySQL. You can order the results to return the most informative data in the database. Never query for all columns from a table. You must query only the columns that are needed to answer the question. Wrap each column name in backticks (`) to denote them as delimited identifiers. Pay attention to use only the column names you can see in the tables below. Be careful to not query for columns that do not exist. Also, pay attention to which column is in which table. Pay attention to use CURDATE() function to get the current date, if the question involves "today". Use the following format: Question: Question here SQLQuery: Query to run with no pre-amble SQLResult: Result of the SQLQuery Answer: Final answer here No pre-amble. """ example_prompt = PromptTemplate( input_variables=["Question", "SQLQuery", "SQLResult","Answer",], template="\nQuestion: {Question}\nSQLQuery: {SQLQuery}\nSQLResult: {SQLResult}\nAnswer: {Answer}", ) few_shot_prompt = FewShotPromptTemplate( example_selector=example_selector, example_prompt=example_prompt, prefix=mysql_prompt, suffix=PROMPT_SUFFIX, input_variables=["input", "table_info", "top_k"], # 这些变量会在prefix和suffix中使用 ) chain = SQLDatabaseChain.from_llm(llm, db, verbose=True, prompt=few_shot_prompt) return chain
报错堆栈
C:\Users\176760\PycharmProjects\TShirtExc\.venv\Scripts\python.exe C:\Users\176760\PycharmProjects\TShirtExc\langchain_helper.py Traceback (most recent call last): File "C:\Users\176760\PycharmProjects\TShirtExc\langchain_helper.py", line 6, in <module> from langchain_experimental.sql import SQLDatabaseSequentialChain File "C:\Users\176760\PycharmProjects\TShirtExc\.venv\Lib\site-packages\langchain_experimental\sql\__init__.py", line 3, in <module> from langchain_experimental.sql.base import SQLDatabaseChain, SQLDatabaseSequentialChain File "C:\Users\176760\PycharmProjects\TShirtExc\.venv\Lib\site-packages\langchain_experimental\sql\base.py", line 24, in <module> class SQLDatabaseChain(Chain): File "C:\Users\176760\PycharmProjects\TShirtExc\.venv\Lib\site-packages\pydantic\v1\main.py", line 221, in __new__ inferred = ModelField.infer( ^^^^^^^^^^^^^^^^^ File "C:\Users\176760\PycharmProjects\TShirtExc\.venv\Lib\site-packages\pydantic\v1\fields.py", line 504, in infer return cls( ^^^^ File "C:\Users\176760\PycharmProjects\TShirtExc\.venv\Lib\site-packages\pydantic\v1\fields.py", line 434, in __init__ self.prepare() File "C:\Users\176760\PycharmProjects\TShirtExc\.venv\Lib\site-packages\pydantic\v1\fields.py", line 544, in prepare self._set_default_and_type() File "C:\Users\176760\PycharmProjects\TShirtExc\.venv\Lib\site-packages\pydantic\v1\fields.py", line 568, in _set_default_and_type default_value = self.get_default() ^^^^^^^^^^^^^^^^^^ File "C:\Users\176760\PycharmProjects\TShirtExc\.venv\Lib\site-packages\pydantic\v1\fields.py", line 437, in get_default return smart_deepcopy(self.default) if self.default_factory is None else self.default_factory() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\176760\PycharmProjects\TShirtExc\.venv\Lib\site-packages\pydantic\v1\utils.py", line 694, in smart_deepcopy return deepcopy(obj) # slowest way when we actually might need a deepcopy ^^^^^^^^^^^^^ File "C:\Users\176760\AppData\Local\Programs\Python\Python312\Lib\copy.py", line 162, in deepcopy y = _reconstruct(x, memo, *rv) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\176760\AppData\Local\Programs\Python\Python312\Lib\copy.py", line 259, in _reconstruct state = deepcopy(state, memo) ^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\176760\AppData\Local\Programs\Python\Python312\Lib\copy.py", line 136, in deepcopy y = copier(x, memo) ^^^^^^^^^^^^^^^ File "C:\Users\176760\AppData\Local\Programs\Python\Python312\Lib\copy.py", line 221, in _deepcopy_dict y[deepcopy(key, memo)] = deepcopy(value, memo) ^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\176760\AppData\Local\Programs\Python\Python312\Lib\copy.py", line 151, in deepcopy rv = reductor(4) ^^^^^^^^^^^ TypeError: cannot pickle 'classmethod' object Process finished with exit code 1
问题分析
错误并非来自用户代码,而是依赖包版本兼容性问题:
- Python 3.12对pickle序列化机制做了调整,旧版的Pydantic v1和langchain-experimental模块无法适配这种变化
- 报错发生在导入
SQLDatabaseSequentialChain时,langchain-experimental的SQL模块内部在初始化SQLDatabaseChain类时,Pydantic v1尝试深拷贝包含classmethod的默认值,触发了序列化失败
解决方案
方案1:降级Python版本
将Python版本从3.12降级到3.11,该版本对旧版依赖的兼容性更好,能直接解决这个序列化问题。
方案2:升级LangChain相关依赖
执行以下命令升级所有相关包到最新稳定版,新版本已经修复了Python 3.12的兼容性问题:
pip install --upgrade langchain langchain-experimental langchain-google-genai pydantic
方案3:替换过时的SQLDatabaseChain
SQLDatabaseChain属于langchain-experimental模块,已被标记为过时,推荐使用LangChain官方推荐的SQL工具链替代。示例代码如下:
from langchain_google_genai import ChatGoogleGenerativeAI from langchain.sql_database import SQLDatabase from langchain.agents import create_sql_agent from langchain.agents.agent_toolkits import SQLDatabaseToolkit def get_sql_agent_chain(): db_user = "root" db_password = "******" db_host = "localhost" db_name = "pras_tshirts" db = SQLDatabase.from_uri(f"mysql+pymysql://{db_user}:{db_password}@{db_host}/{db_name}", sample_rows_in_table_info=3) llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash", google_api_key=os.environ["GOOGLE_API_KEY"], temperature=0.4) toolkit = SQLDatabaseToolkit(db=db, llm=llm) agent = create_sql_agent( llm=llm, toolkit=toolkit, verbose=True ) return agent
内容的提问来源于stack exchange,提问作者Prasana Balakrishnan
相关产品推荐
相关产品推荐

