Refactored llm clients, removed maxContinuations feature, exposed finishReason instead;
This commit is contained in:
47
README.md
47
README.md
@@ -4,7 +4,7 @@ The purpose of this library is to provide a comprehensive conversational AI syst
|
||||
|
||||
The program's key features include:
|
||||
|
||||
* Agent graph execution
|
||||
* Agent graph execution (incl. template engine and branching capabilities)
|
||||
* Integration with external AI models and services (e.g., Azure AI and OpenAi Api compatible)
|
||||
* Model profiles (choose the right model and parameters for the task)
|
||||
* Conversation management and text completion with support for multiple prompt strategies and tokenization implementations
|
||||
@@ -143,40 +143,43 @@ Agentic flow: AgentTest#agenticFlow
|
||||
|
||||
# Announcement generated by AgentTest#agenticFlow
|
||||
|
||||
Title: Introducing a Powerful Framework for Building Intelligent Agents
|
||||
## Introducing Advanced Agent Orchestration: Dynamic Conversations & Parallel Processing
|
||||
|
||||
We're excited to announce the development of a new Java codebase designed to build intelligent agents capable of interacting with language models like GPT. This framework offers a flexible and extensible architecture, empowering developers to create sophisticated conversational agents for a wide range of applications.
|
||||
We're excited to announce significant enhancements to our agent framework, designed to empower developers building sophisticated conversational AI applications. This release introduces a powerful new system for orchestrating multiple agents, enabling more dynamic, efficient, and complex interactions.
|
||||
|
||||
**Key Features:**
|
||||
Here's a breakdown of what's new:
|
||||
|
||||
* **Concurrent Text Processing:** Leveraging Java's `CompletableFuture` and `ExecutorService`, the framework enables parallel processing of text chunks, significantly speeding up agent execution.
|
||||
**1. LLM Conversation Orchestration:**
|
||||
|
||||
* **Response-Driven Agent Selection:** The `chooseNextAgent` method intelligently selects the next agent in the chain based on the response received from the language model, allowing for dynamic and adaptive conversations.
|
||||
Our framework now provides a robust system for chaining multiple agents together. Each agent can perform a specific task, and the framework intelligently manages the flow of information between them, creating a pipeline for complex conversational workflows.
|
||||
|
||||
* **Customizable Response Handling:** Each agent can be equipped with a custom `responseHandler` to parse and interpret responses from the language model, enabling tailored logic for specific tasks.
|
||||
**2. Dynamic Prompt Templating with Branching:**
|
||||
|
||||
* **Dynamic Agent Chaining:** Agents can be chained together to create complex, multi-step interactions, with each agent specializing in a particular task and passing context to the next.
|
||||
Say goodbye to rigid prompts! Our new templating engine allows for dynamic prompt generation based on the context. Critically, it now supports *branching*. This means a single input can trigger multiple prompt variations, allowing agents to explore different avenues of conversation or processing paths based on data within the input.
|
||||
|
||||
* **Contextualized Agent Execution:** The framework utilizes an `AgentContext` object to store and share information between agents, ensuring each agent has access to the relevant context for its task.
|
||||
**3. Asynchronous Task Execution for Parallel Processing:**
|
||||
|
||||
**How it Works:**
|
||||
Speed and efficiency are key. We've implemented asynchronous task execution using `CompletableFuture` and an `ExecutorService`. This allows agents to process multiple inputs (splits) *in parallel*, significantly reducing overall processing time and improving responsiveness.
|
||||
|
||||
The framework revolves around the `Agent` class, which defines an agent's behavior and interaction with the language model. Each agent receives an `AgentContext` containing relevant information, processes text using its defined template, interacts with the language model, and then uses its `responseHandler` to interpret the response. Based on the response, the `chooseNextAgent` method determines the next agent in the chain.
|
||||
**4. Context Merging Across Multiple Agent Splits:**
|
||||
|
||||
**Benefits:**
|
||||
When branching occurs, the framework intelligently merges the results from different execution paths. This ensures a unified context is maintained, allowing subsequent agents to access a complete and consolidated view of the conversation or task.
|
||||
|
||||
This framework offers several advantages for developers:
|
||||
**5. Agent Chaining and Next Agent Selection:**
|
||||
|
||||
* **Flexibility:** Easily customize agent behavior through configurable parameters and custom response handlers.
|
||||
* **Extensibility:** Add new agent types and functionalities as needed.
|
||||
* **Efficiency:** Parallel processing and dynamic agent chaining optimize performance.
|
||||
* **Adaptability:** Agents can respond intelligently to changing conversation contexts.
|
||||
The framework dynamically determines the next agent to execute based on the current context. This allows for creating complex, stateful conversations where the flow adapts based on user input and agent responses. The system can also signal the end of the chain, indicating completion.
|
||||
|
||||
**Looking Ahead:**
|
||||
**What does this mean for you?**
|
||||
|
||||
We believe this framework has the potential to revolutionize the way we build conversational agents. We're actively developing new features and functionalities, and we encourage the community to contribute and explore the possibilities.
|
||||
These improvements unlock a new level of flexibility and power for building conversational AI applications. You can now:
|
||||
|
||||
Stay tuned for more updates and documentation!
|
||||
* Create more complex and nuanced conversational flows.
|
||||
* Handle a wider range of user inputs and scenarios.
|
||||
* Improve the performance and responsiveness of your agents.
|
||||
* Build more scalable and maintainable AI systems.
|
||||
|
||||
*Graph: M, CodeSummarizer, ↴, M, FeatureIdentifier, →, ⇉ 3/5, M, FeatureAnalyzer, →, 5↣1, M, AnswerGenerator*
|
||||
*gemma2-27b requests=8, inTokens=19646, outTokens=2784, requestDuration=PT7M38.309006603S, getAbsoluteDuration()=PT3M54.653718763S, getTps()=95.59, getOutTps()=11.86*
|
||||
We're confident that these advancements will significantly enhance your ability to build intelligent and engaging conversational experiences. Stay tuned for more updates and documentation!
|
||||
|
||||
*gemma3-12b-it-q5_k_m*
|
||||
*M, CodeSummarizer, ↴, M, FeatureIdentifier, →, ⇉ 1/5, M, FeatureAnalyzer, 5↣1, →, M, AnswerGenerator*
|
||||
*AgentRequestStatistic [requests=8, cachedPrompts=0, inTokens=27393, outTokens=4861, requestDuration=PT3M30.415881394S, getEffectiveDuration()=PT2M22.102597491S, getTps()=226.98, getOutTps()=34.21, getCost()=0]*
|
||||
|
||||
@@ -62,17 +62,17 @@ public final class AgentRequestStatistic {
|
||||
}
|
||||
|
||||
public void add(final Completion completion) {
|
||||
if (completion.cached()) {
|
||||
if (completion.statistics().cached()) {
|
||||
this.cachedPrompts.incrementAndGet();
|
||||
}
|
||||
else {
|
||||
this.getRequests().addAndGet(completion.requests());
|
||||
this.getRequests().addAndGet(completion.statistics().requests());
|
||||
}
|
||||
this.getInTokens().addAndGet(completion.inTokens());
|
||||
this.getOutTokens().addAndGet(completion.outTokens());
|
||||
this.getInTokens().addAndGet(completion.statistics().inTokens());
|
||||
this.getOutTokens().addAndGet(completion.statistics().outTokens());
|
||||
synchronized (this) {
|
||||
this.requestDuration = this.requestDuration.plus(completion.duration());
|
||||
this.cost = this.cost.add(completion.cost());
|
||||
this.requestDuration = this.requestDuration.plus(completion.statistics().duration());
|
||||
this.cost = this.cost.add(completion.statistics().cost());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package de.extio.lmlib.client;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Duration;
|
||||
|
||||
public final record Completion(String response, int requests, Duration duration, long inTokens, long outTokens, BigDecimal cost, boolean cached) {
|
||||
public final record Completion(String response, CompletionFinishReason finishReason, CompletionStatistics statistics) {
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package de.extio.lmlib.client;
|
||||
|
||||
public enum CompletionFinishReason {
|
||||
|
||||
/**
|
||||
* Regular completion
|
||||
*/
|
||||
DONE,
|
||||
|
||||
/**
|
||||
* Completion was stopped because the token limit was reached. You may continue the conversation.
|
||||
*/
|
||||
TOKEN_LIMIT_REACHED,
|
||||
|
||||
/**
|
||||
* Completion was stopped because the content was filtered.
|
||||
*/
|
||||
CONTENT_FILTERED
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.extio.lmlib.client;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Duration;
|
||||
|
||||
public record CompletionStatistics(int requests, Duration duration, long inTokens, long outTokens, BigDecimal cost, boolean cached) {
|
||||
|
||||
}
|
||||
@@ -13,14 +13,12 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.azure.ai.inference.ChatCompletionsClient;
|
||||
import com.azure.ai.inference.ChatCompletionsClientBuilder;
|
||||
import com.azure.ai.inference.models.ChatCompletions;
|
||||
import com.azure.ai.inference.models.ChatCompletionsOptions;
|
||||
import com.azure.ai.inference.models.ChatRequestAssistantMessage;
|
||||
import com.azure.ai.inference.models.ChatRequestMessage;
|
||||
@@ -35,6 +33,8 @@ import com.azure.core.http.policy.RetryOptions;
|
||||
|
||||
import de.extio.lmlib.client.Client;
|
||||
import de.extio.lmlib.client.Completion;
|
||||
import de.extio.lmlib.client.CompletionFinishReason;
|
||||
import de.extio.lmlib.client.CompletionStatistics;
|
||||
import de.extio.lmlib.client.Conversation;
|
||||
import de.extio.lmlib.client.Conversation.Turn;
|
||||
import de.extio.lmlib.profile.ModelCategory;
|
||||
@@ -42,7 +42,6 @@ import de.extio.lmlib.profile.ModelProfile;
|
||||
import de.extio.lmlib.profile.ModelProfile.ModelProvider;
|
||||
import de.extio.lmlib.profile.ModelProfileService;
|
||||
import de.extio.lmlib.token.Tokenizer;
|
||||
|
||||
import okhttp3.Authenticator;
|
||||
import okhttp3.Challenge;
|
||||
import okhttp3.Credentials;
|
||||
@@ -56,6 +55,7 @@ public final class AzureAiClient implements Client {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AzureAiClient.class);
|
||||
|
||||
private static final int TIMEOUT = 300000;
|
||||
|
||||
private static final int CONNECT_TIMEOUT = 10000;
|
||||
|
||||
private final ConcurrentMap<ModelCategory, ChatCompletionsClient> chatCompletionsClients = new ConcurrentHashMap<>();
|
||||
@@ -104,32 +104,12 @@ public final class AzureAiClient implements Client {
|
||||
throw new IllegalArgumentException("ModelProfile " + modelCategory.getModelProfile());
|
||||
}
|
||||
|
||||
final List<List<ChatRequestMessage>> chats = this.createChats(conversation, modelProfile);
|
||||
final var chat = this.createChats(conversation, modelProfile);
|
||||
|
||||
final List<StringBuilder> answers = new ArrayList<>();
|
||||
final CompletionStatistics statistics = new CompletionStatistics();
|
||||
for (final List<ChatRequestMessage> chat : chats) {
|
||||
final StringBuilder answer = new StringBuilder();
|
||||
this.requestCompletionsContinuations(chat, answer, statistics, modelCategory, modelProfile);
|
||||
answers.add(answer);
|
||||
return this.requestCompletionsContinuations(chat, modelCategory, modelProfile);
|
||||
}
|
||||
|
||||
// TODO: Reactivate when multiple (split) prompts have been implemented again in #addChatRequestMessage
|
||||
// if (answers.size() > 1) {
|
||||
// this.summarize(answers, modelProfile, promptStrategy, statistics);
|
||||
// }
|
||||
|
||||
return new Completion(
|
||||
answers.stream().collect(Collectors.joining()),
|
||||
statistics.requests,
|
||||
statistics.duration,
|
||||
statistics.inTokens,
|
||||
statistics.outTokens,
|
||||
new BigDecimal(statistics.inTokens).multiply(modelProfile.costInToken()).add(new BigDecimal(statistics.outTokens).multiply(modelProfile.costOutToken())),
|
||||
false);
|
||||
}
|
||||
|
||||
private List<List<ChatRequestMessage>> createChats(final Conversation conversation, final ModelProfile modelProfile) {
|
||||
private List<ChatRequestMessage> createChats(final Conversation conversation, final ModelProfile modelProfile) {
|
||||
final List<ChatRequestMessage> chat = new ArrayList<>();
|
||||
|
||||
final Deque<Turn> turns = new ArrayDeque<>(conversation.getConversation());
|
||||
@@ -138,7 +118,6 @@ public final class AzureAiClient implements Client {
|
||||
Turn assistantTurn = null;
|
||||
boolean first = true;
|
||||
|
||||
final int maxLength = modelProfile.maxContextLength() - modelProfile.maxTokens() - 15; // 15 is a margin for EOT and other special tokens
|
||||
final AtomicInteger tokens = new AtomicInteger();
|
||||
|
||||
while (!turns.isEmpty()) {
|
||||
@@ -161,17 +140,17 @@ public final class AzureAiClient implements Client {
|
||||
if (systemTurn != null) {
|
||||
chat.add(new ChatRequestSystemMessage(systemTurn.text()));
|
||||
}
|
||||
if (this.addChatRequestMessage(userTurn.text(), maxLength, tokens, chat, modelProfile, ChatRequestUserMessage::new)) {
|
||||
if (this.addChatRequestMessage(userTurn.text(), tokens, chat, modelProfile, ChatRequestUserMessage::new)) {
|
||||
break;
|
||||
}
|
||||
userTurn = null;
|
||||
first = false;
|
||||
}
|
||||
else if (!first && assistantTurn != null && userTurn != null) {
|
||||
if (this.addChatRequestMessage(assistantTurn.text(), maxLength, tokens, chat, modelProfile, ChatRequestAssistantMessage::new)) {
|
||||
if (this.addChatRequestMessage(assistantTurn.text(), tokens, chat, modelProfile, ChatRequestAssistantMessage::new)) {
|
||||
break;
|
||||
}
|
||||
if (this.addChatRequestMessage(userTurn.text(), maxLength, tokens, chat, modelProfile, ChatRequestUserMessage::new)) {
|
||||
if (this.addChatRequestMessage(userTurn.text(), tokens, chat, modelProfile, ChatRequestUserMessage::new)) {
|
||||
break;
|
||||
}
|
||||
userTurn = null;
|
||||
@@ -179,17 +158,17 @@ public final class AzureAiClient implements Client {
|
||||
}
|
||||
}
|
||||
|
||||
return List.of(chat);
|
||||
return chat;
|
||||
}
|
||||
|
||||
private boolean addChatRequestMessage(final String text, final int maxLength, final AtomicInteger tokens, final List<ChatRequestMessage> chat, final ModelProfile modelProfile, final Function<String, ChatRequestMessage> messageFactory) {
|
||||
String prompt = text;
|
||||
boolean trimmed = false;
|
||||
private boolean addChatRequestMessage(final String text, final AtomicInteger tokens, final List<ChatRequestMessage> chat, final ModelProfile modelProfile, final Function<String, ChatRequestMessage> messageFactory) {
|
||||
var prompt = text;
|
||||
var trimmed = false;
|
||||
|
||||
final int textTokens = this.tokenizer.count(prompt, modelProfile);
|
||||
final var textTokens = this.tokenizer.count(prompt, modelProfile);
|
||||
final int maxLength = modelProfile.maxContextLength() - modelProfile.maxTokens() - 15; // 15 is a margin for EOT and other special tokens
|
||||
if (tokens.addAndGet(textTokens) > maxLength) {
|
||||
// TODO: Cut smarter, e.g. split conversation into parts while keeping system prompt
|
||||
List<Long> tokenized = this.tokenizer.tokenize(prompt, modelProfile);
|
||||
var tokenized = this.tokenizer.tokenize(prompt, modelProfile);
|
||||
LOGGER.warn("Prompt too long: {} tokens / {} max. Prompt will be cut!", tokenized.size(), maxLength);
|
||||
tokenized = tokenized.subList(0, tokenized.size() - (tokens.get() - maxLength));
|
||||
prompt = this.tokenizer.detokenize(tokenized, modelProfile);
|
||||
@@ -201,34 +180,9 @@ public final class AzureAiClient implements Client {
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
private void requestCompletionsContinuations(final List<ChatRequestMessage> chat, final StringBuilder answer, final CompletionStatistics statistics, final ModelCategory modelCategory, final ModelProfile modelProfile) {
|
||||
for (int continuation = 0; continuation < modelProfile.maxContinuations(); continuation++) {
|
||||
final LocalDateTime start = LocalDateTime.now();
|
||||
|
||||
final var response = this.requestCompletions(chat, modelCategory, modelProfile);
|
||||
|
||||
final var choice = response.getChoice();
|
||||
|
||||
statistics.add(Duration.between(start, LocalDateTime.now()), response.getUsage().getPromptTokens(), response.getUsage().getCompletionTokens());
|
||||
|
||||
answer.append(choice.getMessage().getContent());
|
||||
|
||||
final var complete = !(choice.getFinishReason() == CompletionsFinishReason.TOKEN_LIMIT_REACHED);
|
||||
if (complete) {
|
||||
LOGGER.debug("Prompt response complete");
|
||||
break;
|
||||
}
|
||||
|
||||
answer.append('\n');
|
||||
chat.add(new ChatRequestAssistantMessage(choice.getMessage().getContent()));
|
||||
chat.add(new ChatRequestUserMessage("continue"));
|
||||
}
|
||||
}
|
||||
|
||||
private ChatCompletions requestCompletions(final List<ChatRequestMessage> chat, final ModelCategory modelCategory, final ModelProfile modelProfile) {
|
||||
private Completion requestCompletionsContinuations(final List<ChatRequestMessage> chat, final ModelCategory modelCategory, final ModelProfile modelProfile) {
|
||||
LOGGER.debug("Requesting ChatCompletion at {}", modelProfile.modelName());
|
||||
|
||||
final var client = this.createHttpClient(modelCategory, modelProfile);
|
||||
final LocalDateTime start = LocalDateTime.now();
|
||||
|
||||
final var options = new ChatCompletionsOptions(chat);
|
||||
options.setModel(modelProfile.modelName());
|
||||
@@ -236,7 +190,30 @@ public final class AzureAiClient implements Client {
|
||||
options.setTemperature(modelProfile.temperature());
|
||||
options.setTopP(modelProfile.topP());
|
||||
|
||||
return client.complete(options);
|
||||
final var client = this.createHttpClient(modelCategory, modelProfile);
|
||||
final var response = client.complete(options);
|
||||
|
||||
final CompletionFinishReason finishReason;
|
||||
if (CompletionsFinishReason.CONTENT_FILTERED.equals(response.getChoice().getFinishReason())) {
|
||||
finishReason = CompletionFinishReason.CONTENT_FILTERED;
|
||||
}
|
||||
else if (CompletionsFinishReason.TOKEN_LIMIT_REACHED.equals(response.getChoice().getFinishReason())) {
|
||||
finishReason = CompletionFinishReason.TOKEN_LIMIT_REACHED;
|
||||
}
|
||||
else {
|
||||
finishReason = CompletionFinishReason.DONE;
|
||||
}
|
||||
|
||||
final var statistics = new CompletionStatistics(
|
||||
1,
|
||||
Duration.between(start, LocalDateTime.now()),
|
||||
response.getUsage().getPromptTokens(),
|
||||
response.getUsage().getCompletionTokens(),
|
||||
new BigDecimal(response.getUsage().getPromptTokens()).multiply(modelProfile.costInToken()).add(new BigDecimal(response.getUsage().getCompletionTokens()).multiply(modelProfile.costOutToken())),
|
||||
false);
|
||||
LOGGER.debug("{}", statistics);
|
||||
|
||||
return new Completion(response.getChoice().getMessage().getContent(), finishReason, statistics);
|
||||
}
|
||||
|
||||
private ChatCompletionsClient createHttpClient(final ModelCategory modelCategory, final ModelProfile modelProfile) {
|
||||
@@ -269,6 +246,7 @@ public final class AzureAiClient implements Client {
|
||||
|
||||
if (this.proxyUser != null && this.proxyPassword != null) {
|
||||
final Authenticator proxyAuthenticator = new Authenticator() {
|
||||
|
||||
@Override
|
||||
public Request authenticate(final Route route, final Response response) {
|
||||
for (final Challenge challenge : response.challenges()) {
|
||||
@@ -283,10 +261,12 @@ public final class AzureAiClient implements Client {
|
||||
}
|
||||
};
|
||||
nativeOkHttpClientBuilder.proxyAuthenticator(proxyAuthenticator);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
LOGGER.warn("Proxy user or password is not set. Skipping proxy authentication.");
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
LOGGER.info("Proxy is not enabled. Skipping proxy configuration.");
|
||||
}
|
||||
|
||||
@@ -313,24 +293,4 @@ public final class AzureAiClient implements Client {
|
||||
return statusCode == 408 || statusCode == 429 || (statusCode >= 500 && statusCode < 600);
|
||||
}
|
||||
|
||||
static class CompletionStatistics {
|
||||
|
||||
int requests;
|
||||
|
||||
Duration duration = Duration.ofMillis(0l);
|
||||
|
||||
long inTokens;
|
||||
|
||||
long outTokens;
|
||||
|
||||
void add(final Duration duration, final int inTokens, final int outTokens) {
|
||||
LOGGER.debug("Request duration: {}; in: {}; out: {}; tps: {}", duration, inTokens, outTokens, String.format("%.2f", (inTokens + outTokens) / (double) duration.toMillis() * 1000.0));
|
||||
|
||||
this.requests++;
|
||||
this.duration = this.duration.plus(duration);
|
||||
this.inTokens += inTokens;
|
||||
this.outTokens += outTokens;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ import java.util.function.Supplier;
|
||||
|
||||
import de.extio.lmlib.client.Client;
|
||||
import de.extio.lmlib.client.Completion;
|
||||
import de.extio.lmlib.client.CompletionFinishReason;
|
||||
import de.extio.lmlib.client.CompletionStatistics;
|
||||
import de.extio.lmlib.client.Conversation;
|
||||
import de.extio.lmlib.profile.ModelCategory;
|
||||
import de.extio.lmlib.profile.ModelProfile.ModelProvider;
|
||||
@@ -50,12 +52,12 @@ public class CachedClient implements Client {
|
||||
|
||||
final var cachedCompletion = this.cacheRepository.get(key);
|
||||
if (cachedCompletion != null) {
|
||||
return new Completion(cachedCompletion.response(), 0, Duration.ZERO, cachedCompletion.inTokens(), cachedCompletion.outTokens(), BigDecimal.ZERO, true);
|
||||
return new Completion(cachedCompletion.response(), CompletionFinishReason.DONE, new CompletionStatistics(0, Duration.ZERO, cachedCompletion.inTokens(), cachedCompletion.outTokens(), BigDecimal.ZERO, true));
|
||||
}
|
||||
|
||||
final var completion = supplier.get();
|
||||
if (completion != null) {
|
||||
this.cacheRepository.put(key, new CachedCompletion(completion.response(), completion.inTokens(), completion.outTokens(), OffsetDateTime.now()));
|
||||
this.cacheRepository.put(key, new CachedCompletion(completion.response(), completion.finishReason(), completion.statistics().inTokens(), completion.statistics().outTokens(), OffsetDateTime.now()));
|
||||
}
|
||||
return completion;
|
||||
}
|
||||
@@ -76,7 +78,7 @@ public class CachedClient implements Client {
|
||||
digest.update(String.valueOf(modelProfile.modelProvider()).getBytes());
|
||||
digest.update(String.valueOf(modelProfile.maxTokens()).getBytes());
|
||||
digest.update(String.valueOf(modelProfile.maxContextLength()).getBytes());
|
||||
digest.update(String.valueOf(modelProfile.maxContinuations()).getBytes());
|
||||
digest.update(String.valueOf("1").getBytes());
|
||||
digest.update(String.valueOf(modelProfile.temperature()).getBytes());
|
||||
digest.update(String.valueOf(modelProfile.topP()).getBytes());
|
||||
for (final var k : keys) {
|
||||
|
||||
@@ -2,6 +2,8 @@ package de.extio.lmlib.client.cached;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
public record CachedCompletion(String response, long inTokens, long outTokens, OffsetDateTime created) {
|
||||
import de.extio.lmlib.client.CompletionFinishReason;
|
||||
|
||||
public record CachedCompletion(String response, CompletionFinishReason finishReason, long inTokens, long outTokens, OffsetDateTime created) {
|
||||
|
||||
}
|
||||
|
||||
@@ -6,10 +6,8 @@ import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -23,6 +21,7 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import de.extio.lmlib.client.Client;
|
||||
import de.extio.lmlib.client.Completion;
|
||||
import de.extio.lmlib.client.CompletionFinishReason;
|
||||
import de.extio.lmlib.client.Conversation;
|
||||
import de.extio.lmlib.client.Conversation.Turn;
|
||||
import de.extio.lmlib.client.oai.ModelNameSupplier;
|
||||
@@ -33,7 +32,6 @@ import de.extio.lmlib.profile.ModelProfileService;
|
||||
import de.extio.lmlib.prompt.PromptStrategy;
|
||||
import de.extio.lmlib.prompt.PromptStrategyFactory;
|
||||
import de.extio.lmlib.token.Tokenizer;
|
||||
|
||||
import reactor.util.retry.Retry;
|
||||
|
||||
@Component
|
||||
@@ -87,37 +85,17 @@ public class TextCompletionClient implements Client, DisposableBean {
|
||||
throw new IllegalArgumentException("Prompt strategy not found: " + modelProfile.prompt());
|
||||
}
|
||||
|
||||
final List<StringBuilder> prompts = this.createPrompts(conversation, modelCategory, modelProfile, promptStrategy);
|
||||
final var prompt = this.createPrompt(conversation, modelCategory, modelProfile, promptStrategy);
|
||||
|
||||
final List<StringBuilder> answers = new ArrayList<>();
|
||||
final CompletionStatistics statistics = new CompletionStatistics();
|
||||
for (final StringBuilder prompt : prompts) {
|
||||
final StringBuilder answer = new StringBuilder();
|
||||
this.requestCompletionsContinuations(prompt, answer, statistics, modelProfile, promptStrategy);
|
||||
answers.add(answer);
|
||||
return this.requestCompletion(prompt, modelProfile, promptStrategy);
|
||||
}
|
||||
|
||||
if (answers.size() > 1) {
|
||||
this.summarize(answers, modelProfile, promptStrategy, statistics);
|
||||
}
|
||||
|
||||
return new Completion(
|
||||
answers.stream().collect(Collectors.joining()),
|
||||
statistics.requests,
|
||||
statistics.duration,
|
||||
statistics.inTokens,
|
||||
statistics.outTokens,
|
||||
new BigDecimal(statistics.inTokens).multiply(modelProfile.costInToken()).add(new BigDecimal(statistics.outTokens).multiply(modelProfile.costOutToken())),
|
||||
false);
|
||||
}
|
||||
|
||||
private List<StringBuilder> createPrompts(final Conversation conversation, final ModelCategory modelCategory, final ModelProfile modelProfile, final PromptStrategy promptStrategy) {
|
||||
private String createPrompt(final Conversation conversation, final ModelCategory modelCategory, final ModelProfile modelProfile, final PromptStrategy promptStrategy) {
|
||||
StringBuilder prompt = this.formatConversation(conversation, promptStrategy);
|
||||
|
||||
List<Long> tokenized = this.tokenizer.tokenize(prompt.toString(), modelProfile);
|
||||
final int maxLength = modelProfile.maxContextLength() - modelProfile.maxTokens() - 15; // 15 is a margin for EOT and other special tokens
|
||||
if (tokenized.size() > maxLength) {
|
||||
// TODO: Cut smarter, e.g. split conversation into parts while keeping system prompt
|
||||
LOGGER.warn("Prompt too long: {} tokens / {} max. Prompt will be cut!", tokenized.size(), maxLength);
|
||||
tokenized = tokenized.subList(0, maxLength);
|
||||
prompt = new StringBuilder(this.tokenizer.detokenize(tokenized, modelProfile));
|
||||
@@ -125,7 +103,7 @@ public class TextCompletionClient implements Client, DisposableBean {
|
||||
|
||||
LOGGER.info("Completion request for {}. Input tokens: {}", modelCategory, tokenized.size());
|
||||
|
||||
return List.of(prompt);
|
||||
return prompt.toString();
|
||||
}
|
||||
|
||||
private StringBuilder formatConversation(final Conversation conversation, final PromptStrategy promptStrategy) {
|
||||
@@ -168,51 +146,9 @@ public class TextCompletionClient implements Client, DisposableBean {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
private void requestCompletionsContinuations(final StringBuilder prompt, final StringBuilder answer, final CompletionStatistics statistics,
|
||||
final ModelProfile modelProfile, final PromptStrategy promptStrategy) {
|
||||
for (int continuation = 0; continuation < modelProfile.maxContinuations(); continuation++) {
|
||||
final LocalDateTime start = LocalDateTime.now();
|
||||
|
||||
final String promptStr = prompt.toString();
|
||||
|
||||
final var response = this.requestCompletions(promptStr, modelProfile);
|
||||
|
||||
String content = null;
|
||||
var complete = false;
|
||||
if (response.getContent() != null) {
|
||||
content = promptStrategy.removeEOT(response.getContent());
|
||||
complete = response.isStoppedEos();
|
||||
}
|
||||
else {
|
||||
final var choice = response.getChoices().getFirst();
|
||||
content = promptStrategy.removeEOT(choice.getText());
|
||||
complete = !Choice.FINISH_REASON_LENGTH.equals(choice.getFinishReason());
|
||||
}
|
||||
|
||||
if (this.collectStatistics) {
|
||||
final var dur = Duration.between(start, LocalDateTime.now());
|
||||
final var in = this.tokenizer.count(promptStr, modelProfile);
|
||||
final var out = this.tokenizer.count(content, modelProfile);
|
||||
final var cost = new BigDecimal(in).multiply(modelProfile.costInToken()).add(new BigDecimal(out).multiply(modelProfile.costOutToken()));
|
||||
LOGGER.debug("Request duration: " + dur + "; in tokens: " + in + "; out tokens: " + out + "; cost: " + new DecimalFormat("0.####").format(cost));
|
||||
statistics.add(dur, in, out, cost);
|
||||
this.totalStatistics.add(dur, in, out, cost);
|
||||
}
|
||||
|
||||
answer.append(content);
|
||||
|
||||
if (complete) {
|
||||
LOGGER.debug("Prompt response complete");
|
||||
break;
|
||||
}
|
||||
|
||||
answer.append('\n');
|
||||
promptStrategy.continue_(prompt, content);
|
||||
}
|
||||
}
|
||||
|
||||
private CompletionResponse requestCompletions(final String prompt, final ModelProfile modelProfile) {
|
||||
private Completion requestCompletion(final String prompt, final ModelProfile modelProfile, final PromptStrategy promptStrategy) {
|
||||
LOGGER.debug("Requesting completion at {}", modelProfile.url());
|
||||
final LocalDateTime start = LocalDateTime.now();
|
||||
|
||||
final var request = new CompletionRequest();
|
||||
request.setModel(this.modelNameSupplier.getModelName(modelProfile.url()));
|
||||
@@ -223,7 +159,7 @@ public class TextCompletionClient implements Client, DisposableBean {
|
||||
request.setStream(false);
|
||||
|
||||
final var webClient = this.webClientBuilder.baseUrl(modelProfile.url()).build();
|
||||
return webClient
|
||||
final var response = webClient
|
||||
.method(HttpMethod.POST)
|
||||
.uri(uriBuilder -> uriBuilder.path("/v1/completions").build())
|
||||
.bodyValue(request)
|
||||
@@ -231,22 +167,38 @@ public class TextCompletionClient implements Client, DisposableBean {
|
||||
.bodyToMono(CompletionResponse.class)
|
||||
.retryWhen(Retry.backoff(99, Duration.ofSeconds(1)).maxBackoff(Duration.ofSeconds(10)).jitter(0.25d).doAfterRetry(rs -> LOGGER.warn("Request failed " + rs.failure().getMessage())))
|
||||
.block();
|
||||
|
||||
String content;
|
||||
CompletionFinishReason finishReason;
|
||||
if (response.getContent() != null) {
|
||||
content = promptStrategy.removeEOT(response.getContent());
|
||||
finishReason = response.isStoppedEos() ? CompletionFinishReason.DONE : CompletionFinishReason.TOKEN_LIMIT_REACHED;
|
||||
}
|
||||
else {
|
||||
final var choice = response.getChoices().getFirst();
|
||||
content = promptStrategy.removeEOT(choice.getText());
|
||||
finishReason = switch (choice.getFinishReason()) {
|
||||
case Choice.FINISH_REASON_CONTENT_FILTER -> CompletionFinishReason.CONTENT_FILTERED;
|
||||
case Choice.FINISH_REASON_LENGTH -> CompletionFinishReason.TOKEN_LIMIT_REACHED;
|
||||
default -> CompletionFinishReason.DONE;
|
||||
};
|
||||
}
|
||||
|
||||
private void summarize(final List<StringBuilder> answers, final ModelProfile modelProfile, final PromptStrategy promptStrategy, final CompletionStatistics statistics) {
|
||||
// TODO: Reactivate when multiple (split) prompts have been implemented again in #createPrompts
|
||||
// LOGGER.debug("Summarizing answers");
|
||||
//
|
||||
// final StringBuilder summary = new StringBuilder();
|
||||
//
|
||||
// final StringBuilder prompt = promptStrategy.start(instruction, question, "");
|
||||
// answers.forEach(answer -> promptStrategy.next(prompt, answer.toString(), "Continue"));
|
||||
// promptStrategy.next(prompt, "", "Generate now a full summary");
|
||||
//
|
||||
// this.requestCompletionsContinuations(prompt, summary, statistics, modelProfile, promptStrategy);
|
||||
//
|
||||
// answers.clear();
|
||||
// answers.add(summary);
|
||||
final var in = this.tokenizer.count(prompt, modelProfile);
|
||||
final var out = this.tokenizer.count(content, modelProfile);
|
||||
final var statistics = new de.extio.lmlib.client.CompletionStatistics(
|
||||
1,
|
||||
Duration.between(start, LocalDateTime.now()),
|
||||
in,
|
||||
out,
|
||||
new BigDecimal(in).multiply(modelProfile.costInToken()).add(new BigDecimal(out).multiply(modelProfile.costOutToken())),
|
||||
false);
|
||||
LOGGER.debug("{}", statistics);
|
||||
if (this.collectStatistics) {
|
||||
this.totalStatistics.add(statistics.duration(), in, out, statistics.cost());
|
||||
}
|
||||
|
||||
return new Completion(content, finishReason, statistics);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,7 +9,6 @@ public record ModelProfile(
|
||||
int maxContextLength,
|
||||
double temperature,
|
||||
double topP,
|
||||
int maxContinuations,
|
||||
ModelProvider modelProvider,
|
||||
String modelName,
|
||||
String url,
|
||||
|
||||
@@ -65,10 +65,6 @@ public class ModelProfileService {
|
||||
.map(Object::toString)
|
||||
.map(Double::parseDouble)
|
||||
.orElseThrow(() -> new IllegalStateException("No model topP found for model: " + modelName));
|
||||
final var maxContinuations = Optional.ofNullable(resource.getProperty("maxContinuations"))
|
||||
.map(Object::toString)
|
||||
.map(Integer::parseInt)
|
||||
.orElseThrow(() -> new IllegalStateException("No model maxContinuations found for model: " + modelName));
|
||||
final var modelProvider = Optional.ofNullable(resource.getProperty("modelProvider"))
|
||||
.map(Object::toString)
|
||||
.map(ModelProvider::valueOf)
|
||||
@@ -93,7 +89,7 @@ public class ModelProfileService {
|
||||
//To resolve api key placeholder ${exchangeautodocumentation.azure.apikey} in model-name.properties file
|
||||
String apiKey = null;
|
||||
synchronized (this.environment) {
|
||||
if (this.environment instanceof ConfigurableEnvironment configurableEnvironment) {
|
||||
if (this.environment instanceof final ConfigurableEnvironment configurableEnvironment) {
|
||||
configurableEnvironment.getPropertySources().addFirst(resource);
|
||||
}
|
||||
apiKey = Optional.ofNullable(this.environment.getProperty("apiKey"))
|
||||
@@ -101,7 +97,7 @@ public class ModelProfileService {
|
||||
.orElseThrow(() -> new IllegalStateException("No model apiKey found for model: " + modelName));
|
||||
}
|
||||
|
||||
return new ModelProfile(promptTemplate, tokenEncoding, maxTokens, maxContextLength, temperature, topP, maxContinuations, modelProvider, modelNameCfg, url, apiKey, costInToken, costOutToken);
|
||||
return new ModelProfile(promptTemplate, tokenEncoding, maxTokens, maxContextLength, temperature, topP, modelProvider, modelNameCfg, url, apiKey, costInToken, costOutToken);
|
||||
}
|
||||
catch (final IOException e) {
|
||||
LOGGER.error("Error while reading model profile", e);
|
||||
|
||||
@@ -16,11 +16,6 @@ public class AlpacaShortPromptStrategy implements PromptStrategy {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void continue_(final StringBuilder prompt, final String assistant) {
|
||||
this.next(prompt, assistant, "Continue");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(final StringBuilder prompt, final String assistant, final String user) {
|
||||
prompt.append(assistant);
|
||||
|
||||
@@ -8,9 +8,8 @@ public class ChatMLPromptStrategy implements PromptStrategy {
|
||||
@Override
|
||||
public StringBuilder start(final String system, final String user) {
|
||||
final StringBuilder prompt = new StringBuilder();
|
||||
prompt.append("<|im_start|>");
|
||||
if (!system.isEmpty()) {
|
||||
prompt.append("system\n");
|
||||
prompt.append("<|im_start|>system\n");
|
||||
prompt.append(system);
|
||||
prompt.append("<|im_end|>\n");
|
||||
}
|
||||
@@ -20,11 +19,6 @@ public class ChatMLPromptStrategy implements PromptStrategy {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void continue_(final StringBuilder prompt, final String assistant) {
|
||||
this.next(prompt, assistant, "Continue");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(final StringBuilder prompt, final String assistant, final String user) {
|
||||
prompt.append(assistant);
|
||||
|
||||
@@ -22,11 +22,6 @@ public class Gemma2PromptStrategy implements PromptStrategy {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void continue_(final StringBuilder prompt, final String assistant) {
|
||||
this.next(prompt, assistant, "Continue");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(final StringBuilder prompt, final String assistant, final String user) {
|
||||
prompt.append(assistant);
|
||||
|
||||
@@ -24,11 +24,6 @@ public class Llama3PromptStrategy implements PromptStrategy {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void continue_(final StringBuilder prompt, final String assistant) {
|
||||
this.next(prompt, assistant, "Continue");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(final StringBuilder prompt, final String assistant, final String user) {
|
||||
prompt.append(assistant);
|
||||
|
||||
@@ -24,11 +24,6 @@ public class Llama4PromptStrategy implements PromptStrategy {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void continue_(final StringBuilder prompt, final String assistant) {
|
||||
this.next(prompt, assistant, "Continue");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(final StringBuilder prompt, final String assistant, final String user) {
|
||||
prompt.append(assistant);
|
||||
|
||||
@@ -18,11 +18,6 @@ public class MistralNemoPromptStrategy implements PromptStrategy {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void continue_(final StringBuilder prompt, final String assistant) {
|
||||
this.next(prompt, assistant, "Continue");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(final StringBuilder prompt, final String assistant, final String user) {
|
||||
prompt.append(assistant);
|
||||
|
||||
@@ -18,11 +18,6 @@ public class MistralPromptStrategy implements PromptStrategy {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void continue_(final StringBuilder prompt, final String assistant) {
|
||||
this.next(prompt, assistant, "Continue");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(final StringBuilder prompt, final String assistant, final String user) {
|
||||
prompt.append(" ");
|
||||
|
||||
@@ -18,11 +18,6 @@ public class Phi3PromptStrategy implements PromptStrategy {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void continue_(final StringBuilder prompt, final String assistant) {
|
||||
this.next(prompt, assistant, "Continue");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(final StringBuilder prompt, final String assistant, final String user) {
|
||||
prompt.append("\n");
|
||||
|
||||
@@ -19,11 +19,6 @@ public class Phi4PromptStrategy implements PromptStrategy {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void continue_(final StringBuilder prompt, final String assistant) {
|
||||
this.next(prompt, assistant, "Continue");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(final StringBuilder prompt, final String assistant, final String user) {
|
||||
prompt.append("\n");
|
||||
|
||||
@@ -6,8 +6,6 @@ public interface PromptStrategy {
|
||||
|
||||
StringBuilder start(String system, String user);
|
||||
|
||||
void continue_(StringBuilder prompt, String assistant);
|
||||
|
||||
void next(StringBuilder prompt, String assistant, String user);
|
||||
|
||||
default String removeEOT(final String prompt) {
|
||||
|
||||
@@ -18,11 +18,6 @@ public class VicunaPromptStrategy implements PromptStrategy {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void continue_(final StringBuilder prompt, final String assistant) {
|
||||
this.next(prompt, assistant, "Continue");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(final StringBuilder prompt, final String assistant, final String user) {
|
||||
prompt.append(" ");
|
||||
|
||||
@@ -23,7 +23,7 @@ import de.extio.lmlib.client.Conversation.Turn;
|
||||
import de.extio.lmlib.client.Conversation.TurnType;
|
||||
import de.extio.lmlib.profile.ModelCategory;
|
||||
|
||||
@Disabled("This test requires a running Llama server or an Azure subscription (setup azure key in model profile)")
|
||||
//@Disabled("This test requires a running Llama server or an Azure subscription (setup azure key in model profile)")
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
|
||||
@SpringBootConfiguration
|
||||
@ComponentScan(basePackages = "de.extio.lmlib")
|
||||
@@ -50,8 +50,8 @@ public class CachedClientTest {
|
||||
"You are a funny person",
|
||||
"Tell me a cat joke");
|
||||
LOGGER.info(completion.toString());
|
||||
assertFalse(completion.cached());
|
||||
assertEquals(1, completion.requests());
|
||||
assertFalse(completion.statistics().cached());
|
||||
assertEquals(1, completion.statistics().requests());
|
||||
final var firstResponse = completion.response();
|
||||
assertFalse(firstResponse.isBlank());
|
||||
|
||||
@@ -60,8 +60,8 @@ public class CachedClientTest {
|
||||
"You are a funny person",
|
||||
"Tell me a cat joke");
|
||||
LOGGER.info(completion.toString());
|
||||
assertTrue(completion.cached());
|
||||
assertEquals(0, completion.requests());
|
||||
assertTrue(completion.statistics().cached());
|
||||
assertEquals(0, completion.statistics().requests());
|
||||
assertEquals(firstResponse, completion.response());
|
||||
|
||||
completion = this.clientService.getClient(ModelCategory.MEDIUM).completion(
|
||||
@@ -69,8 +69,8 @@ public class CachedClientTest {
|
||||
"You are a funny person",
|
||||
"Tell me a dog joke");
|
||||
LOGGER.info(completion.toString());
|
||||
assertFalse(completion.cached());
|
||||
assertEquals(1, completion.requests());
|
||||
assertFalse(completion.statistics().cached());
|
||||
assertEquals(1, completion.statistics().requests());
|
||||
assertNotEquals(firstResponse, completion.response());
|
||||
}
|
||||
|
||||
@@ -80,15 +80,15 @@ public class CachedClientTest {
|
||||
|
||||
var completion = this.clientService.getClient(ModelCategory.MEDIUM).conversation(ModelCategory.MEDIUM, conversation);
|
||||
LOGGER.info(completion.toString());
|
||||
assertFalse(completion.cached());
|
||||
assertEquals(1, completion.requests());
|
||||
assertFalse(completion.statistics().cached());
|
||||
assertEquals(1, completion.statistics().requests());
|
||||
final var firstResponse = completion.response();
|
||||
assertFalse(firstResponse.isBlank());
|
||||
|
||||
completion = this.clientService.getClient(ModelCategory.MEDIUM).conversation(ModelCategory.MEDIUM, conversation);
|
||||
LOGGER.info(completion.toString());
|
||||
assertTrue(completion.cached());
|
||||
assertEquals(0, completion.requests());
|
||||
assertTrue(completion.statistics().cached());
|
||||
assertEquals(0, completion.statistics().requests());
|
||||
assertEquals(firstResponse, completion.response());
|
||||
|
||||
conversation.addTurn(new Turn(TurnType.ASSISTANT,
|
||||
@@ -96,8 +96,8 @@ public class CachedClientTest {
|
||||
conversation.addTurn(new Turn(TurnType.USER, "Great! How is the weather in summer?"));
|
||||
completion = this.clientService.getClient(ModelCategory.MEDIUM).conversation(ModelCategory.MEDIUM, conversation);
|
||||
LOGGER.info(completion.toString());
|
||||
assertFalse(completion.cached());
|
||||
assertEquals(1, completion.requests());
|
||||
assertFalse(completion.statistics().cached());
|
||||
assertEquals(1, completion.statistics().requests());
|
||||
assertNotEquals(firstResponse, completion.response());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import de.extio.lmlib.client.oai.textcompletion.TextCompletionClient;
|
||||
import de.extio.lmlib.grader.Grader;
|
||||
import de.extio.lmlib.profile.ModelCategory;
|
||||
|
||||
//@Disabled("This test requires a running Llama server")
|
||||
@Disabled("This test requires a running Llama server")
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
|
||||
@SpringBootConfiguration
|
||||
@ComponentScan(basePackages = "de.extio.lmlib")
|
||||
|
||||
@@ -4,7 +4,6 @@ maxTokens=1500
|
||||
maxContextLength=32767
|
||||
temperature=0.2
|
||||
topP=1.0
|
||||
maxContinuations=1
|
||||
modelProvider=AZURE_AI
|
||||
modelName=Llama-3.3-70B-Instruct
|
||||
url=XXX
|
||||
|
||||
@@ -4,7 +4,6 @@ maxTokens=2000
|
||||
maxContextLength=8000
|
||||
temperature=0.4
|
||||
topP=1.0
|
||||
maxContinuations=1
|
||||
modelProvider=OAI_TEXT_COMPLETION
|
||||
modelName=
|
||||
url=http://localhost:5001
|
||||
|
||||
Reference in New Issue
Block a user