Skip to content

Commit d64a365

Browse files
committed
Fix reactor CI: keep class-level @builder, re-root crash-dump paths, README
- TrainingParameters: keep class-level Lombok @builder @Getter but satisfy the strict javadoc build (failOnWarnings) — replace the raw-source-invisible {@link #builder()} with {@code builder()} and add an explicit private all-args constructor so javadoc sees a real constructor (no synthetic-default warning); Lombok generates the builder around it. Verified: compile + javadoc:jar clean, TrainingParametersTest (3) green. - publish.yml: re-root the Java test jobs' crash-dump/surefire upload globs to llama/ (hs_err_pid*, *.hprof, target/surefire-reports/*) now that surefire runs against -f llama/pom.xml; core.* stays at workspace root (absolute core_pattern). - README: add Jlama and LangChain4j to the Similar Projects section. - Apply clang-format 22.1.5 (train_engine.cpp) and spotless (Java) from the #289 merge. - .gitignore: catch llama/.jqwik-database (un-anchored pattern). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Rt1paYztGJ2AKUuBuAGDXE
1 parent 91466f0 commit d64a365

8 files changed

Lines changed: 144 additions & 93 deletions

File tree

.github/workflows/publish.yml

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,13 +1108,13 @@ jobs:
11081108
with:
11091109
name: error-log-linux-x86_64
11101110
path: |
1111-
${{ github.workspace }}/hs_err_pid*.log
1111+
${{ github.workspace }}/llama/hs_err_pid*.log
11121112
${{ github.workspace }}/core.*
1113-
${{ github.workspace }}/*.hprof
1114-
${{ github.workspace }}/target/surefire-reports/*.dump
1115-
${{ github.workspace }}/target/surefire-reports/*.dumpstream
1116-
${{ github.workspace }}/target/surefire-reports/*.txt
1117-
${{ github.workspace }}/target/surefire-reports/TEST-*.xml
1113+
${{ github.workspace }}/llama/*.hprof
1114+
${{ github.workspace }}/llama/target/surefire-reports/*.dump
1115+
${{ github.workspace }}/llama/target/surefire-reports/*.dumpstream
1116+
${{ github.workspace }}/llama/target/surefire-reports/*.txt
1117+
${{ github.workspace }}/llama/target/surefire-reports/TEST-*.xml
11181118
if-no-files-found: warn
11191119

11201120
# ---------------------------------------------------------------------------
@@ -1202,12 +1202,12 @@ jobs:
12021202
with:
12031203
name: error-log-macos-14-metal
12041204
path: |
1205-
${{ github.workspace }}/hs_err_pid*.log
1206-
${{ github.workspace }}/*.hprof
1207-
${{ github.workspace }}/target/surefire-reports/*.dump
1208-
${{ github.workspace }}/target/surefire-reports/*.dumpstream
1209-
${{ github.workspace }}/target/surefire-reports/*.txt
1210-
${{ github.workspace }}/target/surefire-reports/TEST-*.xml
1205+
${{ github.workspace }}/llama/hs_err_pid*.log
1206+
${{ github.workspace }}/llama/*.hprof
1207+
${{ github.workspace }}/llama/target/surefire-reports/*.dump
1208+
${{ github.workspace }}/llama/target/surefire-reports/*.dumpstream
1209+
${{ github.workspace }}/llama/target/surefire-reports/*.txt
1210+
${{ github.workspace }}/llama/target/surefire-reports/TEST-*.xml
12111211
if-no-files-found: warn
12121212

12131213
test-java-macos-arm64-no-metal:
@@ -1266,12 +1266,12 @@ jobs:
12661266
with:
12671267
name: error-log-macos-15-no-metal
12681268
path: |
1269-
${{ github.workspace }}/hs_err_pid*.log
1270-
${{ github.workspace }}/*.hprof
1271-
${{ github.workspace }}/target/surefire-reports/*.dump
1272-
${{ github.workspace }}/target/surefire-reports/*.dumpstream
1273-
${{ github.workspace }}/target/surefire-reports/*.txt
1274-
${{ github.workspace }}/target/surefire-reports/TEST-*.xml
1269+
${{ github.workspace }}/llama/hs_err_pid*.log
1270+
${{ github.workspace }}/llama/*.hprof
1271+
${{ github.workspace }}/llama/target/surefire-reports/*.dump
1272+
${{ github.workspace }}/llama/target/surefire-reports/*.dumpstream
1273+
${{ github.workspace }}/llama/target/surefire-reports/*.txt
1274+
${{ github.workspace }}/llama/target/surefire-reports/TEST-*.xml
12751275
if-no-files-found: warn
12761276

12771277
test-java-macos-arm64-metal-15:
@@ -1330,12 +1330,12 @@ jobs:
13301330
with:
13311331
name: error-log-macos-15-metal
13321332
path: |
1333-
${{ github.workspace }}/hs_err_pid*.log
1334-
${{ github.workspace }}/*.hprof
1335-
${{ github.workspace }}/target/surefire-reports/*.dump
1336-
${{ github.workspace }}/target/surefire-reports/*.dumpstream
1337-
${{ github.workspace }}/target/surefire-reports/*.txt
1338-
${{ github.workspace }}/target/surefire-reports/TEST-*.xml
1333+
${{ github.workspace }}/llama/hs_err_pid*.log
1334+
${{ github.workspace }}/llama/*.hprof
1335+
${{ github.workspace }}/llama/target/surefire-reports/*.dump
1336+
${{ github.workspace }}/llama/target/surefire-reports/*.dumpstream
1337+
${{ github.workspace }}/llama/target/surefire-reports/*.txt
1338+
${{ github.workspace }}/llama/target/surefire-reports/TEST-*.xml
13391339
if-no-files-found: warn
13401340

13411341
test-java-windows-x86_64:
@@ -1413,13 +1413,13 @@ jobs:
14131413
with:
14141414
name: windows-output
14151415
path: |
1416-
${{ github.workspace }}\hs_err_pid*.log
1417-
${{ github.workspace }}\*.hprof
1416+
${{ github.workspace }}\llama\hs_err_pid*.log
1417+
${{ github.workspace }}\llama\*.hprof
14181418
${{ github.workspace }}\dumps\*.dmp
1419-
${{ github.workspace }}\target\surefire-reports\*.dump
1420-
${{ github.workspace }}\target\surefire-reports\*.dumpstream
1421-
${{ github.workspace }}\target\surefire-reports\*.txt
1422-
${{ github.workspace }}\target\surefire-reports\TEST-*.xml
1419+
${{ github.workspace }}\llama\target\surefire-reports\*.dump
1420+
${{ github.workspace }}\llama\target\surefire-reports\*.dumpstream
1421+
${{ github.workspace }}\llama\target\surefire-reports\*.txt
1422+
${{ github.workspace }}\llama\target\surefire-reports\TEST-*.xml
14231423
${{ github.workspace }}/llama/src/main/resources/net/ladenthin/llama/**/*
14241424
if-no-files-found: warn
14251425

@@ -1502,13 +1502,13 @@ jobs:
15021502
with:
15031503
name: windows-output-msvc
15041504
path: |
1505-
${{ github.workspace }}\hs_err_pid*.log
1506-
${{ github.workspace }}\*.hprof
1505+
${{ github.workspace }}\llama\hs_err_pid*.log
1506+
${{ github.workspace }}\llama\*.hprof
15071507
${{ github.workspace }}\dumps\*.dmp
1508-
${{ github.workspace }}\target\surefire-reports\*.dump
1509-
${{ github.workspace }}\target\surefire-reports\*.dumpstream
1510-
${{ github.workspace }}\target\surefire-reports\*.txt
1511-
${{ github.workspace }}\target\surefire-reports\TEST-*.xml
1508+
${{ github.workspace }}\llama\target\surefire-reports\*.dump
1509+
${{ github.workspace }}\llama\target\surefire-reports\*.dumpstream
1510+
${{ github.workspace }}\llama\target\surefire-reports\*.txt
1511+
${{ github.workspace }}\llama\target\surefire-reports\TEST-*.xml
15121512
${{ github.workspace }}/llama/src/main/resources/net/ladenthin/llama/**/*
15131513
if-no-files-found: warn
15141514

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ llama/src/test/resources/**/*.gbnf
6161
**/*.lastModified
6262
llama/src/main/cpp/llama.cpp/
6363

64-
# jcstress / jqwik test outputs (generated in repo root)
65-
/.jqwik-database
64+
# jcstress / jqwik test outputs (generated in the module dir where surefire runs, e.g. llama/)
65+
.jqwik-database
6666

6767
# Local AI agent tooling (not part of the project)
6868
AGENTS.md

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,3 +931,11 @@ The system's updated C++ runtime will be used instead, resolving the crash.
931931
- [gptoss.java](https://github.com/mukel/gptoss.java) — GPT-OSS architecture inference.
932932
- [qwen35.java](https://github.com/mukel/qwen35.java) — Qwen 3.5 inference.
933933
- [nemotron3.java](https://github.com/mukel/nemotron3.java) — NVIDIA Nemotron-3 inference.
934+
935+
**Pure-Java inference engines (no JNI / no llama.cpp)**
936+
937+
- [Jlama](https://github.com/tjake/Jlama) — a full pure-Java LLM inference engine for the JVM (multiple model architectures, quantization, and distributed inference) built on the Java Vector API. A no-native alternative to the JNI approach here; different design point (pure JVM portability vs. GGUF compatibility and llama.cpp performance via JNI).
938+
939+
**Frameworks / orchestration**
940+
941+
- [LangChain4j](https://github.com/langchain4j/langchain4j) — LLM-application framework for Java (chat, embeddings, RAG, tool calling, agents) over a unified provider API. This project ships a first-class **in-process** integration — see the [`llama-langchain4j`](llama-langchain4j/) module — so a llama.cpp model plugs straight into LangChain4j's `ChatModel` / `StreamingChatModel` / `EmbeddingModel` / `ScoringModel` without an HTTP hop.

llama/src/main/cpp/train_engine.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ bool finetune(const finetune_config &cfg, std::string &err) {
3737
params.n_ubatch = cfg.n_ubatch;
3838
}
3939

40-
params.optimizer =
41-
cfg.optimizer == 1 ? GGML_OPT_OPTIMIZER_TYPE_SGD : GGML_OPT_OPTIMIZER_TYPE_ADAMW;
40+
params.optimizer = cfg.optimizer == 1 ? GGML_OPT_OPTIMIZER_TYPE_SGD : GGML_OPT_OPTIMIZER_TYPE_ADAMW;
4241
params.lr.lr0 = cfg.learning_rate;
4342
params.lr.lr_min = cfg.lr_min;
4443
params.lr.decay_epochs = cfg.decay_epochs;
@@ -99,8 +98,8 @@ bool finetune(const finetune_config &cfg, std::string &err) {
9998
ggml_opt_result_t result_eval = ggml_opt_result_init();
10099

101100
for (params.lr.epoch = 0; params.lr.epoch < params.lr.epochs; ++params.lr.epoch) {
102-
llama_opt_epoch(ctx, dataset, result_train, result_eval, idata_split,
103-
ggml_opt_epoch_callback_progress_bar, ggml_opt_epoch_callback_progress_bar);
101+
llama_opt_epoch(ctx, dataset, result_train, result_eval, idata_split, ggml_opt_epoch_callback_progress_bar,
102+
ggml_opt_epoch_callback_progress_bar);
104103
ggml_opt_result_reset(result_train);
105104
ggml_opt_result_reset(result_eval);
106105
}
@@ -118,8 +117,8 @@ bool finetune(const finetune_config &cfg, std::string &err) {
118117

119118
} // namespace jllama_train
120119

121-
extern "C" JNIEXPORT jstring JNICALL
122-
Java_net_ladenthin_llama_LlamaTrainer_finetuneNative(JNIEnv *env, jclass, jstring jconfig) {
120+
extern "C" JNIEXPORT jstring JNICALL Java_net_ladenthin_llama_LlamaTrainer_finetuneNative(JNIEnv *env, jclass,
121+
jstring jconfig) {
123122
std::string config_json;
124123
if (jconfig != nullptr) {
125124
const char *c = env->GetStringUTFChars(jconfig, nullptr);

llama/src/main/java/net/ladenthin/llama/LlamaTrainer.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,13 @@ public static void finetune(TrainingParameters parameters) {
5151
* @throws LlamaException if the model cannot be loaded or training fails
5252
*/
5353
public static void finetune(Path model, String trainingText, Path output, int epochs, float learningRate) {
54-
finetune(
55-
TrainingParameters.builder()
56-
.modelPath(model)
57-
.trainingText(trainingText)
58-
.outputPath(output)
59-
.epochs(epochs)
60-
.learningRate(learningRate)
61-
.build());
54+
finetune(TrainingParameters.builder()
55+
.modelPath(model)
56+
.trainingText(trainingText)
57+
.outputPath(output)
58+
.epochs(epochs)
59+
.learningRate(learningRate)
60+
.build());
6261
}
6362

6463
private static native String finetuneNative(String configJson);

llama/src/main/java/net/ladenthin/llama/parameters/TrainingParameters.java

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
/**
1616
* Immutable configuration for a {@link net.ladenthin.llama.LlamaTrainer} fine-tuning run.
1717
*
18-
* <p>Build with {@link #builder()}; only {@code modelPath} and {@code outputPath} are required, and
18+
* <p>Build with {@code builder()}; only {@code modelPath} and {@code outputPath} are required, and
1919
* exactly one of {@code trainingText} / {@code trainingFile} should be set. All other fields default
2020
* to values that mirror upstream llama.cpp's fine-tuning defaults. The configuration is serialized to
2121
* JSON via {@link #toJson()} and parsed by the native layer, the same way {@link ModelParameters} and
@@ -38,40 +38,88 @@ public final class TrainingParameters {
3838
private final Path outputPath;
3939

4040
// Number of passes over the corpus (at least 1).
41-
@Builder.Default private final int epochs = 2;
41+
@Builder.Default
42+
private final int epochs = 2;
4243

4344
// Learning rate at the first epoch.
44-
@Builder.Default private final float learningRate = 1e-5f;
45+
@Builder.Default
46+
private final float learningRate = 1e-5f;
4547

4648
// Minimum learning rate for decay, or -1 to disable decay.
47-
@Builder.Default private final float lrMin = -1f;
49+
@Builder.Default
50+
private final float lrMin = -1f;
4851

4952
// If > 0, decay the learning rate from learningRate to lrMin over this many epochs.
50-
@Builder.Default private final float decayEpochs = -1f;
53+
@Builder.Default
54+
private final float decayEpochs = -1f;
5155

5256
// Weight decay (0 disables it).
53-
@Builder.Default private final float weightDecay = 0f;
57+
@Builder.Default
58+
private final float weightDecay = 0f;
5459

5560
// Optimizer algorithm.
56-
@Builder.Default private final Optimizer optimizer = Optimizer.ADAMW;
61+
@Builder.Default
62+
private final Optimizer optimizer = Optimizer.ADAMW;
5763

5864
// Context size in tokens, or 0 to use the model's trained context.
59-
@Builder.Default private final int nCtx = 0;
65+
@Builder.Default
66+
private final int nCtx = 0;
6067

6168
// Layers to offload to the GPU, or -1 for automatic.
62-
@Builder.Default private final int nGpuLayers = -1;
69+
@Builder.Default
70+
private final int nGpuLayers = -1;
6371

6472
// Fraction of the corpus held out for validation.
65-
@Builder.Default private final float valSplit = 0.05f;
73+
@Builder.Default
74+
private final float valSplit = 0.05f;
6675

6776
// Logical batch size, or 0 to use the native default.
68-
@Builder.Default private final int nBatch = 0;
77+
@Builder.Default
78+
private final int nBatch = 0;
6979

7080
// Physical (micro) batch size, or 0 to use the native default.
71-
@Builder.Default private final int nUbatch = 0;
81+
@Builder.Default
82+
private final int nUbatch = 0;
7283

7384
private static final ObjectMapper MAPPER = new ObjectMapper();
7485

86+
// Explicit all-args constructor used by the Lombok-generated builder. Declared explicitly (rather
87+
// than letting @Builder synthesize the package-private one) so Javadoc sees a real constructor and
88+
// does not emit the "use of default constructor, which does not provide a comment" warning; it is
89+
// private, so it is not part of the public API and is not doclint-checked.
90+
private TrainingParameters(
91+
Path modelPath,
92+
@Nullable String trainingText,
93+
@Nullable Path trainingFile,
94+
Path outputPath,
95+
int epochs,
96+
float learningRate,
97+
float lrMin,
98+
float decayEpochs,
99+
float weightDecay,
100+
Optimizer optimizer,
101+
int nCtx,
102+
int nGpuLayers,
103+
float valSplit,
104+
int nBatch,
105+
int nUbatch) {
106+
this.modelPath = modelPath;
107+
this.trainingText = trainingText;
108+
this.trainingFile = trainingFile;
109+
this.outputPath = outputPath;
110+
this.epochs = epochs;
111+
this.learningRate = learningRate;
112+
this.lrMin = lrMin;
113+
this.decayEpochs = decayEpochs;
114+
this.weightDecay = weightDecay;
115+
this.optimizer = optimizer;
116+
this.nCtx = nCtx;
117+
this.nGpuLayers = nGpuLayers;
118+
this.valSplit = valSplit;
119+
this.nBatch = nBatch;
120+
this.nUbatch = nUbatch;
121+
}
122+
75123
/**
76124
* Serialize this configuration to the JSON object the native fine-tuning layer expects.
77125
*

llama/src/test/java/net/ladenthin/llama/LlamaTrainerIntegrationTest.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,14 @@ void finetuneWritesAnOutputModel(@TempDir Path tmp) throws Exception {
3737
}
3838

3939
Path output = tmp.resolve("finetuned.gguf");
40-
LlamaTrainer.finetune(
41-
TrainingParameters.builder()
42-
.modelPath(Paths.get(modelPath))
43-
.trainingText(corpus.toString())
44-
.outputPath(output)
45-
.epochs(1)
46-
.learningRate(1e-5f)
47-
.optimizer(Optimizer.ADAMW)
48-
.build());
40+
LlamaTrainer.finetune(TrainingParameters.builder()
41+
.modelPath(Paths.get(modelPath))
42+
.trainingText(corpus.toString())
43+
.outputPath(output)
44+
.epochs(1)
45+
.learningRate(1e-5f)
46+
.optimizer(Optimizer.ADAMW)
47+
.build());
4948

5049
assertThat(Files.exists(output), is(true));
5150
assertThat(Files.size(output), greaterThan(0L));

llama/src/test/java/net/ladenthin/llama/parameters/TrainingParametersTest.java

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,11 @@ private JsonNode json(TrainingParameters parameters) throws Exception {
2424

2525
@Test
2626
void defaultsSerializeWithExpectedValues() throws Exception {
27-
TrainingParameters parameters =
28-
TrainingParameters.builder()
29-
.modelPath(Paths.get("base.gguf"))
30-
.trainingText("hello world")
31-
.outputPath(Paths.get("tuned.gguf"))
32-
.build();
27+
TrainingParameters parameters = TrainingParameters.builder()
28+
.modelPath(Paths.get("base.gguf"))
29+
.trainingText("hello world")
30+
.outputPath(Paths.get("tuned.gguf"))
31+
.build();
3332

3433
JsonNode node = json(parameters);
3534
assertThat(node.get("model_path").asText(), is("base.gguf"));
@@ -46,20 +45,19 @@ void defaultsSerializeWithExpectedValues() throws Exception {
4645

4746
@Test
4847
void customValuesSerialize() throws Exception {
49-
TrainingParameters parameters =
50-
TrainingParameters.builder()
51-
.modelPath(Paths.get("base.gguf"))
52-
.trainingFile(Paths.get("corpus.txt"))
53-
.outputPath(Paths.get("tuned.gguf"))
54-
.epochs(5)
55-
.learningRate(3e-4f)
56-
.optimizer(Optimizer.SGD)
57-
.nCtx(512)
58-
.nGpuLayers(0)
59-
.valSplit(0.1f)
60-
.nBatch(256)
61-
.nUbatch(64)
62-
.build();
48+
TrainingParameters parameters = TrainingParameters.builder()
49+
.modelPath(Paths.get("base.gguf"))
50+
.trainingFile(Paths.get("corpus.txt"))
51+
.outputPath(Paths.get("tuned.gguf"))
52+
.epochs(5)
53+
.learningRate(3e-4f)
54+
.optimizer(Optimizer.SGD)
55+
.nCtx(512)
56+
.nGpuLayers(0)
57+
.valSplit(0.1f)
58+
.nBatch(256)
59+
.nUbatch(64)
60+
.build();
6361

6462
JsonNode node = json(parameters);
6563
assertThat(node.get("epochs").asInt(), is(5));

0 commit comments

Comments
 (0)