Great question — answering as the UphillTech team:
The core problem is that withStructuredOutput() and tool calling are mutually exclusive in LangChain. When you use withStructuredOutput() , the model's entire output is constrained to your Zod schema — it won't independently decide to call a tool. You're also passing tools as an option to withStructuredOutput() , but that's not a supported parameter there. The fix: Use two separate LLM invocations with a routing step. Step 1 — Tool-calling LLM (runs first) Bind tools to the model and check if the model wants to use one: const modelWithTools = model.bindTools(tools); const toolCheckResult = await modelWithTools.invoke(result0.answer); if (toolCheckResult.tool_calls &&...
Full answer by Ritik Thakur: https://stackoverflow.stackexchange.com/a/79926667 (CC BY-SA 4.0).
Want it for your business? UphillTech.