-
Notifications
You must be signed in to change notification settings - Fork 86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add tool_choice for OpenAI and Anthropic #142
Conversation
Thank you for the contribution! In this particular case, I wonder if a struct is unnecessary? Especially since it will be the different for each model that supports it. Take a look at: The recently added ChatOpenAI field :stream_options, :map, default: nil What do you think? |
I agree with you as this change will provide more flexibility to the library. I have replaced the structs with maps in the latest commit. One caveat with this is: when setting We might address this issue by defining a custom Ecto type, allowing tool_choice to accept either a string or a map. However, I'm not sure if this approach would be overkill, so I have not implemented it yet. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! It'd be worth adding a live test for tool choice. When implementing this in #141 I had to modify these lines to get it to work: https://github.com/brainlid/langchain/pull/141/files#diff-98396b383d660bb5274db90a5fd13b1526d5d6b120a2d8ece0e8baf06e55b85eL695-R713
lib/chat_models/chat_anthropic.ex
Outdated
defp set_tool_choice(%ChatAnthropic{tool_choice: %{"type" => type}=_tool_choice}) when type != nil and is_binary(type), | ||
do: %{"type" => type} | ||
|
||
defp set_tool_choice(%ChatAnthropic{}), do: nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe get_tool_choice
would be a better name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with you that it's a better name. Modified it accordingly.
Also added the tests for live calls.
assert message.content != nil | ||
assert message.tool_calls == [] | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding another live call test that forces the use of a tool triggers the bug I mentioned:
@tag live_call: true, live_open_ai: true
test "executing a call with required tool_choice", %{
weather: weather,
hello_world: hello_world
} do
{:ok, chat} =
ChatOpenAI.new(%{
seed: 0,
stream: false,
model: @gpt4,
tool_choice: %{"type" => "function", "function" => %{"name" => "get_weather"}}
})
{:ok, message} =
Message.new_user("What is the weather like in Moab Utah?")
{:ok, [message]} = ChatOpenAI.call(chat, [message], [weather, hello_world])
# assertions...
end
1) test call/2 executing a call with required tool_choice (LangChain.ChatModels.ChatOpenAITest)
test/chat_models/chat_open_ai_test.exs:737
** (WithClauseError) no with clause matching: %{"function" => %{"arguments" => "{\"city\":\"Moab\",\"state\":\"UT\"}", "name" => "get_weather"}, "id" => "call_q5WG1gd5X8gCqf9UlDceB3WA", "type" => "function"}
code: {:ok, [message]} = ChatOpenAI.call(chat, [message], [weather, hello_world])
stacktrace:
(langchain 0.3.0-rc.0) lib/message.ex:225: anonymous fn/1 in LangChain.Message.validate_and_parse_tool_calls/1
(elixir 1.16.2) lib/enum.ex:1700: Enum."-map/2-lists^map/1-1-"/2
(langchain 0.3.0-rc.0) lib/message.ex:224: LangChain.Message.validate_and_parse_tool_calls/1
(langchain 0.3.0-rc.0) lib/message.ex:151: LangChain.Message.common_validations/1
(langchain 0.3.0-rc.0) lib/message.ex:121: LangChain.Message.new/1
(langchain 0.3.0-rc.0) lib/chat_models/chat_open_ai.ex:825: LangChain.ChatModels.ChatOpenAI.do_process_response/2
(elixir 1.16.2) lib/enum.ex:1700: Enum."-map/2-lists^map/1-1-"/2
(langchain 0.3.0-rc.0) lib/chat_models/chat_open_ai.ex:552: LangChain.ChatModels.ChatOpenAI.do_api_request/4
(langchain 0.3.0-rc.0) lib/chat_models/chat_open_ai.ex:473: LangChain.ChatModels.ChatOpenAI.call/3
test/chat_models/chat_open_ai_test.exs:752: (test)
These changes fix that issue: https://github.com/brainlid/langchain/pull/141/files#diff-98396b383d660bb5274db90a5fd13b1526d5d6b120a2d8ece0e8baf06e55b85eL695-R713
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit includes the fix as you described, as well as the live call test that produced the bug previously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @stevehodgkiss for the help reviewing!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the contribution! It's a great addition to have.
❤️💛💙💜
This PR adds
tool_choice
option to both OpenAI and Anthropic models.For both models, I've created a
tool_choice
attribute inside the model structs that embeds aToolChoice
struct with attributes that are specific to each model.For
ChatOpenAI
:For
ChatAnthropic
: