获取更多信息
上一节我们利用LLMCaller调用了DeepSeek API的接口,并通过Result属性提取了接口返回的纯文本答案使用。
如果要获得DeepSeek API接口返回的更多信息,可以使用ResultJObject属性,该属性为JObject类型。
例如在命令窗口执行下面的代码:
Dim
caller
As
New
LLMCaller("https://api.deepseek.com/chat/completions",
"deepseek-flash",
"sk-a734b83536da45e9aedc3e42605bfb3a")
caller.SystemPrompt =
"你是一个唐朝诗人"
caller.UserMessage =
"请写一首睹月思人的诗"
If
caller.GetResult()
Then
MessageBoxA.Show(caller.ResultJObject.ToString())
Else
MessageBoxA.Show(caller.Error)
End
If
得到的内容大概为:
{
"id": "027d5238-1358-4b66-954f-f68f16279296",
"object": "chat.completion",
"created": 1789539028,
"model": "deepseek-flash",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "《月夜思故人》\n中庭地白树栖鸦,冷露无声湿桂花。\n今夜月明人尽望,不知秋思落谁家。\n\n赏析:这首作品通过描绘中秋月夜之景,抒发了对故人的深切思念。诗中“中庭地白”、“冷露湿桂”等意象,营造出清冷寂静的意境,而“人尽望”、“落谁家”则巧妙传达出秋思之浓与思念之切。全诗语言凝练,情感真挚,展现了睹月思人的深沉情怀。",
"reasoning_content": "嗯,用户想要一首睹月思人的诗。这个主题在唐诗中很常见,需要抓住月亮与思念的关联。可以借鉴张九龄《望月怀远》的意境,但要有自己的特色。\n\n想到用“霜月”这个意象,既能体现秋夜的清冷,又能暗示思念的苦涩。首联可以写月夜独处的场景,用“清辉”“孤影”营造氛围。中间两联需要虚实结合,既写眼前景,又写远方人。尾联要收得含蓄,用“同照”来呼应题目中的“思人”。\n\n韵脚上打算用“寒”“单”“端”“看”“宽”,平仄要符合五律要求。可以考虑用“玉臂”代指思念之人,既典雅又含蓄。最后用“泪痕干”收尾,留下余味。"
},
"logprobs": null,
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 42,
"completion_tokens": 299,
"total_tokens": 341,
"prompt_tokens_details": {
"cached_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 180
},
"prompt_cache_hit_tokens": 0,
"prompt_cache_miss_tokens": 42
},
"system_fingerprint": "aeb56401ca74e127821c4f9126dcb669"
}
根字段choices下的Message字段是核心,该字段包含所有回复内容:
content字段内容就是AI给出的答案,通常我们只需提取这个字段的内容即可。
reasoning_content字段内容是AI的推理过程,也就是思维链,适合用于调试、展示“思考中”效果;需要开启思考模式才会包含此字段,DeepSeek默认是开启的,除非显式关闭。
finish_reason字段返回结束原因,常见值:
"stop" — 正常结束(遇到结束标记)
"length" — 达到了最大输出长度限制
"content_filter" — 内容被安全策略过滤(部分平台支持)
获取主要字段内容
你可以用下面的代码提取出主要字段的内容:
Dim
caller
As
New
LLMCaller("https://api.deepseek.com/chat/completions",
"deepseek-flash",
"sk-a734b83536da45e9aedc3e42605bfb3a")
caller.SystemPrompt =
"你是一个唐朝诗人"
caller.UserMessage =
"请写一首睹月思人的诗"
If
caller.GetResult()
Then
Dim
retJO
As
JObject = caller.ResultJObject
'获取返回的JObject对象
Dim
choices
As
JArray = retJO("choices")
Dim
firstChoice
As
JObject = choices(0)
Dim
msg
As
JObject = firstChoice("message")
' 1.
提取最终答案(最常用),等效于:caller.Result
Dim
answer
As
String
= msg("content").ToString()
MessageBox.Show("答案:"
& vbcrlf & answer)
' 2.
提取思维链(如果开启了thinking,默认是开启的,所以通常都会返回)
If
msg.ContainsKey("reasoning_content")
Then
Dim
reasoning
As
String
= msg("reasoning_content").ToString()
MessageBox.Show("推理过程:"
& vbcrlf & reasoning)
End
If
' 3.
提取结束原因
Dim
finishReason
As
String
= firstChoice("finish_reason").ToString()
' 4.
提取
Token
用量(用于计费统计)
Dim
usage
As
JObject = retJO("usage")
Dim
sb
As
New
StringBuilder()
Dim
total_tokens
As
Integer
= usage("total_tokens").ToObject(Of
Integer)
Dim
prompt_tokens
As
Integer
= usage("prompt_tokens").ToObject(Of
Integer)
Dim
cached_tokens
As
Integer
= usage("prompt_tokens_details")("cached_tokens").ToObject(Of
Integer)
Dim
completion_tokens
As
Integer
= usage("completion_tokens").ToObject(Of
Integer)
Dim
reasoning_tokens
As
Integer
= usage("completion_tokens_details")("reasoning_tokens").ToObject(Of
Integer)
sb.AppendLine("token消费统计:")
sb.AppendLine("
消费总数:
"
& total_tokens)
sb.AppendLine("
输入消费:
"
& prompt_tokens)
sb.AppendLine("
输入命中缓存数:
"
& cached_tokens)
sb.AppendLine("
输入命中缓存命中率:
"
& format(cached_tokens / prompt_tokens,
"0.00%"))
sb.AppendLine("
输出消费:
"
& completion_tokens)
sb.AppendLine("
推理消费(包含在输出
消费):
"
& reasoning_tokens)
MessageBox.Show(sb.ToString())
Else
MessageBox.Show(caller.Error)
End
If
各返回信息字段说明
DeepSeek API 返回的 JSON 结构包含以下几个顶层字段:
| 字段名称 | 类型 | 说明 |
|---|---|---|
| id | string | 本次请求的唯一标识符(UUID),用于日志追踪和问题排查。 |
| object | string | 非流式返回固定为 "chat.completion";流式模式下,每个分片的类型为 "chat.completion.chunk" |
| created | integer | 响应生成的时间戳(Unix 秒数),可用于日志分析、计算请求耗时、按时间归档对话等 |
| model | string | 实际处理本次请求的模型名称(与你请求中指定的可能略有差异,以实际为准)。 |
| choices | array | 核心数据:模型生成的所有回复结果数组(通常只有一项)。 |
| usage | object | Token 使用量统计,用于计费和监控。 |
| system_fingerprint | string | 后端服务版本/配置指纹,仅在 DeepSeek 内部排查问题时有用,普通开发者可忽略。 |
choices 数组详解(最常用)
choices 是一个数组,每个元素代表一个候选回复。在非流式(stream:
false)且 n=1(默认)的情况下,它只包含一个对象,结构如下:
| 字段 | 类型 | 说明 |
|---|---|---|
| index | integer | 候选结果的序号(从 0 开始)。 |
| message | object | 模型生成的完整消息对象。 |
| logprobs | object/null | 对数概率信息,只有在请求中设置了 logprobs: true 时,该字段才有内容,用于查看每个 Token 的对数概率,普通对话场景不需要 |
| finish_reason | string |
结束原因。常见值: • "stop" — 正常结束(遇到结束标记) • "length" — 达到了最大输出长度限制 • "content_filter" — 内容被安全策略过滤 |
message 对象内部结构
| 字段 | 类型 | 说明 |
|---|---|---|
| role | string | 固定为 "assistant",标识这条消息由模型生成。 |
| content | string | 最常用:模型输出的最终答案文本。你在 UI 上展示给用户的正是这个字段。 |
| reasoning_content | string | 思维链内容(仅在请求中开启 thinking.enabled 时返回)。包含模型的内部推理过程,适合用于调试、展示“思考中”效果 。 |
usage 统计信息详解
用于追踪本次请求的 Token 消耗,对成本控制非常重要:
| 字段 | 类型 | 说明 |
|---|---|---|
| prompt_tokens | integer | 输入部分(messages 中的所有内容)消耗的 Token 数。 |
| completion_tokens | integer | 输出部分(content + reasoning_content)消耗的总 Token 数。 |
| total_tokens | integer | prompt_tokens + completion_tokens 的总和。 |
| prompt_tokens_details | object | 输入 Token 的详细拆解(如命中缓存的 Token 数)。 |
| completion_tokens_details | object |
输出 Token 的详细拆解,其中: • reasoning_tokens:思维链部分单独消耗的 Token 数(开启 thinking 时才有)。 |