Adding Ollama as a conversation component for local dev/running of LLMs (#3688)
Signed-off-by: Emmanuel Auffray <emmanuel.auffray@gmail.com> Co-authored-by: Mike Nguyen <hey@mike.ee> Co-authored-by: Yaron Schneider <schneider.yaron@live.com>
This commit is contained in:
parent
b348969d81
commit
47947d8770
|
@ -0,0 +1,23 @@
|
|||
# yaml-language-server: $schema=../../../component-metadata-schema.json
|
||||
schemaVersion: v1
|
||||
type: conversation
|
||||
name: ollama
|
||||
version: v1
|
||||
status: alpha
|
||||
title: "Ollama"
|
||||
urls:
|
||||
- title: Reference
|
||||
url: https://docs.dapr.io/reference/components-reference/supported-conversation/ollama/
|
||||
metadata:
|
||||
- name: model
|
||||
required: false
|
||||
description: |
|
||||
The Ollama LLM to use. Defaults to llama3.2:latest
|
||||
type: string
|
||||
example: 'llama3.2:latest'
|
||||
- name: cacheTTL
|
||||
required: false
|
||||
description: |
|
||||
A time-to-live value for a prompt cache to expire. Uses Golang durations
|
||||
type: string
|
||||
example: '10m'
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
Copyright 2024 The Dapr Authors
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package ollama
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
"github.com/dapr/components-contrib/conversation"
|
||||
"github.com/dapr/components-contrib/metadata"
|
||||
"github.com/dapr/kit/logger"
|
||||
kmeta "github.com/dapr/kit/metadata"
|
||||
|
||||
"github.com/tmc/langchaingo/llms"
|
||||
"github.com/tmc/langchaingo/llms/ollama"
|
||||
)
|
||||
|
||||
type Ollama struct {
|
||||
llm llms.Model
|
||||
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
func NewOllama(logger logger.Logger) conversation.Conversation {
|
||||
o := &Ollama{
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
const defaultModel = "llama3.2:latest"
|
||||
|
||||
func (o *Ollama) Init(ctx context.Context, meta conversation.Metadata) error {
|
||||
md := conversation.LangchainMetadata{}
|
||||
err := kmeta.DecodeMetadata(meta.Properties, &md)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
model := defaultModel
|
||||
if md.Model != "" {
|
||||
model = md.Model
|
||||
}
|
||||
|
||||
llm, err := ollama.New(
|
||||
ollama.WithModel(model),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.llm = llm
|
||||
|
||||
if md.CacheTTL != "" {
|
||||
cachedModel, cacheErr := conversation.CacheModel(ctx, md.CacheTTL, o.llm)
|
||||
if cacheErr != nil {
|
||||
return cacheErr
|
||||
}
|
||||
|
||||
o.llm = cachedModel
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Ollama) GetComponentMetadata() (metadataInfo metadata.MetadataMap) {
|
||||
metadataStruct := conversation.LangchainMetadata{}
|
||||
metadata.GetMetadataInfoFromStructType(reflect.TypeOf(metadataStruct), &metadataInfo, metadata.ConversationType)
|
||||
return
|
||||
}
|
||||
|
||||
func (o *Ollama) Converse(ctx context.Context, r *conversation.ConversationRequest) (res *conversation.ConversationResponse, err error) {
|
||||
messages := make([]llms.MessageContent, 0, len(r.Inputs))
|
||||
|
||||
for _, input := range r.Inputs {
|
||||
role := conversation.ConvertLangchainRole(input.Role)
|
||||
|
||||
messages = append(messages, llms.MessageContent{
|
||||
Role: role,
|
||||
Parts: []llms.ContentPart{
|
||||
llms.TextPart(input.Message),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
opts := []llms.CallOption{}
|
||||
|
||||
if r.Temperature > 0 {
|
||||
opts = append(opts, conversation.LangchainTemperature(r.Temperature))
|
||||
}
|
||||
|
||||
resp, err := o.llm.GenerateContent(ctx, messages, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
outputs := make([]conversation.ConversationResult, 0, len(resp.Choices))
|
||||
|
||||
for i := range resp.Choices {
|
||||
outputs = append(outputs, conversation.ConversationResult{
|
||||
Result: resp.Choices[i].Content,
|
||||
Parameters: r.Parameters,
|
||||
})
|
||||
}
|
||||
|
||||
res = &conversation.ConversationResponse{
|
||||
Outputs: outputs,
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (o *Ollama) Close() error {
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue