xyy45 opened a new issue, #4391:
URL: https://github.com/apache/hertzbeat/issues/4391
### Is there an existing issue for this?
- [x] I have searched the existing issues
### Current Behavior
Two related things in `hertzbeat-ai` that make non-OpenAI providers awkward
to set up. Both are on
current `master` (2.0-SNAPSHOT). I ran the app against a local recording
proxy to see what it
actually sends rather than guessing from the code.
**1. `temperature` is fixed in code.**
`hertzbeat-ai/.../config/LlmConfig.java:104-109` builds the options with
`.temperature(0.3)`, and
`ModelProviderConfig`
(`hertzbeat-common-core/.../entity/dto/ModelProviderConfig.java:33-54`) only
has `type / code / baseUrl / model / apiKey / participationModel`, so there
is no way to change or
drop it. This is the body the proxy recorded, with message contents and tool
schemas left out:
```json
{
"model": "deepseek-reasoner",
"temperature": 0.3,
"stream": true,
"stream_options": { "include_usage": true },
"tools": [ "..." ],
"messages": [ "..." ]
}
```
Those six keys are all that goes out. `top_p`, `n`, `tool_choice`,
`response_format` and
`max_tokens` are not sent. So the one generation parameter that does get
sent is the one a model is
most likely to disagree about, and an operator cannot touch it.
**2. `baseUrl` and `model` are filled in from a hardcoded list of `code`
values.**
`LlmConfig.java:79-101`: when `baseUrl` is empty it is chosen by `code`, and
the `else` branch sets
`https://api.openai.com/v1`. `model` works the same way and falls through to
`gpt-5` (I read that
off the source, I could not confirm it on the wire since the request is
rejected before the model is
checked). Nothing is logged about the fallthrough, so all you get back is an
error from a host you
never configured.
### Expected Behavior
Generation parameters that are fixed in code today should be settable per
provider, and left out of
the request when not set. I am not saying `0.3` is the wrong default, it
should stay the default,
this is only about making it overridable.
A `code` the backend does not know should fail or at least warn, instead of
quietly inheriting
OpenAI's endpoint.
### Steps To Reproduce
1. `POST /api/config/provider` with
`{"type":"provider","code":"deepseek","apiKey":"sk-invalid","participationModel":"PROTECTED"}`,
leave `baseUrl` empty
2. `POST /api/chat/stream` with `{"message":"hi"}` - the error comes back
from `api.openai.com`, see logs below
3. For the temperature part, point any provider `baseUrl` at a local
listener and send one chat
message; the outbound body carries `temperature` regardless of provider
or model
### Environment
- Version: 2.0-SNAPSHOT (master)
- Module: hertzbeat-ai
- OS: macOS, JDK 25, embedded H2
### Debug logs
The key was a throwaway value, so the reply below is the vendor's own masked
text. Note the host in
the OkHttp thread name, and that `LlmConfig` only logs bean lifecycle at
that moment:
```
2026-09-21 09:43:59 [http-nio-1157-exec-1] INFO
org.apache.hertzbeat.ai.config.LlmConfig - Provider configuration change event
received, refreshing ChatClient bean
2026-09-21 09:44:17 [OkHttp https://api.openai.com/...] ERROR
org.springframework.ai.chat.model.MessageAggregator - Aggregation Error
java.util.concurrent.CompletionException:
com.openai.errors.UnauthorizedException: 401: Incorrect API key provided:
sk-fake-***********nope. You can find your API key at
https://platform.openai.com/account/api-keys.
at
com.openai.core.http.RetryingHttpClient.executeAsync$executeWithRetries$lambda$1(RetryingHttpClient.kt:127)
at
org.springframework.ai.openai.http.okhttp.SpringAiOpenAiHttpClient$1.onResponse(SpringAiOpenAiHttpClient.java:137)
```
It also reaches the chat client as-is:
```
event:error
data:{"conversationId":4,"response":"An error occurred:
com.openai.errors.UnauthorizedException: 401: Incorrect API key provided:
sk-fake-***********nope. You can find your API key at
https://platform.openai.com/account/api-keys.","userMessageId":5,"assistantMessageId":null}
```
### Anything else?
On how far this reaches: the UI cannot produce case 2, since
`web-app/src/app/pojo/ModelProviderConfig.ts:37-56` only offers `openai` /
`zai` / `zhipu` in the
dropdown and fills in a `baseUrl` for them. Case 2 needs `POST
/api/config/provider`, which accepts
any `code` string without checking it. Case 1 does affect anyone using the
UI.
This is not the cause of #3971 and I am not proposing a fix for it here.
That reporter did set
`https://api.deepseek.com/v1`, so the empty-`baseUrl` branch is never
entered, and I have not
reproduced their 400 myself.
I'd like to work on this. What I have in mind is an optional parameter field
on `ModelProviderConfig`
plus the matching change in `LlmConfig`, a warn when `code` is unknown, and
unit tests for
`LlmConfig`, which has none today. No new provider names hardcoded. Say the
word if you would rather
see it done differently and I'll adjust before opening the PR.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail:
[email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]