Giter VIP home page Giter VIP logo

spring-ai's People

Contributors

adambchouti avatar anush008 avatar eddumelendez avatar habuma avatar hemeda3 avatar hyune-c avatar iamsagar44 avatar izeye avatar jexp avatar jm-lab avatar joshlong avatar jtsnr avatar jvalkeal avatar jxblum avatar kirbstomper avatar mackey0225 avatar making avatar markpollack avatar meistermeier avatar mkheck avatar nd-bichri avatar ogzugru avatar omkar-shetkar avatar pablosanchi avatar ricken07 avatar siddharthshankarpaul avatar thomasvitale avatar tzolov avatar youngmoneee avatar zucchivan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spring-ai's Issues

Improve Ollama IT by caching the image with model

Hi,

I have an improvement for OllamaAutoConfigurationIT which can help when working locally. The current issue as described in the test is the model is around 3GB which can take quite a while depending on internet speed.

My approach using the Testcontainers lifecycle:
First test execution

  1. Pull image from registry
  2. Start container
  3. Once the container has started, pull the model
  4. Test execution
  5. When test is finishing, commit the changes in the container and create a local image.
  6. Stop container, stop test

Second test execution

  1. Start container using the local image that already contains the model
  2. Test execution
  3. Stop container, stop test

If there is interest on this, I can provide the PR.

Create GenerativeTextTemplate that streamlines usage of AiClient, Prompts, and OutputParsers

There is an analogy to make between GenerationTemplate and JdbcTemplate that will help simplify the use of the lower level classes such as AiClient, Prompts, and OutputParsers. Note: AiClient should likely be renamed GenerationClient as it is focused on generation, specifcally text, so perhaps even TextGenerationClient as we haven't yet experimented with multi-modal apis.

DataSource <-> AiClient

String Query with placeholdres <-> Prompt with placeholders

RowMapper <-> OutputParser

The simplest method (which is a default method in AiClient) is string input and string output, that could be removed from the AiClient interface and used in GenerateTemplate instead. Here are a few sample signatures for consideration.

public interface GenerateOperations {

	String generate(String message);

	String generate(String message, Map<String, Object> model)

	String generate(PromptTemplate promptTemplate, Map<String, Object> model);
	
	<T> T generate(String message, Class<T> elementType, Map<String, Object> model);

	<T> T generate(String message, OutputParser<T> parser, Map<String, Object> model);

	<T> List<T> generateList(String message, Class<T> elementType, Map<String, Object> model);

	<T> List<T> generateList(String message, OutputParser<T> parser, Map<String, Object> model);

        AiResponse generateResponse(PromptTemplate promptTemplate, Map<String, Object> model);
}

Example usage

ActorsFilms actorsFilms = generateTemplate.generate("Generate the filmography for the actor {actor}",
 		                                    ActorsFilms.class, Map.of("actor", "Tom Hanks"));

Simple "chains" for flows can be done with standard Java functional programming, and we can see how our needs for a "chain" or a "flow" evolve over time. e.g. the example of a chain from langchain using functional programming

	@Test
	void functionalChains() {
		Function<String, String> combinedFunction = generateSynopsis.andThen(generateReview);
		System.out.println(combinedFunction.apply("Tragedy at sunset on the beach"));
	}

	private Function<String, String> generateSynopsis = title -> {
		String synopsisInput = """
				You are a playwright. Given the title of play, it is your job to write a synopsis for that title.

				Title: {title}
				Playwright: This is a synopsis for the above play:""";

		return generateTemplate.generate(synopsisInput, Map.of("title", title));
	};

	private Function<String, String> generateReview = synopsis -> {
		String synopsisInput = """
				You are a play critic from the New York Times. Given the synopsis of play, it is your job to write a review for that play.

				Play Synopsis:
				{synopsis}
				Review from a New York Times play critic of the above play:""";

		return generateTemplate.generate(synopsisInput, Map.of("synopsis", synopsis));
	};

Vector Store similarity search with metadata filters.

Most of the vector store implementations provide, usually proprietary, capabilities for embedding search with metadata filters.

  • Pinecone offers filtering with metadata using custom (Mongo inspired) query language. The PineconeVectorStore implementation maps the document metadata to the native Pinecone json metadata format.
  • PostgresSQL's JSONB column allows JsonPath filter expressions (e.g. @@). The PgVectorSore implementation uses jsonb column to store the document's metadata and can leverage this functionality.
  • Neo4J ?
  • Milvus ?

