feat(model): LLM 多供应商适配(Adapter/OpenAI 非流式+SSE 流式/per-role 路由/主备降级/多模态检测/调用记录)
This commit is contained in:
1 parent
51b2bdfba2
commit
d09ccc7570
9 files changed
+1285
No files matched your search
@@ -0,0 +1,137 @@
|
||||
// Package model provides a vendor-agnostic LLM adapter layer for Cyrene v2.
|
||||
//
|
||||
// It defines a normalized Message/Request/Response vocabulary, a single
|
||||
// Adapter interface implemented by OpenAIChatAdapter (which speaks the
|
||||
// OpenAI-compatible /chat/completions protocol used by OpenAI, DashScope/百炼,
|
||||
// local gateways and proxies), a per-role Router, an automatic fallback Chain,
|
||||
// multimodal (vision) detection, and per-call CallRecord accounting.
|
||||
//
|
||||
// The full tool loop (schema registration, argument binding, result re-feed) is
|
||||
// deferred to M2; this package only carries interface-level placeholders
|
||||
// (ToolSpec) so the wire contract is ready without executing any loop.
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
// Role identifies who authored a message. The values are vendor-agnostic and
|
||||
// translated to each provider's own role vocabulary by the adapter.
|
||||
type Role string
|
||||
|
||||
const (
|
||||
// RoleSystem is a system/instruction message.
|
||||
RoleSystem Role = "system"
|
||||
// RoleUser is an end-user message.
|
||||
RoleUser Role = "user"
|
||||
// RoleAssistant is an assistant (model) message.
|
||||
RoleAssistant Role = "assistant"
|
||||
// RoleTool is a tool-result message (reserved for the M2 tool loop).
|
||||
RoleTool Role = "tool"
|
||||
)
|
||||
|
||||
// ContentType describes the kind of payload inside a Content part.
|
||||
type ContentType string
|
||||
|
||||
const (
|
||||
// ContentTypeText is a plain-text content part.
|
||||
ContentTypeText ContentType = "text"
|
||||
// ContentTypeImage is an image content part.
|
||||
ContentTypeImage ContentType = "image_url"
|
||||
)
|
||||
|
||||
// Content is a single, possibly multimodal, part of a message.
|
||||
type Content struct {
|
||||
// Type distinguishes a text part from an image part.
|
||||
Type ContentType
|
||||
// Text is the text payload when Type == ContentTypeText.
|
||||
Text string
|
||||
// ImageURL is the image source when Type == ContentTypeImage. It may be a
|
||||
// data: URI or an http(s):// URL.
|
||||
ImageURL string
|
||||
}
|
||||
|
||||
// Message is a single conversation turn, normalized across providers.
|
||||
type Message struct {
|
||||
Role Role
|
||||
// Content carries one or more parts. A text-only message uses a single
|
||||
// ContentTypeText part.
|
||||
Content []Content
|
||||
// ToolCallID and ToolCallName are reserved as interface-level placeholders
|
||||
// for the M2 tool loop; they are ignored by current adapters.
|
||||
ToolCallID string
|
||||
ToolCallName string
|
||||
}
|
||||
|
||||
// TextMessage builds a text-only message.
|
||||
func TextMessage(role Role, text string) Message {
|
||||
return Message{Role: role, Content: []Content{{Type: ContentTypeText, Text: text}}}
|
||||
}
|
||||
|
||||
// ImageMessage builds a message carrying optional text plus an image. imageURL
|
||||
// may be a data: URI or an http(s):// URL. An empty text omits the text part.
|
||||
func ImageMessage(role Role, text, imageURL string) Message {
|
||||
parts := make([]Content, 0, 2)
|
||||
if text != "" {
|
||||
parts = append(parts, Content{Type: ContentTypeText, Text: text})
|
||||
}
|
||||
parts = append(parts, Content{Type: ContentTypeImage, ImageURL: imageURL})
|
||||
return Message{Role: role, Content: parts}
|
||||
}
|
||||
|
||||
// ToolSpec is an interface-level placeholder for a tool/function schema. The
|
||||
// full tool loop (registration, argument binding, result re-feed) is M2; here
|
||||
// it only lets a request advertise tools to the provider in the wire contract.
|
||||
type ToolSpec struct {
|
||||
Name string
|
||||
Description string
|
||||
// Parameters is the JSON Schema for the tool arguments. Populated from M2.
|
||||
Parameters any
|
||||
}
|
||||
|
||||
// Request is a completion request, normalized across providers.
|
||||
type Request struct {
|
||||
// Model overrides the adapter's configured default model. Empty means the
|
||||
// adapter default (or the chain step model) applies.
|
||||
Model string
|
||||
Messages []Message
|
||||
// Temperature is the sampling temperature. nil means the provider default.
|
||||
Temperature *float64
|
||||
// MaxTokens caps the generated tokens. Zero means the provider default.
|
||||
MaxTokens int
|
||||
// Purpose labels the call for CallRecord accounting (e.g. "chat").
|
||||
Purpose string
|
||||
// Tools is the interface-level placeholder for M2 function calling.
|
||||
Tools []ToolSpec
|
||||
}
|
||||
|
||||
// Response is a normalized completion result.
|
||||
type Response struct {
|
||||
// Model is the model that produced the response.
|
||||
Model string
|
||||
Content string
|
||||
// Message is the normalized assistant message.
|
||||
Message Message
|
||||
// PromptTokens, CompletionTokens and TotalTokens report provider usage when
|
||||
// available; zero when the provider does not return it.
|
||||
PromptTokens int
|
||||
CompletionTokens int
|
||||
TotalTokens int
|
||||
}
|
||||
|
||||
// CallRecord describes a single successfully completed LLM call, for the M9
|
||||
// monitor/frontend. A failed attempt emits no record.
|
||||
type CallRecord struct {
|
||||
// Model is the model that served the request.
|
||||
Model string
|
||||
// Purpose labels what the call was for.
|
||||
Purpose string
|
||||
// Tokens is the total token consumption reported by the provider.
|
||||
Tokens int
|
||||
// TookMs is the end-to-end call latency in milliseconds.
|
||||
TookMs int64
|
||||
}
|
||||
|
||||
// Options carries per-call knobs layered on top of the Request.
|
||||
type Options struct {
|
||||
// Timeout bounds a single HTTP call. Zero uses the adapter client timeout.
|
||||
Timeout time.Duration
|
||||
}
|
||||
Reference in new issue
Block a user