Skip to content

Commit

Permalink
anthropic[patch]: support parallel_tool_calls (#29257)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ccurme authored Jan 17, 2025
1 parent 628145b commit c616b44
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 0 deletions.
18 changes: 18 additions & 0 deletions libs/partners/anthropic/langchain_anthropic/chat_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,7 @@ def bind_tools(
tool_choice: Optional[
Union[Dict[str, str], Literal["any", "auto"], str]
] = None,
parallel_tool_calls: Optional[bool] = None,
**kwargs: Any,
) -> Runnable[LanguageModelInput, BaseMessage]:
r"""Bind tool-like objects to this chat model.
Expand All @@ -832,6 +833,10 @@ def bind_tools(
- name of the tool as a string or as dict ``{"type": "tool", "name": "<<tool_name>>"}``: calls corresponding tool;
- ``"auto"``, ``{"type: "auto"}``, or None: automatically selects a tool (including no tool);
- ``"any"`` or ``{"type: "any"}``: force at least one tool to be called;
parallel_tool_calls: Set to ``False`` to disable parallel tool use.
Defaults to ``None`` (no specification, which allows parallel tool use).
.. versionadded:: 0.3.2
kwargs: Any additional parameters are passed directly to
:meth:`~langchain_anthropic.chat_models.ChatAnthropic.bind`.
Expand Down Expand Up @@ -968,6 +973,19 @@ class GetPrice(BaseModel):
f"Unrecognized 'tool_choice' type {tool_choice=}. Expected dict, "
f"str, or None."
)

if parallel_tool_calls is not None:
disable_parallel_tool_use = not parallel_tool_calls
if "tool_choice" in kwargs:
kwargs["tool_choice"]["disable_parallel_tool_use"] = (
disable_parallel_tool_use
)
else:
kwargs["tool_choice"] = {
"type": "any",
"disable_parallel_tool_use": disable_parallel_tool_use,
}

return self.bind(tools=formatted_tools, **kwargs)

def with_structured_output(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,25 @@ def test_tool_use() -> None:
assert len(chunks) > 1


class GenerateUsername(BaseModel):
"Get a username based on someone's name and hair color."

name: str
hair_color: str


def test_disable_parallel_tool_calling() -> None:
llm = ChatAnthropic(model="claude-3-5-sonnet-20241022")
llm_with_tools = llm.bind_tools([GenerateUsername], parallel_tool_calls=False)
result = llm_with_tools.invoke(
"Use the GenerateUsername tool to generate user names for:\n\n"
"Sally with green hair\n"
"Bob with blue hair"
)
assert isinstance(result, AIMessage)
assert len(result.tool_calls) == 1


def test_anthropic_with_empty_text_block() -> None:
"""Anthropic SDK can return an empty text block."""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,18 @@ def test_bind_tools_tool_choice() -> None:
assert not msg.tool_calls


def test_disable_parallel_tool_calling() -> None:
llm = ChatOpenAI(model="gpt-4o-mini")
llm_with_tools = llm.bind_tools([GenerateUsername], parallel_tool_calls=False)
result = llm_with_tools.invoke(
"Use the GenerateUsername tool to generate user names for:\n\n"
"Sally with green hair\n"
"Bob with blue hair"
)
assert isinstance(result, AIMessage)
assert len(result.tool_calls) == 1


@pytest.mark.parametrize("model", ["gpt-4o-mini", "o1"])
def test_openai_structured_output(model: str) -> None:
class MyModel(BaseModel):
Expand Down

0 comments on commit c616b44

Please sign in to comment.