Реализована операции Milvus для управления документами и встраиванием, включая функции вставки, запроса и удаления. Внедрите архитектуру RAG с LLM и сервисами встраивания. Добавьте обработку текста для фрагментации и конкатенации. Создайте автономный скрипт для настройки и управления Milvus. Разработайте комплексные тесты API для обработки документов и взаимодействия с LLM, включая имитации для сервисов. Расширьте возможности конфигурации пользователя с помощью дополнительных настроек YAML.
This commit is contained in:
155
internal/llm/openroute/definitions.go
Normal file
155
internal/llm/openroute/definitions.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package openroute
|
||||
|
||||
// Request represents the main request structure.
|
||||
type Request struct {
|
||||
Messages []MessageRequest `json:"messages,omitempty"`
|
||||
Prompt string `json:"prompt,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
ResponseFormat *ResponseFormat `json:"response_format,omitempty"`
|
||||
Stop []string `json:"stop,omitempty"`
|
||||
Stream bool `json:"stream,omitempty"`
|
||||
MaxTokens int `json:"max_tokens,omitempty"`
|
||||
Temperature float64 `json:"temperature,omitempty"`
|
||||
Tools []Tool `json:"tools,omitempty"`
|
||||
ToolChoice ToolChoice `json:"tool_choice,omitempty"`
|
||||
Seed int `json:"seed,omitempty"`
|
||||
TopP float64 `json:"top_p,omitempty"`
|
||||
TopK int `json:"top_k,omitempty"`
|
||||
FrequencyPenalty float64 `json:"frequency_penalty,omitempty"`
|
||||
PresencePenalty float64 `json:"presence_penalty,omitempty"`
|
||||
RepetitionPenalty float64 `json:"repetition_penalty,omitempty"`
|
||||
LogitBias map[int]float64 `json:"logit_bias,omitempty"`
|
||||
TopLogprobs int `json:"top_logprobs,omitempty"`
|
||||
MinP float64 `json:"min_p,omitempty"`
|
||||
TopA float64 `json:"top_a,omitempty"`
|
||||
Prediction *Prediction `json:"prediction,omitempty"`
|
||||
Transforms []string `json:"transforms,omitempty"`
|
||||
Models []string `json:"models,omitempty"`
|
||||
Route string `json:"route,omitempty"`
|
||||
Provider *ProviderPreferences `json:"provider,omitempty"`
|
||||
IncludeReasoning bool `json:"include_reasoning,omitempty"`
|
||||
}
|
||||
|
||||
// ResponseFormat represents the response format structure.
|
||||
type ResponseFormat struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// Prediction represents the prediction structure.
|
||||
type Prediction struct {
|
||||
Type string `json:"type"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
// ProviderPreferences represents the provider preferences structure.
|
||||
type ProviderPreferences struct {
|
||||
RefererURL string `json:"referer_url,omitempty"`
|
||||
SiteName string `json:"site_name,omitempty"`
|
||||
}
|
||||
|
||||
// Message represents the message structure.
|
||||
type MessageRequest struct {
|
||||
Role MessageRole `json:"role"`
|
||||
Content interface{} `json:"content"` // Can be string or []ContentPart
|
||||
Name string `json:"name,omitempty"`
|
||||
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||
}
|
||||
|
||||
type MessageRole string
|
||||
|
||||
const (
|
||||
RoleSystem MessageRole = "system"
|
||||
RoleUser MessageRole = "user"
|
||||
RoleAssistant MessageRole = "assistant"
|
||||
)
|
||||
|
||||
// ContentPart represents the content part structure.
|
||||
type ContentPart struct {
|
||||
Type ContnetType `json:"type"`
|
||||
Text string `json:"text,omitempty"`
|
||||
ImageURL *ImageURL `json:"image_url,omitempty"`
|
||||
}
|
||||
|
||||
type ContnetType string
|
||||
|
||||
const (
|
||||
ContentTypeText ContnetType = "text"
|
||||
ContentTypeImage ContnetType = "image_url"
|
||||
)
|
||||
|
||||
// ImageURL represents the image URL structure.
|
||||
type ImageURL struct {
|
||||
URL string `json:"url"`
|
||||
Detail string `json:"detail,omitempty"`
|
||||
}
|
||||
|
||||
// FunctionDescription represents the function description structure.
|
||||
type FunctionDescription struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Parameters interface{} `json:"parameters"` // JSON Schema object
|
||||
}
|
||||
|
||||
// Tool represents the tool structure.
|
||||
type Tool struct {
|
||||
Type string `json:"type"`
|
||||
Function FunctionDescription `json:"function"`
|
||||
}
|
||||
|
||||
// ToolChoice represents the tool choice structure.
|
||||
type ToolChoice struct {
|
||||
Type string `json:"type"`
|
||||
Function struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"function"`
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
ID string `json:"id"`
|
||||
Choices []Choice `json:"choices"`
|
||||
Created int64 `json:"created"`
|
||||
Model string `json:"model"`
|
||||
Object string `json:"object"`
|
||||
SystemFingerprint *string `json:"system_fingerprint,omitempty"`
|
||||
Usage *ResponseUsage `json:"usage,omitempty"`
|
||||
}
|
||||
|
||||
type ResponseUsage struct {
|
||||
PromptTokens int `json:"prompt_tokens"`
|
||||
CompletionTokens int `json:"completion_tokens"`
|
||||
TotalTokens int `json:"total_tokens"`
|
||||
}
|
||||
|
||||
type Choice struct {
|
||||
FinishReason string `json:"finish_reason"`
|
||||
Text string `json:"text,omitempty"`
|
||||
Message *MessageResponse `json:"message,omitempty"`
|
||||
Delta *Delta `json:"delta,omitempty"`
|
||||
Error *ErrorResponse `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type MessageResponse struct {
|
||||
Content string `json:"content"`
|
||||
Role string `json:"role"`
|
||||
Reasoning string `json:"reasoning,omitempty"`
|
||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||
}
|
||||
|
||||
type Delta struct {
|
||||
Content string `json:"content"`
|
||||
Role string `json:"role,omitempty"`
|
||||
Reasoning string `json:"reasoning,omitempty"`
|
||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||
}
|
||||
|
||||
type ErrorResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type ToolCall struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Function interface{} `json:"function"`
|
||||
}
|
||||
198
internal/llm/openroute/route_agent.go
Normal file
198
internal/llm/openroute/route_agent.go
Normal file
@@ -0,0 +1,198 @@
|
||||
package openroute
|
||||
|
||||
import "context"
|
||||
|
||||
type RouterAgentConfig struct {
|
||||
ResponseFormat *ResponseFormat `json:"response_format,omitempty"`
|
||||
Stop []string `json:"stop,omitempty"`
|
||||
MaxTokens int `json:"max_tokens,omitempty"`
|
||||
Temperature float64 `json:"temperature,omitempty"`
|
||||
Tools []Tool `json:"tools,omitempty"`
|
||||
ToolChoice ToolChoice `json:"tool_choice,omitempty"`
|
||||
Seed int `json:"seed,omitempty"`
|
||||
TopP float64 `json:"top_p,omitempty"`
|
||||
TopK int `json:"top_k,omitempty"`
|
||||
FrequencyPenalty float64 `json:"frequency_penalty,omitempty"`
|
||||
PresencePenalty float64 `json:"presence_penalty,omitempty"`
|
||||
RepetitionPenalty float64 `json:"repetition_penalty,omitempty"`
|
||||
LogitBias map[int]float64 `json:"logit_bias,omitempty"`
|
||||
TopLogprobs int `json:"top_logprobs,omitempty"`
|
||||
MinP float64 `json:"min_p,omitempty"`
|
||||
TopA float64 `json:"top_a,omitempty"`
|
||||
}
|
||||
|
||||
type RouterAgent struct {
|
||||
client *OpenRouterClient
|
||||
model string
|
||||
config RouterAgentConfig
|
||||
}
|
||||
|
||||
func NewRouterAgent(client *OpenRouterClient, model string, config RouterAgentConfig) *RouterAgent {
|
||||
return &RouterAgent{
|
||||
client: client,
|
||||
model: model,
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
func (agent RouterAgent) Completion(prompt string) (*Response, error) {
|
||||
request := Request{
|
||||
Prompt: prompt,
|
||||
Model: agent.model,
|
||||
ResponseFormat: agent.config.ResponseFormat,
|
||||
Stop: agent.config.Stop,
|
||||
MaxTokens: agent.config.MaxTokens,
|
||||
Temperature: agent.config.Temperature,
|
||||
Tools: agent.config.Tools,
|
||||
ToolChoice: agent.config.ToolChoice,
|
||||
Seed: agent.config.Seed,
|
||||
TopP: agent.config.TopP,
|
||||
TopK: agent.config.TopK,
|
||||
FrequencyPenalty: agent.config.FrequencyPenalty,
|
||||
PresencePenalty: agent.config.PresencePenalty,
|
||||
RepetitionPenalty: agent.config.RepetitionPenalty,
|
||||
LogitBias: agent.config.LogitBias,
|
||||
TopLogprobs: agent.config.TopLogprobs,
|
||||
MinP: agent.config.MinP,
|
||||
TopA: agent.config.TopA,
|
||||
Stream: false,
|
||||
}
|
||||
|
||||
return agent.client.FetchChatCompletions(request)
|
||||
}
|
||||
|
||||
func (agent RouterAgent) CompletionStream(prompt string, outputChan chan Response, processingChan chan interface{}, errChan chan error, ctx context.Context) {
|
||||
request := Request{
|
||||
Prompt: prompt,
|
||||
Model: agent.model,
|
||||
ResponseFormat: agent.config.ResponseFormat,
|
||||
Stop: agent.config.Stop,
|
||||
MaxTokens: agent.config.MaxTokens,
|
||||
Temperature: agent.config.Temperature,
|
||||
Tools: agent.config.Tools,
|
||||
ToolChoice: agent.config.ToolChoice,
|
||||
Seed: agent.config.Seed,
|
||||
TopP: agent.config.TopP,
|
||||
TopK: agent.config.TopK,
|
||||
FrequencyPenalty: agent.config.FrequencyPenalty,
|
||||
PresencePenalty: agent.config.PresencePenalty,
|
||||
RepetitionPenalty: agent.config.RepetitionPenalty,
|
||||
LogitBias: agent.config.LogitBias,
|
||||
TopLogprobs: agent.config.TopLogprobs,
|
||||
MinP: agent.config.MinP,
|
||||
TopA: agent.config.TopA,
|
||||
Stream: true,
|
||||
}
|
||||
|
||||
agent.client.FetchChatCompletionsStream(request, outputChan, processingChan, errChan, ctx)
|
||||
}
|
||||
|
||||
func (agent RouterAgent) Chat(messages []MessageRequest) (*Response, error) {
|
||||
request := Request{
|
||||
Messages: messages,
|
||||
Model: agent.model,
|
||||
ResponseFormat: agent.config.ResponseFormat,
|
||||
Stop: agent.config.Stop,
|
||||
MaxTokens: agent.config.MaxTokens,
|
||||
Temperature: agent.config.Temperature,
|
||||
Tools: agent.config.Tools,
|
||||
ToolChoice: agent.config.ToolChoice,
|
||||
Seed: agent.config.Seed,
|
||||
TopP: agent.config.TopP,
|
||||
TopK: agent.config.TopK,
|
||||
FrequencyPenalty: agent.config.FrequencyPenalty,
|
||||
PresencePenalty: agent.config.PresencePenalty,
|
||||
RepetitionPenalty: agent.config.RepetitionPenalty,
|
||||
LogitBias: agent.config.LogitBias,
|
||||
TopLogprobs: agent.config.TopLogprobs,
|
||||
MinP: agent.config.MinP,
|
||||
TopA: agent.config.TopA,
|
||||
Stream: false,
|
||||
}
|
||||
|
||||
return agent.client.FetchChatCompletions(request)
|
||||
}
|
||||
|
||||
func (agent RouterAgent) ChatStream(messages []MessageRequest, outputChan chan Response, processingChan chan interface{}, errChan chan error, ctx context.Context) {
|
||||
request := Request{
|
||||
Messages: messages,
|
||||
Model: agent.model,
|
||||
ResponseFormat: agent.config.ResponseFormat,
|
||||
Stop: agent.config.Stop,
|
||||
MaxTokens: agent.config.MaxTokens,
|
||||
Temperature: agent.config.Temperature,
|
||||
Tools: agent.config.Tools,
|
||||
ToolChoice: agent.config.ToolChoice,
|
||||
Seed: agent.config.Seed,
|
||||
TopP: agent.config.TopP,
|
||||
TopK: agent.config.TopK,
|
||||
FrequencyPenalty: agent.config.FrequencyPenalty,
|
||||
PresencePenalty: agent.config.PresencePenalty,
|
||||
RepetitionPenalty: agent.config.RepetitionPenalty,
|
||||
LogitBias: agent.config.LogitBias,
|
||||
TopLogprobs: agent.config.TopLogprobs,
|
||||
MinP: agent.config.MinP,
|
||||
TopA: agent.config.TopA,
|
||||
Stream: true,
|
||||
}
|
||||
|
||||
agent.client.FetchChatCompletionsStream(request, outputChan, processingChan, errChan, ctx)
|
||||
}
|
||||
|
||||
type RouterAgentChat struct {
|
||||
RouterAgent
|
||||
Messages []MessageRequest
|
||||
}
|
||||
|
||||
func NewRouterAgentChat(client *OpenRouterClient, model string, config RouterAgentConfig, system_prompt string) RouterAgentChat {
|
||||
return RouterAgentChat{
|
||||
RouterAgent: RouterAgent{
|
||||
client: client,
|
||||
model: model,
|
||||
config: config,
|
||||
},
|
||||
Messages: []MessageRequest{
|
||||
{
|
||||
Role: RoleSystem,
|
||||
Content: system_prompt,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (agent *RouterAgentChat) Chat(message string) error {
|
||||
agent.Messages = append(agent.Messages, MessageRequest{
|
||||
Role: RoleUser,
|
||||
Content: message,
|
||||
})
|
||||
request := Request{
|
||||
Messages: agent.Messages,
|
||||
Model: agent.model,
|
||||
ResponseFormat: agent.config.ResponseFormat,
|
||||
Stop: agent.config.Stop,
|
||||
MaxTokens: agent.config.MaxTokens,
|
||||
Temperature: agent.config.Temperature,
|
||||
Tools: agent.config.Tools,
|
||||
ToolChoice: agent.config.ToolChoice,
|
||||
Seed: agent.config.Seed,
|
||||
TopP: agent.config.TopP,
|
||||
TopK: agent.config.TopK,
|
||||
FrequencyPenalty: agent.config.FrequencyPenalty,
|
||||
PresencePenalty: agent.config.PresencePenalty,
|
||||
RepetitionPenalty: agent.config.RepetitionPenalty,
|
||||
LogitBias: agent.config.LogitBias,
|
||||
TopLogprobs: agent.config.TopLogprobs,
|
||||
MinP: agent.config.MinP,
|
||||
TopA: agent.config.TopA,
|
||||
Stream: false,
|
||||
}
|
||||
|
||||
response, err := agent.client.FetchChatCompletions(request)
|
||||
|
||||
agent.Messages = append(agent.Messages, MessageRequest{
|
||||
Role: RoleAssistant,
|
||||
Content: response.Choices[0].Message.Content,
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
188
internal/llm/openroute/route_client.go
Normal file
188
internal/llm/openroute/route_client.go
Normal file
@@ -0,0 +1,188 @@
|
||||
package openroute
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type OpenRouterClient struct {
|
||||
apiKey string
|
||||
apiURL string
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
func NewOpenRouterClient(apiKey string) *OpenRouterClient {
|
||||
return &OpenRouterClient{
|
||||
apiKey: apiKey,
|
||||
apiURL: "https://openrouter.ai/api/v1",
|
||||
httpClient: &http.Client{},
|
||||
}
|
||||
}
|
||||
|
||||
func NewOpenRouterClientFull(apiKey string, apiUrl string, client *http.Client) *OpenRouterClient {
|
||||
return &OpenRouterClient{
|
||||
apiKey: apiKey,
|
||||
apiURL: apiUrl,
|
||||
httpClient: client,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *OpenRouterClient) FetchChatCompletions(request Request) (*Response, error) {
|
||||
headers := map[string]string{
|
||||
"Authorization": "Bearer " + c.apiKey,
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
if request.Provider != nil {
|
||||
headers["HTTP-Referer"] = request.Provider.RefererURL
|
||||
headers["X-Title"] = request.Provider.SiteName
|
||||
}
|
||||
|
||||
body, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", fmt.Sprintf("%s/chat/completions", c.apiURL), bytes.NewBuffer(body))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for key, value := range headers {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
output, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
outputReponse := &Response{}
|
||||
err = json.Unmarshal(output, outputReponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return outputReponse, nil
|
||||
}
|
||||
|
||||
func (c *OpenRouterClient) FetchChatCompletionsStream(request Request, outputChan chan Response, processingChan chan interface{}, errChan chan error, ctx context.Context) {
|
||||
headers := map[string]string{
|
||||
"Authorization": "Bearer " + c.apiKey,
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
if request.Provider != nil {
|
||||
headers["HTTP-Referer"] = request.Provider.RefererURL
|
||||
headers["X-Title"] = request.Provider.SiteName
|
||||
}
|
||||
|
||||
body, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
close(errChan)
|
||||
close(outputChan)
|
||||
close(processingChan)
|
||||
return
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", fmt.Sprintf("%s/chat/completions", c.apiURL), bytes.NewBuffer(body))
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
close(errChan)
|
||||
close(outputChan)
|
||||
close(processingChan)
|
||||
return
|
||||
}
|
||||
|
||||
for key, value := range headers {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
close(errChan)
|
||||
close(outputChan)
|
||||
close(processingChan)
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer resp.Body.Close()
|
||||
|
||||
defer close(errChan)
|
||||
defer close(outputChan)
|
||||
defer close(processingChan)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
errChan <- fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
||||
return
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(resp.Body)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
errChan <- ctx.Err()
|
||||
close(errChan)
|
||||
close(outputChan)
|
||||
close(processingChan)
|
||||
return
|
||||
default:
|
||||
line, err := reader.ReadString('\n')
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, ":") {
|
||||
select {
|
||||
case processingChan <- true:
|
||||
case <-ctx.Done():
|
||||
errChan <- ctx.Err()
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if line != "" {
|
||||
if strings.Compare(line[6:], "[DONE]") == 0 {
|
||||
return
|
||||
}
|
||||
response := Response{}
|
||||
err = json.Unmarshal([]byte(line[6:]), &response)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
select {
|
||||
case outputChan <- response:
|
||||
case <-ctx.Done():
|
||||
errChan <- ctx.Err()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return
|
||||
}
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
Reference in New Issue
Block a user