From cb5ac07e3cf336dca9fc23360a95a19e21afb221 Mon Sep 17 00:00:00 2001 From: LoveLosita <2810873701@qq.com> Date: Thu, 5 Mar 2026 21:44:22 +0800 Subject: [PATCH] =?UTF-8?q?Version:=200.4.2.dev.260305=20feat:=20?= =?UTF-8?q?=F0=9F=A7=A0=20=E6=94=AF=E6=8C=81=E5=88=87=E6=8D=A2=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E6=80=9D=E8=80=83=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 新增模型思考开关配置,支持动态控制模型是否启用思考模式 --- backend/agent/graph.go | 34 ++++++++++++++++++++++++++++------ backend/api/agent.go | 2 +- backend/model/agent.go | 3 ++- backend/service/agent.go | 4 ++-- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/backend/agent/graph.go b/backend/agent/graph.go index e6a5891..49073d1 100644 --- a/backend/agent/graph.go +++ b/backend/agent/graph.go @@ -8,6 +8,7 @@ import ( "github.com/cloudwego/eino-ext/components/model/ark" "github.com/cloudwego/eino/schema" + arkModel "github.com/volcengine/volcengine-go-sdk/service/arkruntime/model" ) // StreamResponse 专为 Apifox/前端 识别设计的极简结构 @@ -31,10 +32,25 @@ func ToStreamResponseDTO(chunk *schema.Message) StreamResponse { return dto } +func ToStreamReasoningResponseDTO(chunk *schema.Message) StreamResponse { + var dto StreamResponse + dto.Choices = append(dto.Choices, struct { + Delta struct { + Content string `json:"content"` + } `json:"delta"` + }{}) + dto.Choices[0].Delta.Content = chunk.ReasoningContent + return dto +} + // ToOpenAIStream 负责将 Eino 的内部 Chunk 转换为 OpenAI 兼容的 data: {JSON} 字符串 func ToOpenAIStream(chunk *schema.Message) (string, error) { - dto := ToStreamResponseDTO(chunk) - + var dto StreamResponse + if chunk.ReasoningContent != "" { + dto = ToStreamReasoningResponseDTO(chunk) + } else { + dto = ToStreamResponseDTO(chunk) + } jsonBytes, err := json.Marshal(dto) if err != nil { return "", err @@ -43,7 +59,7 @@ func ToOpenAIStream(chunk *schema.Message) (string, error) { return string(jsonBytes), nil } -func StreamChat(ctx context.Context, llm *ark.ChatModel, userInput string, chatHistory []*schema.Message, outChan chan<- string) (string, error) { +func StreamChat(ctx context.Context, llm *ark.ChatModel, userInput string, ifThinking bool, chatHistory []*schema.Message, outChan chan<- string) (string, error) { // 1. 组装消息 messages := make([]*schema.Message, 0) // A. 塞入 System Message (人设) @@ -55,7 +71,13 @@ func StreamChat(ctx context.Context, llm *ark.ChatModel, userInput string, chatH // C. 塞入用户当前的消息 (当前需求) messages = append(messages, schema.UserMessage(userInput)) // 2. 调用流式接口 - reader, err := llm.Stream(ctx, messages) + var thinking *ark.Thinking + if ifThinking { + thinking = &arkModel.Thinking{Type: arkModel.ThinkingTypeEnabled} + } else { + thinking = &arkModel.Thinking{Type: arkModel.ThinkingTypeDisabled} + } + reader, err := llm.Stream(ctx, messages, ark.WithThinking(thinking)) if err != nil { return "", err } @@ -71,9 +93,9 @@ func StreamChat(ctx context.Context, llm *ark.ChatModel, userInput string, chatH if err != nil { return "", err } - if chunk.Content == "" { + /*if chunk.Content == "" { // 过滤掉空内容,避免发送无效消息 continue - } + }*/ fullText.WriteString(chunk.Content) // 将内容发送到通道中供前端消费 retChuck, err := ToOpenAIStream(chunk) diff --git a/backend/api/agent.go b/backend/api/agent.go index edfa2b3..7322804 100644 --- a/backend/api/agent.go +++ b/backend/api/agent.go @@ -35,7 +35,7 @@ func (api *AgentHandler) ChatAgent(c *gin.Context) { } userID := c.GetInt("user_id") // 从上下文中获取用户 ID // 3. 调用 Service 层的聊天方法,获取输出通道和错误通道 - outChan, errChan := api.svc.AgentChat(c.Request.Context(), req.Message, userID, req.ConversationID) + outChan, errChan := api.svc.AgentChat(c.Request.Context(), req.Message, req.Thinking, userID, req.ConversationID) // 4. 循环转发消息/错误 c.Stream(func(w io.Writer) bool { select { diff --git a/backend/model/agent.go b/backend/model/agent.go index 11dbac1..da4ff5b 100644 --- a/backend/model/agent.go +++ b/backend/model/agent.go @@ -5,7 +5,8 @@ import "time" type UserSendMessageRequest struct { ConversationID string `json:"conversation_id,omitempty"` // 可选,指定对话 ID Message string `json:"message" binding:"required"` - Model string `json:"model,omitempty"` // 可选,指定使用的模型 + Model string `json:"model,omitempty"` // 可选,指定使用的模型 + Thinking bool `json:"thinking,omitempty"` // 可选,是否开启思考模式 } type SSEResponse struct { diff --git a/backend/service/agent.go b/backend/service/agent.go index 223f75e..2b23d53 100644 --- a/backend/service/agent.go +++ b/backend/service/agent.go @@ -22,7 +22,7 @@ func NewAgentService(aiHub *inits.AIHub, repo *dao.AgentDAO) *AgentService { } } -func (s *AgentService) AgentChat(ctx context.Context, userMessage string, userID int, chatID string) (<-chan string, <-chan error) { +func (s *AgentService) AgentChat(ctx context.Context, userMessage string, ifThinking bool, userID int, chatID string) (<-chan string, <-chan error) { //1. 创建一个输出通道 outChan := make(chan string, 5) errChan := make(chan error, 1) @@ -69,7 +69,7 @@ func (s *AgentService) AgentChat(ctx context.Context, userMessage string, userID go func() { defer close(outChan) // 确保在函数结束时关闭通道 //3. 调用 StreamChat 函数进行流式聊天 - fullText, err := agent.StreamChat(ctx, s.AIHub.Worker, userMessage, chatHistory, outChan) + fullText, err := agent.StreamChat(ctx, s.AIHub.Worker, userMessage, ifThinking, chatHistory, outChan) if err != nil { errChan <- err return