新增 TakeBusinessFields、WriteBusinessFields、SetByPath 与 GetByPath 等工具,支持按映射路径写入请求体与解析响应,并更新相关依赖。
102 lines
2.7 KiB
Go
102 lines
2.7 KiB
Go
package service
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
|
|
modelUtils "model-gateway/service/utils"
|
|
|
|
"github.com/gogf/gf/v2/util/gconv"
|
|
)
|
|
|
|
// streamToolCallAcc 流式 tool_call 按 index 累加的碎片(OpenAI 兼容 delta 格式)
|
|
type streamToolCallAcc struct {
|
|
id string
|
|
typ string
|
|
fnName string
|
|
fnArgs strings.Builder
|
|
}
|
|
|
|
// streamToolCallDelta OpenAI 兼容流式 tool_call 增量片段,字段名集中于此
|
|
type streamToolCallDelta struct {
|
|
Index int `json:"index"`
|
|
Id string `json:"id"`
|
|
Type string `json:"type"`
|
|
Function struct {
|
|
Name string `json:"name"`
|
|
Arguments string `json:"arguments"`
|
|
} `json:"function"`
|
|
}
|
|
|
|
// toStreamToolCallDeltas 把 JSON 反序列化的 any 数组在边界转成强类型片段
|
|
func toStreamToolCallDeltas(rawCalls []any) []streamToolCallDelta {
|
|
var deltas []streamToolCallDelta
|
|
if err := gconv.Structs(rawCalls, &deltas); err != nil {
|
|
return nil
|
|
}
|
|
return deltas
|
|
}
|
|
|
|
// accumulateStreamToolCallsByPath 按配置路径从 chunk 读取 tool_calls 数组并累加。
|
|
// 路径未命中或值非数组时无副作用(不创建任何槽位)。
|
|
func accumulateStreamToolCallsByPath(chunk map[string]any, toolsPath string, acc map[int]*streamToolCallAcc) {
|
|
raw := modelUtils.GetByPathValue(chunk, modelUtils.CleanFieldPath(toolsPath))
|
|
rawCalls, _ := raw.([]any)
|
|
accumulateToolCallFragments(toStreamToolCallDeltas(rawCalls), acc)
|
|
}
|
|
|
|
// accumulateToolCallFragments 按 index 累加 tool_calls 增量片段:
|
|
// id/type/function.name 首片段补齐,function.arguments 为字符串片段需按 index 拼接。
|
|
func accumulateToolCallFragments(rawCalls []streamToolCallDelta, acc map[int]*streamToolCallAcc) {
|
|
for _, d := range rawCalls {
|
|
slot, ok := acc[d.Index]
|
|
if !ok {
|
|
slot = &streamToolCallAcc{}
|
|
acc[d.Index] = slot
|
|
}
|
|
if d.Id != "" {
|
|
slot.id = d.Id
|
|
}
|
|
if d.Type != "" {
|
|
slot.typ = d.Type
|
|
}
|
|
if d.Function.Name != "" {
|
|
slot.fnName = d.Function.Name
|
|
}
|
|
slot.fnArgs.WriteString(d.Function.Arguments)
|
|
}
|
|
}
|
|
|
|
// finalizeStreamToolCalls 把累加结果按 index 升序转为 []map[string]any,形状对齐 dto.ModelTool。
|
|
// 无有效工具返回 nil。
|
|
func finalizeStreamToolCalls(acc map[int]*streamToolCallAcc) []map[string]any {
|
|
if len(acc) == 0 {
|
|
return nil
|
|
}
|
|
idx := make([]int, 0, len(acc))
|
|
for i := range acc {
|
|
idx = append(idx, i)
|
|
}
|
|
sort.Ints(idx)
|
|
tools := make([]map[string]any, 0, len(idx))
|
|
for _, i := range idx {
|
|
s := acc[i]
|
|
fn := map[string]any{}
|
|
if s.fnName != "" {
|
|
fn["name"] = s.fnName
|
|
}
|
|
if s.fnArgs.Len() > 0 {
|
|
fn["arguments"] = s.fnArgs.String()
|
|
}
|
|
tool := map[string]any{"function": fn}
|
|
if s.id != "" {
|
|
tool["id"] = s.id
|
|
}
|
|
if s.typ != "" {
|
|
tool["type"] = s.typ
|
|
}
|
|
tools = append(tools, tool)
|
|
}
|
|
return tools
|
|
}
|