Skip to content

Commit c616b44

Browse files
authored
anthropic[patch]: support parallel_tool_calls (#29257)
Need to: - Update docs - Decide if this is an explicit kwarg of bind_tools - Decide if this should be in standard test with flag for supporting
1 parent 628145b commit c616b44

File tree

3 files changed

+49
-0
lines changed

3 files changed

+49
-0
lines changed

libs/partners/anthropic/langchain_anthropic/chat_models.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,7 @@ def bind_tools(
819819
tool_choice: Optional[
820820
Union[Dict[str, str], Literal["any", "auto"], str]
821821
] = None,
822+
parallel_tool_calls: Optional[bool] = None,
822823
**kwargs: Any,
823824
) -> Runnable[LanguageModelInput, BaseMessage]:
824825
r"""Bind tool-like objects to this chat model.
@@ -832,6 +833,10 @@ def bind_tools(
832833
- name of the tool as a string or as dict ``{"type": "tool", "name": "<<tool_name>>"}``: calls corresponding tool;
833834
- ``"auto"``, ``{"type: "auto"}``, or None: automatically selects a tool (including no tool);
834835
- ``"any"`` or ``{"type: "any"}``: force at least one tool to be called;
836+
parallel_tool_calls: Set to ``False`` to disable parallel tool use.
837+
Defaults to ``None`` (no specification, which allows parallel tool use).
838+
839+
.. versionadded:: 0.3.2
835840
kwargs: Any additional parameters are passed directly to
836841
:meth:`~langchain_anthropic.chat_models.ChatAnthropic.bind`.
837842
@@ -968,6 +973,19 @@ class GetPrice(BaseModel):
968973
f"Unrecognized 'tool_choice' type {tool_choice=}. Expected dict, "
969974
f"str, or None."
970975
)
976+
977+
if parallel_tool_calls is not None:
978+
disable_parallel_tool_use = not parallel_tool_calls
979+
if "tool_choice" in kwargs:
980+
kwargs["tool_choice"]["disable_parallel_tool_use"] = (
981+
disable_parallel_tool_use
982+
)
983+
else:
984+
kwargs["tool_choice"] = {
985+
"type": "any",
986+
"disable_parallel_tool_use": disable_parallel_tool_use,
987+
}
988+
971989
return self.bind(tools=formatted_tools, **kwargs)
972990

973991
def with_structured_output(

libs/partners/anthropic/tests/integration_tests/test_chat_models.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,25 @@ def test_tool_use() -> None:
444444
assert len(chunks) > 1
445445

446446

447+
class GenerateUsername(BaseModel):
448+
"Get a username based on someone's name and hair color."
449+
450+
name: str
451+
hair_color: str
452+
453+
454+
def test_disable_parallel_tool_calling() -> None:
455+
llm = ChatAnthropic(model="claude-3-5-sonnet-20241022")
456+
llm_with_tools = llm.bind_tools([GenerateUsername], parallel_tool_calls=False)
457+
result = llm_with_tools.invoke(
458+
"Use the GenerateUsername tool to generate user names for:\n\n"
459+
"Sally with green hair\n"
460+
"Bob with blue hair"
461+
)
462+
assert isinstance(result, AIMessage)
463+
assert len(result.tool_calls) == 1
464+
465+
447466
def test_anthropic_with_empty_text_block() -> None:
448467
"""Anthropic SDK can return an empty text block."""
449468

libs/partners/openai/tests/integration_tests/chat_models/test_base.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,18 @@ def test_bind_tools_tool_choice() -> None:
630630
assert not msg.tool_calls
631631

632632

633+
def test_disable_parallel_tool_calling() -> None:
634+
llm = ChatOpenAI(model="gpt-4o-mini")
635+
llm_with_tools = llm.bind_tools([GenerateUsername], parallel_tool_calls=False)
636+
result = llm_with_tools.invoke(
637+
"Use the GenerateUsername tool to generate user names for:\n\n"
638+
"Sally with green hair\n"
639+
"Bob with blue hair"
640+
)
641+
assert isinstance(result, AIMessage)
642+
assert len(result.tool_calls) == 1
643+
644+
633645
@pytest.mark.parametrize("model", ["gpt-4o-mini", "o1"])
634646
def test_openai_structured_output(model: str) -> None:
635647
class MyModel(BaseModel):

0 commit comments

Comments
 (0)