AI & Agent Dev Bug Sandbox logo
AI & Agent Dev Bug Sandbox
Back to Radar

Langchain-Openai With_structured_output() Silently Drops Previously Bound Tools, Causing Hallucinated Responses

When .bind(tools=[...]) is called before .with_structured_output(schema) on ChatOpenAI, the tool bindings are silently discarded from the HTTP request. The model returns a plausible but hallucinated structured output because the tools (e.g., web_search) were never sent to the API. This affects both OpenAI native tools and custom LangChain tools, and there is no error or warning.

highConfidence 92%Langchain-OpenaiAffected V1.1.7

Origin Analysis

with_structured_output() internally builds a new RunnableSequence with its own model bindings to enforce the output schema via response_format or tool_choice. These new bindings replace the model's existing kwargs instead of merging them. As a result, any previously bound tools (and other kwargs) are overwritten and never included in the OpenAI API request.
1. Instantiate ChatOpenAI(model='gpt-5-mini').\n2. Bind an OpenAI native tool: llm_with_tools = llm.bind(tools=[{'type': 'web_search'}]).\n3. Apply structured output: chain = llm_with_tools.with_structured_output(WeatherResponse).\n4. Invoke with a question that requires tool use, e.g., 'What is the weather in San Francisco right now?'.\n5. Observe that the returned object contains plausible but hallucinated data (e.g., estimated temperature) because the web_search tool was never sent to OpenAI.\n6. Inspect raw HTTP request to confirm that 'tools' is missing from the payload while 'response_format' is present.

Fixing Code Block

Edge Case Audit

This is a user-side monkey patch, not an official library fix. It bypasses the original `with_structured_output` implementation when tools are present, which means any advanced features handled by the original method (such as `include_raw` handling, model-specific fallback to function_calling, or non-strict schema modes) are not preserved. The patch assumes OpenAI's JSON schema strict mode is appropriate and uses `convert_to_openai_function(..., strict=True)`, which may fail for schemas that do not meet strict-mode requirements. Additionally, the monkey patch is global and not thread-safe: if multiple threads set different patch versions, behavior may be inconsistent. It may also break when LangChain updates `with_structured_output` internals. To roll back, simply remove the monkey patch assignment (`ChatOpenAI.with_structured_output = _original_with_structured_output`) and restart the process. For production use, prefer the official fix when available or use the explicit `.bind(tools=..., response_format=...)` workaround.

Ecosystem Topology