refactor: rename "invoker" to "ChainNode" and rename RouterChain.java to RouterNode.java

This commit is contained in:
Michael Yang 2024-04-25 17:29:30 +08:00
parent 543bf600c6
commit ace2dacc4e
16 changed files with 239 additions and 207 deletions

View File

@ -15,27 +15,22 @@
*/
package com.agentsflex.chain;
public abstract class BaseChain<Input, Output> extends Chain<Input, Output> implements Invoker {
public abstract class BaseChain<Input, Output> extends Chain<Input, Output> implements ChainNode {
private Condition condition;
protected boolean skip;
@Override
public Condition getCondition() {
return condition;
public boolean isSkip() {
return skip;
}
@Override
public void setCondition(Condition condition) {
this.condition = condition;
public void skip() {
this.skip = true;
}
@Override
public Object getId() {
return super.getId();
}
@Override
public Object invoke(Object prevResult, Chain<?, ?> chain) {
public Object execute(Object prevResult, Chain<?, ?> chain) {
//noinspection unchecked
return execute((Input) prevResult);
}

View File

@ -16,7 +16,8 @@
package com.agentsflex.chain;
import com.agentsflex.agent.Agent;
import com.agentsflex.chain.events.OnErrorEvent;
import com.agentsflex.chain.event.OnErrorEvent;
import com.agentsflex.chain.node.AgentNode;
import com.agentsflex.memory.ContextMemory;
import com.agentsflex.memory.DefaultContextMemory;
@ -28,11 +29,12 @@ import java.util.Map;
public abstract class Chain<Input, Output> implements Serializable {
protected Object id;
protected ContextMemory context = new DefaultContextMemory();
protected Map<String, List<ChainEventListener>> listeners = new HashMap<>();
protected List<Invoker> invokers;
protected List<ChainNode> chainNodes;
protected Chain<?, ?> parent;
@ -83,30 +85,26 @@ public abstract class Chain<Input, Output> implements Serializable {
}
}
public List<Invoker> getInvokers() {
return invokers;
public List<ChainNode> getInvokers() {
return chainNodes;
}
public void setInvokers(List<Invoker> invokers) {
this.invokers = invokers;
public void setInvokers(List<ChainNode> chainNodes) {
this.chainNodes = chainNodes;
}
public void addInvoker(Invoker invoker) {
if (invokers == null) {
this.invokers = new ArrayList<>();
public void addInvoker(ChainNode chainNode) {
if (chainNodes == null) {
this.chainNodes = new ArrayList<>();
}
if (invoker instanceof Chain) {
((Chain<?, ?>) invoker).parent = this;
if (chainNode instanceof Chain) {
((Chain<?, ?>) chainNode).parent = this;
}
invokers.add(invoker);
chainNodes.add(chainNode);
}
public void addInvoker(Agent<?> agent) {
addInvoker(new AgentInvoker(agent));
}
public void addInvoker(Agent<?> agent, Condition condition) {
addInvoker(new AgentInvoker(agent, condition));
addInvoker(new AgentNode(agent));
}
public Input getInput() {
@ -168,6 +166,22 @@ public abstract class Chain<Input, Output> implements Serializable {
return stopFlag;
}
public Object get(String key) {
return this.context.get(key);
}
public Object getGlobal(String key) {
Object object = this.context.get(key);
if (object != null) {
return object;
}
if (parent != null) {
return parent.getGlobal(key);
}
return null;
}
public Output execute(Input input) {
this.input = input;
this.lastResult = input;

View File

@ -15,6 +15,11 @@
*/
package com.agentsflex.chain;
public interface Condition {
boolean check(Object result, Chain<?, ?> chain);
public interface ChainNode {
Object getId();
boolean isSkip();
Object execute(Object prevResult, Chain<?, ?> chain);
}

View File

@ -16,8 +16,9 @@
package com.agentsflex.chain;
import com.agentsflex.agent.Agent;
import com.agentsflex.chain.events.OnErrorEvent;
import com.agentsflex.chain.events.OnInvokeAfter;
import com.agentsflex.chain.event.OnErrorEvent;
import com.agentsflex.chain.event.OnInvokeAfter;
import com.agentsflex.chain.node.AgentNode;
import java.util.ArrayList;
import java.util.Arrays;
@ -36,30 +37,31 @@ public class LoopChain<Input, Output> extends BaseChain<Input, Output> {
}
public LoopChain(Agent<?>... agents) {
List<Invoker> invokers = new ArrayList<>(agents.length);
List<ChainNode> chainNodes = new ArrayList<>(agents.length);
for (Agent<?> agent : agents) {
invokers.add(new AgentInvoker(agent));
chainNodes.add(new AgentNode(agent));
}
setInvokers(invokers);
setInvokers(chainNodes);
}
public LoopChain(Invoker... invokers) {
setInvokers(new ArrayList<>(Arrays.asList(invokers)));
public LoopChain(ChainNode... chainNodes) {
setInvokers(new ArrayList<>(Arrays.asList(chainNodes)));
}
@Override
protected void doExecuteAndSetOutput() {
while (!isStop()) {
for (Invoker invoker : invokers) {
for (ChainNode node : chainNodes) {
if (isStop()) {
break;
}
try {
if (invoker.checkCondition(lastResult, this)) {
lastResult = invoker.invoke(lastResult, this);
notify(new OnInvokeAfter(this, invoker, lastResult));
Object result = node.execute(this.lastResult, this);
if (!node.isSkip()) {
this.lastResult = result;
}
notify(new OnInvokeAfter(this, node, lastResult));
} catch (Exception e) {
notify(new OnErrorEvent(this, e));
}

View File

@ -16,8 +16,9 @@
package com.agentsflex.chain;
import com.agentsflex.agent.Agent;
import com.agentsflex.chain.events.OnErrorEvent;
import com.agentsflex.chain.events.OnInvokeAfter;
import com.agentsflex.chain.event.OnErrorEvent;
import com.agentsflex.chain.event.OnInvokeAfter;
import com.agentsflex.chain.node.AgentNode;
import java.util.ArrayList;
import java.util.Arrays;
@ -35,15 +36,15 @@ public abstract class ParallelChain<Input, Output> extends BaseChain<Input, Outp
}
public ParallelChain(Agent<?>... agents) {
List<Invoker> invokers = new ArrayList<>(agents.length);
List<ChainNode> chainNodes = new ArrayList<>(agents.length);
for (Agent<?> agent : agents) {
invokers.add(new AgentInvoker(agent));
chainNodes.add(new AgentNode(agent));
}
setInvokers(invokers);
setInvokers(chainNodes);
}
public ParallelChain(Invoker... invokers) {
setInvokers(new ArrayList<>(Arrays.asList(invokers)));
public ParallelChain(ChainNode... chainNodes) {
setInvokers(new ArrayList<>(Arrays.asList(chainNodes)));
}
@ -54,16 +55,16 @@ public abstract class ParallelChain<Input, Output> extends BaseChain<Input, Outp
@Override
protected void doExecuteAndSetOutput() {
List<Object> allResult = new ArrayList<>();
for (Invoker invoker : invokers) {
for (ChainNode node : chainNodes) {
if (isStop()) {
break;
}
try {
if (invoker.checkCondition(lastResult, this)) {
Object result = invoker.invoke(lastResult, this);
Object result = node.execute(this.lastResult, this);
if (!node.isSkip()) {
allResult.add(result);
notify(new OnInvokeAfter(this, invoker, result));
}
notify(new OnInvokeAfter(this, node, lastResult));
} catch (Exception e) {
notify(new OnErrorEvent(this, e));
}

View File

@ -1,79 +0,0 @@
/*
* Copyright (c) 2022-2023, Agents-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.agentsflex.chain;
import com.agentsflex.agent.Agent;
import com.agentsflex.chain.events.OnInvokeAfter;
import com.agentsflex.util.StringUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
public abstract class RouterChain<Input, Output> extends BaseChain<Input, Output> {
public RouterChain() {
}
public RouterChain(Agent<?>... agents) {
List<Invoker> invokers = new ArrayList<>(agents.length);
for (Agent<?> agent : agents) {
invokers.add(new AgentInvoker(agent));
}
setInvokers(invokers);
}
public RouterChain(Invoker... invokers) {
setInvokers(new ArrayList<>(Arrays.asList(invokers)));
}
@Override
protected void doExecuteAndSetOutput() {
String result = route();
if (StringUtil.noText(result)) {
stop();
return;
}
List<Invoker> findInvokers = new ArrayList<>();
String[] ids = result.split(",");
for (String id : ids) {
for (Invoker invoker : this.invokers) {
if (Objects.equals(id, String.valueOf(invoker.getId()))) {
findInvokers.add(invoker);
}
}
}
if (findInvokers.isEmpty()) {
stop();
return;
}
if (findInvokers.size() == 1) {
Invoker invoker = findInvokers.get(0);
this.lastResult = invoker.invoke(this.lastResult, this);
notify(new OnInvokeAfter(this, invoker, this.lastResult));
} else {
lastResult = new SequentialChain<>(findInvokers).execute(this.lastResult);
}
}
protected abstract String route();
}

View File

@ -16,8 +16,9 @@
package com.agentsflex.chain;
import com.agentsflex.agent.Agent;
import com.agentsflex.chain.events.OnErrorEvent;
import com.agentsflex.chain.events.OnInvokeAfter;
import com.agentsflex.chain.event.OnErrorEvent;
import com.agentsflex.chain.event.OnInvokeAfter;
import com.agentsflex.chain.node.AgentNode;
import java.util.ArrayList;
import java.util.Arrays;
@ -36,34 +37,35 @@ public class SequentialChain<Input, Output> extends BaseChain<Input, Output> {
}
public SequentialChain(Agent<?>... agents) {
List<Invoker> invokers = new ArrayList<>(agents.length);
List<ChainNode> chainNodes = new ArrayList<>(agents.length);
for (Agent<?> agent : agents) {
invokers.add(new AgentInvoker(agent));
chainNodes.add(new AgentNode(agent));
}
setInvokers(invokers);
setInvokers(chainNodes);
}
public SequentialChain(Invoker... invokers) {
setInvokers(new ArrayList<>(Arrays.asList(invokers)));
public SequentialChain(ChainNode... chainNodes) {
setInvokers(new ArrayList<>(Arrays.asList(chainNodes)));
}
public SequentialChain(Collection<Invoker> invokers) {
setInvokers(new ArrayList<>(invokers));
public SequentialChain(Collection<ChainNode> chainNodes) {
setInvokers(new ArrayList<>(chainNodes));
}
@Override
protected void doExecuteAndSetOutput() {
for (Invoker invoker : invokers) {
for (ChainNode node : chainNodes) {
if (isStop()) {
break;
}
try {
if (invoker.checkCondition(lastResult, this)) {
lastResult = invoker.invoke(lastResult, this);
notify(new OnInvokeAfter(this, invoker, lastResult));
Object result = node.execute(this.lastResult, this);
if (!node.isSkip()) {
this.lastResult = result;
}
notify(new OnInvokeAfter(this, node, lastResult));
} catch (Exception e) {
notify(new OnErrorEvent(this, e));
}

View File

@ -1,4 +1,4 @@
package com.agentsflex.chain.events;
package com.agentsflex.chain.event;
import com.agentsflex.chain.Chain;
import com.agentsflex.chain.ChainEvent;

View File

@ -1,18 +1,18 @@
package com.agentsflex.chain.events;
package com.agentsflex.chain.event;
import com.agentsflex.chain.Chain;
import com.agentsflex.chain.ChainEvent;
import com.agentsflex.chain.Invoker;
import com.agentsflex.chain.ChainNode;
public class OnInvokeAfter implements ChainEvent {
private Chain<?,?> chain;
private Invoker invoker;
private ChainNode chainNode;
private Object result;
public OnInvokeAfter(Chain<?, ?> chain, Invoker invoker, Object result) {
public OnInvokeAfter(Chain<?, ?> chain, ChainNode chainNode, Object result) {
this.chain = chain;
this.invoker = invoker;
this.chainNode = chainNode;
this.result = result;
}
@ -29,12 +29,12 @@ public class OnInvokeAfter implements ChainEvent {
this.chain = chain;
}
public Invoker getInvoker() {
return invoker;
public ChainNode getInvoker() {
return chainNode;
}
public void setInvoker(Invoker invoker) {
this.invoker = invoker;
public void setInvoker(ChainNode chainNode) {
this.chainNode = chainNode;
}
public Object getResult() {

View File

@ -13,42 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.agentsflex.chain;
package com.agentsflex.chain.node;
import com.agentsflex.agent.Agent;
import com.agentsflex.chain.Chain;
public class AgentInvoker implements Invoker {
public class AgentNode extends BaseNode {
private final Agent<?> agent;
private Condition condition;
public AgentInvoker(Agent<?> agent) {
public AgentNode(Agent<?> agent) {
this.agent = agent;
}
public AgentInvoker(Agent<?> agent, Condition condition) {
this.agent = agent;
this.condition = condition;
}
@Override
public boolean checkCondition(Object prevResult, Chain<?, ?> chain) {
return condition == null || condition.check(prevResult, chain);
}
@Override
public Object invoke(Object prevResult, Chain<?, ?> chain) {
public Object execute(Object prevResult, Chain<?, ?> chain) {
return agent.execute(prevResult, chain);
}
public Condition getCondition() {
return condition;
}
public void setCondition(Condition condition) {
this.condition = condition;
}
@Override
public Object getId() {
return agent.getId();
return this.id != null ? this.id : agent.getId();
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2022-2023, Agents-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.agentsflex.chain.node;
import com.agentsflex.chain.ChainNode;
public abstract class BaseNode implements ChainNode {
protected Object id;
protected boolean skip;
@Override
public Object getId() {
return id;
}
public void setId(Object id) {
this.id = id;
}
@Override
public boolean isSkip() {
return skip;
}
public void skip() {
this.skip = true;
}
}

View File

@ -13,20 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.agentsflex.chain;
package com.agentsflex.chain.node;
public interface Invoker {
import com.agentsflex.chain.Chain;
Condition getCondition();
public interface ELEngine {
void setCondition(Condition condition);
String run(String elContent, Object prevResult, Chain<?, ?> chain);
Object getId();
default boolean checkCondition(Object prevResult, Chain<?, ?> chain) {
Condition condition = getCondition();
return condition == null || condition.check(prevResult, chain);
}
Object invoke(Object prevResult, Chain<?, ?> chain);
}

View File

@ -13,13 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.agentsflex.chain;
package com.agentsflex.chain.node;
import com.agentsflex.agent.Agent;
import com.agentsflex.chain.Chain;
import com.agentsflex.chain.ChainNode;
public abstract class ELRouterChain<Input, Output> extends RouterChain<Input, Output> {
import java.util.List;
public class ELRouterNode extends RouterNode {
private String elContent;
private ELEngine elEngine;
public String getElContent() {
return elContent;
@ -29,21 +33,20 @@ public abstract class ELRouterChain<Input, Output> extends RouterChain<Input, Ou
this.elContent = elContent;
}
public ELRouterChain() {
public ELEngine getElEngine() {
return elEngine;
}
public ELRouterChain(Agent<?>... agents) {
super(agents);
public void setElEngine(ELEngine elEngine) {
this.elEngine = elEngine;
}
public ELRouterChain(Invoker... invokers) {
super(invokers);
public ELRouterNode(List<ChainNode> nodes) {
super(nodes);
}
@Override
protected String route() {
return runEl();
protected String route(Object prevResult, Chain<?, ?> chain) {
return elEngine.run(elContent, prevResult, chain);
}
protected abstract String runEl();
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2022-2023, Agents-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.agentsflex.chain.node;
import com.agentsflex.chain.Chain;
import com.agentsflex.chain.ChainNode;
import com.agentsflex.util.StringUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public abstract class RouterNode extends BaseNode {
private List<ChainNode> nodes;
public RouterNode(List<ChainNode> nodes) {
this.nodes = nodes;
}
@Override
public Object execute(Object prevResult, Chain<?, ?> chain) {
String result = route(prevResult, chain);
if (StringUtil.noText(result)) {
return null;
}
List<ChainNode> findNodes = new ArrayList<>();
String[] ids = result.split(",");
for (String id : ids) {
for (ChainNode invoker : this.nodes) {
if (Objects.equals(id, String.valueOf(invoker.getId()))) {
findNodes.add(invoker);
}
}
}
if (findNodes.isEmpty()) {
return null;
}
if (findNodes.size() == 1) {
ChainNode node = findNodes.get(0);
return node.execute(chain.getLastResult(), chain);
}
return onMatchMultiNodes(findNodes);
}
protected Object onMatchMultiNodes(List<ChainNode> nodes) {
//todo 支持自定义多匹配策略
throw new RuntimeException("Can not support match multi nodes");
}
protected abstract String route(Object prevResult, Chain<?, ?> chain);
}

View File

@ -15,9 +15,9 @@
*/
package com.agentsflex.core.test;
import com.agentsflex.chain.AgentInvoker;
import com.agentsflex.chain.Chain;
import com.agentsflex.chain.SequentialChain;
import com.agentsflex.chain.node.AgentNode;
import org.junit.Test;
public class ChainTest {
@ -44,7 +44,7 @@ public class ChainTest {
SimpleAgent2 agent22 = new SimpleAgent2();
Chain<String, String> chain2 = new SequentialChain<>(new AgentInvoker(agent22), chain1);
Chain<String, String> chain2 = new SequentialChain<>(new AgentNode(agent22), chain1);
String execute = chain2.execute("xxx");

View File

@ -91,12 +91,11 @@ public void testChain() {
![](../../assets/images/chians-01.png)
数据流向: agent3 --> agent4 --> chain1而 chain1 内部又包含 agent1 --> agent2 的过程,
在 Agents-Flex 中,我们内置了 4 种不同的 Agents 执行链,他们分别是:
在 Agents-Flex 中,我们内置了 3 种不同的 Agents 执行链,他们分别是:
- SequentialChain顺序执行链
- ParallelChain并发并行执行链
- LoopChain循环执行连
- RouterChain路由执行链
而以上 4 种执行链中,每个又可以作为其他执行链的子链进行执行,从而形成强大而复杂的 Agents 执行链条。
而以上 3 种执行链中,每个又可以作为其他执行链的子链进行执行,从而形成强大而复杂的 Agents 执行链条。