110 lines
4.5 KiB
Go
110 lines
4.5 KiB
Go
/*
|
|
* Copyright 2024 CloudWeGo 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 model
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/cloudwego/eino/schema"
|
|
)
|
|
|
|
// messageType is the sealed type constraint for message types used in BaseModel.
|
|
// Only *schema.Message and *schema.AgenticMessage satisfy this constraint.
|
|
type messageType interface {
|
|
*schema.Message | *schema.AgenticMessage
|
|
}
|
|
|
|
// BaseModel is the generic base model interface parameterized by message type M.
|
|
// It exposes two modes of interaction:
|
|
// - [BaseModel.Generate]: blocks until the model returns a complete response.
|
|
// - [BaseModel.Stream]: returns a [schema.StreamReader] that yields message
|
|
// chunks incrementally as the model generates them.
|
|
type BaseModel[M messageType] interface {
|
|
Generate(ctx context.Context, input []M, opts ...Option) (M, error)
|
|
Stream(ctx context.Context, input []M, opts ...Option) (*schema.StreamReader[M], error)
|
|
}
|
|
|
|
// BaseChatModel is a backward-compatible type alias for BaseModel specialized
|
|
// with *schema.Message. All existing code using model.BaseChatModel continues
|
|
// to work without modification.
|
|
//
|
|
// It exposes two modes of interaction:
|
|
// - [BaseChatModel.Generate]: blocks until the model returns a complete response.
|
|
// - [BaseChatModel.Stream]: returns a [schema.StreamReader] that yields message
|
|
// chunks incrementally as the model generates them.
|
|
//
|
|
// The input is a slice of [schema.Message] representing the conversation history.
|
|
// Messages carry a role (system, user, assistant, tool) and support multimodal
|
|
// content (text, images, audio, video). Tool messages must include a ToolCallID
|
|
// that correlates them with a prior assistant tool-call message.
|
|
//
|
|
// Stream usage — the caller is responsible for closing the reader:
|
|
//
|
|
// reader, err := m.Stream(ctx, messages)
|
|
// if err != nil { ... }
|
|
// defer reader.Close()
|
|
// for {
|
|
// chunk, err := reader.Recv()
|
|
// if errors.Is(err, io.EOF) { break }
|
|
// if err != nil { ... }
|
|
// // handle chunk
|
|
// }
|
|
//
|
|
// Note: a [schema.StreamReader] can only be read once. If multiple consumers
|
|
// need the stream, it must be copied before reading.
|
|
//
|
|
//go:generate mockgen -destination ../../internal/mock/components/model/ChatModel_mock.go --package model github.com/cloudwego/eino/components/model BaseChatModel,ChatModel,ToolCallingChatModel
|
|
type BaseChatModel = BaseModel[*schema.Message]
|
|
|
|
// Deprecated: Use [ToolCallingChatModel] instead.
|
|
//
|
|
// ChatModel extends [BaseChatModel] with tool binding via [ChatModel.BindTools].
|
|
// BindTools mutates the instance in place, which causes a race condition when
|
|
// the same instance is used concurrently: one goroutine's tool list can
|
|
// overwrite another's. Prefer [ToolCallingChatModel.WithTools], which returns
|
|
// a new immutable instance and is safe for concurrent use.
|
|
type ChatModel interface {
|
|
BaseChatModel
|
|
|
|
// BindTools bind tools to the model.
|
|
// BindTools before requesting ChatModel generally.
|
|
// notice the non-atomic problem of BindTools and Generate.
|
|
BindTools(tools []*schema.ToolInfo) error
|
|
}
|
|
|
|
// ToolCallingChatModel extends [BaseChatModel] with safe tool binding.
|
|
//
|
|
// Unlike the deprecated [ChatModel.BindTools], [ToolCallingChatModel.WithTools]
|
|
// does not mutate the receiver — it returns a new instance with the given tools
|
|
// attached. This makes it safe to share a base model instance across goroutines
|
|
// and derive per-request variants with different tool sets:
|
|
//
|
|
// base, _ := openai.NewChatModel(ctx, cfg) // shared, no tools
|
|
// withSearch, _ := base.WithTools([]*schema.ToolInfo{searchTool})
|
|
// withCalc, _ := base.WithTools([]*schema.ToolInfo{calcTool})
|
|
type ToolCallingChatModel interface {
|
|
BaseChatModel
|
|
|
|
WithTools(tools []*schema.ToolInfo) (ToolCallingChatModel, error)
|
|
}
|
|
|
|
// AgenticModel is a type alias for BaseModel specialized with
|
|
// *schema.AgenticMessage. Unlike ToolCallingChatModel, agentic models do NOT
|
|
// expose a WithTools method; tools are passed at request time via the
|
|
// model.WithTools option, consistent with how ChatModelAgent binds tools.
|
|
type AgenticModel = BaseModel[*schema.AgenticMessage]
|