Ref:
[1] https://www.pinecone.io/learn/vector-search-filtering/

Add invocation retry capabilities for AiClient, EmbeddingClient and VectorStore

The AiClient, EmbeddingClient or VectorStore clients interaction with their remote service endpoints could suffer from transient errors such as a momentary network glitch or rate limitation errors.
Often, those communication issues are resolvable by repetitive service invocation or altering the invocation rate.

We should provide a retry-decorators that automatically re-invoke the failed operations according to pre-configured retry policies.

Simplify the VectorStore#similaritySearch signature

Currently the VectorStore interface offers at least 5 variations of the similaritySearch() method, each with different set of arguments.

We should collapse all methods into a single similaritySearch(SearchRequest req) using a convenient SearchRequest builder like:

vectorStore.similaritySearch(
    SearchRequest.query("Hello World")
	.withTopK(5)
	.withSimilarityThreshold(0.6)
	.withFilterExpression("country == 'UK"));

Support AWS Bedrock

Please do a quick search on Github issues first, the feature you are about to request might have already been requested.

Expected Behavior
It would be nice to add support for AWS Bedrock.

Current Behavior
No support yet
Context
In general AWS Bedrock will probably be relevant since a lot of people are on AWS and will probably not migrate everything over.

I could pitch in time to make it happen.
As a first pitch I would probably start with inference

Add docs and examples for spring-ai-test

The spring-ai-test is meant to help evaluating generative responses using the the LLM itself.
But is it stands at the moment it is not obvious how to make use of it.

Review Message interface

There is a method String getMessageTypeValue(); which is not needed. This was used in the implementation of the Microsoft ACME fitness store and is no longer needed.

Consider making the interface generic, interface Message<T> { T getContent(); ... } A quick spike using Whisper or DallE etc would show if this class is usable in the context of other types of content.

Also review if there is a need for Map<String, Object> getProperties(); It doesn't seem necessary and is likely just a hold over from the initial work to create the org.springframework.ai.prompt.messages when modifying the langhchain design.

Also review the naming of MessageType - perhaps Role is more succinct.

Add Redis as a Vector Store

Current Version of the Spring AI allows InMemoryVectorStore but RedisVectorStore is expected along with.

Expected Behavior

Redis should be able to use as VectorStore

Current Behavior

InMemoryVectorStore is supported.

Context

I am working on document querying use-case with azure openai embedding stored in Redis. So i request the team to implement Redis as Vector Store

Consider moving `AiResponse` and `Generation` to a separate package from `AiClient`

The AiResponse and Generation types are fairly common across different AI providers, AFAICT. Although, where we refer to what the AI returns as a Generation, others refer to this as a Completion, or based on use, a Choice.

Regardless, like Prompt, I think that AiResponse and Generation warrant their own top-level package, such as org.springframework.ai.generation, or org.springframework.ai.response.

Food for thought.

Remove use of Supplier/Consumer in org.springframework.ai.document and replace with Function

The use of Supplier/Consumer was found to be limiting in a few scenarios. In the case of loading documents from a Resource, the use of a Supplier made the class stateful, meaning a new class instance was needed per Resource. Instead using a Functional interface so that the Resource is the input makes it easier to process many files.

So move from

interface DocumentReader extends Supplier<List<Document>>

to

interface DocumentReader<I> extends Function<I, List<Document>>

and have an implementation that takes a Spring Resource as input:

public class ResourceNewDocumentReader implements NewDocumentReader<Resource> {
    @Override
    public List<Document> apply(Resource resource) {
        ...
    }
}

The case of consumer is a bit less clear, perhaps the current DocumentWriter can still exist, but we could have our current implementations that write to the vector store implement DocumentTransformer so that if we wanted to chain together writin to multiple vector stores, the output from one could be changed to another. Maybe DocumentProcessor would be better then instead of DocumentTransformer

Using Void in a function instead of consumer is also an option, though it looks a little odd now that I write it out.

public interface DocumentWriter extends Consumer<List<Document>>

to

public interface DocumentCreator<O> extends Function<List<Document>, O> {

}

and

