如何在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
相关产品推荐
相关产品推荐

