Files
2026-07-13 12:49:10 +08:00

256 lines
7.7 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 "github.com/cloudwego/eino/schema"
// Options is the common options for the model.
type Options struct {
// Temperature is the temperature for the model, which controls the randomness of the model.
Temperature *float32
// Model is the model name.
Model *string
// TopP is the top p for the model, which controls the diversity of the model.
TopP *float32
// Tools is a list of tools the model may call.
Tools []*schema.ToolInfo
// DeferredTools is a list of tools to be registered with defer_loading=true
// for the model's built-in (server-side) tool search capability.
// These tools are sent to the model API but not loaded into context upfront —
// only their names and descriptions are visible to the model. The model's
// built-in tool search tool searches through them and loads matching ones
// on demand.
DeferredTools []*schema.ToolInfo
ToolSearchTool *schema.ToolInfo
// MaxTokens is the max number of tokens, if reached the max tokens, the model will stop generating, and mostly return a finish reason of "length".
MaxTokens *int
// Stop is the stop words for the model, which controls the stopping condition of the model.
Stop []string
// Options only available for chat model.
// ToolChoice controls which tool is called by the model.
ToolChoice *schema.ToolChoice
// AllowedToolNames specifies a list of tool names that the model is allowed to call.
// This allows for constraining the model to a specific subset of the available tools.
AllowedToolNames []string
// Options only available for agentic model.
// AgenticToolChoice controls how the agentic model calls tools.
AgenticToolChoice *schema.AgenticToolChoice
}
// Option is a call-time option for a ChatModel. Options are immutable and
// composable: each Option carries either a common-option setter (applied via
// [GetCommonOptions]) or an implementation-specific setter (applied via
// [GetImplSpecificOptions]), never both.
type Option struct {
apply func(opts *Options)
implSpecificOptFn any
}
// WithTemperature is the option to set the temperature for the model.
func WithTemperature(temperature float32) Option {
return Option{
apply: func(opts *Options) {
opts.Temperature = &temperature
},
}
}
// WithMaxTokens is the option to set the max tokens for the model.
func WithMaxTokens(maxTokens int) Option {
return Option{
apply: func(opts *Options) {
opts.MaxTokens = &maxTokens
},
}
}
// WithModel is the option to set the model name.
func WithModel(name string) Option {
return Option{
apply: func(opts *Options) {
opts.Model = &name
},
}
}
// WithTopP is the option to set the top p for the model.
func WithTopP(topP float32) Option {
return Option{
apply: func(opts *Options) {
opts.TopP = &topP
},
}
}
// WithStop is the option to set the stop words for the model.
func WithStop(stop []string) Option {
return Option{
apply: func(opts *Options) {
opts.Stop = stop
},
}
}
// WithTools is the option to set tools for the model.
func WithTools(tools []*schema.ToolInfo) Option {
if tools == nil {
tools = []*schema.ToolInfo{}
}
return Option{
apply: func(opts *Options) {
opts.Tools = tools
},
}
}
// WithToolSearchTool is the option to register a tool search tool with the model.
// When set, the model uses this tool to discover and load deferred tools on demand.
// Note: The tool search tool should NOT be included in WithTools.
func WithToolSearchTool(tool *schema.ToolInfo) Option {
return Option{
apply: func(opts *Options) {
opts.ToolSearchTool = tool
},
}
}
// WithDeferredTools is the option to set deferred tools for the model's
// built-in (server-side) tool search. These tools are registered with
// defer_loading=true so the model can discover and load them on demand
// via its native tool search capability.
// Note: Deferred tools should NOT be included in WithTools.
func WithDeferredTools(tools []*schema.ToolInfo) Option {
if tools == nil {
tools = []*schema.ToolInfo{}
}
return Option{
apply: func(opts *Options) {
opts.DeferredTools = tools
},
}
}
// WithToolChoice sets the tool choice for the model. It also allows for providing a list of
// tool names to constrain the model to a specific subset of the available tools.
// Only available for ChatModel.
func WithToolChoice(toolChoice schema.ToolChoice, allowedToolNames ...string) Option {
return Option{
apply: func(opts *Options) {
opts.ToolChoice = &toolChoice
opts.AllowedToolNames = allowedToolNames
},
}
}
// WithAgenticToolChoice is the option to set tool choice for the agentic model.
// Only available for AgenticModel.
func WithAgenticToolChoice(toolChoice *schema.AgenticToolChoice) Option {
return Option{
apply: func(opts *Options) {
opts.AgenticToolChoice = toolChoice
},
}
}
// WrapImplSpecificOptFn is the option to wrap the implementation specific option function.
// WrapImplSpecificOptFn wraps an implementation-specific option function into
// an [Option] so it can be passed alongside standard options.
//
// This is intended for ChatModel implementors, not callers. Define a typed
// setter for your own config struct and expose it as an Option:
//
// // In your implementation package:
// func WithMyParam(v string) model.Option {
// return model.WrapImplSpecificOptFn(func(o *MyOptions) {
// o.MyParam = v
// })
// }
//
// Callers can then mix standard and implementation-specific options freely:
//
// model.Generate(ctx, msgs,
// model.WithTemperature(0.7),
// mypkg.WithMyParam("value"),
// )
func WrapImplSpecificOptFn[T any](optFn func(*T)) Option {
return Option{
implSpecificOptFn: optFn,
}
}
// GetCommonOptions extracts standard [Options] from an Option list, merging
// them onto base. If base is nil, a zero-value Options is used.
//
// Implementors must call this to honour options passed by callers:
//
// func (m *MyModel) Generate(ctx context.Context, input []*schema.Message, opts ...model.Option) (*schema.Message, error) {
// options := model.GetCommonOptions(&model.Options{Temperature: &m.defaultTemp}, opts...)
// // use options.Temperature, options.Tools, etc.
// }
func GetCommonOptions(base *Options, opts ...Option) *Options {
if base == nil {
base = &Options{}
}
for i := range opts {
opt := opts[i]
if opt.apply != nil {
opt.apply(base)
}
}
return base
}
// GetImplSpecificOptions extracts implementation-specific options from an
// Option list, merging them onto base. If base is nil, a zero-value T is used.
//
// Call this alongside [GetCommonOptions] to support both standard and custom
// options in your implementation:
//
// type MyOptions struct { MyParam string }
//
// func (m *MyModel) Generate(ctx context.Context, input []*schema.Message, opts ...model.Option) (*schema.Message, error) {
// common := model.GetCommonOptions(nil, opts...)
// myOpts := model.GetImplSpecificOptions(&MyOptions{MyParam: "default"}, opts...)
// // use common.Temperature, myOpts.MyParam, etc.
// }
func GetImplSpecificOptions[T any](base *T, opts ...Option) *T {
if base == nil {
base = new(T)
}
for i := range opts {
opt := opts[i]
if opt.implSpecificOptFn != nil {
optFn, ok := opt.implSpecificOptFn.(func(*T))
if ok {
optFn(base)
}
}
}
return base
}