mirror of
https://github.com/discourse/discourse.git
synced 2026-08-08 17:53:55 +08:00
Previously, most built-in agents overrode `temperature` with a fixed value, along with a handful of other call sites (the LLM connectivity probe, the Hugging Face default options, the LLM report automation default, and the evals judge). This was a historical artifact from when temperature was a meaningful toggle across models. This change drops those overrides so everything runs at the model's native temperature, which is what modern models expect and what several providers enforce regardless.
103 lines
2.5 KiB
Ruby
Vendored
103 lines
2.5 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
module DiscourseAi
|
|
module Configuration
|
|
class LlmValidator
|
|
TEST_PROMPT = "How much is 1 + 1?"
|
|
|
|
attr_reader :last_failed_mode
|
|
|
|
def initialize(opts = {})
|
|
@opts = opts
|
|
end
|
|
|
|
def valid_value?(val)
|
|
if val == ""
|
|
if @opts[:name] == :ai_default_llm_model
|
|
@parent_module_names = []
|
|
|
|
enabled_settings.each do |setting_name|
|
|
if SiteSetting.public_send(setting_name) == true
|
|
@parent_module_names << setting_name
|
|
@parent_enabled = true
|
|
end
|
|
end
|
|
|
|
return !@parent_enabled
|
|
end
|
|
end
|
|
|
|
run_test(val).tap { |result| @unreachable = result }
|
|
rescue StandardError => e
|
|
raise e if Rails.env.test?
|
|
@unreachable = true
|
|
true
|
|
end
|
|
|
|
def run_test(val)
|
|
llm = DiscourseAi::Completions::Llm.proxy(val)
|
|
|
|
@last_failed_mode = :non_streaming
|
|
raise empty_response_error if probe(llm).blank?
|
|
|
|
@last_failed_mode = :streaming
|
|
streamed = +""
|
|
probe(llm) { |partial| streamed << partial.to_s if partial.is_a?(String) }
|
|
raise empty_response_error if streamed.blank?
|
|
|
|
@last_failed_mode = nil
|
|
true
|
|
end
|
|
|
|
def is_using(llm_model)
|
|
in_use_by = AiAgent.where(default_llm_id: llm_model.id).pluck(:name)
|
|
|
|
in_use_by << "ai_default_llm_model" if SiteSetting.ai_default_llm_model.to_i == llm_model.id
|
|
|
|
in_use_by
|
|
end
|
|
|
|
def error_message
|
|
if @parent_enabled && @parent_module_names.present?
|
|
return(
|
|
I18n.t(
|
|
"discourse_ai.llm.configuration.disable_modules_first",
|
|
settings: @parent_module_names.join(", "),
|
|
)
|
|
)
|
|
end
|
|
|
|
return unless @unreachable
|
|
|
|
I18n.t("discourse_ai.llm.configuration.model_unreachable")
|
|
end
|
|
|
|
def enabled_settings
|
|
%i[
|
|
ai_embeddings_semantic_search_enabled
|
|
ai_helper_enabled
|
|
ai_summarization_enabled
|
|
ai_translation_enabled
|
|
]
|
|
end
|
|
|
|
private
|
|
|
|
def probe(llm, &blk)
|
|
llm.generate(
|
|
TEST_PROMPT,
|
|
user: @opts[:user] || Discourse.system_user,
|
|
feature_name: "llm_validator",
|
|
top_p: 0.9,
|
|
&blk
|
|
)
|
|
end
|
|
|
|
def empty_response_error
|
|
DiscourseAi::Completions::Endpoints::Base::CompletionFailed.new(
|
|
I18n.t("discourse_ai.llm.configuration.empty_response"),
|
|
)
|
|
end
|
|
end
|
|
end
|
|
end
|