Task Reflection Examples
Basic Reflection — Accumulating Improvements Across Runs
Section titled “Basic Reflection — Accumulating Improvements Across Runs”import net.agentensemble.Ensemble;import net.agentensemble.Task;import net.agentensemble.reflection.InMemoryReflectionStore;import net.agentensemble.reflection.ReflectionStore;
// Keep the same store instance across runs to persist reflectionsReflectionStore store = new InMemoryReflectionStore();
Task researchTask = Task.builder() .description("Research the top 5 AI trends of 2025") .expectedOutput("A structured report with trend name, description, and impact assessment") .reflect(true) // enable with default settings .build();
Ensemble ensemble = Ensemble.builder() .chatLanguageModel(model) .task(researchTask) .reflectionStore(store) .build();
// Run 1: baseline execution, reflection stored afterwardEnsembleOutput run1 = ensemble.run();System.out.println("Run 1 complete: " + run1.getRaw());
// Run 2: reflection notes injected into promptEnsembleOutput run2 = ensemble.run();System.out.println("Run 2 complete: " + run2.getRaw());
// Run 3: further refinedEnsembleOutput run3 = ensemble.run();System.out.println("Run 3 complete: " + run3.getRaw());Using a Cheaper Model for Reflection
Section titled “Using a Cheaper Model for Reflection”ChatModel primaryModel = OpenAiChatModel.builder() .apiKey(apiKey) .modelName("gpt-4o") .build();
ChatModel reflectionModel = OpenAiChatModel.builder() .apiKey(apiKey) .modelName("gpt-4o-mini") // cheaper for meta-analysis .build();
Task task = Task.builder() .description("Write a detailed technical architecture document") .expectedOutput("A structured architecture doc with sections: Overview, Components, Data Flow, Security") .reflect(ReflectionConfig.builder() .model(reflectionModel) .build()) .build();
Ensemble.builder() .chatLanguageModel(primaryModel) .task(task) .reflectionStore(new InMemoryReflectionStore()) .build() .run();Observing Reflection Events
Section titled “Observing Reflection Events”ReflectionStore store = new InMemoryReflectionStore();
Ensemble.builder() .chatLanguageModel(model) .task(Task.builder() .description("Summarise the quarterly earnings report") .expectedOutput("A concise executive summary with key metrics") .reflect(true) .build()) .reflectionStore(store) .onTaskReflected(event -> { System.out.printf("[Reflection] Task: %s | Run: %d | First: %s%n", event.taskDescription(), event.reflection().runCount(), event.isFirstReflection()); System.out.println(" Refined description: " + event.reflection().refinedDescription()); System.out.println(" Observations: " + event.reflection().observations()); }) .build() .run();Custom Reflection Strategy
Section titled “Custom Reflection Strategy”// Domain-specific strategy that checks output against a known rubricReflectionStrategy rubricStrategy = input -> { String output = input.taskOutput(); List<String> observations = new ArrayList<>(); List<String> suggestions = new ArrayList<>();
if (!output.contains("Executive Summary")) { observations.add("Output was missing an Executive Summary section"); suggestions.add("Explicitly require an Executive Summary in the task description"); } if (output.length() < 500) { observations.add("Output was shorter than expected for a detailed report"); suggestions.add("Specify a minimum length or section count in the expected output"); }
String refinedDesc = input.task().getDescription() + " Include an Executive Summary section.";
return TaskReflection.ofFirstRun( refinedDesc, input.task().getExpectedOutput(), observations, suggestions );};
Task task = Task.builder() .description("Produce a market analysis report") .expectedOutput("A detailed market analysis") .reflect(ReflectionConfig.builder() .strategy(rubricStrategy) .build()) .build();Reflection with Multiple Tasks in a Pipeline
Section titled “Reflection with Multiple Tasks in a Pipeline”Only tasks with .reflect(true) will be reflected on. Tasks without it run normally:
Task fetchTask = Task.builder() .description("Fetch the latest earnings data from the financial API") .expectedOutput("JSON array of quarterly earnings records") .handler(ctx -> ToolResult.success(apiClient.fetchEarnings())) // No reflection -- this is a deterministic data fetch, no prompt to improve .build();
Task analysisTask = Task.builder() .description("Analyse the earnings data and identify key trends") .expectedOutput("A structured analysis with trend identification and year-over-year comparison") .context(List.of(fetchTask)) .reflect(true) // reflection only on the analytical step .build();
ReflectionStore store = new InMemoryReflectionStore();
Ensemble.builder() .chatLanguageModel(model) .task(fetchTask) .task(analysisTask) .reflectionStore(store) .build() .run();Inspecting a Stored Reflection
Section titled “Inspecting a Stored Reflection”ReflectionStore store = new InMemoryReflectionStore();
Task task = Task.builder() .description("Write a technical blog post about microservices") .expectedOutput("A 600-800 word blog post with introduction, 3 main points, and conclusion") .reflect(true) .build();
Ensemble.builder() .chatLanguageModel(model) .task(task) .reflectionStore(store) .build() .run();
// Inspect the stored reflection directlyString identity = TaskIdentity.of(task);store.retrieve(identity).ifPresent(reflection -> { System.out.println("Refined description: " + reflection.refinedDescription()); System.out.println("Refined expected output: " + reflection.refinedExpectedOutput()); System.out.println("Observations:"); reflection.observations().forEach(o -> System.out.println(" - " + o)); System.out.println("Suggestions:"); reflection.suggestions().forEach(s -> System.out.println(" - " + s)); System.out.println("Run count: " + reflection.runCount());});