You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Delphi中获取Jan AI API POST请求的正确JSON响应?

问题解决:Delphi调用Jan API流式响应解析失败

问题原因

当请求参数stream:true时,Jan API返回的是**Server-Sent Events(SSE)**格式的流式响应,而非单一完整JSON。每个响应块格式为:

data: {"choices":[{"finish_reason":null,"index":0,"delta":{"content":"Hello"}}]}

data: {"choices":[{"finish_reason":"stop","index":0,"delta":{}}]}

Delphi的TIdHTTP.Post默认会将所有分块内容直接拼接成字符串,导致最终内容不符合JSON语法,无法解析。

解决方案

方案1:关闭流式响应(简单快速)

将请求参数中的"stream":true改为"stream":false,API会返回完整的单一JSON,现有代码可直接正常解析:

procedure TForm2.Button1Click(Sender: TObject);
var
  IdHTTP: TIdHTTP;
  RequestData: TStringStream;
  ResponseData: string;
  JsonResponse: TJSONObject;
begin
  IdHTTP := TIdHTTP.Create;
  RequestData := TStringStream.Create;
  try
    IdHTTP.Request.ContentType := 'application/json';
    // 修改stream为false
    RequestData.WriteString('{"messages":[{"content":"You are a helpful assistant.","role":"system"},{"content":"How are you?","role":"user"}],"model":"tinyllama-1.1b","stream":false,"max_tokens":2048,"stop":["hello","Hello","HELLO","hELLO"],"frequency_penalty":0,"presence_penalty":0,"temperature":0.7,"top_p":0.95}');
    ResponseData := IdHTTP.Post('http://localhost:1337/v1/chat/completions', RequestData);
    Memo2.Lines.Add(ResponseData);
    JsonResponse := TJSONObject.ParseJSONValue(ResponseData) as TJSONObject;
    if Assigned(JsonResponse) then
    try
      // 解析content示例
      Memo1.Lines.Add('AI响应内容:' + JsonResponse.GetValue<TJSONArray>('choices').Items[0].GetValue<TJSONObject>('message').GetValue<string>('content'));
    finally
      JsonResponse.Free;
    end;
  finally
    IdHTTP.Free;
    RequestData.Free;
  end;
end;

方案2:处理流式SSE响应(保留实时输出)

如果需要保留流式实时获取响应的功能,需要逐块读取并解析SSE格式的响应:

procedure TForm2.Button1Click(Sender: TObject);
var
  IdHTTP: TIdHTTP;
  RequestData: TStringStream;
  ResponseStream: TStringStream;
  Line: string;
  JsonStr: string;
  JsonObj: TJSONObject;
begin
  IdHTTP := TIdHTTP.Create;
  RequestData := TStringStream.Create;
  ResponseStream := TStringStream.Create('');
  try
    IdHTTP.Request.ContentType := 'application/json';
    RequestData.WriteString('{"messages":[{"content":"You are a helpful assistant.","role":"system"},{"content":"How are you?","role":"user"}],"model":"tinyllama-1.1b","stream":true,"max_tokens":2048,"stop":["hello","Hello","HELLO","hELLO"],"frequency_penalty":0,"presence_penalty":0,"temperature":0.7,"top_p":0.95}');
    
    // 发送请求并获取响应流
    IdHTTP.Post('http://localhost:1337/v1/chat/completions', RequestData, ResponseStream);
    ResponseStream.Position := 0;
    
    // 逐行解析SSE响应
    while not ResponseStream.Eof do
    begin
      Line := ResponseStream.ReadLn;
      // 过滤SSE的data:前缀和空行
      if StartsStr('data:', Line) then
      begin
        JsonStr := Copy(Line, 6, Length(Line)-5);
        // 忽略结束信号(data: [DONE])
        if JsonStr <> '[DONE]' then
        begin
          JsonObj := TJSONObject.ParseJSONValue(JsonStr) as TJSONObject;
          if Assigned(JsonObj) then
          try
            // 提取流式输出的content片段
            var DeltaObj := JsonObj.GetValue<TJSONArray>('choices').Items[0].GetValue<TJSONObject>('delta');
            if DeltaObj.Contains('content') then
            begin
              Memo2.Lines.Add(DeltaObj.GetValue<string>('content'));
            end;
          finally
            JsonObj.Free;
          end;
        end;
      end;
    end;
  finally
    IdHTTP.Free;
    RequestData.Free;
    ResponseStream.Free;
  end;
end;

额外优化建议

  • Delphi字符串中直接使用双引号时,建议用单引号包裹整个JSON字符串,避免转义混乱。
  • 解析JSON时务必添加Assigned判断,避免空指针异常。

内容的提问来源于stack exchange,提问作者Anton Tretyak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 21:00:38