diff --git a/backend/app/data/catalog_assistant.py b/backend/app/data/catalog_assistant.py index 9dadbd98..c6e5d9fa 100644 --- a/backend/app/data/catalog_assistant.py +++ b/backend/app/data/catalog_assistant.py @@ -813,11 +813,12 @@ async def stream(model: Any, model_id: str, ctx: AssistantContext, history: list[Any] = [SystemMessage(content=ctx.system), *_history(messages)] tools = _Tools(ctx) - runner = model.bind_tools(ctx.tools()) usage = {"input_tokens": 0, "output_tokens": 0} wrote = "" names = [t["function"]["name"] for t in ctx.tools()] try: + # 绑工具也放在这里面:响应头已经发出去了,出了错要照实交一条错误事件,不能让流半路断掉 + runner = model.bind_tools(ctx.tools()) for round_no in range(MAX_ROUNDS): fresh = True message: Any = None diff --git a/backend/tests/test_catalog_assistant.py b/backend/tests/test_catalog_assistant.py index f8f90b6f..8013dd75 100644 --- a/backend/tests/test_catalog_assistant.py +++ b/backend/tests/test_catalog_assistant.py @@ -524,6 +524,19 @@ async def test_errors_end_the_stream_without_done(client, tmp_path, monkeypatch) assert "上限" in events[-1]["message"] +async def test_a_model_without_tools_reports_an_error_event(client, tmp_path, monkeypatch): + sid = await _source(client, tmp_path) + + class NoTools(Scripted): + def bind_tools(self, tools, **_): + raise NotImplementedError("这个模型不支持工具调用") + + use(monkeypatch, NoTools([])) + events, _ = await _talk(client, sid, _ask("你好")) + assert events == [{"type": "error", "code": "assistant_failed", "message": events[0]["message"]}] + assert "工具调用" in events[0]["message"] + + async def test_transient_errors_are_retried_before_any_output(client, tmp_path, monkeypatch): sid = await _source(client, tmp_path) monkeypatch.setattr(catalog_assistant, "RETRY_DELAYS_S", (0.0, 0.0))