Feature: Support third-party model strings like groq/model-id via a ServiceLoader SPI
Maintainer thường phản hồi trong vòng 1 ngày
Đánh giá
Issue này chưa được đánh giá.
Mô tả
Please make sure you read the contribution guide and file the issues in the right place.
Contribution guide.
🔴 Required Information
Is your feature request related to a specific problem?
Yes. ADK Java has no convention-based way to resolve a model name string to a third-party
backend. The official bridges (contrib/langchain4j, contrib/spring-ai) cover many
providers, but agents receive constructed model objects — the string form
(.model("groq/<model-id>")) does not resolve through them. The only native mechanism for
string resolution today is calling LlmRegistry.registerLlm(pattern, factory) manually in
every application before any agent is built.
Python ADK gets zero-code provider switching via LiteLLM — a model string from config resolves
at runtime. Java has no equivalent, which hurts:
- Multi-agent cost optimization — assigning different models to different agents in one
pipeline (Gemini where its built-in tools are needed, fast hosted models for generation,
local Ollama for lightweight steps) currently requires provider construction code in every
application. - Configuration-driven deployments — the model cannot be swapped via config alone; a code
change and rebuild are required. - Local development — using Ollama offline should be a dependency swap, not code.
There is also a subtle correctness constraint any solution must respect. When an agent is
created with .model("groq/some-model"), that string is not what reaches the provider:
LlmRegistry calls the registered factory with the requested name, and the "model" field in
the outgoing request is whatever name the returned BaseLlm was constructed with
(Basic.java copies it into LlmRequest.model; ChatCompletionsRequest sends it verbatim).
Since providers accept only bare model IDs, pattern-based registration needs a name-aware
factory: build a distinct instance per requested name and strip the routing prefix before
construction, so the backend receives an ID it recognizes rather than "groq/some-model".
Describe the Solution You'd Like
A minimal SPI in ADK core (3 classes, no new dependencies), discovered via the standard
java.util.ServiceLoader mechanism:
ModelProvider— SPI interface:prefix()(routing namespace, e.g.groq) +
createFromBareModelName(name)→BaseLlm. A defaultcreate(name)strips the prefix, so
the backend always receives the bare model ID.ModelProviderRegistry—registerAll()discovers allModelProviderimplementations
on the classpath viaServiceLoaderand registers each with the existingLlmRegistry.
Providers that fail to instantiate are logged and skipped without affecting the rest.OpenAiCompatibleLlm— a thinBaseLlmover ADK's native
ChatCompletionsHttpClientfor anyPOST /v1/chat/completionsendpoint (Groq, Ollama,
OpenRouter, ...). Constructed with the bare model ID, which is what the
backend receives as the wire-format"model"field.
Usage — one explicit opt-in line, then model strings resolve from the classpath:
ModelProviderRegistry.registerAll();
LlmAgent agent =
LlmAgent.builder()
.name("assistant")
.model("groq/some-model") // resolved via the Groq provider JAR
.build();
A provider is a one-class JAR plus a META-INF/services/com.google.adk.models.ModelProvider
entry — no ADK changes needed to add new providers, ever:
public final class GroqModelProvider implements ModelProvider {
@Override public String prefix() { return "groq"; }
@Override public BaseLlm createFromBareModelName(String bareModelName) {
return new OpenAiCompatibleLlm(
bareModelName,
"https://api.groq.com/openai/v1",
Optional.ofNullable(System.getenv("GROQ_API_KEY")));
}
}
Deliberately out of scope (to keep the change small and uncontroversial): bundled provider
implementations, demo modules, and automatic registerAll() inside Runner/AdkWebServer
(explicit opt-in first; auto-registration can be a follow-up discussion).
Impact on your work
Impact Level: Medium
Not a hard blocker — everything here can be done today with manual LlmRegistry.registerLlm
calls. The cost is recurring friction: every ADK Java application re-implements the same
registration and prefix-stripping boilerplate to mix models per agent (Gemini where its
built-in tools are needed, hosted models like Groq/OpenRouter for generation, local Ollama for
lightweight steps).
The main benefit is to the ADK Java ecosystem: convention-based model selection lets Java
developers build multi-agent systems on any mix of hosted, free-tier, and local models by
changing only dependencies and configuration — no provider-specific Java code in the
application — matching the provider switching Python ADK users already get via LiteLLM and
closing a gap between the two SDKs.
Willingness to contribute
Yes — the implementation is complete and ready to submit:
- ✅ 3 core classes as described (no new dependencies; native
ChatCompletionsHttpClientpath) - ✅ 18 unit tests, all passing (
mvn -pl core test), including an end-to-end test that a
registered provider resolvesgroq/-style strings to an LLM carrying the bare model ID - ✅ google-java-format applied; follows existing
com.google.adk.modelsconventions - ✅ Verified end-to-end against live endpoints (Groq, OpenRouter) with external provider
JARs discovered viaServiceLoader, including streaming and tool calling
Can submit the PR immediately.
🟡 Recommended Information
Describe Alternatives You've Considered
- The official bridges —
contrib/langchain4jandcontrib/spring-ai(status quo) —
both solve implementation boilerplate but not discovery: agents receive a
constructed/injected model object, not a resolvable name string. This proposal addresses
the discovery gap for OpenAI-compatible endpoints; the bridges remain the path for other
providers. - Instance-based registration (e.g. the builder +
registerWithPatternconvenience
sketched in #1202) — a pre-built model object is registered directly. This proposal
registers factories instead:LlmRegistrypasses each requested name to the factory,
which strips the prefix and constructs an instance configured for exactly that model — so
any number of models can be used under one prefix (e.g.groq/llama-3.3-70b-versatileand
groq/gemma2-9b-itin the same pipeline) from a single registration. Happy to align the
two efforts in whichever direction maintainers prefer. - Manual
LlmRegistry.registerLlmcalls in each application — ADK's only native mechanism
for string resolution today. It works, but it is exactly the boilerplate this proposal
removes, and each application re-implements prefix stripping (or forgets to).
Additional Context
The native ChatCompletionsHttpClient path became fully viable for strict OpenAI-compatible
providers in ADK 1.6.0, when the JSON Schema serialization fixes landed (#1265/#1266).
- Ngôn ngữ chính
- Java
- Star
- 1.7k
- Fork
- 433
- Merge trung bình
- 3 ngày 11 giờ
- Pull request đã merge (30 ngày)
- 50
Chuẩn bị môi trường
Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của google/adk-java
-
GeminiUtil placeholder user turn ("Continue output. DO NOT look at this line ...") is flagged by prompt injection filtersCó thể đã có người làm @hemasekhar-p đã nhận 1 ngày trước. Đang mởneeds review
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
google/adk-java#1628 · 1 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[spring-ai] ToolConverter silently drops enum and items from tool parameter schemasCó thể đã có người làm @hirematha đã nhận 3 ngày trước. Đang mởneeds review
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
google/adk-java#1609 · 2 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[spring-ai] Streaming responses ending with CJK punctuation (。!?) are misclassified as partial and never persisted to the sessionCó thể đã có người làm @hirematha đã nhận 3 ngày trước. Đang mởneeds review
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
google/adk-java#1608 · 3 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Claude model throws UnsupportedOperationException("Not supported yet.") on thinking blocks from Claude 5 modelsCó thể đã có người làm @hemasekhar-p đã nhận 1 ngày trước. Đang mởneeds review
google/adk-java#1630 · 2 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[core] Client disconnects don't cancel the model stream (per-step flow is cached) — and there is no public API to cancel an in-flight runCó thể đã có người làm @hemasekhar-p đã nhận 3 ngày trước. Đang mởneeds review
google/adk-java#1618 · 6 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của google/adk-java
Issue tương tự
-
[i18n] 安装实例完成后的成功提示未正确本地化Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
PCL-Community/PCL-CE#3658 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Team/Identity Server Core Type/Improvement U2
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
wso2/product-is#28553 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[Feature]: Page CreationĐang mởfrontend
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 72/100
Paul-Austin-Oswego-CSC480-HCI521/gift-app#116 ·
Maintainer thường phản hồi trong vòng 2 ngày
-
dependencies java
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 62/100
micrometer-metrics/tracing#1588 ·
Maintainer thường phản hồi trong vòng 1 ngày