mirror of
https://github.com/discourse/discourse-ai.git
synced 2025-06-26 17:42:15 +00:00
FEATURE: allow disabling of top_p and temp for thinking models (#1184)
thinking models such as Claude 3.7 Thinking and o1 / o3 do not support top_p or temp. Previously you would have to carefully remove it from everywhere by having it be a provider param we now support blanker removing without forcing people to update automation rules or personas
This commit is contained in:
parent
f4708d4178
commit
8f4cd2fcbd
@ -26,17 +26,23 @@ class LlmModel < ActiveRecord::Base
|
|||||||
access_key_id: :text,
|
access_key_id: :text,
|
||||||
region: :text,
|
region: :text,
|
||||||
disable_native_tools: :checkbox,
|
disable_native_tools: :checkbox,
|
||||||
|
disable_temperature: :checkbox,
|
||||||
|
disable_top_p: :checkbox,
|
||||||
enable_reasoning: :checkbox,
|
enable_reasoning: :checkbox,
|
||||||
reasoning_tokens: :number,
|
reasoning_tokens: :number,
|
||||||
},
|
},
|
||||||
anthropic: {
|
anthropic: {
|
||||||
disable_native_tools: :checkbox,
|
disable_native_tools: :checkbox,
|
||||||
|
disable_temperature: :checkbox,
|
||||||
|
disable_top_p: :checkbox,
|
||||||
enable_reasoning: :checkbox,
|
enable_reasoning: :checkbox,
|
||||||
reasoning_tokens: :number,
|
reasoning_tokens: :number,
|
||||||
},
|
},
|
||||||
open_ai: {
|
open_ai: {
|
||||||
organization: :text,
|
organization: :text,
|
||||||
disable_native_tools: :checkbox,
|
disable_native_tools: :checkbox,
|
||||||
|
disable_temperature: :checkbox,
|
||||||
|
disable_top_p: :checkbox,
|
||||||
disable_streaming: :checkbox,
|
disable_streaming: :checkbox,
|
||||||
reasoning_effort: {
|
reasoning_effort: {
|
||||||
type: :enum,
|
type: :enum,
|
||||||
@ -69,6 +75,8 @@ class LlmModel < ActiveRecord::Base
|
|||||||
provider_order: :text,
|
provider_order: :text,
|
||||||
provider_quantizations: :text,
|
provider_quantizations: :text,
|
||||||
disable_streaming: :checkbox,
|
disable_streaming: :checkbox,
|
||||||
|
disable_temperature: :checkbox,
|
||||||
|
disable_top_p: :checkbox,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -488,6 +488,8 @@ en:
|
|||||||
reasoning_effort: "Reasoning effort (only applicable to reasoning models)"
|
reasoning_effort: "Reasoning effort (only applicable to reasoning models)"
|
||||||
enable_reasoning: "Enable reasoning (only applicable to Sonnet 3.7)"
|
enable_reasoning: "Enable reasoning (only applicable to Sonnet 3.7)"
|
||||||
reasoning_tokens: "Number of tokens used for reasoning"
|
reasoning_tokens: "Number of tokens used for reasoning"
|
||||||
|
disable_temperature: "Disable temperature (some thinking models don't support temperature)"
|
||||||
|
disable_top_p: "Disable top P (some thinking models don't support top P)"
|
||||||
|
|
||||||
related_topics:
|
related_topics:
|
||||||
title: "Related topics"
|
title: "Related topics"
|
||||||
|
@ -10,6 +10,9 @@ module DiscourseAi
|
|||||||
|
|
||||||
def normalize_model_params(model_params)
|
def normalize_model_params(model_params)
|
||||||
# max_tokens, temperature, stop_sequences are already supported
|
# max_tokens, temperature, stop_sequences are already supported
|
||||||
|
model_params = model_params.dup
|
||||||
|
model_params.delete(:top_p) if llm_model.lookup_custom_param("disable_top_p")
|
||||||
|
model_params.delete(:temperature) if llm_model.lookup_custom_param("disable_temperature")
|
||||||
model_params
|
model_params
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -16,6 +16,9 @@ module DiscourseAi
|
|||||||
model_params = model_params.dup
|
model_params = model_params.dup
|
||||||
|
|
||||||
# max_tokens, temperature, stop_sequences, top_p are already supported
|
# max_tokens, temperature, stop_sequences, top_p are already supported
|
||||||
|
#
|
||||||
|
model_params.delete(:top_p) if llm_model.lookup_custom_param("disable_top_p")
|
||||||
|
model_params.delete(:temperature) if llm_model.lookup_custom_param("disable_temperature")
|
||||||
|
|
||||||
model_params
|
model_params
|
||||||
end
|
end
|
||||||
|
@ -24,6 +24,9 @@ module DiscourseAi
|
|||||||
model_params[:stop] = model_params.delete(:stop_sequences)
|
model_params[:stop] = model_params.delete(:stop_sequences)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
model_params.delete(:top_p) if llm_model.lookup_custom_param("disable_top_p")
|
||||||
|
model_params.delete(:temperature) if llm_model.lookup_custom_param("disable_temperature")
|
||||||
|
|
||||||
model_params
|
model_params
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -16,6 +16,9 @@ module DiscourseAi
|
|||||||
model_params[:stop] = model_params.delete(:stop_sequences)
|
model_params[:stop] = model_params.delete(:stop_sequences)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
model_params.delete(:top_p) if llm_model.lookup_custom_param("disable_top_p")
|
||||||
|
model_params.delete(:temperature) if llm_model.lookup_custom_param("disable_temperature")
|
||||||
|
|
||||||
model_params
|
model_params
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -664,4 +664,54 @@ data: {"type":"content_block_start","index":0,"content_block":{"type":"redacted_
|
|||||||
expect(log.feature_name).to eq("testing")
|
expect(log.feature_name).to eq("testing")
|
||||||
expect(log.response_tokens).to eq(30)
|
expect(log.response_tokens).to eq(30)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "parameter disabling" do
|
||||||
|
it "excludes disabled parameters from the request" do
|
||||||
|
model.update!(provider_params: { disable_top_p: true, disable_temperature: true })
|
||||||
|
|
||||||
|
parsed_body = nil
|
||||||
|
stub_request(:post, url).with(
|
||||||
|
body:
|
||||||
|
proc do |req_body|
|
||||||
|
parsed_body = JSON.parse(req_body, symbolize_names: true)
|
||||||
|
true
|
||||||
|
end,
|
||||||
|
headers: {
|
||||||
|
"Content-Type" => "application/json",
|
||||||
|
"X-Api-Key" => "123",
|
||||||
|
"Anthropic-Version" => "2023-06-01",
|
||||||
|
},
|
||||||
|
).to_return(
|
||||||
|
status: 200,
|
||||||
|
body: {
|
||||||
|
id: "msg_123",
|
||||||
|
type: "message",
|
||||||
|
role: "assistant",
|
||||||
|
content: [{ type: "text", text: "test response" }],
|
||||||
|
model: "claude-3-opus-20240229",
|
||||||
|
usage: {
|
||||||
|
input_tokens: 10,
|
||||||
|
output_tokens: 5,
|
||||||
|
},
|
||||||
|
}.to_json,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Request with parameters that should be ignored
|
||||||
|
llm.generate(
|
||||||
|
prompt,
|
||||||
|
user: Discourse.system_user,
|
||||||
|
top_p: 0.9,
|
||||||
|
temperature: 0.8,
|
||||||
|
max_tokens: 500,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Verify disabled parameters aren't included
|
||||||
|
expect(parsed_body).not_to have_key(:top_p)
|
||||||
|
expect(parsed_body).not_to have_key(:temperature)
|
||||||
|
|
||||||
|
# Verify other parameters still work
|
||||||
|
expect(parsed_body).to have_key(:max_tokens)
|
||||||
|
expect(parsed_body[:max_tokens]).to eq(500)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -436,4 +436,52 @@ RSpec.describe DiscourseAi::Completions::Endpoints::AwsBedrock do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "parameter disabling" do
|
||||||
|
it "excludes disabled parameters from the request" do
|
||||||
|
model.update!(
|
||||||
|
provider_params: {
|
||||||
|
access_key_id: "123",
|
||||||
|
region: "us-east-1",
|
||||||
|
disable_top_p: true,
|
||||||
|
disable_temperature: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
proxy = DiscourseAi::Completions::Llm.proxy("custom:#{model.id}")
|
||||||
|
request = nil
|
||||||
|
|
||||||
|
content = {
|
||||||
|
content: [text: "test response"],
|
||||||
|
usage: {
|
||||||
|
input_tokens: 10,
|
||||||
|
output_tokens: 5,
|
||||||
|
},
|
||||||
|
}.to_json
|
||||||
|
|
||||||
|
stub_request(
|
||||||
|
:post,
|
||||||
|
"https://bedrock-runtime.us-east-1.amazonaws.com/model/anthropic.claude-3-sonnet-20240229-v1:0/invoke",
|
||||||
|
)
|
||||||
|
.with do |inner_request|
|
||||||
|
request = inner_request
|
||||||
|
true
|
||||||
|
end
|
||||||
|
.to_return(status: 200, body: content)
|
||||||
|
|
||||||
|
# Request with parameters that should be ignored
|
||||||
|
proxy.generate("test prompt", user: user, top_p: 0.9, temperature: 0.8, max_tokens: 500)
|
||||||
|
|
||||||
|
# Parse the request body
|
||||||
|
request_body = JSON.parse(request.body)
|
||||||
|
|
||||||
|
# Verify disabled parameters aren't included
|
||||||
|
expect(request_body).not_to have_key("top_p")
|
||||||
|
expect(request_body).not_to have_key("temperature")
|
||||||
|
|
||||||
|
# Verify other parameters still work
|
||||||
|
expect(request_body).to have_key("max_tokens")
|
||||||
|
expect(request_body["max_tokens"]).to eq(500)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -395,6 +395,37 @@ RSpec.describe DiscourseAi::Completions::Endpoints::OpenAi do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "parameter disabling" do
|
||||||
|
it "excludes disabled parameters from the request" do
|
||||||
|
model.update!(provider_params: { disable_top_p: true, disable_temperature: true })
|
||||||
|
|
||||||
|
parsed_body = nil
|
||||||
|
stub_request(:post, "https://api.openai.com/v1/chat/completions").with(
|
||||||
|
body:
|
||||||
|
proc do |req_body|
|
||||||
|
parsed_body = JSON.parse(req_body, symbolize_names: true)
|
||||||
|
true
|
||||||
|
end,
|
||||||
|
).to_return(
|
||||||
|
status: 200,
|
||||||
|
body: { choices: [{ message: { content: "test response" } }] }.to_json,
|
||||||
|
)
|
||||||
|
|
||||||
|
dialect = compliance.dialect(prompt: compliance.generic_prompt)
|
||||||
|
|
||||||
|
# Request with parameters that should be ignored
|
||||||
|
endpoint.perform_completion!(dialect, user, { top_p: 0.9, temperature: 0.8, max_tokens: 100 })
|
||||||
|
|
||||||
|
# Verify disabled parameters aren't included
|
||||||
|
expect(parsed_body).not_to have_key(:top_p)
|
||||||
|
expect(parsed_body).not_to have_key(:temperature)
|
||||||
|
|
||||||
|
# Verify other parameters still work
|
||||||
|
expect(parsed_body).to have_key(:max_tokens)
|
||||||
|
expect(parsed_body[:max_tokens]).to eq(100)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "image support" do
|
describe "image support" do
|
||||||
it "can handle images" do
|
it "can handle images" do
|
||||||
model = Fabricate(:llm_model, vision_enabled: true)
|
model = Fabricate(:llm_model, vision_enabled: true)
|
||||||
|
@ -44,4 +44,35 @@ RSpec.describe DiscourseAi::Completions::Endpoints::OpenRouter do
|
|||||||
|
|
||||||
expect(parsed_body).to eq(expected)
|
expect(parsed_body).to eq(expected)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "excludes disabled parameters from the request" do
|
||||||
|
open_router_model.update!(provider_params: { disable_top_p: true, disable_temperature: true })
|
||||||
|
|
||||||
|
parsed_body = nil
|
||||||
|
stub_request(:post, open_router_model.url).with(
|
||||||
|
body: proc { |body| parsed_body = JSON.parse(body, symbolize_names: true) },
|
||||||
|
headers: {
|
||||||
|
"Content-Type" => "application/json",
|
||||||
|
"X-Title" => "Discourse AI",
|
||||||
|
"HTTP-Referer" => "https://www.discourse.org/ai",
|
||||||
|
"Authorization" => "Bearer 123",
|
||||||
|
},
|
||||||
|
).to_return(
|
||||||
|
status: 200,
|
||||||
|
body: { "choices" => [message: { role: "assistant", content: "test response" }] }.to_json,
|
||||||
|
)
|
||||||
|
|
||||||
|
proxy = DiscourseAi::Completions::Llm.proxy("custom:#{open_router_model.id}")
|
||||||
|
|
||||||
|
# Request with parameters that should be ignored
|
||||||
|
proxy.generate("test", user: user, top_p: 0.9, temperature: 0.8, max_tokens: 500)
|
||||||
|
|
||||||
|
# Verify disabled parameters aren't included
|
||||||
|
expect(parsed_body).not_to have_key(:top_p)
|
||||||
|
expect(parsed_body).not_to have_key(:temperature)
|
||||||
|
|
||||||
|
# Verify other parameters still work
|
||||||
|
expect(parsed_body).to have_key(:max_tokens)
|
||||||
|
expect(parsed_body[:max_tokens]).to eq(500)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user