[GH-ISSUE #456] bind_tools after another bind overwrites bound arguments #30

Closed
opened 2026-02-17 17:19:01 -05:00 by yindo · 1 comment
Owner

Originally created by @phschoepf on GitHub (Apr 23, 2025).
Original GitHub issue: https://github.com/langchain-ai/docs/issues/456

Checked other resources

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

Example Code

import json
from langchain_anthropic import ChatAnthropic
from langchain_core.tools.convert import tool


@tool()
def secret_pharse() -> str:
    """Psst! A secret!"""
    return "correct horse battery staple"


model = ChatAnthropic(model_name="claude-3-7-sonnet-latest", max_tokens=16000)
model = model.bind(thinking={"type": "enabled", "budget_tokens": 1024})
model = model.bind_tools([secret_pharse])

response = model.invoke("Can you tell me the secret?")
print(json.dumps(response.content, indent=2))

Expected output: A thinking block and a tool call

Output (thinking block missing):

[
  {
    "text": "I can help you discover the secret phrase. Let me retrieve that for you.",
    "type": "text"
  },
  {
    "id": "toolu_01Rha6sWeWscVY3zjD76EnF7",
    "input": {},
    "name": "secret_pharse",
    "type": "tool_use"
  }
]

Error Message and Stack Trace (if applicable)

No response

Description

I'm trying to use Claude 3.7 Sonnet with thinking mode and tools. I have discovered that when the tools are bound after the arguments enabling thinking mode, the latter are overwritten.
When swapping the order of bind and bind_tools, the issue is resolved and I get the expected output:

[
  {
    "signature": "xxxx",
    "thinking": "The user is asking for a secret. I have a function available called \"secret_pharse\" that might contain this secret. The function doesn't require any parameters, so I can call it directly.",
    "type": "thinking"
  },
  {
    "text": "I can access the secret for you by using the appropriate function.",
    "type": "text"
  },
  {
    "id": "toolu_01UdHBdC9JnpH6uYi9dGQ5rs",
    "input": {},
    "name": "secret_pharse",
    "type": "tool_use"
  }
]

System Info

System Information

OS: Linux
OS Version: langchain-ai/langchain#21~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Mon Feb 24 16:52:15 UTC 2
Python Version: 3.12.3 (main, Feb 4 2025, 14:48:35) [GCC 13.3.0]

Package Information

langchain_core: 0.3.55
langsmith: 0.3.33
langchain_anthropic: 0.3.12

Optional packages not installed

langserve

Other Dependencies

anthropic<1,>=0.49.0: Installed. No version info available.
httpx: 0.28.1
jsonpatch<2.0,>=1.33: Installed. No version info available.
langchain-core<1.0.0,>=0.3.53: Installed. No version info available.
langsmith-pyo3: Installed. No version info available.
langsmith<0.4,>=0.1.125: Installed. No version info available.
openai-agents: Installed. No version info available.
opentelemetry-api: Installed. No version info available.
opentelemetry-exporter-otlp-proto-http: Installed. No version info available.
opentelemetry-sdk: Installed. No version info available.
orjson: 3.10.16
packaging: 24.2
packaging<25,>=23.2: Installed. No version info available.
pydantic: 2.11.3
pydantic<3.0.0,>=2.5.2;: Installed. No version info available.
pydantic<3.0.0,>=2.7.4: Installed. No version info available.
pydantic<3.0.0,>=2.7.4;: Installed. No version info available.
pytest: Installed. No version info available.
PyYAML>=5.3: Installed. No version info available.
requests: 2.32.3
requests-toolbelt: 1.0.0
rich: Installed. No version info available.
tenacity!=8.4.0,<10.0.0,>=8.1.0: Installed. No version info available.
typing-extensions>=4.7: Installed. No version info available.
zstandard: 0.23.0

Originally created by @phschoepf on GitHub (Apr 23, 2025). Original GitHub issue: https://github.com/langchain-ai/docs/issues/456 ### Checked other resources - [x] I added a very descriptive title to this issue. - [x] I used the GitHub search to find a similar question and didn't find it. - [x] I am sure that this is a bug in LangChain rather than my code. - [x] The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package). - [x] I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS. ### Example Code ```python import json from langchain_anthropic import ChatAnthropic from langchain_core.tools.convert import tool @tool() def secret_pharse() -> str: """Psst! A secret!""" return "correct horse battery staple" model = ChatAnthropic(model_name="claude-3-7-sonnet-latest", max_tokens=16000) model = model.bind(thinking={"type": "enabled", "budget_tokens": 1024}) model = model.bind_tools([secret_pharse]) response = model.invoke("Can you tell me the secret?") print(json.dumps(response.content, indent=2)) ``` Expected output: A thinking block and a tool call Output (thinking block missing): ```json [ { "text": "I can help you discover the secret phrase. Let me retrieve that for you.", "type": "text" }, { "id": "toolu_01Rha6sWeWscVY3zjD76EnF7", "input": {}, "name": "secret_pharse", "type": "tool_use" } ] ```` ### Error Message and Stack Trace (if applicable) _No response_ ### Description I'm trying to use Claude 3.7 Sonnet with thinking mode and tools. I have discovered that when the tools are bound *after* the arguments enabling thinking mode, the latter are overwritten. When swapping the order of `bind` and `bind_tools`, the issue is resolved and I get the expected output: ```json [ { "signature": "xxxx", "thinking": "The user is asking for a secret. I have a function available called \"secret_pharse\" that might contain this secret. The function doesn't require any parameters, so I can call it directly.", "type": "thinking" }, { "text": "I can access the secret for you by using the appropriate function.", "type": "text" }, { "id": "toolu_01UdHBdC9JnpH6uYi9dGQ5rs", "input": {}, "name": "secret_pharse", "type": "tool_use" } ] ``` ### System Info System Information ------------------ > OS: Linux > OS Version: langchain-ai/langchain#21~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Mon Feb 24 16:52:15 UTC 2 > Python Version: 3.12.3 (main, Feb 4 2025, 14:48:35) [GCC 13.3.0] Package Information ------------------- > langchain_core: 0.3.55 > langsmith: 0.3.33 > langchain_anthropic: 0.3.12 Optional packages not installed ------------------------------- > langserve Other Dependencies ------------------ > anthropic<1,>=0.49.0: Installed. No version info available. > httpx: 0.28.1 > jsonpatch<2.0,>=1.33: Installed. No version info available. > langchain-core<1.0.0,>=0.3.53: Installed. No version info available. > langsmith-pyo3: Installed. No version info available. > langsmith<0.4,>=0.1.125: Installed. No version info available. > openai-agents: Installed. No version info available. > opentelemetry-api: Installed. No version info available. > opentelemetry-exporter-otlp-proto-http: Installed. No version info available. > opentelemetry-sdk: Installed. No version info available. > orjson: 3.10.16 > packaging: 24.2 > packaging<25,>=23.2: Installed. No version info available. > pydantic: 2.11.3 > pydantic<3.0.0,>=2.5.2;: Installed. No version info available. > pydantic<3.0.0,>=2.7.4: Installed. No version info available. > pydantic<3.0.0,>=2.7.4;: Installed. No version info available. > pytest: Installed. No version info available. > PyYAML>=5.3: Installed. No version info available. > requests: 2.32.3 > requests-toolbelt: 1.0.0 > rich: Installed. No version info available. > tenacity!=8.4.0,<10.0.0,>=8.1.0: Installed. No version info available. > typing-extensions>=4.7: Installed. No version info available. > zstandard: 0.23.0
yindo added the langchainbughelp wanted labels 2026-02-17 17:19:01 -05:00
yindo closed this issue 2026-02-17 17:19:01 -05:00
Author
Owner

@keenborder786 commented on GitHub (Apr 26, 2025):

Yes, this is because when you do .bind first it creates an instance of RunnableBinding and when you call bind_tools again, it calls the ChatAnthropic method called bind_tools where the orginal RunnableBinding instance does not pass the binded attribute of thinking. And when you reverse the order, the bind method of RunnableBinding combines the attributes.
However, to easily solve this in one call:

model = model.bind_tools([secret_pharse], thinking={"type": "enabled", "budget_tokens": 1024})
@keenborder786 commented on GitHub (Apr 26, 2025): Yes, this is because when you do `.bind` first it creates an instance of `RunnableBinding` and when you call `bind_tools` again, it calls the ChatAnthropic method called `bind_tools` where the orginal `RunnableBinding` instance does not pass the binded attribute of `thinking`. And when you reverse the order, the `bind` method of `RunnableBinding` combines the attributes. However, to easily solve this in one call: ```python model = model.bind_tools([secret_pharse], thinking={"type": "enabled", "budget_tokens": 1024}) ```
yindo changed title from `bind_tools` after another `bind` overwrites bound arguments to [GH-ISSUE #456] `bind_tools` after another `bind` overwrites bound arguments 2026-06-05 17:24:38 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/docs#30