Agents Agents — Java examples backed by real provider calls. java examples examples/short-agents src/examples/java/short-agents example Agents

These Java examples are real runnable files. Edit the source file first; this page is rebuilt from the checked-in example and its metadata header.

Java Grounded Support Agent

Answers a support question grounded in a handbook that is kept out of the model prompt via contextFields.

Java
import dev.axllm.ax.*;
import dev.axllm.ax.runtime.quickjs.*;
import java.util.*;

public final class BasicAgentExample {
  static String apiKey() {
    String apiKey = System.getenv("OPENAI_API_KEY");
    if (apiKey == null || apiKey.isBlank()) apiKey = System.getenv("OPENAI_APIKEY");
    if (apiKey == null || apiKey.isBlank()) {
      throw new IllegalStateException("Set OPENAI_API_KEY or OPENAI_APIKEY to run this example.");
    }
    return apiKey;
  }

  static OpenAICompatibleClient client() {
    return new OpenAICompatibleClient(Map.of(
        "api_key", apiKey(),
        "model", System.getenv().getOrDefault("AX_OPENAI_MODEL", "gpt-5.4-mini"),
        "model_config", Map.of("temperature", 0.0)));
  }

  // The handbook can be arbitrarily large. Listing it in `contextFields` keeps it
  // in the agent's runtime so it never inflates the model prompt -- the agent reads
  // it through code, not through tokens. That is the whole point of an Ax agent
  // over a plain gen() call: the source material stays out of the context window.
  static final String HANDBOOK = String.join("\n",
      "# Acme Cloud -- Support Handbook",
      "",
      "## Billing",
      "- Invoices are issued on the 1st of each month and are due net-15.",
      "- Plan downgrades take effect at the END of the current billing cycle, not immediately.",
      "- Refunds are issued to the original payment method within 5 business days.",
      "",
      "## Access",
      "- Seats can be added by any workspace Owner under Settings -> Members.",
      "- SSO (SAML) is available on Enterprise; SCIM provisioning is Owner-only.",
      "",
      "## Incidents",
      "- Status and uptime are published at status.acme.example.",
      "- Sev-1 incidents page the on-call within 5 minutes; updates post every 30 minutes.",
      "",
      "## Data",
      "- Exports are available in CSV and JSON from Settings -> Data.",
      "- Deleted workspaces are recoverable for 30 days, then permanently purged.");

  public static void main(String[] args) throws Exception {
    AxAgent assistant = Ax.agent(
        "question:string, handbook:string -> answer:string, citations:string[] \"Handbook sections the answer relies on\"",
        // Keep the handbook in the runtime, out of the prompt.
        Map.of("contextFields", List.of("handbook"), "runtime", Map.of("language", "JavaScript")));

    try (AxQuickJsCodeRuntime runtime = new AxQuickJsCodeRuntime()) {
      Map<String, Object> result = assistant.forward(
          client(),
          Map.of(
              "question", "A customer downgraded their plan today. When does it take effect, and can they get a refund for the current cycle?",
              "handbook", HANDBOOK),
          Map.of("runtime", runtime, "max_actor_steps", 12));

      System.out.println(Json.pretty(result));
    }
  }
}

Java Incident Triage Agent

Triages a noisy incident report held in contextFields, using a lean contextPolicy to keep the raw log out of the prompt while it reasons.

Java
import dev.axllm.ax.*;
import dev.axllm.ax.runtime.quickjs.*;
import java.util.*;

public final class ToolsAgentExample {
  static String apiKey() {
    String apiKey = System.getenv("OPENAI_API_KEY");
    if (apiKey == null || apiKey.isBlank()) apiKey = System.getenv("OPENAI_APIKEY");
    if (apiKey == null || apiKey.isBlank()) {
      throw new IllegalStateException("Set OPENAI_API_KEY or OPENAI_APIKEY to run this example.");
    }
    return apiKey;
  }

  static OpenAICompatibleClient client() {
    return new OpenAICompatibleClient(Map.of(
        "api_key", apiKey(),
        "model", System.getenv().getOrDefault("AX_OPENAI_MODEL", "gpt-5.4-mini"),
        "model_config", Map.of("temperature", 0.0)));
  }

