Skip to content

AI Agents & LLM Operators

BLOGE treats LLM-driven orchestration as a first-class concern. The bloge-agent-ext module ships an agent DSL and runtime, bloge-common-operators exposes an extended LlmProvider SPI and a conversation-memory operator, and the graph-engine project adds an AI authoring pipeline that generates .bloge DSL from natural language.

The agent loop

An agent is a reasoning loop around an LlmProvider. It calls the model, optionally invokes the tools you declared, feeds observations back into memory, and repeats until an exit condition is met.

bloge
agent customerSupport {
  model                = "gpt-4o"
  system_prompt        = "You are a helpful customer support agent."
  max_turns            = 6
  max_tool_concurrency = 2
  temperature          = 0.2
  memory               = sliding_window(20)

  tool searchKnowledgeBase : KBSearchOperator {
    description = "Search the knowledge base for a relevant article"
    input { query = tool_args.query }
  }

  tool createTicket : CreateTicketOperator {
    description = "Create a support ticket for follow-up"
    input {
      title       = tool_args.title
      description = tool_args.description
      priority    = tool_args.priority
    }
  }

  exit_condition = finish_reason == "stop" || tool_call("escalateToHuman")
}
  • tool_args.<field> is only meaningful inside a tool input { ... } block. The compiler normalizes those references into context paths and infers the JSON tool schema sent to the model.
  • max_tool_concurrency caps how many declared tools may execute in parallel during one reasoning turn; omit it for unlimited fan-out.
  • exit_condition ends the loop — on a natural finish_reason, a specific tool_call(...), or any expression over context.

Streaming agents

For chunked output, use either stream agent ... or streaming = true; the runtime swaps in the StreamingAgentLoopOperator around llmStreamingChat.

Memory strategies

Memory controls what conversation history the model sees each turn:

StrategyBehavior
fullKeep the entire history
sliding_window(n)Keep the most recent n messages
token_budget(n)Keep as much recent history as fits in a token budget
summarySummarize older turns to stay compact

bloge-common-operators also ships a standalone conversation operator with full, sliding_window, and token_budget strategies plus an optional TokenEstimator SPI for precise token counting.

The Java builder

Agents can be built without the DSL via AgentBuilder:

java
AgentLoopOperator agent = AgentBuilder.create("customerSupport")
    .model("gpt-4o")
    .systemPrompt("You are a helpful customer support agent.")
    .maxTurns(6)
    .maxToolConcurrency(2)
    .temperature(0.2)
    .memory(new AgentMemoryStrategy.SlidingWindow(20))
    .tool(new AgentToolRef(
        "searchKnowledgeBase",
        "KBSearchOperator",
        "Search the knowledge base for a relevant article",
        searchToolGraph,
        "searchKnowledgeBase",
        null))
    .exitCondition("finish_reason == \"stop\"")
    .toOperator("CustomerSupportAgent", registry);

Use toBuilder() on a compiled AgentDef to derive variants, or compile a top-level agent document with AgentDslCompiler.

Extended LlmProvider SPI

bloge-common-operators extends the provider contract while keeping the original text-only convenience constructors for backward compatibility:

  • Tool callingToolDefinition, ToolCall.
  • Structured outputResponseFormat.Text, JsonObject, JsonSchema.
  • MultimodalLlmProvider.ContentPart message parts.

The original LlmMessage(role, content) and LlmRequest(model, messages) constructors still work.

Dynamic sub-graphs

The dynamicSubGraph operator sandbox-validates runtime-generated BLOGE DSL via DslSandbox + DslSandboxPolicy, compiles it with the current operator registry, and runs it as a nested sub-graph. This enables graph-factory patterns where an upstream node — say, an LLM — emits a small workflow that executes immediately.

AI authoring pipeline

The standalone graph-engine ai module (bloge-graph-engine-ai) assembles syntax-reference and operator-catalog prompt context, calls an LlmProvider to generate .bloge DSL from natural language, and validates each candidate through a parse → lint → compile pipeline backed by bloge-lint quality scoring, with up to two structured repair retries. The control-plane server exposes it as draft-only /api/v1/ai/validate and /api/v1/ai/generate endpoints that persist nothing.

Next steps