Solon AI Agent Graph 开发
本系列是 Solon AI Agent 与 Solon Flow Graph 的交叉进阶系列。它不定义新的 Agent 类型,也不重复讲通用 Graph API,而是说明如何把 SimpleAgent、ReActAgent、TeamAgent 与确定性业务节点组织成可控制、可测试、可恢复的执行图。
Agent:理解、推理、调用工具并生成结果
Graph:定义顺序、分支、汇聚、循环和子图
FlowContext:传递 Graph 业务数据并保存 FlowTrace
AgentSession:定义会话边界,保存消息历史并持有 FlowContext
FlowEngine:执行 Graph
核心原则:让 Agent 处理不确定的认知任务,让 Graph 处理确定的业务约束。
1、前置阅读
建议先了解:
- Solon AI Agent(ReActAgent)开发
- agent - 认识 Solon AI Agent 接口
- team - TeamAgent 自由模式(NONE 协议)
- Solon Flow Graph 开发
本系列不会重复介绍 ChatModel、各类 Agent 的完整配置,也不会重复 Graph Fluent API、网关和 DSL 的通用参考;这里只讲 Graph 与 Agent 结合后新增的数据、状态和治理问题。
2、为什么需要 Agent Graph?
当系统出现以下要求时,不宜让一个大 Agent 自由决定全部步骤:
- 必须先审核再发布;
- 按金额、风险等级或问题类型选择 Agent;
- 让多个专家分析,再统一汇聚;
- 在敏感工具或业务阶段前等待人工批准;
- 将复杂系统拆成团队和子图;
- 保存执行位置,并在另一进程恢复。
典型结构:
Start
-> 需求分析 Agent
-> Parallel
├─ 技术 Agent ─┐
├─ 成本 Agent ─┼─> 汇聚 -> 决策 Agent
└─ 风险 Agent ─┘
-> 人工审核
-> End
3、两种结合方式
3.1 TeamAgent 内部 Graph
TeamAgent 内部使用 Graph。TeamProtocols.NONE 不预建拓扑,用户通过 graphAdjuster 完整定义结构:
TeamAgent team = TeamAgent.of(null)
.name("content_team")
.protocol(TeamProtocols.NONE)
.agentAdd(analyst, writer)
.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();
这种方式具备 TeamAgent 的 Prompt、TeamTrace、AgentEvent 和结果收敛语义。当系统主体是多个 Agent 的协作时,它是本系列优先讲解的主线方式;如果系统主体是通用业务流程,Agent 只是少量节点,则应选择后面的独立业务 Graph。
NONE是本系列用于讲解“显式 Agent Graph”的默认选择,不是 TeamAgent 构建器的框架默认协议。未显式配置时,TeamAgent 仍使用HIERARCHICAL。NONE也不提供自动协作:它不创建节点、不传递成员结果、不汇总并行结论,只保留 TeamAgent 运行时并把 Graph 定义权交给用户。
3.2 独立业务 Graph 显式调用 Agent
业务 Graph 只在部分节点需要 AI 时,应显式完成 FlowContext -> Prompt -> Agent -> FlowContext 映射:
Graph graph = Graph.create("summary_graph", spec -> {
spec.addStart("start").linkAdd("summary");
spec.addActivity("summary")
.task((ctx, node) -> {
AgentSession session = ctx.getAs(Agent.KEY_SESSION);
String input = ctx.getAs("input.document");
String result = summarizer.prompt(input)
.session(session)
.call()
.getContent();
ctx.put("summary.result", result);
})
.linkAdd("end");
spec.addEnd("end");
});
FlowContext context = FlowContext.of("summary-job-001");
context.put("input.document", "需要摘要的正文");
InMemoryAgentSession.of(context);
FlowEngine.newInstance().eval(graph, context);
InMemoryAgentSession.of(context) 会让 Session 与 Graph 共用同一个 Context。
4、Agent 为什么可以成为节点?
Agent 继承 NamedTaskComponent,因此在 TeamAgent Graph 中可以直接使用:
spec.addActivity(agent);
节点 ID 来自 agent.name();未覆盖 title() 时,标题也默认使用名称;任务入口是 Agent.run(FlowContext, Node)。
但不要由此推断普通独立 Graph 会自动把 context.get("input") 转换成 Prompt。外层不存在 TeamTrace 时,没有团队协议替 Agent 准备本次 Prompt;而且不应依赖 Agent.run 自动创建的临时 Session,它持有独立 Context。独立 Graph 应使用显式适配节点,并预先执行:
InMemoryAgentSession.of(context);
5、三个容易混淆的边界
Agent Graph 不是第四种 Agent
SimpleAgent、ReActAgent、TeamAgent 是执行单元;Agent Graph 是组织这些执行单元的结构。
Agent Graph 不是另一套 Graph 引擎
底层仍是 Solon Flow 的 Graph、FlowContext 和 FlowEngine。
Graph 拓扑不等于数据自动传递
spec.addActivity(analyst).linkAdd(writer.name());
只表示执行顺序。前一个 Agent 的 outputKey 不会自动进入后一个 Agent 的 Prompt,后续文章会专门定义输入输出契约。