  // A raw, noisy incident report. It lives in `contextFields`, so the agent works
  // it inside the runtime; `contextPolicy: lean` keeps the prompt compact by
  // preferring live runtime state and summaries over replaying the raw text.
  static final String REPORT = String.join("\n",
      "[2026-03-02 14:01:22Z] INFO  gateway       deploy svc-checkout-edge v812 -> prod (channel: canary 10%)",
      "[2026-03-02 14:03:10Z] WARN  checkout-api  p95 latency 1180ms (baseline 240ms) region=eu-west-1",
      "[2026-03-02 14:04:55Z] ERROR checkout-api  502 from svc-payments-gw: upstream timeout (10s) tenant_tier=enterprise",
      "[2026-03-02 14:05:01Z] ERROR checkout-api  502 from svc-payments-gw: upstream timeout (10s) tenant_tier=enterprise",
      "[2026-03-02 14:05:40Z] WARN  payments-gw   circuit half-open, 3 retries exhausted for order=ord_99214",
      "[2026-03-02 14:06:12Z] INFO  gateway       canary widened 10% -> 50% for svc-checkout-edge v812",
      "[2026-03-02 14:07:33Z] ERROR checkout-api  502 from svc-payments-gw: upstream timeout (10s) tenant_tier=enterprise",
      "[2026-03-02 14:08:02Z] ERROR checkout-api  user-visible: \"Payment could not be processed\" shown to 1,284 sessions",
      "[2026-03-02 14:09:48Z] WARN  payments-gw   connection pool exhausted (max=64) waiting=210",
      "[2026-03-02 14:11:20Z] INFO  on-call       paged: SEV-2 opened (eu-west-1 checkout error rate 38%)",
      "[2026-03-02 14:14:05Z] INFO  gateway       rollback svc-checkout-edge v812 -> v811 (channel: prod 100%)",
      "[2026-03-02 14:17:41Z] INFO  checkout-api  p95 latency 260ms, error rate 0.4% region=eu-west-1",
      "[2026-03-02 14:19:10Z] INFO  on-call       SEV-2 mitigated, monitoring for 30m");

  public static void main(String[] args) throws Exception {
    AxAgent triage = Ax.agent(
        "report:string, question:string -> severity:class \"low, medium, high, critical\", rootCause:string, nextSteps:string[], evidence:string[] \"Quoted log lines that support the assessment\"",
        Map.of(
            "contextFields", List.of("report"),
            "contextPolicy", Map.of("preset", "lean", "budget", "balanced"),
            "runtime", Map.of("language", "JavaScript")));

    try (AxQuickJsCodeRuntime runtime = new AxQuickJsCodeRuntime()) {
      Map<String, Object> result = triage.forward(
          client(),
          Map.of(
              "report", REPORT,
              "question", "What happened, how bad was it, and what should the on-call do next? Cite the lines you relied on."),
          Map.of("runtime", runtime, "max_actor_steps", 12));

      System.out.println(Json.pretty(result));
    }
  }
}

Java Specialist Planner Agent

A specialist that plans a migration from a long brief held in contextFields, using a checkpointed contextPolicy and a runtime-output cap to stay compact.

Java
import dev.axllm.ax.*;
import dev.axllm.ax.runtime.quickjs.*;
import java.util.*;

public final class HandoffAgentExample {
  static String apiKey() {
    String apiKey = System.getenv("OPENAI_API_KEY");
    if (apiKey == null || apiKey.isBlank()) apiKey = System.getenv("OPENAI_APIKEY");
    if (apiKey == null || apiKey.isBlank()) {
      throw new IllegalStateException("Set OPENAI_API_KEY or OPENAI_APIKEY to run this example.");
    }
    return apiKey;
  }

  static OpenAICompatibleClient client() {
    return new OpenAICompatibleClient(Map.of(
        "api_key", apiKey(),
        "model", System.getenv().getOrDefault("AX_OPENAI_MODEL", "gpt-5.4-mini"),
        "model_config", Map.of("temperature", 0.0)));
  }

  // A long, messy brief -- exactly the kind of input you do not want replayed into
  // the prompt on every turn. `contextFields` holds it in the runtime, the
  // `checkpointed` policy compacts older turns once the prompt grows, and
  // `maxRuntimeChars` caps how much runtime output is echoed back.
  static final String BRIEF = String.join("\n",
      "# Migration brief: monolith -> services (draft, unordered notes)",
      "",
      "Current: single Rails monolith, Postgres primary + 1 replica, Sidekiq for jobs.",
      "Pain: deploys take 40m, one bad migration locks the orders table, on-call burnout.",
      "Constraints: no downtime windows > 5m, PCI scope must shrink, team of 6, 2 quarters.",
      "Hot paths: checkout (writes orders, payments), search (read-heavy), notifications (async).",
      "Known landmines: payments code has no tests; search shares the orders DB; a nightly",
      "cron rebuilds the catalog and pins CPU for ~20m; the replica lags up to 90s under load.",
      "Org wants: independent deploys for checkout, smaller blast radius, an audit trail.",
      "Nice to have: event log for orders, read-model for search, feature flags.",
      "Hard no: a big-bang rewrite; introducing Kubernetes this year.");