public class DocumentWriter implements DocumentCreator<Void>{
    @Override
    public Void apply(List<Document> documents) {
        return null;
    }
}

多个starter同时引用,出现问题,没有设置实例化优先级

Please do a quick search on Github issues first, there might be already a duplicate issue for the one you are about to create.
If the bug is trivial, just go ahead and create the issue. Otherwise, please take a few moments and fill in the following sections:

Bug description
image

Environment
Please provide as many details as possible: Spring AI version, Java version, which vector store you use if any, etc

Steps to reproduce
Steps to reproduce the issue.

Expected behavior
A clear and concise description of what you expected to happen.

Minimal Complete Reproducible example
Please provide a failing test or a minimal complete verifiable example that reproduces the issue.
Bug reports that are reproducible will take priority in resolution over reports that are not reproducible.

Add Azure Cognitive Search as a Vector Store

Azure Cognitive Search provides value add capabilities to users of Azure. In addition to supporting easy document upload and
indexing, indexes that are configured with Vector storage could be integrated and consumed via a VectorStore implementation in Spring AI.

Expected Behavior

Azure Cognitive Search supports a Java search API for uploading, deleting, and searching documents using vector based queries and storage. This API could be wrapped in a Spring AI Vector Store implementation giving Spring AI and Azure users the ability to integrate their existing Cognitive Search indexes with Spring AI.

Conceptually, a user would create a SearchClient instance using existing methods and inject the instance along with an EmbeddingClient into a VectorStore implementation. Using bean creation methods and a PropertiesSource class, the VectorStore creation could look like the following

@Bean
public SearchClient searchClient(AzureSearchClientProperties props) {

	return new SearchClientBuilder().endpoint(props.getEndpoint())
		.credential(new AzureKeyCredential(props.getApiKey()))
		.indexName(props.getIndex())
		.buildClient();
}

@Bean
public VectorStore vectorStore(SearchClient searchClient, EmbeddingClient embeddingClient) {
	return new AzureCognitiveSearchVectorStore(searchClient, embeddingClient);
}

Current Behavior

Spring AI currently does not support Azure Cognitive Search as a VectorStore implementation.

Context

An Azure Spring sample project currently exists that
implements a Cognitive Search based VectorStore. In addition, the Microsoft AI learning pages also demonstrate sample code
that utilizes existing documents already uploaded and indexed into CognitiveSearch. It would be desirable for Spring AI to integrate with Azure Cognitive Search as another VectorStore implementation.

Add Neo4j as a Vector Store

Current Version of the Spring AI allows InMemoryVectorStore but Neo4jVectorStore is expected along with it.

Expected Behavior

Neo4j should be able to use as VectorStore

Current Behavior

InMemoryVectorStore is supported.

Context

I am working on content writer suggestions use-case with azure openai embedding stored in Neo4j. So i request the team to implement Neo4j as Vector Store

Handle functions as an agent

Expected Behavior

