Table of Content
A comprehensive article: Practical examples of multi-round dialogue in large model application development

Updated on:July-08th-2025
Recommendation
In-depth exploration of the challenges and solutions of multi-round dialogue technology in practical applications.
Core content:
1. The complexity of business scenarios faced by multi-round dialogue technology
2. The core process and technical points of implementing a multi-round dialogue system
3. Code implementation case of a multi-round dialogue system under the Golang framework
Yang Fangxian
Founder of 53AI/Most Valuable Expert of Tencent Cloud (TVP)
1. Problems in actual implementation scenarios
There are a series of problems in the implementation of multi-round dialogue in business scenarios:
Complexity of business scenarios
Limitations of model capabilities
Complexity of engineering implementation
2. Core Process of Implementation
From an engineering perspective, the core of implementing a multi-round dialogue system needs to be carried out from the following aspects:
Contextual control: set timeouts and cancel where appropriate. Initialize the request pipeline: create a model response channel and an interrupt listening channel. Pre-processing: - Creating an Initial Message Record
- Conduct security audits on user issues
Interrupt monitoring: Create a coroutine to monitor the user's interrupt request. Memory Network: Stores and indexes historical conversations. Model building prompt words: prompt words required to build the AI model based on the request content. Call the model to get the answer: Asynchronously call the AI model and send the response to the output channel. Handling model responses: Using select to monitor multiple channels Handling timeouts Process the data packet returned by the model Handling user interrupt requests End logic: Update final message content and status Recording session history Set output information
3. Code Implementation
The following is the practice of Kratos framework and SSE push technology based on Golang .
Core processing flow:
func (f *FreeAskUsecase) freeAskHandle(ctx context.Context, req *FreeAskReq, output *FreeAskResp) { // Context control ctx, cancel := context.WithTimeout(ctx, time.Minute*2) defer cancel() // Initialize request pipeline modelCh := make(chan *ModelResponse, 10) interruptCh := make(chan struct{}, 1) var msgIdStr string var msg *Message // Pre-processing: create message, security audit, etc. msg, err := f.createInitialMessage(ctx, req) if err != nil { f.log.Errorf("Failed to create initial message: %v", err) output.Status = StatusFailed output.Message = "Failed to create message" return } msgIdStr = msg.Msg.Id output.MsgId = msgIdStr // Get historical conversation records chatHistory, err := f.repo.GetRecentChatHistory(ctx, req.TalId, req.SubjectId, 2) if err != nil { f.log.Warnf("Failed to get historical conversation records: %v", err) // Continue processing, does not affect the main process } // Build message history messages := make([]Message, 0, len(chatHistory)*2+1) // System prompt words systemPrompt := f.buildSystemPrompt(req.SubjectId, intent, intentDetails) messages = append(messages, Message{ Role: "system", // System role Content: systemPrompt, }) // Add historical conversations for _, chat := range chatHistory { // User question messages = append(messages, Message{ Role: "user", // User role Content: chat.Question, }) // AI answers messages = append(messages, Message{ Role: "assistant", // Model role Content: chat.Answer, }) } // Add current question messages = append(messages, Message{ Role: "user", Content: req.Question, }) // User intent recognition intent, intentDetails := f.recognizeUserIntent(ctx, req.Question) f.log.Infof("User intent recognition result: %s, details: %+v", intent, intentDetails) // Handle special requests according to intent if f.handleSpecialIntent(ctx, intent, intentDetails, req, output) { // If the special intent has been processed, return directly return } // Security audit safeResult, err := f.safetyCheck(ctx, req.Question) if err != nil || !safeResult.IsSafe { f.log.Errorf("Content security audit failed: } prompt, err := f.buildPromptWithOptions(ctx, req, promptOptions) if err != nil { f.log.Errorf("Failed to build prompt word: %v", err) output.Status = StatusFailed output.Message = "System processing exception" return } // Create DeepSeek-R1 model request modelRequest := &DeepSeekModelRequest{ Model: "deepseek-r1", Messages: messages, MaxTokens: 2048, Temperature: 0.7, Stream: true,// Streaming output } // Build model context modelCtx, modelCancel := context.WithCancel(ctx) defer modelCancel() // Add interrupt processing go func() { select { case <-interruptCh: // Receive interrupt signal and cancel model request modelCancel() case <-ctx.Done(): // Context has ended return } }() // Create response channel modelCh := make(chan *DeepSeekResponse, 10) // Asynchronous call model go func() { defer close(modelCh) // Call DeepSeek-R1 model for streaming generation err := f.deepSeekClient.GenerateStream(modelCtx, modelRequest, func(chunk *DeepSeekChunk) error { if chunk.Error != nil { modelCh <- &DeepSeekResponse{ Error: chunk.Error, } return chunk.Error } // Process model streaming response modelCh <- &DeepSeekResponse{ Content: chunk.Content, IsFinal: chunk.IsFinal, ToolCalls: chunk.ToolCalls, GeneratedText: chunk.GeneratedText, Usage: chunk.Usage, } return nil }) if err != nil && !errors.Is(err, context.Canceled) { f.log.Errorf("DeepSeek-R1 model call failed: %v", err) modelCh <- &DeepSeekResponse{ Error: err, } } }() // 5. Process model response var fullContent strings.Builder isFirstChunk := true for { select { case <-ctx.Done(): // Processing timeout f.log.Warnf("Request processing timeout: %s", msgIdStr) output.Status = StatusTimeout output.Message = "Processing timeout, please try again later" // Send timeout event via SSE sseWriter.WriteEvent(&SSEEvent{ Event: "timeout", Data: map[string]interface{}{ "msg_id": msgIdStr, "message": "Processing timeout, please try again later", }, }) // Update message status f.repo.UpdateMessageStatus(ctx, msgIdStr, MessageStatusFailed) return case resp, ok := <-modelCh: if !ok { // Processing response end goto END } // Processing model returned error if resp.Error != nil { f.log.Errorf("Model returns error: %v", resp.Error) output.Status = StatusFailed output.Message = "AI failed to generate answer" // Send error event via SSE sseWriter.WriteEvent(&SSEEvent{ Event: "error", Data: map[string]interface{}{ "msg_id": msgIdStr, "message": "AI failed to generate answer", }, }) f.repo.UpdateMessageStatus(ctx, msgIdStr,MessageStatusFailed) return } // Process the data packet returned by the model // Append content, security check, send to the client, etc. content := resp.Content // Safety check each fragment if len(content) > 0 { safeResult, _ := f.safetyCheck(ctx, content) if !safeResult.IsSafe { f.log.Warnf("The model reply content has security risks: %s", content) content = "Sorry, I can't provide an answer in this regard." } } // Append to full content fullContent.WriteString(content) // If it is the first data packet, update the message status to in progress if isFirstChunk { isFirstChunk = false f.repo.UpdateMessageStatus(ctx, msgIdStr, MessageStatusInProgress) // Return the initial response to the client output.Status = StatusSuccess output.AnswerBegin = content // Send start event via SSE sseWriter.WriteEvent(&SSEEvent{ Event: "answer_begin", Data: map[string]interface{}{ "msg_id": msgIdStr, "content": content, }, }) } else { // Not the first data packet, send the content fragment through SSE sseWriter.WriteEvent(&SSEEvent{ Event: "answer_chunk", Data: map[string]interface{}{ "msg_id": msgIdStr, "content": content, }, }) } // If the response contains a special tag, handle special logic if resp.HasSpecialFunction { f.handleSpecialFunction(ctx, resp.SpecialFunction, msgIdStr, req.TalId, sseWriter) } case _, ok := <-interruptCh: if !ok { continue } // Handle user interrupt f.log.Infof("User interrupt request: %s", msgIdStr) msg.Msg.IsInterrupt = 1 // Send interrupt event through SSE sseWriter.WriteEvent(&SSEEvent{ Event: "interrupted", Data: map[string]interface{}{ "msg_id": msgIdStr, }, }) f.handelInterrupt(ctx, msgIdStr, msg.SubjectId) goto END } } END: // Processing end logic // Generate prompt words, update messages, etc. finalContent := fullContent.String() // Update final message content and status err = f.repo.UpdateMessageContent(ctx, msgIdStr, finalContent) if err != nil { f.log.Errorf("Failed to update message content: %v", err) } if msg.Msg.IsInterrupt == 0 { // End normally f.repo.UpdateMessageStatus(ctx, msgIdStr, MessageStatusCompleted) //Send completion event sseWriter.WriteEvent(&SSEEvent{ Event: "answer_complete", Data: map[string]interface{}{ "msg_id": msgIdStr, "content":finalContent, }, }) // Record session history f.updateSessionHistory(ctx, req.TalId, req.Question, finalContent, msgIdStr) } else { // Interruption ends f.repo.UpdateMessageStatus(ctx, msgIdStr, MessageStatusInterrupted) } // Set output information output.FullAnswer = finalContent output.Status = StatusSuccess output.Suggestions = suggestions output.Knowledge = knowledge}
Processing intent recognition special logic:
// Handle special intent func (f *FreeAskUsecase) handleSpecialIntent(ctx context.Context, intent string, details map[string]interface{}, req *FreeAskReq, output *FreeAskResp) bool { switch intent { case "greeting": // Handle greeting intent output.FullAnswer = f.generateGreeting(req.TalId, details) output.Status = StatusSuccess return true case "homework_submission": // Handle homework submission intent if subjectID, ok := details["subject_id"].(string); ok { // Redirect to homework submission service redirectInfo := f.homeworkService.GetSubmissionRedirect(ctx, req.TalId, subjectID) output.RedirectInfo = redirectInfo output.Status = StatusRedirect return true } case "schedule_query": // Handle schedule query intent if date, ok := details["date"].(string); ok { scheduleInfo := f.scheduleService.GetSchedule(ctx, req.TalId, date) output.FullAnswer = f.formatScheduleResponse(scheduleInfo) output.Status = StatusSuccess output.StructuredData = scheduleInfo return true } case "calculator_request": // 处理算算请求 if expression, ok := details["expression"].(string); ok { result, err := f.calculatorService.Calculate(ctx, expression) if err == nil { output.FullAnswer = fmt.Sprintf("Calculation result is: %s", result) output.Status = StatusSuccess output.StructuredData = map[string]interface{}{ "type": "calculation", "expression": expression, "result": result, } return true } } } // If it is not a special intention or the processing fails, return false and continue normal processing return false}
// Build system prompt words func (f *FreeAskUsecase) buildSystemPrompt(subjectId int32, intent string, intentDetails map[string]interface{}) string { var builder strings.Builder // Basic teaching role definition builder.WriteString("You are a professional education assistant named "xxx Learning Assistant"."") // Add specific guidance according to the subject switch subjectId { case 1: // Mathematics builder.WriteString("You are good at math teaching and can explain math concepts and problem-solving steps in a clear way. Please focus on cultivating students' mathematical thinking and problem-solving ability."") case 2: // Chinese builder.WriteString("You are good at Chinese teaching and can help analyze the meaning of articles, explain words, and guide writing. Please focus on cultivating students' language expression and comprehension ability."") case 3: // English builder.WriteString("You are good at English teaching and can help students master English knowledge, understand grammar rules, and improve language application ability. Please answer in Chinese and intersperse English explanations as appropriate."") case 4: // Physics builder.WriteString("You are good at teaching physics and can explain physical concepts, formulas and phenomena. Please focus on cultivating students' scientific thinking and experimental spirit.") default: builder.WriteString("You can provide comprehensive subject guidance, including answering questions, explaining knowledge and guiding learning methods.") } // Add teaching style and method guidance builder.WriteString("\n\nPlease follow the following teaching principles:") builder.WriteString("\n1. Step by step: from simple to complex, make sure students can understand each step") builder.WriteString("\n2. Learn by analogy: use analogies and examples to help understand") builder.WriteString("\n3. Heuristic teaching: guide students to think instead of giving answers directly") builder.WriteString("\n4. Be patient and friendly: use encouraging language to create a positive learning atmosphere") // Add specific guidance based on intent if intent == "homework_help" { builder.WriteString("\n\nStudents are currently seeking help with their homework. Please guide them to understand the problem and provide ideas for solving the problem, but do not give a complete answer directly.") } else if intent == "concept_explanation" { builder.WriteString("\n\nStudents are currently seeking help with a concept. Please explain the relevant concepts in plain language and vivid examples.") } // Add output format requirements builder.WriteString("\n\nAnswer format requirements:") builder.WriteString("\n- Briefly summarize the problem at the beginning") builder.WriteString("\n- Explain in detail step by step") builder.WriteString("\n- Use formulas, charts, etc. to assist in explanation as appropriate") builder.WriteString("\n- Summarize the key points or give extended thinking at the end") return builder.String()}