Hello world:构建第一个 Agent Graph
2026年9月18日 上午11:49:51
本篇使用两个 SimpleAgent(或者 ReActAgent) 构建最小 Graph:分析员先提炼需求,作者再读取分析结果并生成提纲。
start -> analyst -> writer -> end
1、引入依赖
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-ai-agent</artifactId>
</dependency>
solon-ai-agent 已包含 Agent Graph 所需的 Solon Flow 依赖。
2、创建 ChatModel
ChatModel chatModel = ChatModel.of("https://api.example.com/v1/chat/completions")
.apiKey(System.getenv("LLM_API_KEY"))
.model("your-model")
.build();
密钥应由环境变量或安全配置注入,不要直接写进源码。
3、创建 Agent
Agent analyst = SimpleAgent.of(chatModel)
.name("analyst")
.role("需求分析师")
.instruction("提炼目标、受众和三个关键要点。")
.outputKey("analysis_result")
.build();
Agent writer = SimpleAgent.of(chatModel)
.name("writer")
.role("技术文章作者")
.instruction("根据用户任务和以下分析生成文章提纲:\n"
+ "#{analysis_result}")
.outputKey("draft_result")
.build();
analyst 完成后把文本写入 analysis_result。writer 的系统指令在执行时使用 Session Context 渲染,因此能显式消费这个结果。
outputKey只负责把响应回填到 Context,不会自动把它加入下一个 Agent 的 Prompt。这里真正完成交接的是#{analysis_result}模板。
4、构建 Graph
TeamAgent team = TeamAgent.of(null)
.name("article_graph")
.role("文章生产 Graph")
.protocol(TeamProtocols.NONE)
.agentAdd(analyst, writer)
.outputKey("article_result")
.graphAdjuster(spec -> {
spec.addStart(Agent.ID_START)
.linkAdd(analyst.name());
spec.addActivity(analyst)
.linkAdd(writer.name());
spec.addActivity(writer)
.linkAdd(Agent.ID_END);
spec.addEnd(Agent.ID_END);
})
.build();
这里有四个要点:
NONE不预建节点,必须自行添加 Start、Activity、End 和连接;- Agent 名称成为节点 ID,在同一 Graph 中必须唯一;
NONE仍有 TeamAgent、TeamTrace 和团队原始 Prompt,但不会自动把成员输出接力给后续 Agent;- 未显式设置
TeamTrace.finalAnswer时,TeamAgent 会回退到最后一条 Agent 记录的文本作为结果。
5、执行
AgentSession session = InMemoryAgentSession.of("article-job-001");
TeamResponse response = team.prompt(
"为 Java 开发者设计一篇 Graph 与 Agent 结合的入门文章")
.session(session)
.call();
System.out.println(response.getContent());
读取各阶段结果:
FlowContext context = session.getContext();
String analysis = context.getAs("analysis_result");
String draft = context.getAs("draft_result");
String finalResult = context.getAs("article_result");
draft_result 是作者输出;article_result 是 TeamAgent 的最终回填值。在这个线性 Graph 中,两者通常相同。
6、查看结构和协作记录
System.out.println(team.getGraph().toYaml());
System.out.println(team.getGraph().toPlantuml());
TeamTrace trace = team.getTrace(session);
trace.getRecords().forEach(record ->
System.out.println(record.getSource() + ": " + record.getContent()));
正常情况下,Agent 记录包含:
analyst
writer
TeamTrace 记录 Agent 协作,不等于所有 Graph 节点的完整执行历史;普通 Activity 和 Gateway 应通过 Flow 拦截器或业务状态验证。
7、如果不想使用模板
复杂交接可以插入显式适配节点。下面的定义用于替换前面 analyst -> writer 的两段连接:
spec.addActivity(analyst)
.linkAdd("write_with_context");
spec.addActivity("write_with_context")
.task((ctx, node) -> {
AgentSession current = ctx.getAs(Agent.KEY_SESSION);
String analysis = ctx.getAs("analysis_result");
String result = writer.prompt("请根据以下分析生成提纲:\n" + analysis)
.session(current)
.call()
.getContent();
ctx.put("draft_result", result);
TeamTrace trace = TeamTrace.getCurrent(ctx);
if (trace != null) {
trace.setFinalAnswer(result);
}
})
.linkAdd(Agent.ID_END);
这种写法让 Prompt 来源、结果键和最终答案都完全显式,适合普通独立 Graph 或复杂聚合场景。