I want to be able to provide Spring AI with one or more functions that could be used to provide additional information or functionality. (See https://platform.openai.com/docs/guides/gpt/function-calling). Moreover, when the response to a prompt indicates that a function should be called, I'd like it if that decision, the call to the function, and the reissuing of a new prompt were all handled internally by Spring AI. This behavior is what I believe is commonly referred to as an "agent".

In short, I'd like to be able to configure Spring AI with one or more functions (perhaps as lambdas or method references) that could be used later. Then, if I ask a question that the LLM needs more information to answer, Spring AI would call those functions for me and resubmit the prompt. I don't want to have to do what is shown as "step 2" in the example at https://platform.openai.com/docs/guides/gpt/function-calling. That decision making should be handled internally by Spring AI.

My primary desire is to have function support, but almost as importantly, I want to not have to deal with the back and forth interactions in my own code. I want Spring AI to handle that internally.

Current Behavior

Spring AI does not yet support functions, so at this point there's no need for agent behavior. Currently Spring AI only handles one-turn Q&A type interactions.

Context

As an example (drawn from the aforementioned documentation), if I were to ask what the weather is in Boston, most/all LLMs wouldn't know that answer because they're not trained on real-time or even relatively current data. But if I provide a function that can lookup the weather in a city, then instead of the LLM responding that it doesn't know what the weather is, it could respond with an instruction to call the function. The application (or the agent on behalf of the application) would call that function as instructed, then submit a new prompt with weather data from which the LLM would be able to generate the desired answer.

Paragraph Pdf Document Reader issue

Bug description
ParagraphPdfDocumentReader causing NullPointerException when reading sample1.pdf
https://github.com/spring-projects-experimental/spring-ai/blob/main/document-readers/pdf-reader/src/test/resources/sample1.pdf

Environment
Spring Boot version: 3.1.4
Spring AI version: 0.7.0-SNAPSHOT
Java version: openjdk version "17.0.2" 2022-01-18

Steps to reproduce
Add dependency spring-ai-pdf-document-reader: 0.7.0-SNAPSHOT version to pom.xml

`

    <dependency>
     <groupId>org.springframework.experimental.ai</groupId>
     <artifactId>spring-ai-pdf-document-reader</artifactId>
     <version>0.7.0-SNAPSHOT</version>
   </dependency>

`

Code to read paragraphs:
`

    var documents = pdfReader.get();

   ParagraphPdfDocumentReader pdfReader = new ParagraphPdfDocumentReader(
            "file:\\C:\\Users\\test\\sample1.pdf",
            PdfDocumentReaderConfig.builder()
                    .build());

    var documents = pdfReader.get();

    for (Document document : documents) {
        System.out.println(document.getContent());
    }

`

Expected behavior
It should read each paragraph from the sample1.pdf file

Exception
`

  java.lang.NullPointerException: Cannot invoke "org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineNode.getFirstChild()" because "bookmark" is null
at org.springframework.ai.reader.pdf.config.ParagraphManager.generateParagraphs(ParagraphManager.java:131) ~[spring-ai-pdf-document-reader-0.7.0-20231019.142632-5.jar:0.7.0-SNAPSHOT]
at org.springframework.ai.reader.pdf.config.ParagraphManager.<init>(ParagraphManager.java:82) ~[spring-ai-pdf-document-reader-0.7.0-20231019.142632-5.jar:0.7.0-SNAPSHOT]
at org.springframework.ai.reader.pdf.ParagraphPdfDocumentReader.<init>(ParagraphPdfDocumentReader.java:109) ~[spring-ai-pdf-document-reader-0.7.0-20231019.142632-5.jar:0.7.0-SNAPSHOT]
at org.springframework.ai.reader.pdf.ParagraphPdfDocumentReader.<init>(ParagraphPdfDocumentReader.java:92) ~[spring-ai-pdf-document-reader-0.7.0-20231019.142632-5.jar:0.7.0-SNAPSHOT]

`

Tidy up project directory structure

The generative AI client implementations are modules sitting at the top of the project, e.g. spring-ai-ollama. Create a directory, generative-clients and put the various client modules in that directory

Add Chroma Vector Store integration

Chroma is a popular open-source embedding database. It gives you the tools to store document embeddings, content and metadata and to search through those embeddings including metadata filtering.

Improve the Document API

  • Currently the Document mixes multiple concerns that should be isolated in dedicated classes.
  • Encapsulate the content formatting into a separate ContentFormatter abstraction.
  • Refactoring the document loading and indexing strategy.
  • Moves toward ETL processing model.
  • Add metadata enriching transformers as DocumentTranformer.

Remove chain package

The chain idea from langchain involves 'workflow' and often type unsafe access to input and output. Instead of following down that path, first extract the key helper classes that are needed for use cases and later revisit how they can be composed into a chain/flow. There is some example usage of 'chaining' based on langchain's example using java.util.Function in #108

Helper classes envisioned are GenerationTemplate (similar to LLMChain) and ChatEngine (similar to conversationalchain)

Review package org.springframework.ai.client

The current implementation is focused on text/code based GenerativeAI use cases as input and output. The name AiClient, is likely too broad. There isn't yet a ton of experience with multi-modal language models and such a generic name might be better suited in that use case.

Consider to rename AiClient. Here are some things to consider.

  • There is friction with Java naming conventions and standard use of the abbreviation AI.
  • Consider renaming AiClient to GenerativeClient and perhaps the package name to org.sf.ai.client.generative
  • Consider making Generation an interface with a generic type.

Parent Document Retriever feature.

Expected Behavior

Lanchain's Parent Document Retriever feature is expected in Spring AI

Current Behavior
Files are chunked and cretead embeddings for them. We would like to have child chunks for parent chunks of the document.

AI client library

Apologies for creating an issue to only ask a question, but I don't see the discussions enabled for this repository.

Why don't you use Azure client library instead of theokanning client? Did you consider it?

It provides sync and async clients. And it's very easy to switch from Azure API to Open AI API

Investigate Documents Used for VectorDB testing

I just noticed when writing the README for the Neo4j store that the sentence in the PgVector store is a little bit vague.
Yes, it's true that the document will be there but it is either to expect that it is the first in the collection or we should set the "top-k amount" to 1 in the example snippet, or?

https://github.com/spring-projects-experimental/spring-ai/blob/0a584f0dc2483ef9ad0741c8598998e489b64726/vector-stores/spring-ai-pgvector-store/README.md?plain=1#L141-L145

A little bit tweaked in the Neo4j store README:
https://github.com/spring-projects-experimental/spring-ai/blob/0a584f0dc2483ef9ad0741c8598998e489b64726/vector-stores/spring-ai-neo4j-store/README.md?plain=1#L114-L118

Add Auto-Configurations and Boot starters for all Vector Store implementations

Most Spring-ai vector store implementations already have a proper boot auto-configurations in place.
Create the corresponding Spring Boot Starters under the spring-ai-spring-boot-starters and update the VectorStore's README.md with both starter usage instructions.

Change `AzureOpenAiEmbeddingOptions` and `AzureOpenAiChatOptions` use of `setModel` to `setDeployentName` as that matches Azure OpenAI terminology.

Bug description
spring-ai-azure-openai-spring-boot-starter reports issue about DeploymentNotFound ( it requires Azure model deployment name)
with properties included
spring.ai.azure.openai.api-key= spring.ai.azure.openai.endpoint=https://abc.openai.azure.com/ spring.ai.azure.openai.embedding-model=text-embedding-ada-002

com.azure.core.exception.ResourceNotFoundException: Status code 404, "{"error":{"code":"DeploymentNotFound", "message":"The API deployment for this resource does not exist. If you created the deployment within the last 5 minutes, please wait a moment and try again."}}" at com.azure.core.implementation.http.rest.RestProxyBase.instantiateUnexpectedException(RestProxyBase.java:347) ~[azure-core-1.41.0.jar:1.41.0] at com.azure.core.implementation.http.rest.SyncRestProxy.ensureExpectedStatus(SyncRestProxy.java:130) ~[azure-core-1.41.0.jar:1.41.0] at com.azure.core.implementation.http.rest.SyncRestProxy.handleRestReturnType(SyncRestProxy.java:213) ~[azure-core-1.41.0.jar:1.41.0] at com.azure.core.implementation.http.rest.SyncRestProxy.invoke(SyncRestProxy.java:81) ~[azure-core-1.41.0.jar:1.41.0] at com.azure.core.implementation.http.rest.RestProxyBase.invoke(RestProxyBase.java:109) ~[azure-core-1.41.0.jar:1.41.0] at com.azure.core.http.rest.RestProxy.invoke(RestProxy.java:91) ~[azure-core-1.41.0.jar:1.41.0] at jdk.proxy2/jdk.proxy2.$Proxy75.getChatCompletionsSync(Unknown Source) ~[na:na] at com.azure.ai.openai.implementation.OpenAIClientImpl.getChatCompletionsWithResponse(OpenAIClientImpl.java:897) ~[azure-ai-openai-1.0.0-beta.3.jar:1.0.0-beta.3] at com.azure.ai.openai.OpenAIClient.getChatCompletionsWithResponse(OpenAIClient.java:294) ~[azure-ai-openai-1.0.0-beta.3.jar:1.0.0-beta.3] at com.azure.ai.openai.OpenAIClient.getChatCompletions(OpenAIClient.java:430) ~[azure-ai-openai-1.0.0-beta.3.jar:1.0.0-beta.3] at org.springframework.ai.azure.openai.client.AzureOpenAiClient.generate(AzureOpenAiClient.java:60) ~[spring-ai-azure-openai-0.2.0-20230908.193706-31.jar:0.2.0-SNAPSHOT] at org.springframework.ai.openai.samples.helloworld.simple.SimpleAiController.completion(SimpleAiController.java:21) ~[classes/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-6.0.11.jar:6.0.11] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-6.0.11.jar:6.0.11] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) ~[spring-webmvc-6.0.11.jar:6.0.11] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) ~[spring-webmvc-6.0.11.jar:6.0.11] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-6.0.11.jar:6.0.11] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-6.0.11.jar:6.0.11] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081) ~[spring-webmvc-6.0.11.jar:6.0.11] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974) ~[spring-webmvc-6.0.11.jar:6.0.11] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011) ~[spring-webmvc-6.0.11.jar:6.0.11] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) ~[spring-webmvc-6.0.11.jar:6.0.11] at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) ~[tomcat-embed-core-10.1.11.jar:6.0] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.0.11.jar:6.0.11] at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-10.1.11.jar:6.0] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-10.1.11.jar:10.1.11] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.0.11.jar:6.0.11] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.11.jar:6.0.11] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.0.11.jar:6.0.11] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.11.jar:6.0.11] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:109) ~[spring-web-6.0.11.jar:6.0.11] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.11.jar:6.0.11] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.0.11.jar:6.0.11] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.11.jar:6.0.11] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:166) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1740) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-10.1.11.jar:10.1.11] at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]