  public static void main(String[] args) throws Exception {
    AxAgent specialist = Ax.agent(
        "brief:string, goal:string -> plan:string[] \"Ordered, concrete steps\", answer:string, risks:string[]",
        Map.of(
            "contextFields", List.of("brief"),
            "contextPolicy", Map.of("preset", "checkpointed", "budget", "balanced"),
            "maxRuntimeChars", 3000,
            "runtime", Map.of("language", "JavaScript")));

    try (AxQuickJsCodeRuntime runtime = new AxQuickJsCodeRuntime()) {
      Map<String, Object> result = specialist.forward(
          client(),
          Map.of(
              "brief", BRIEF,
              "goal", "Propose a safe, incremental 2-quarter plan to split checkout out first, respecting the hard constraints."),
          Map.of("runtime", runtime, "max_actor_steps", 12));

      System.out.println(Json.pretty(result));
    }
  }
}

Java Multi-Model Panel

Fans one question across three providers (OpenAI, Gemini, Anthropic), then judges the candidates and synthesizes a single grounded answer.

Java
import dev.axllm.ax.*;
import java.util.*;

public final class ModelPanelExample {
  static String firstNonBlank(String... values) {
    for (String value : values) {
      if (value != null && !value.isBlank()) return value;
    }
    return null;
  }

  public static void main(String[] args) throws Exception {
    String openaiKey = firstNonBlank(System.getenv("OPENAI_API_KEY"), System.getenv("OPENAI_APIKEY"));
    String googleKey = firstNonBlank(System.getenv("GOOGLE_APIKEY"), System.getenv("GOOGLE_API_KEY"));
    String anthropicKey = firstNonBlank(System.getenv("ANTHROPIC_APIKEY"), System.getenv("ANTHROPIC_API_KEY"));
    if (openaiKey == null || googleKey == null || anthropicKey == null) {
      throw new IllegalStateException(
          "Set OPENAI_APIKEY, GOOGLE_APIKEY, and ANTHROPIC_APIKEY to run this multi-provider panel.");
    }

    // A panel of three different providers, each answering the same question
    // independently. Plain ax() composition (no agent runtime): fan out to the
    // panel, judge the candidates, then synthesize one grounded answer.
    List<String> panelModels = List.of(
        "openai/gpt-5.4-mini",
        "google/gemini-3.5-flash",
        "anthropic/claude-haiku-4.5");
    List<AiClient> panelClients = List.of(
        new OpenAICompatibleClient(Map.of(
            "api_key", openaiKey, "model", "gpt-5.4-mini", "model_config", Map.of("temperature", 0.0))),
        new GoogleGeminiClient(Map.of(
            "api_key", googleKey, "model", "gemini-3.5-flash")),
        new AnthropicClient(Map.of(
            "api_key", anthropicKey, "model", "claude-haiku-4-5")));

    AxGen researcher = Ax.ax(
        "question:string -> answer:string, keyFindings:string[], citations:string[], confidence:number");
    researcher.setInstruction(
        "Answer independently. Use evidence. Call out uncertainty. Do not optimize for consensus.");

    AxGen judge = Ax.ax(
        "question:string, candidates:json -> consensus:string[], contradictions:string[], uniqueInsights:string[], blindSpots:string[]");
    judge.setInstruction(
        "Compare the candidates. Find agreement, conflicts, missing coverage, and unique useful points.");

    AxGen synthesizer = Ax.ax(
        "question:string, candidates:json, review:json -> answer:string, citations:string[], caveats:string[]");
    synthesizer.setInstruction(
        "Write one final answer grounded in the candidates and review. Resolve conflicts explicitly.");

    String question = "What are the strongest arguments for and against a national carbon tax?";

    List<Object> candidates = new ArrayList<>();
    for (int i = 0; i < panelClients.size(); i++) {
      Map<String, Object> response = researcher.forward(panelClients.get(i), Map.of("question", question));
      Map<String, Object> candidate = new LinkedHashMap<>();
      candidate.put("model", panelModels.get(i));
      candidate.putAll(response);
      candidates.add(candidate);
      System.out.println("[panel] " + panelModels.get(i) + " responded.");
    }

    // The judge + synthesizer run on one of the panel clients (OpenAI here).
    AiClient orchestrator = panelClients.get(0);
    Map<String, Object> review = judge.forward(orchestrator, Map.of("question", question, "candidates", candidates));
    Map<String, Object> finalAnswer = synthesizer.forward(
        orchestrator, Map.of("question", question, "candidates", candidates, "review", review));

    System.out.println(Json.pretty(finalAnswer));
  }
}
Docs