LLM 服务链的端到端延迟优化并行调用与预取策略的工程方案一、LLM 服务链的延迟构成一个典型的 AI 应用调用的不是单个 LLM而是一条服务链意图识别 → Prompt 组装 → LLM 推理 → 结果解析 → 后续处理。更复杂的场景涉及多模型协作用廉价模型做意图分类用主力模型做生成用专用模型做安全审核。延迟的构成总延迟 串行延迟之和 最长的并行延迟 串行调用无优化 意图分类 (500ms) Prompt 组装 (0ms*) LLM 推理 (3000ms) 安全审核 (400ms) 3900ms 并行优化后 max(意图分类 (500ms), Prompt 预取 (0ms)) LLM 推理 (3000ms) max(安全审核 (400ms), 后处理 (200ms)) 3500ms 节省 400ms (10%) 具体时序变化体现在任务重叠上串行模式下各阶段依次执行总耗时累加而优化后的并行模式将意图识别与 Prompt 预组装重叠同时将安全审核与结果后处理重叠仅保留模型推理作为关键路径上的串行瓶颈从而实现了整体延迟的降低。 ## 二、并行调用利用多模型的独立性 如果服务链中的多个 LLM 调用之间不存在数据依赖就应该并行执行 go func processUserQuery(ctx context.Context, query string) (*Response, error) { var ( intent *IntentResult moderation *ModerationResult err1, err2 error --- wg sync.WaitGroup ) wg.Add(2) // 并行调用意图识别 内容审核 go func() { defer wg.Done() intent, err1 classifyIntent(ctx, query) }() go func() { defer wg.Done() moderation, err2 moderateContent(ctx, query) }() wg.Wait() if err1 ! nil { return nil, fmt.Errorf(intent classification failed: %w, err1) } if err2 ! nil { return nil, fmt.Errorf(content moderation failed: %w, err2) } // 提前拦截内容违规直接拒绝不需要后续推理 if moderation.Flagged { return Response{Rejected: true, Reason: moderation.Reason}, nil } // 根据意图选择 Prompt 模板调用主力模型 prompt : buildPrompt(intent, query) return callMainModel(ctx, prompt) }并行调用的超时与错误处理func parallelCallWithTimeout(ctx context.Context, calls []LLMCall) ([]*Result, error) { results : make([]*Result, len(calls)) errs : make([]error, len(calls)) var wg sync.WaitGroup wg.Add(len(calls)) for i, call : range calls { go func(idx int, c LLMCall) { defer wg.Done() callCtx, cancel : context.WithTimeout(ctx, c.Timeout) defer cancel() results[idx], errs[idx] executeCall(callCtx, c) }(i, call) } wg.Wait() // 降级策略如果意图分类失败使用默认意图 // 如果审核失败非超时保守拒绝 for i, err : range errs { if err ! nil calls[i].Fallback ! nil { results[i] calls[i].Fallback } } return results, nil }三、预取策略提前准备依赖数据预取的核心思想是在 LLM 推理的等待时间内并行获取后续步骤需要的数据func handleAgentTask(ctx context.Context, task AgentTask) (*AgentResponse, error) { // 第一阶段LLM 推理主路径耗时最长 llmDone : make(chan *LLMResponse, 1) llmErr : make(chan error, 1) go func() { resp, err : callLLM(ctx, task.Prompt) if err ! nil { llmErr - err return } llmDone - resp }() // 在 LLM 推理期间预取后续可能需要的数据 prefetchResults : make(map[string]interface{}) var prefetchMu sync.Mutex var prefetchWg sync.WaitGroup // 预取工具调用可能需要的上下文数据 prefetchWg.Add(3) go func() { defer prefetchWg.Done() data, _ : fetchUserProfile(ctx, task.UserID) prefetchMu.Lock() prefetchResults[user_profile] data prefetchMu.Unlock() }() go func() { defer prefetchWg.Done() data, _ : fetchRecentHistory(ctx, task.UserID, 10) prefetchMu.Lock() prefetchResults[recent_history] data prefetchMu.Unlock() }() go func() { defer prefetchWg.Done() data, _ : semanticSearch(ctx, task.Query) prefetchMu.Lock() prefetchResults[search_results] data prefetchMu.Unlock() }() // 等待 LLM 响应 select { case resp : -llmDone: // LLM 完成等待预取可能已经完成 prefetchWg.Wait() return executeTools(ctx, resp, prefetchResults) case err : -llmErr: return nil, err case -ctx.Done(): return nil, ctx.Err() } }四、流式输出下的延迟感知流式输出改变了延迟的感知方式——用户不需要等完整结果看到第一个字即可开始阅读。TTFTTime To First Token是最关键的指标type StreamMetrics struct { TTFT time.Duration // 首 Token 延迟 TPS float64 // Tokens Per Second TotalTokens int } func streamWithMetrics(ctx context.Context, prompt string, writer io.Writer) (*StreamMetrics, error) { start : time.Now() stream, err : llmClient.CreateChatCompletionStream(ctx, prompt) if err ! nil { return nil, err } defer stream.Close() metrics : StreamMetrics{} tokenCount : 0 for { chunk, err : stream.Recv() if err io.EOF { break } if err ! nil { return nil, err } if tokenCount 0 { metrics.TTFT time.Since(start) } tokenCount writer.Write([]byte(chunk.Content)) } metrics.TotalTokens tokenCount metrics.TPS float64(tokenCount) / time.Since(start).Seconds() return metrics, nil }五、总结LLM 服务链的延迟优化核心是并行化无依赖的 LLM 调用意图识别、内容审核并行执行预取策略在 LLM 推理等待期间并行获取后续数据。流式输出降低感知延迟TTFT 是关键指标。超时控制和降级策略是并行的必要配套——单点超时不阻塞全链路降级方案兜底保持服务可用。整体延迟可降低 10%-30%具体取决于并行化的程度。
LLM 服务链的端到端延迟优化:并行调用与预取策略的工程方案
LLM 服务链的端到端延迟优化并行调用与预取策略的工程方案一、LLM 服务链的延迟构成一个典型的 AI 应用调用的不是单个 LLM而是一条服务链意图识别 → Prompt 组装 → LLM 推理 → 结果解析 → 后续处理。更复杂的场景涉及多模型协作用廉价模型做意图分类用主力模型做生成用专用模型做安全审核。延迟的构成总延迟 串行延迟之和 最长的并行延迟 串行调用无优化 意图分类 (500ms) Prompt 组装 (0ms*) LLM 推理 (3000ms) 安全审核 (400ms) 3900ms 并行优化后 max(意图分类 (500ms), Prompt 预取 (0ms)) LLM 推理 (3000ms) max(安全审核 (400ms), 后处理 (200ms)) 3500ms 节省 400ms (10%) 具体时序变化体现在任务重叠上串行模式下各阶段依次执行总耗时累加而优化后的并行模式将意图识别与 Prompt 预组装重叠同时将安全审核与结果后处理重叠仅保留模型推理作为关键路径上的串行瓶颈从而实现了整体延迟的降低。 ## 二、并行调用利用多模型的独立性 如果服务链中的多个 LLM 调用之间不存在数据依赖就应该并行执行 go func processUserQuery(ctx context.Context, query string) (*Response, error) { var ( intent *IntentResult moderation *ModerationResult err1, err2 error --- wg sync.WaitGroup ) wg.Add(2) // 并行调用意图识别 内容审核 go func() { defer wg.Done() intent, err1 classifyIntent(ctx, query) }() go func() { defer wg.Done() moderation, err2 moderateContent(ctx, query) }() wg.Wait() if err1 ! nil { return nil, fmt.Errorf(intent classification failed: %w, err1) } if err2 ! nil { return nil, fmt.Errorf(content moderation failed: %w, err2) } // 提前拦截内容违规直接拒绝不需要后续推理 if moderation.Flagged { return Response{Rejected: true, Reason: moderation.Reason}, nil } // 根据意图选择 Prompt 模板调用主力模型 prompt : buildPrompt(intent, query) return callMainModel(ctx, prompt) }并行调用的超时与错误处理func parallelCallWithTimeout(ctx context.Context, calls []LLMCall) ([]*Result, error) { results : make([]*Result, len(calls)) errs : make([]error, len(calls)) var wg sync.WaitGroup wg.Add(len(calls)) for i, call : range calls { go func(idx int, c LLMCall) { defer wg.Done() callCtx, cancel : context.WithTimeout(ctx, c.Timeout) defer cancel() results[idx], errs[idx] executeCall(callCtx, c) }(i, call) } wg.Wait() // 降级策略如果意图分类失败使用默认意图 // 如果审核失败非超时保守拒绝 for i, err : range errs { if err ! nil calls[i].Fallback ! nil { results[i] calls[i].Fallback } } return results, nil }三、预取策略提前准备依赖数据预取的核心思想是在 LLM 推理的等待时间内并行获取后续步骤需要的数据func handleAgentTask(ctx context.Context, task AgentTask) (*AgentResponse, error) { // 第一阶段LLM 推理主路径耗时最长 llmDone : make(chan *LLMResponse, 1) llmErr : make(chan error, 1) go func() { resp, err : callLLM(ctx, task.Prompt) if err ! nil { llmErr - err return } llmDone - resp }() // 在 LLM 推理期间预取后续可能需要的数据 prefetchResults : make(map[string]interface{}) var prefetchMu sync.Mutex var prefetchWg sync.WaitGroup // 预取工具调用可能需要的上下文数据 prefetchWg.Add(3) go func() { defer prefetchWg.Done() data, _ : fetchUserProfile(ctx, task.UserID) prefetchMu.Lock() prefetchResults[user_profile] data prefetchMu.Unlock() }() go func() { defer prefetchWg.Done() data, _ : fetchRecentHistory(ctx, task.UserID, 10) prefetchMu.Lock() prefetchResults[recent_history] data prefetchMu.Unlock() }() go func() { defer prefetchWg.Done() data, _ : semanticSearch(ctx, task.Query) prefetchMu.Lock() prefetchResults[search_results] data prefetchMu.Unlock() }() // 等待 LLM 响应 select { case resp : -llmDone: // LLM 完成等待预取可能已经完成 prefetchWg.Wait() return executeTools(ctx, resp, prefetchResults) case err : -llmErr: return nil, err case -ctx.Done(): return nil, ctx.Err() } }四、流式输出下的延迟感知流式输出改变了延迟的感知方式——用户不需要等完整结果看到第一个字即可开始阅读。TTFTTime To First Token是最关键的指标type StreamMetrics struct { TTFT time.Duration // 首 Token 延迟 TPS float64 // Tokens Per Second TotalTokens int } func streamWithMetrics(ctx context.Context, prompt string, writer io.Writer) (*StreamMetrics, error) { start : time.Now() stream, err : llmClient.CreateChatCompletionStream(ctx, prompt) if err ! nil { return nil, err } defer stream.Close() metrics : StreamMetrics{} tokenCount : 0 for { chunk, err : stream.Recv() if err io.EOF { break } if err ! nil { return nil, err } if tokenCount 0 { metrics.TTFT time.Since(start) } tokenCount writer.Write([]byte(chunk.Content)) } metrics.TotalTokens tokenCount metrics.TPS float64(tokenCount) / time.Since(start).Seconds() return metrics, nil }五、总结LLM 服务链的延迟优化核心是并行化无依赖的 LLM 调用意图识别、内容审核并行执行预取策略在 LLM 推理等待期间并行获取后续数据。流式输出降低感知延迟TTFT 是关键指标。超时控制和降级策略是并行的必要配套——单点超时不阻塞全链路降级方案兜底保持服务可用。整体延迟可降低 10%-30%具体取决于并行化的程度。