Environment
spring-ai-azure-openai-spring-boot-starter : 0.2.0-SNAPSHOT
spring boot: 3.1.2

Steps to reproduce
Just run the application and access the endpoint /ai/sample

Expected behavior
It has to connect to Azure OpenAI and get the response.

Minimal Complete Reproducible example
https://github.com/rd-1-2022/ai-azure-openai-helloworld.git

Stream support in `AiClient`

Context

Applications using AI often use a UI that generates text little by little in a stream instead of outputting texts all at once. The current spring-ai AiClient does not support stream output.

Expected Behavior

I hope that generateStream method will be added to AiClient. As for the return value, Flux<AiResponse> is promising, but if you want to avoid dependence on reactor, you can also consider the JDK standard Flow.Publisher<AiResponse>.

For example, openai-java used in OpenAiClient uses Flowable. This can be converted to Flux or Flow.Publisher.

https://github.com/TheoKanning/openai-java/blob/650d76b87a3246a52247b231f8d47f994ae63020/service/src/main/java/com/theokanning/openai/service/OpenAiService.java#L150

This is a little off topic, but openai-java uses outdated RxJava2 and has an unnecessary number of dependencies (e.g. kotlin sdk). Since spring-ai does not use all OpenAI APIs, I think it is better to have an in-house OpenAI client that implements only the minimum API with WebClient that supports the streaming.

