Posts
All the articles I've posted.
-
Spring Boot #2 — CRUD with REST API · Layered Architecture · Global Exception Handler
Following Spring Boot #1 (first run · DI), #2 covers CRUD with REST API. Starting from the definition that REST is a combination of URL + HTTP method (GET/POST/PUT/DELETE), I completed todos CRUD by attaching @GetMapping · @PostMapping · @PutMapping · @DeleteMapping to the controller. I organized curl options (-X method · -H format · -d data) and verified the flow with a 5-step curl sequence (create → list all → update → delete → final check). Since the controller was holding all the logic, I split it into a service → layered architecture (Controller = request/response / Service = logic / Repository = storage). For exception handling: custom exception → 404 response, and with a Global Exception Handler in place, the controller just throws while the handler takes care of the response mapping — extending into practice the "throw forces propagation" contract I learned in the Java #3 post. Two trial-and-error incidents (trying to start the server without a referenced class present · writing package code before adding the library) got folded into my study guidelines to prevent recurrence.
-
Spring Boot #1 — First Run (bootRun · Embedded Tomcat) · @RestController · Getting a Feel for Dependency Injection
Wrapping up Java #3 (Exceptions · Concurrency · Gradle), I'm starting Spring Boot today. I pulled a hello-spring project from Spring Initializr and ran it with ./gradlew bootRun — the terminal looks stuck at "80% EXECUTING" but the server is actually already up on port 8080 (the Gradle daemon is holding onto the process, which is why the progress bar shows that way). Spring Boot has Tomcat embedded, so port 8080 comes up without installing a separate WAS. With no endpoint defined, hitting 8080 gives an error page — you need @RestController + @GetMapping to specify a path before a response is attached. Then, getting a feel for dependency injection (DI) — the reason a service gets injected into a controller without the controller ever calling new on it is that Spring creates one instance of the @Service class at startup, keeps it as a bean, and automatically plugs it into the controller's constructor. The interface sense I've been building since Java #1 — the contractual nature of using something handed to you without knowing its implementation — shows up here in an automated form within Spring. This is exactly why coupling goes down and testing gets easier.
-
Eval Study #4 — HITL Agent Regression Test, Passed but for the Wrong Reason
Following the previous post (agent tool selection · multi-step eval), this is a regression test for an HITL agent. This time, instead of a (question · expected tool) test set, I wrote unit-test style functions covering 3 axes of pitfalls (entering the breakpoint for dangerous tools / responding on every turn in multi-turn conversations / not misclassifying safe tools), with sys.exit(1) as the exit code on regression. The first run passed 3/3 — but that wasn't the right answer. The "call only after confirming clear intent" prompt that had been an issue before was still lingering, and the LLM was passing the test via its own self-defense mechanism. When I provoked it with a delete case, our HITL didn't trigger at all — only the LLM's own confirmation remained. Removing the prompt → the failure shifted to the tool simply not being called at all. Eventually, minimizing the prompt to "call the tool that matches the task the user requested" made it stop exactly at the delete_user tool (HITL working, exit code 0). Passing an eval by itself isn't a safety signal — verifying why it passed is the real safety. Pausing the LLM study series here for now, to resume after wrapping up backend studies.
-
Eval Study #3 — Agent Eval, the Limits of Single-Step Scoring, and Multi-Step Grading
Expanding from RAG Eval to agent Eval. Agents have 6 axes to judge (tool selection, argument extraction, multi-step trajectory, termination judgment, safety guards, final answer quality), so separating axes—like unit tests before integration tests—makes it faster to pinpoint causes. Today I covered just 3: tool selection, multi-step, and trap regression. I fed in MCP server tool metadata (name, description, schema) and measured against a (question, expected tool, expected args, level) test set → tool selection accuracy 11/13 = 84.6%. Two failure cases were interesting — (1) a single-step eval falsely flagged a case that was actually correct as a multi-step trajectory, showing the limits of single-step scoring, and (2) an ambiguous tool description caused "electricity bill" to wrongly pick consumption, while "how much money is it?" got it right — patching the system prompt instead of fixing the description risks overfitting. I then switched to multi-step eval (did it call all necessary tools, in order, using prior results, with correct termination judgment) → 4/4 = 100%, and the case that failed under single-step scoring now passed.