问题:
使用pyinstaller打包PyQT + langchain + chroma 的项目在invoke时莫名退出
摘要:
使用PyQT、 langchain 和 chroma 构建了一个本地的个人知识库应用,并最终使用pyinstaller把应用打包为exe。当前的问题是,在开发环境中一切正常可以进行知识库的创建以及对某个知识库进行问答,但是当我打包成exe时,对知识库的创建和查询时程序就自动退出了,try catch无异常输出。同时,当我单独打包langchain相关的内容发现功能也是正常的。
| 描述 | 结果 |
|---|---|
| 只使用langchain(开发环境和打包后) | 正常 |
| langchain + PyQT (开发环境) | 正常 |
| langchain + PyQT (打包后) | 失败 |
详细信息:
初始化 client_manager
embeddings = OllamaEmbeddings(
model=self.setting_data.get("embedding_model")
)
chroma_client = Chroma(
persist_directory=self.vector_store_path,
embedding_function=embeddings,
client_settings=chromadb.config.Settings(
anonymized_telemetry=False
)
)
self.client_manager = ChromaCollectionManager(
chroma_client,
embeddings,
{
"persist_directory": self.vector_store_path,
"anonymized_telemetry": False
}
)
PyQT中调用
self.llm = ChatOllama(
base_url="http://localhost:11434",
model=self.setting_data.get("model", "qwen3:0.6b"),
temperature=self.setting_data.get("temperature"),
max_tokens=self.setting_data.get("max_length")
)
self.langchain_thread = ChatWithKnowledge(self.llm,context, self.chroma_collection)
self.langchain_thread.response_signal.connect(self.on_ollama_response)
self.langchain_thread.error_signal.connect(self.on_ollama_error)
self.langchain_thread.start()
ChatWithKnowledge
class ChatWithKnowledge(QThread):
response_signal = pyqtSignal(str)
error_signal = pyqtSignal(str)
def __init__(self, llm, store, chroma):
super().__init__()
self.llm = llm
self.store = store
self.chroma = chroma
def extract_real_answer(self, content):
"""
去除AI回复中的think部分,只保留真正的回答。
例如:如果内容包含</think>,则只保留其后的内容。
"""
if "</think>" in content:
return content.split("</think>")[-1].strip()
return content
def run(self):
try:
print("初始化 retriever chain")
qa_chain = RetrievalQA.from_chain_type(
llm=self.llm,
chain_type="stuff",
retriever=self.chroma.as_retriever(search_kwargs={"k": 5}),
return_source_documents=True
)
print("初始化知识库")
"""提问并获取答案"""
if not qa_chain:
print("知识库未初始化")
self.error_signal.emit(f"知识库未初始化")
else:
print(f"我的问题是:{self.store}")
try:
# 这一步出错了
result = qa_chain.invoke({"query": self.store})
print("回答:", result)
answer = result["result"]
sources = result.get("source_documents", [])
reference_list = []
if sources:
for i, doc in enumerate(sources[:3], 1):
source = doc.metadata.get('source', '未知来源')
reference_list.append(f"<li>{os.path.basename(source)}</li>")
reference_html = f"<h4>相关文档:<h4/><ol>{''.join(reference_list)}</ol>"
print("===response result===>", answer)
self.response_signal.emit(self.extract_real_answer(answer) + reference_html)
except BaseException as e:
print("==发生错误==>", e)
except Exception as e:
print("==error=>", e)
self.error_signal.emit(f"出现错误,请重试 {e}")
打包配置
# -*- mode: python ; coding: utf-8 -*-
from PyInstaller.utils.hooks import collect_submodules,collect_dynamic_libs
chromadb_hidden_imports = collect_submodules('chromadb')
numpy_hidden_imports = collect_submodules('numpy')
langchain_hidden_imports = collect_submodules('langchain')
lc_chains_hidden_imports = collect_submodules('langchain.chains')
lc_ollama_hidden_imports = collect_submodules('langchain_ollama')
lc_community_hidden_imports = collect_submodules('langchain_community')
lc_core_hidden_imports = collect_submodules('langchain_core')
llama_cpp_hidden_imports = collect_submodules('llama_cpp')
chromadb_libs = collect_dynamic_libs('chromadb')
llama_cpp_libs = collect_dynamic_libs('llama_cpp')
hnswlib_cpp_libs = collect_dynamic_libs('hnswlib')
a = Analysis(
['main.py'],
pathex=['D:\\workspace\\app'],
binaries=chromadb_libs+llama_cpp_libs+hnswlib_cpp_libs,
datas=[],
hiddenimports=[
'PyQt5',
'PyQt5.QtCore',
'PyQt5.QtGui',
'PyQt5.QtWidgets',
'docx',
'PyPDF2',
'speech_recognition',
'json',
'pypdf',
'sqlite3',
'chromadb.db.duckdb',
'hnswlib',
'faiss',
"chromadb",
"chromadb.db",
"chromadb.utils",
"chromadb.api",
"chromadb.ingest",
"chromadb.segment",
"chromadb.telemetry",
"chromadb.config",
"chromadb.utils.embedding_functions",
"duckdb",
"sqlite3",
"sentence_transformers",
"tiktoken",
"langchain",
"langchain_community",
"ollama_chroma",
] + llama_cpp_hidden_imports+ numpy_hidden_imports + chromadb_hidden_imports + langchain_hidden_imports + lc_chains_hidden_imports + lc_ollama_hidden_imports + lc_community_hidden_imports + lc_core_hidden_imports,
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='Client',
debug=True,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
icon='favicon.ico',
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
windows_api=True,
)
运行日志
[PYI-43896:DEBUG] LOADER: running main.py
Failed to send telemetry event ClientStartEvent: capture() takes 1 positional argument but 3 were given
Failed to send telemetry event ClientCreateCollectionEvent: capture() takes 1 positional argument but 3 were given
Failed to send telemetry event ClientStartEvent: capture() takes 1 positional argument but 3 were given
Failed to send telemetry event ClientCreateCollectionEvent: capture() takes 1 positional argument but 3 were given
['dna-extract6', 'test4', 'test7', 'dna-extract', 'dna-extract3', 'test5', 'test-word', 'test2', 'how2install', 'dna-extract10', 'install', 'dna-extract8', 'install2', 'test1', 'dna-extract11', 'dna-extract2', 'dna-extract12', 'dna-extract9', 'test8', 'test6', 'langchain']
======开始使用知识库进行问答====
====我的问题是=== 使用知识库了
[PYI-47092:DEBUG] LOADER: child process has finished - exiting the wait loop!
[PYI-47092:DEBUG] LOADER: made it out of the waiting loop!
[PYI-47092:DEBUG] LOADER: waiting 250 ms in case we receive WM_QUERYENDSESSION...
[PYI-47092:DEBUG] LOADER: waited 49 ms / 250 ms...
[PYI-47092:DEBUG] LOADER: waited 100 ms / 250 ms...
[PYI-47092:DEBUG] LOADER: waited 160 ms / 250 ms...
[PYI-47092:DEBUG] LOADER: waited 213 ms / 250 ms...
[PYI-47092:DEBUG] LOADER: waited 264 ms / 250 ms...
[PYI-47092:DEBUG] LOADER: done waiting for WM_QUERYENDSESSION - timed-out!
[PYI-47092:DEBUG] LOADER: retrieving process exit code and performing cleanup...
[PYI-47092:DEBUG] LOADER: child process exited (return code: 0)
[PYI-47092:DEBUG] LOADER: performing cleanup...
[PYI-47092:DEBUG] LOADER: removing temporary directory: C:\Users\Yunlong\AppData\Local\Temp\_MEI470922
[PYI-47092:DEBUG] LOADER: temporary directory C:\Users\Yunlong\AppData\Local\Temp\_MEI470922 was successfully removed.
[PYI-47092:DEBUG] LOADER: end of process reached!