Avoid duplicated entries in VectorStore(s) by allowing generation of Document ID based on the hashed document content.

Currently the Document if not provided with an explicit ID, generates a random UUID for every document.
Even if the document content/metadata haven't changed a new ID is generated every time.
This will lead to document content duplications in the Vector store.

To prevent this type of unnecessary duplications we can allow generation of Document ID based on the hashed document content+metadata.

Following snippet is inspired by a langchain4j vector store implementations.

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

....

public static String generateIdFrom(String contentWithMetadata) {
    try {
	    byte[] hashBytes = MessageDigest.getInstance("SHA-256").digest(contentWithMetadata.getBytes(StandardCharsets.UTF_8));
	    StringBuilder sb = new StringBuilder();
	    for (byte b : hashBytes) {
		    sb.append(String.format("%02x", b));
	    }
	    return UUID.nameUUIDFromBytes(sb.toString().getBytes(StandardCharsets.UTF_8)).toString();
    }
    catch (NoSuchAlgorithmException e) {
	    throw new IllegalArgumentException(e);
    }
}

Create a ChatEngine helper class

This would be akin to llamindex chatengine as well as what was done in canopy from pinecone.

This is the alternative to following the design in langchain which adds on workflow/chain elements that at the moment is too premature (in my mind) to delve into and can be added later. Functional programming chain in Java can also be useful in this context, will wait and see how it evolved.

Provide prompt options on a call by call basis

Our local OpenAI endpoint has a very small default max_tokens against the chat completion.
We like to make it adjustable

Expected Behavior

Hoping this code.

https://github.com/spring-projects-experimental/spring-ai/blob/main/spring-ai-openai/src/main/java/org/springframework/ai/openai/client/OpenAiClient.java

