Skip to content
Embabel 文档版本 0.3.0-SNAPSHOT 源快照 ca34a33f 更新于 2026-09-29

30 · 推理与思考(Thinking)

动机(Motivation)

有时除了拿到结构化结果,你还需要校验 LLM 的推理过程。

设想这样一个场景:用户想规划一次度假,指定偏好目的地是希腊和意大利,可用出行日期在 6 月、8 月或 9 月。 他们让 LLM 找出"一周行程、票价可承受"的航班选项。LLM 返回了一个结构化的 Flight 对象, 包含去程/返程日期、目的地与价格。即使输出符合预期的 schema,你可能仍然想确认:

  • 航班日期确实落在所要求的月份内;
  • 目的地确实在希腊或意大利,而不是别的地方。

如果航班详情超出了用户的条件范围,能访问 LLM 的推理过程就能帮你理解它为什么做了这些选择。

一个更重要的用例是:LLM 无法完成请求时 —— 例如因为用户条件含糊或自相矛盾而无法创建所要求的对象。 这时,即便没有产出结果,thinking 块也能解释哪里出了问题。

概念(Concepts)

  • ThinkingBlock —— 承载 LLM 推理细节的抽象,包括标签类型、标签值与推理文本内容。
  • ThinkingTagType —— 定义推理标记类型的枚举:
    • TAG:XML 风格标签;
    • PREFIX:行前缀,例如 //THINKING:;
    • NO_PREFIX:JSON 输出之前未打标签的推理文本。
  • ThinkingResponse —— 响应包装器,同时持有结果对象与 ThinkingBlock 列表。
  • ThinkingException —— 对象实例化失败时仍会保留 thinking 块的异常,使错误场景下也能调试。
  • thinking() —— PromptRunner 上启用 thinking 提取的核心 API 方法。

示例:处理对象与 thinking 块

java
// 用 LLM 与可选工具配置 PromptRunner
PromptRunner runner = ai.withDefaultLlm() // 该示例使用 claude-sonnet-4-5
        .withToolObject(Tooling.class);

String prompt = """
        What is the hottest month in Florida and its average high temperature?
        Please provide a detailed analysis of your reasoning.
        """;

// 用 thinking() 启用 thinking 块提取
ThinkingResponse<MonthItem> response = runner
        .thinking()
        .createObject(prompt, MonthItem.class);

// 取结构化结果
MonthItem result = response.getResult();

// 取 LLM 的推理过程
List<ThinkingBlock> thinkingBlocks = response.getThinkingBlocks();

// 查看单个 thinking 块
for (ThinkingBlock block : thinkingBlocks) {
    System.out.println("Type: " + block.getTagType());   // TAG、PREFIX 或 NO_PREFIX
    System.out.println("Tag: " + block.getTagValue());   // 例如 "think"、"analysis"
    System.out.println("Content: " + block.getContent());
}

示例:优雅地处理失败

当 LLM 可能无法产出合法结果时,用 createObjectIfPossible:

java
ThinkingResponse<MonthItem> response = runner
        .thinking()
        .createObjectIfPossible(prompt, MonthItem.class);

MonthItem result = response.getResult();
if (result != null) {
    // 处理结果
} else {
    // 对象创建失败 —— 检查推理过程,理解原因
    for (ThinkingBlock block : response.getThinkingBlocks()) {
        logger.info("LLM reasoning: {}", block.getContent());
    }
}

提供方说明(Provider Notes)

Embabel 通过提供方中立的 API 暴露 thinking:

  • PromptRunner.thinking()
  • LlmOptions.thinking

这仍然是启用推理/思考模式的主要公开 API。

在底层,各提供方集成可能对 Thinking 做不同翻译,以匹配提供方自身的能力。 例如,Google GenAI 会把 Embabel 的 thinking 选项映射到对应的 Spring AI Google GenAI chat options, 例如 includeThoughts 与 thinkingBudget。

调用方不需要任何新的应用层 thinking API。 总体上,既有应用应继续使用 Embabel 的通用 thinking API, 而不是提供方专属配置。

有些提供方还会在模型的 YAML 里定义模型级默认值,但显式的运行时 thinking 请求仍然走 LlmOptions.thinking。

提供方的行为可能略有差异,取决于 Spring AI 如何暴露推理数据:

  • 部分提供方在 assistant message 本身上暴露推理;
  • 另一些通过 generation metadata 暴露。

因此,提取出的 thinking 块是否存在、以及形态如何,可能随提供方与 Spring AI 集成版本而略有不同。

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。