我的后端正在运行具有某些可运行项的 langchain 路由。我希望能够向前端返回“404 Not found”之类的 http 异常,但是当我使用
raise HTTPException(status_code=404, detail="Item not found")
引发它时,会创建 CancelledException 并且前端收到“内部服务器错误”。我怎样才能做到这一点?
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/my-code-path/.venv/lib/python3.10/site-packages/sse_starlette/sse.py", line 269, in __call__
await wrap(partial(self.listen_for_disconnect, receive))
File "/my-code-path/.venv/lib/python3.10/site-packages/sse_starlette/sse.py", line 258, in wrap
await func()
File "/my-code-path/.venv/lib/python3.10/site-packages/sse_starlette/sse.py", line 215, in listen_for_disconnect
message = await receive()
File "/my-code-path/.venv/lib/python3.10/site-packages/uvicorn/protocols/http/httptools_impl.py", line 596, in receive
await self.message_event.wait()
File "/usr/lib/python3.10/asyncio/locks.py", line 214, in wait
await fut
asyncio.exceptions.CancelledError: Cancelled by cancel scope 7fba499a8490
During handling of the above exception, another exception occurred:
+ Exception Group Traceback (most recent call last):
| File "/my-code-path/.venv/lib/python3.10/site-packages/uvicorn/protocols/http/httptools_impl.py", line 435, in run_asgi
| result = await app( # type: ignore[func-returns-value]
| File "/my-code-path/.venv/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
| return await self.app(scope, receive, send)
| File "/my-code-path/.venv/lib/python3.10/site-packages/fastapi/applications.py", line 276, in __call__
| await super().__call__(scope, receive, send)
| File "/my-code-path/.venv/lib/python3.10/site-packages/starlette/applications.py", line 122, in __call__
| await self.middleware_stack(scope, receive, send)
| File "/my-code-path/.venv/lib/python3.10/site-packages/starlette/middleware/errors.py", line 184, in __call__
| raise exc
| File "/my-code-path/.venv/lib/python3.10/site-packages/starlette/middleware/errors.py", line 162, in __call__
| await self.app(scope, receive, _send)
| File "/my-code-path/.venv/lib/python3.10/site-packages/starlette/middleware/cors.py", line 91, in __call__
| await self.simple_response(scope, receive, send, request_headers=headers)
| File "/my-code-path/.venv/lib/python3.10/site-packages/starlette/middleware/cors.py", line 146, in simple_response
| await self.app(scope, receive, send)
| File "/my-code-path/.venv/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
| raise exc
| File "/my-code-path/.venv/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
| await self.app(scope, receive, sender)
| File "/my-code-path/.venv/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
| raise e
| File "/my-code-path/.venv/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
| await self.app(scope, receive, send)
| File "/my-code-path/.venv/lib/python3.10/site-packages/starlette/routing.py", line 718, in __call__
| await route.handle(scope, receive, send)
| File "/my-code-path/.venv/lib/python3.10/site-packages/starlette/routing.py", line 276, in handle
| await self.app(scope, receive, send)
| File "/my-code-path/.venv/lib/python3.10/site-packages/starlette/routing.py", line 69, in app
| await response(scope, receive, send)
| File "/my-code-path/.venv/lib/python3.10/site-packages/sse_starlette/sse.py", line 255, in __call__
| async with anyio.create_task_group() as task_group:
| File "/my-code-path/.venv/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 680, in __aexit__
| raise BaseExceptionGroup(
| exceptiongroup.ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
+-+---------------- 1 ----------------
| Traceback (most recent call last):
| File "/my-code-path/.venv/lib/python3.10/site-packages/sse_starlette/sse.py", line 258, in wrap
| await func()
| File "/my-code-path/.venv/lib/python3.10/site-packages/sse_starlette/sse.py", line 245, in stream_response
| async for data in self.body_iterator:
| File "/my-code-path/.venv/lib/python3.10/site-packages/langserve/api_handler.py", line 1121, in _stream
| async for chunk in self._runnable.astream(
| File "/my-code-path/.venv/lib/python3.10/site-packages/langchain_core/runnables/base.py", line 4745, in astream
| async for item in self.bound.astream(
| File "/my-code-path/.venv/lib/python3.10/site-packages/langchain_core/runnables/base.py", line 2898, in astream
| async for chunk in self.atransform(input_aiter(), config, **kwargs):
| File "/my-code-path/.venv/lib/python3.10/site-packages/langchain_core/runnables/base.py", line 2881, in atransform
| async for chunk in self._atransform_stream_with_config(
| File "/my-code-path/.venv/lib/python3.10/site-packages/langchain_core/runnables/base.py", line 1972, in _atransform_stream_with_config
| chunk = cast(Output, await py_anext(iterator))
| File "/my-code-path/.venv/lib/python3.10/site-packages/langchain_core/runnables/base.py", line 2851, in _atransform
| async for output in final_pipeline:
| File "/my-code-path/.venv/lib/python3.10/site-packages/langchain_core/runnables/base.py", line 4178, in atransform
| async for output in self._atransform_stream_with_config(
| File "/my-code-path/.venv/lib/python3.10/site-packages/langchain_core/runnables/base.py", line 1972, in _atransform_stream_with_config
| chunk = cast(Output, await py_anext(iterator))
| File "/my-code-path/.venv/lib/python3.10/site-packages/langchain_core/runnables/base.py", line 4147, in _atransform
| output = await acall_func_with_variable_args(
| File "/my-code-path/.venv/lib/python3.10/site-packages/langchain_core/runnables/base.py", line 4122, in f
| return await run_in_executor(config, func, *args, **kwargs)
| File "/my-code-path/.venv/lib/python3.10/site-packages/langchain_core/runnables/config.py", line 547, in run_in_executor
| return await asyncio.get_running_loop().run_in_executor(
| File "/usr/lib/python3.10/concurrent/futures/thread.py", line 58, in run
| result = self.fn(*self.args, **self.kwargs)
| File "/my-code-path/.venv/lib/python3.10/site-packages/langchain_core/runnables/base.py", line 4116, in func
| return call_func_with_variable_args(
| File "/my-code-path/.venv/lib/python3.10/site-packages/langchain_core/runnables/config.py", line 380, in call_func_with_variable_args
| return func(input, **kwargs) # type: ignore[call-arg]
| File "/my-code-path/src/chains/forms/refine_chain.py", line 65, in get_refined_runnable_map
| raise HTTPException(status_code=404, detail="Item not found")
| fastapi.exceptions.HTTPException
+------------------------------------
我尝试寻找一种方法以某种方式捕获该异常,但可运行对象直接插入到“add_routes”函数中,因此我不知道如何执行此操作,因为可运行对象内的任何异常都会引发“CancelledException”。
refine_chain = RefineChain(custom_app, tool_name)
add_routes(
app,
refine_chain.get_runnable().with_config({"tags": [custom_app]}),
enabled_endpoints=["stream"],
path=f"/{custom_app}/{tool_name}/refine",
config_keys=["configurable"],
dependencies=[Depends(get_current_active_username)],
)
我通常通过
exception_handler
-s 来管理异常,因此当项目增长时它可以扩展得更多,以下是我将如何实现处理代码引发的 asyncio.exceptions.CancelledError
:
@app.exception_handler(asyncio.exceptions.CancelledError)
async def http_exception_handler(req: Request, exc: RequestValidationError) -> Response:
error_message = 'Bad Request'
return JSONResponse(
status_code=400,
content={"message": error_message},
)
注:
app
是app = FastAPI(...)
您可以根据自己的喜好自定义
JSONResponse
,添加 404
以及您想要的任何消息。
LangServe 的当前实现对流方法有硬编码的错误处理:
https://github.com/langchain-ai/langserve/blob/v0.3.0/langserve/api_handler.py#L1210-L1219
LangServe 存储库中有一个未解决的问题来解决此限制: https://github.com/langchain-ai/langserve/issues/481
因此,客户端将始终收到相同的“内部服务器错误”消息。