Looks something like this

	private ChatCompletionRequest getChatCompletionRequest(String text) {
		List<ChatMessage> chatMessages = List.of(new ChatMessage("user", text));
		logger.trace("ChatMessages: ", chatMessages);
		ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
			.model(this.model)
			.temperature(this.temperature)
			.messages(List.of(new ChatMessage("user", text)))
                         .maxTokens(4000) /// ADD HERE
 			.build();
		logger.trace("ChatCompletionRequest: ", chatCompletionRequest);
		return chatCompletionRequest;
	}

Current Behavior

max tokens not adjustable

Context

PromptTemplate can't be reused with different model data

This was tested with Spring AI 0.7.0-SNAPSHOT.

Once a PromptTemplate has been created without model data and then used once via the render() method that takes model data, it cannot be reused with different model data. Attempting to do so will result in a prompt that contains the original model data. For example, I would expect the following test to pass. But it does not as described in the comments.

    @Test
    public void testPromptTemplate() {
        PromptTemplate pt = new PromptTemplate("Here is the input: {input}");

        String output1 = pt.render(Map.of("input", "Hello, world!"));
        Assertions.assertThat(output1).isEqualTo("Here is the input: Hello, world!");

        String output2 = pt.render(Map.of("input", "Goodbye, world!"));
        // This next assertion fails!!!
        // The rendered output is the "Hello world" from the first time!!!
        Assertions.assertThat(output2).isEqualTo("Here is the input: Goodbye, world!");
    }

This is appears to be because of the if statement at https://github.com/spring-projects-experimental/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/prompt/PromptTemplate.java#L141 that prevents new model data from being given to the ST instance unless that key is null.

Note that I've tested the same thing with both the Python and Node.js implementations of PromptTemplate from Langchain and they both work as I'd expect. That is, the PromptTemplate can be reused with new model data. For the sake of clarity, here's what I did in Python:

from langchain.prompts import PromptTemplate

prompt_template = PromptTemplate.from_template(
    "Here is the input: {input}"
)

output1 = prompt_template.format(input="Hello, world!")
print(output1)
# Here is the input: Hello, world!

output2 = prompt_template.format(input="Goodbye, world!")
print(output2)
# Here is the input: Goodbye, world!

And here is what I did in Node.js:

import { PromptTemplate } from "langchain/prompts";

const pt = PromptTemplate.fromTemplate('Here is the input: {input}');

const output1 = await pt.format({input: "Hello, world!"});
console.log(output1);
// Here is the input: Hello, world!

const output2 = await pt.format({input: "Goodbye, world!"});
console.log(output2);
// Here is the input: Goodbye, world!

In both cases, the result was (as expected):

Here is the input: Hello, world!
Here is the input: Goodbye, world!

I'd expect Spring AI's PromptTemplate to be reusable in the same way.

Retrieve embedding model dimensions

Expected Behavior

The EmbeddingClient interface should expose a method to report the dimension size of the configured embedding model.

Current Behavior

Currently the users must retrieve this information manually from the documentations of the used models.

Context

The dimensions are need to configure VectorStores and at the moment has to be specified explicitly.
Instead they could obtain this information directly from the provided EmbeddingClient instance.

Excuse me, can you support the proxy mode of openAI-java later?

Please do a quick search on Github issues first, the feature you are about to request might have already been requested.

Expected Behavior

I now want to use vpn to access gpt. However, it seems that we do not have this entrance yet. We hope that we can support a method similar to openAI-java sdk in the future.

Current Behavior

DocumentReader for all kinds of documents

Current Version of the Spring AI allows JsonReader and TextReader.

Expected Behavior

More DocumentReader implementations should allow reading all kinds documents (PDF, word, html, ...)

Current Behavior

DocumentReader is implemented only for Json and Text content types.

Context

I am working on document querying use-case with azure openai to load all the documents and create embeddings to store them in Redis. So i request the team to implement DocumentLoader.

Embedding clients in different maven modules share the same package name, this needs to change

For example, the module spring-ai-postgresml-embedding-client has the class PostgresMEmbeddingClient in the package org.springframework.ai.embedding and transformers-embedding module has TransformersEmbeddingClient in the same package org.springframework.ai.embedding

When making this change, create a more specific name for the transformers-embedding perhaps onnx-embedding-client?

Also, there is a convention of having the artifact contain the prefix spring-ai. The Postgres embedding clients doesn't follow this convention.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.