Remove chain package. Fixes #109
This commit is contained in:
25
README.md
25
README.md
@@ -232,31 +232,6 @@ Though the `DocumentWriter` interface isn't exclusively for Vector Database writ
|
||||
They ascertain which document sections the AI should use for generating responses.
|
||||
Examples of Vector Databases include Chroma, Postgres, Pinecone, Weaviate, Mongo Atlas, and Redis. Spring AI's `VectorStore` abstraction permits effortless transitions between database implementations.
|
||||
|
||||
### Chaining together multiple AI model interactions
|
||||
|
||||
**Chains:** Many AI solutions require multiple AI interactions to respond to a single user input.
|
||||
"Chains" organize these interactions, offering modular AI workflows that promote reusability.
|
||||
While you can create custom Chains tailored to your specific use case, pre-configured use-case-specific Chains are provided to accelerate your development.
|
||||
Use cases such as Question-Answering, Text Generation, and Summarization are examples.
|
||||
|
||||
* This is currently a work in progress.
|
||||
|
||||
### Memory
|
||||
|
||||
**Memory:** To support multiple AI model interactions, your application must recall the previous inputs and outputs.
|
||||
A variety of algorithms are available for different scenarios, often backed by databases like Redis, Cassandra, MongoDB, Postgres, and other database technologies.
|
||||
|
||||
* This is currently a work in progress
|
||||
|
||||
### Agents
|
||||
|
||||
Beyond Chains, Agents represent the next level of sophistication.
|
||||
Agents use the AI models themselves to determine the techniques and steps to respond to a user's query.
|
||||
Agents might even dynamically access external data sources to retrieve information necessary for responding to a user.
|
||||
It's getting a bit funky, isn't it?
|
||||
|
||||
* This is currently a work in progress
|
||||
|
||||
## Building
|
||||
|
||||
To build with only unit tests
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
package org.springframework.ai.chain;
|
||||
|
||||
import org.springframework.ai.memory.Memory;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public abstract class AbstractChain implements Chain {
|
||||
|
||||
private Optional<Memory> memory = Optional.empty();
|
||||
|
||||
public Optional<Memory> getMemory() {
|
||||
return this.memory;
|
||||
}
|
||||
|
||||
public void setMemory(Memory memory) {
|
||||
Objects.requireNonNull(memory, "Memory can not be null.");
|
||||
this.memory = Optional.of(memory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract List<String> getInputKeys();
|
||||
|
||||
@Override
|
||||
public abstract List<String> getOutputKeys();
|
||||
|
||||
// TODO validation of input/outputs
|
||||
|
||||
@Override
|
||||
public AiOutput apply(AiInput aiInput) {
|
||||
AiInput aiInputToUse = preProcess(aiInput);
|
||||
AiOutput aiOutput = doApply(aiInputToUse);
|
||||
Map<String, Object> outputMapToUse = postProcess(aiInput, aiOutput);
|
||||
return new AiOutput(outputMapToUse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiInput preProcess(AiInput aiInput) {
|
||||
validateInputs(aiInput.getInputData());
|
||||
return aiInput;
|
||||
}
|
||||
|
||||
protected abstract AiOutput doApply(AiInput aiInput);
|
||||
|
||||
@Override
|
||||
public Map<String, Object> postProcess(AiInput aiInput, AiOutput aiOutput) {
|
||||
validateOutputs(aiOutput.getOutputData());
|
||||
Map<String, Object> combindedMap = new HashMap<>();
|
||||
combindedMap.putAll(aiInput.getInputData());
|
||||
combindedMap.putAll(aiOutput.getOutputData());
|
||||
return combindedMap;
|
||||
}
|
||||
|
||||
protected void validateOutputs(Map<String, Object> outputMap) {
|
||||
Set<String> missingKeys = new HashSet<>(getOutputKeys());
|
||||
missingKeys.removeAll(outputMap.keySet());
|
||||
if (!missingKeys.isEmpty()) {
|
||||
throw new IllegalArgumentException("Missing some output keys: " + missingKeys);
|
||||
}
|
||||
}
|
||||
|
||||
protected void validateInputs(Map<String, Object> inputMap) {
|
||||
Set<String> missingKeys = new HashSet<>(getInputKeys());
|
||||
missingKeys.removeAll(inputMap.keySet());
|
||||
if (!missingKeys.isEmpty()) {
|
||||
throw new IllegalArgumentException("Missing some input keys: " + missingKeys);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package org.springframework.ai.chain;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class AiInput {
|
||||
|
||||
private Map<String, Object> inputData;
|
||||
|
||||
public AiInput(Map<String, Object> inputData) {
|
||||
this.inputData = inputData;
|
||||
}
|
||||
|
||||
Map<String, Object> getInputData() {
|
||||
return inputData;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package org.springframework.ai.chain;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class AiOutput {
|
||||
|
||||
private final Map<String, Object> outputData;
|
||||
|
||||
public AiOutput(Map<String, Object> outputData) {
|
||||
this.outputData = outputData;
|
||||
}
|
||||
|
||||
Map<String, Object> getOutputData() {
|
||||
return this.outputData;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package org.springframework.ai.chain;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface Chain extends Function<AiInput, AiOutput> {
|
||||
|
||||
List<String> getInputKeys();
|
||||
|
||||
List<String> getOutputKeys();
|
||||
|
||||
AiInput preProcess(AiInput aiInput);
|
||||
|
||||
Map<String, Object> postProcess(AiInput aiInput, AiOutput aiOutput);
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package org.springframework.ai.memory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface Memory {
|
||||
|
||||
/**
|
||||
* The keys that the memory will add to Chain inputs
|
||||
*/
|
||||
List<String> getKeys();
|
||||
|
||||
/**
|
||||
* Return key-value pairs given the text input to the chain
|
||||
* @param inputs input of the chain
|
||||
* @return key-value pairs from memory
|
||||
*/
|
||||
Map<String, Object> load(Map<String, Object> inputs);
|
||||
|
||||
void save(Map<String, Object> inputs, Map<String, Object> outputs);
|
||||
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package org.springframework.ai.chain;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ai.memory.Memory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||
|
||||
class ChainTests {
|
||||
|
||||
@Test
|
||||
void badInputs() {
|
||||
Chain chain = new FakeChain();
|
||||
AiInput aiInput = new AiInput(Map.of("foobar", "baz"));
|
||||
assertThatThrownBy(() -> chain.apply(aiInput)).isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("Missing some input keys");
|
||||
}
|
||||
|
||||
@Test
|
||||
void correctInputs() {
|
||||
Chain chain = new FakeChain();
|
||||
AiInput aiInput = new AiInput(Map.of("foo", "bar"));
|
||||
AiOutput aiOutput = chain.apply(aiInput);
|
||||
assertThat(aiOutput.getOutputData()).containsEntry("foo", "bar").containsEntry("bar", "baz");
|
||||
}
|
||||
|
||||
class FakeChain extends AbstractChain {
|
||||
|
||||
private boolean beCorrect = true;
|
||||
|
||||
private List<String> inputKeys = List.of("foo");
|
||||
|
||||
public FakeChain() {
|
||||
}
|
||||
|
||||
public FakeChain(boolean beCorrect) {
|
||||
this.beCorrect = beCorrect;
|
||||
}
|
||||
|
||||
public FakeChain(List<String> inputKeys) {
|
||||
this.inputKeys = inputKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getInputKeys() {
|
||||
return this.inputKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getOutputKeys() {
|
||||
return List.of("bar");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AiOutput doApply(AiInput aiInput) {
|
||||
if (beCorrect) {
|
||||
return new AiOutput(Map.of("bar", "baz"));
|
||||
}
|
||||
else {
|
||||
return new AiOutput(Map.of("baz", "bar"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FakeMemory implements Memory {
|
||||
|
||||
@Override
|
||||
public List<String> getKeys() {
|
||||
return List.of("baz");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> load(Map<String, Object> inputs) {
|
||||
return Map.of("baz", "foo");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(Map<String, Object> inputs, Map<String, Object> outputs) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -56,13 +56,6 @@ Output parsing employs meticulously crafted prompts, often necessitating multipl
|
||||
|
||||
This challenge has prompted OpenAI to introduce 'OpenAI Functions' as a means to specify the desired output format from the model precisely.
|
||||
|
||||
== Chaining Calls
|
||||
|
||||
A Chain is a concept that represents a series of calls to an AI model.
|
||||
It uses the output from one call as the input to another.
|
||||
|
||||
By chaining calls together, you can support complex use cases by composing pipelines of multiple chains.
|
||||
|
||||
== Customizing Models: Integrating Your Data
|
||||
|
||||
How can you equip the AI model with information it hasn't been trained on?
|
||||
|
||||
@@ -73,7 +73,6 @@ public class AcmeIT extends AbstractIT {
|
||||
|
||||
// Now user query
|
||||
|
||||
// This will be wrapped up in a chain
|
||||
VectorStoreRetriever vectorStoreRetriever = new VectorStoreRetriever(vectorStore);
|
||||
|
||||
logger.info("Retrieving relevant documents");
|
||||
|
||||
Reference in New Issue
Block a user