Flask/LangChain/asyncio应用中"Event loop is closed"错误排查与解决
问题背景
使用Flask(已安装async扩展)、LangChain和asyncio技术栈,目标是并行执行多个LLM请求。
问题现象
应用每处理两次请求,终端会抛出与analyses列表项数量一致的错误:
ERROR:asyncio:Task exception was never retrieved future: <Task finished name='Task-44' coro=<AsyncClient.aclose() done, defined at [path]\flask-server\venv\Lib\site-packages\httpx\_client.py:2011> exception=RuntimeError('Event loop is closed')> [Traceback without references to application files] RuntimeError: Event loop is closed
该错误不影响应用正常返回响应,但需解决。
疑问
- 如何避免此
RuntimeError? - 问题根源是什么?哪些事件循环在何时被关闭,为何会引发问题?
相关代码
# logic import asyncio async def run_analyses(analyses): tasks = [] for analysis in analyses: task = asyncio.create_task(run_analysis(analysis)) tasks.append(task) results = await asyncio.gather(*tasks) return results async def run_analysis(analysis): messages = ... llm = ChatAnthropic(...) response = await llm.ainvoke(messages) result = response.content return result # app.py using Flask import asyncio @app.route('/process', methods=['POST']) async def process(): data = request.json analyses = data['analyses'] results = await run_analyses(analyses) return jsonify(results) if __name__ == '__main__': app.run(debug=True, port=5000)
已尝试方案
- 尝试
await主程序的app.run - 添加/移除
asyncio.create_task - 按照GPT4建议操作1小时但无效
问题根源分析
- 事件循环生命周期不匹配:Flask的debug模式默认启用自动重载机制,每次触发重载时,旧事件循环会被关闭,但LangChain的
ChatAnthropic内部使用的httpx.AsyncClient后台仍有未完成的aclose()关闭任务,这些任务在旧循环关闭后才执行,导致抛出Event loop is closed错误。 - 客户端实例重复创建:
run_analysis函数每次调用都会新建ChatAnthropic实例,每个实例对应独立的AsyncClient。请求完成后,客户端的关闭任务被加入事件循环,若此时循环因Flask重载提前关闭,就会触发错误。
解决方法
方法1:禁用Flask的debug模式
debug模式的自动重载是触发问题的核心,关闭后事件循环会保持稳定:
if __name__ == '__main__': app.run(debug=False, port=5000)
方法2:复用LLM客户端实例
避免每次请求新建ChatAnthropic实例,复用客户端可减少后台关闭任务,同时提升性能:
# 全局复用LLM客户端 llm = ChatAnthropic(...) async def run_analysis(analysis): messages = ... response = await llm.ainvoke(messages) result = response.content return result
方法3:手动管理事件循环(适配debug模式)
若必须使用debug模式,可手动创建并维护事件循环,避免Flask自动管理的冲突:
import asyncio from flask import Flask app = Flask(__name__) @app.route('/process', methods=['POST']) async def process(): data = request.json analyses = data['analyses'] results = await run_analyses(analyses) return jsonify(results) if __name__ == '__main__': loop = asyncio.get_event_loop() try: loop.run_until_complete(app.run(debug=True, port=5000)) finally: loop.close()
方法4:捕获客户端关闭异常(临时兜底)
通过包装ainvoke方法或修改客户端配置,确保aclose()任务即使在循环关闭时也不会抛出未处理异常(不推荐作为主要解决方案)。
内容的提问来源于stack exchange,提问作者RudolfKaiser
相关产品推荐
相关产品推荐

