# OpenAI 接口接入调试：流式传输优化

> 发布时间: 2026-08-02 18:26

# OpenAI 接口接入调试记录

## 完成的功能

1. 制作基于流式传输的 OpenAI 接口调用工具
2. 制作关于剧情生成的提示词

## 过程中遇到的问题

### 问题一：调用流式传输接口等待时间过长

**原因**：`HttpCompletionOption` 指示 HttpClient 操作是在响应可利用时立即视为已完成，还是在读取包含上下文的整个答案信息之后才视为已完成。默认为 `HttpCompletionOption.ResponseContentRead`，这会使在所有响应结束之后才视为完成，而实际只需要在响应可利用时返回，所以需要修改为 `HttpCompletionOption.ResponseHeadersRead`

```csharp
//修改前
//此处测试耗时基本在80s以上
var requestTimer = Stopwatch.StartNew();
//PostAsJsonAsync 本身不支持直接传入 HttpCompletionOption
HttpResponseMessage httpResponseMessage = await client.PostAsJsonAsync<AIChat>("", aiChat);
requestTimer.Stop();

//修改后
var requestContent = JsonContent.Create(aiChat, mediaType: new MediaTypeHeaderValue("application/json"));
using var request = new HttpRequestMessage(HttpMethod.Post, "")
{
    Content = requestContent,
    VersionPolicy = HttpVersionPolicy.RequestVersionExact
};
//此时平均响应在1s左右
var sw = Stopwatch.StartNew();
using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
sw.Stop();
```

### 问题二：流式传输的底层逻辑

所谓流式传输就是 http 建立 socket 协议之后不立即断开连接，而是按照一定的协议，在 socket 断开之前一直保持连接，直到服务端发送完毕，客户端接收完毕，才断开连接，即客户端会收到多次返回消息，需按约定格式一一处理

```csharp
// 持续读取流数据直到结束
while (!reader.EndOfStream)
{
    // 异步读取一行数据
    var line = await reader.ReadLineAsync();
    
    // 跳过空行处理
    if (string.IsNullOrEmpty(line)) continue;
    
    // 检测流结束标记
    if (line == "data: [DONE]")
    {
        Console.WriteLine("\nStream completed");
        break; // 终止循环
    }

    // 处理有效数据行（服务端返回的SSE格式数据）
    if (line.StartsWith("data: "))
    {
        try
        {
            // 提取有效JSON部分（去除开头的"data: "）
            var json = line["data: ".Length..];
            
            // 反序列化JSON为响应对象
            var responsejson = JsonSerializer.Deserialize<StreamResponse>(json);
            
            // 解析模型思考过程内容（如模型内部推理过程）
            var think = responsejson?.choices.FirstOrDefault()?.delta?.reasoning_content ?? "";
            
            // 处理思考内容输出
            if (!string.IsNullOrEmpty(think))
            {
                // 状态切换：当开始思考时输出提示
                if (!bThinking)
                {
                    fileWriter.WriteLine("\nThinking...");  // 写入思考提示
                    bThinking = !bThinking;                 // 切换状态标志
                }
                fileWriter.Write(think);  // 持续写入思考内容
            }

            // 解析实际响应内容（模型最终输出的对话内容）
            var chunk = responsejson?.choices.FirstOrDefault()?.delta?.content ?? "";
            
            // 处理最终内容输出
            if (!string.IsNullOrEmpty(chunk))
            {
                // 状态切换：当开始输出正式内容时输出提示
                if (bThinking)
                {
                    fileWriter.WriteLine("\nSay:");         // 写入内容提示
                    bThinking = !bThinking;                 // 重置状态标志
                }
                fileWriter.Write(chunk);  // 持续写入对话内容
            }
        }
        catch (Exception ex)
        {
            // 异常处理：输出解析错误信息（保留控制台输出用于调试）
            Console.WriteLine($"Parse error: {ex.Message}");
        }
    }
}
```

## 未解决的问题

1. 模型输出的文本符合 json 格式，但是会在 json 前后添加 markdown 的 json 标记，目前暂无法消除，需要进一步研究
2. 文档中 response_format 可以指定模型输出 json 格式的内容，但是事实上模型经常输出错误的格式