When we build AI systems with multiple agents, it’s not enough for each agent to just do its job in isolation. Agents need to communicate and share information. For example, if one agent writes a poem, another agent might edit it, and yet another might convert it to uppercase. To make this collaboration possible, LangChain4j provides a mechanism called AgenticScope.
Think of AgenticScope as a shared notebook where agents can write down their results and read what others have written. It also keeps track of who did what and when, giving you a complete history of the conversation between agents.
What is AgenticScope?
· A shared environment where agents in the same system can store and read variables.
· Helps agents collaborate by passing results between each other.
· Keeps a record of all agent calls and responses so you can reconstruct the conversation later.
Imagine you and your friends are solving a puzzle together. Instead of shouting answers, you all write your findings in a shared notebook. Each friend can look at what’s already written, add new notes, or edit something. That’s what AgenticScope does for AI agents.
The AgenticScope Interface:
public interface AgenticScope { void writeState(String key, Object value); // Add a piece of info Object readState(String key); // Get a piece of info boolean hasState(String key); // Check if something exists Map<String, Object> state(); // Get all shared info String contextAsConversation(String... agents); // See conversation history }
Think of writeState as writing in the notebook and readState as reading from it.
Example in Action
Let’s say we have three agents:
· Poet: writes a poem about robots
· PoemEditor: polishes the poem
· PoemInUppercase: makes it all uppercase
We connect them in sequence using LangChain4j:
UntypedAgent untypedAgent = AgenticServices.sequenceBuilder() .subAgents(poet, poemEditor, poemInUppercase) .outputName("poemInCapitalLetters") .build(); Map<String, Object> input = Map.of("theme", "Robots"); // Run the agents with AgenticScope ResultWithAgenticScope<String> poem = untypedAgent.invokeWithAgenticScope(input); AgenticScope agenticScope = poem.agenticScope(); // Inspect shared state Map<String, Object> state = agenticScope.state(); System.out.println(state);
What Happens Behind the Scenes
· The Poet writes a poem about robots and saves it in the AgenticScope.
· The PoemEditor reads that poem, edits it, and writes the new version back into the scope.
· The PoemInUppercase reads the edited poem, makes it uppercase, and writes the result.
· Finally, you can inspect the scope to see all intermediate steps as well as the final result.
Find the below working Application.
Step 1: Define Agents.
Poet.java
package com.sample.app.agents; import dev.langchain4j.agentic.Agent; import dev.langchain4j.service.UserMessage; import dev.langchain4j.service.V; public interface Poet { @UserMessage( """ You are a poet. Write a short poem of no more than 4 lines about the given theme. Return only the poem and nothing else. The theme is {{theme}}. """) @Agent(description = "Generates a short poem based on the given theme", name = "Poet") String generatePoem(@V("theme") String theme); }
PoemEditor.java
package com.sample.app.agents; import dev.langchain4j.agentic.Agent; import dev.langchain4j.service.UserMessage; import dev.langchain4j.service.V; public interface PoemEditor { @UserMessage( """ You are a professional Poem Editor. Analyze and rewrite the following {{poem}} to better align with the target theme of {{theme}}. Return only the poem and nothing else. """) @Agent(description = "Generates a short poem based on the given theme", name = "Poet") String generatePoem(@V("poem") String poemToEdit, @V("theme") String targetTheme); }
PoemInUppercase.java
package com.sample.app.agents; import dev.langchain4j.agentic.Agent; import dev.langchain4j.service.UserMessage; import dev.langchain4j.service.V; public interface PoemInUppercase { @UserMessage( """ Return only the following {{editedPoem}} in uppercase and nothing else. """) @Agent(description = "Convert the Poem to Uppercase", name = "PoemInUppercase") String generatePoem(@V("editedPoem") String poem); }
Step 2: Define AgenticScopeDemo class.
AgenticScopeDemo.java
package com.sample.app.agents.workflows; import com.sample.app.agents.PoemEditor; import com.sample.app.agents.PoemInUppercase; import com.sample.app.agents.Poet; import dev.langchain4j.agentic.AgenticServices; import dev.langchain4j.agentic.UntypedAgent; import dev.langchain4j.agentic.scope.AgenticScope; import dev.langchain4j.agentic.scope.ResultWithAgenticScope; import dev.langchain4j.model.ollama.OllamaChatModel; import java.util.Map; public class AgenticScopeDemo { public static void main(String[] args) { // Initialize LLM model OllamaChatModel chatModel = OllamaChatModel.builder().baseUrl("http://localhost:11434").modelName("llama3.2").build(); Poet poet = AgenticServices.agentBuilder(Poet.class).chatModel(chatModel).outputName("poem").build(); PoemEditor poemEditor = AgenticServices.agentBuilder(PoemEditor.class) .chatModel(chatModel) .outputName("editedPoem") .build(); PoemInUppercase poemInUppercase = AgenticServices.agentBuilder(PoemInUppercase.class) .chatModel(chatModel) .outputName("poemInCapitalLetters") .build(); UntypedAgent untypedAgent = AgenticServices.sequenceBuilder() .subAgents(poet, poemEditor, poemInUppercase) .outputName("poemInCapitalLetters") .build(); Map<String, Object> input = Map.of("theme", "Robots"); System.out.println("----------------------------------------------------------"); ResultWithAgenticScope<String> poem = untypedAgent.invokeWithAgenticScope(input); System.out.println(poem.result()); AgenticScope agenticScope = poem.agenticScope(); Map<String, Object> state = agenticScope.state(); for(String key: state.keySet()) { System.out.println("\t" + key + " = " + state.get(key).toString().replace("\n", " ")); } System.out.println("\n----------------------------------------------------------"); poem = untypedAgent.invokeWithAgenticScope(input); System.out.println(poem.result()); agenticScope = poem.agenticScope(); state = agenticScope.state(); for(String key: state.keySet()) { System.out.println("\t" + key + " = " + state.get(key).toString().replace("\n", " ")); } } }
Output
METAL HEARTS THAT BEAT WITH STONE,
CIRCUIT HUM, A MECHANICAL TONE,
GEARS SHIFT SMOOTH, WITH CALCULATED MIGHT,
FORGED FROM CODE, IN DIGITAL LIGHT.
theme = Robots
poem = Metal hearts that beat with stone, Their electronic eyes shine like moan, Rustic limbs that move with precision cold, Forged from wires, souls grown old.
editedPoem = Metal hearts that beat with stone, Circuits hum, a mechanical tone, Gears shift smooth, with calculated might, Forged from code, in digital light.
poemInCapitalLetters = METAL HEARTS THAT BEAT WITH STONE, CIRCUIT HUM, A MECHANICAL TONE, GEARS SHIFT SMOOTH, WITH CALCULATED MIGHT, FORGED FROM CODE, IN DIGITAL LIGHT.
----------------------------------------------------------
WHIRRING MINDS WITH LOGIC'S STEADY PACE,
THEY RISE FROM WIRES, A MECHANICAL THRONE,
ECHOES OF CODE, IN METALLIC BONE.
theme = Robots
poem = Metal hearts that beat in time, Whirring souls with calculating mind, They rise from dust, a synthetic reign, Echoes of man, in artificial frame.
editedPoem = Metal hearts that beat in digital space, Whirring minds with logic's steady pace, They rise from wires, a mechanical throne, Echoes of code, in metallic bone.
poemInCapitalLetters = WHIRRING MINDS WITH LOGIC'S STEADY PACE, THEY RISE FROM WIRES, A MECHANICAL THRONE, ECHOES OF CODE, IN METALLIC BONE.
Previous Next Home
No comments:
Post a Comment