LLM-Cookbook 学习——搭建基于 ChatGPT 的问答系统:处理输入——思维链推理 Chain of Thought Reasoning

📅 2026/8/18 20:02:52
LLM-Cookbook 学习——搭建基于 ChatGPT 的问答系统:处理输入——思维链推理 Chain of Thought Reasoning
一、本章主要学习什么用户输入已经确定可以处理那么怎样让模型更可靠地解决复杂问题对于简单问题1 1 ?模型可以直接问题 ↓ 答案但是对于比较复杂的问题例如用户提到了两个产品 ↓ 需要找到两个产品 ↓ 读取产品价格 ↓ 判断用户的前提是否正确 ↓ 进行价格比较 ↓ 纠正用户 ↓ 生成最终回答实际上包含很多步骤。因此本章引入Chain of Thought 思维链推理教程的基本思路是不要急着让模型直接得到最终结论而是把任务拆成一系列步骤让模型按照这些步骤处理。Datawhale 原章节就是围绕“分步骤处理产品客服问题”和“Inner Monologue”展开。二、什么是 Chain of ThoughtChain of Thought简称CoT中文一般翻译为思维链可以先简单理解成把一个复杂问题拆解成多个中间步骤再得到最终结果。例如有一道问题商品 A250 元 商品 B1000 元 用户问 商品 A 比商品 B 贵多少如果模型直接回答就需要自己一次性完成理解问题 读取数据 发现用户假设 比较价格 纠正用户 计算差值 组织答案一种分步处理方式则是Step 1 判断用户询问哪些商品 ↓ Step 2 找到商品对应信息 ↓ Step 3 找出用户做出的假设 ↓ Step 4 检查这个假设是否正确 ↓ Step 5 根据检查结果回答用户这就是本章所谓的逐步推理三、为什么复杂问题需要分步骤假设模型面对BlueWave Chromebook 比 TechPro Desktop 贵多少已知BlueWave Chromebook $249.99 TechPro Desktop $999.99这里隐藏了一个陷阱用户其实默认BlueWave Chromebook TechPro Desktop但实际上249.99 999.99如果模型没有认真检查问题本身的前提很可能直接按照用户的假设计算“贵多少”而正确处理过程应该是① 用户提到了哪两个产品 ② 两个产品的信息是否存在 ③ 用户是不是假设 Chromebook 更贵 ④ 查价格 Chromebook 249.99 Desktop 999.99 ⑤ 判断 用户假设错误 ⑥ 回答 Chromebook 并不更贵 而是更便宜。所以复杂任务中一个很重要的原则就是先验证前提再得出结论。四、本章使用的客服案例教程中准备了五个产品例如TechPro Ultrabook BlueWave Gaming Laptop PowerLite Convertible TechPro Desktop BlueWave Chromebook每个产品又包含产品名称 类别 品牌 型号 保修期 评分 配置 产品描述 价格然后要求模型根据这些已知信息回答用户问题。例如BlueWave Chromebook 价格 $249.99而TechPro Desktop 价格 $999.99教程并没有简单地告诉模型“回答用户问题”而是在system_message中规定了一系列处理步骤。这就是这一章最重要的代码设计。五、System Prompt 为什么要拆成 Step 1、Step 2……整体逻辑可以简化成system_message 请按照以下步骤回答用户问题。 Step 1: 判断用户是否询问具体产品。 Step 2: 如果涉及具体产品检查产品是否存在于给定产品列表。 Step 3: 判断用户的问题中是否包含某些假设。 Step 4: 根据产品信息验证这些假设是否正确。 Step 5: 如果用户的假设错误先纠正错误 再回答最终问题。 这里非常值得注意。我们没有只说请认真回答问题因为“认真”非常抽象。我们告诉模型的是具体要做什么 ↓ 按照什么顺序做 ↓ 每一步检查什么因此模型面对复杂任务时会有更明确的任务结构。六、真正重要的不是“思考”而是任务分解学习 CoT 时很容易形成一个误区CoT 在 Prompt 后面加一句 “请一步一步思考”其实本章真正值得学习的地方并不是这一句话。更重要的是Task Decomposition——任务分解。也就是把一个复杂任务拆成子任务 1 ↓ 子任务 2 ↓ 子任务 3 ↓ 子任务 4 ↓ 最终结果例如“判断这段 Datasheet 能否生成测试项”可以拆成Step 1 判断是否包含 Electrical Characteristics Step 2 识别参数名称和 Symbol Step 3 识别 Test Condition Step 4 提取 Min / Typ / Max Step 5 检查单位 Step 6 检查条件是否完整 Step 7 决定是否可以形成 Test Item Step 8 生成结构化结果这比“请分析 Datasheet 并生成测试项”更加可控。七、delimiter 在这一章再次出现前面几章我们已经见过delimiter ####这一章依然使用它。例如Step 1: #### ... Step 2: #### ... Step 3: #### ...这里 delimiter 的主要作用还是给不同内容建立清晰边界。比如用户输入 #### BlueWave Chromebook 比 TechPro Desktop 贵多少 ####模型比较容易区分System Instruction和User Query当前 OpenAI 针对 reasoning model 的官方提示建议仍然推荐合理使用 Markdown、XML、标题等 delimiter 来区分输入的不同部分。八、教程中的五个步骤分别是什么意思我们把原教程的 Prompt 抽象一下。Step 1判断是不是具体产品问题类似用户是不是在询问具体产品例如BlueWave Chromebook 贵吗属于Specific Product九、Step 2检查产品是否真的存在假设用户问你们家的 MacBook Pro 多少钱但是系统产品库中只有TechPro Ultrabook BlueWave Gaming Laptop PowerLite Convertible TechPro Desktop BlueWave Chromebook那么模型不应该凭自己的世界知识回答 MacBook 的信息。而应该判断MacBook Pro 不在提供的产品列表中这是非常重要的一个思想只根据提供的数据回答而不是让模型随便补充。这和后面 RAG 中Grounding 基于给定知识回答的思想非常类似。十、Step 3识别用户隐含的假设这是本章特别值得学习的一步。用户问题不一定只是Query里面还可能包含Assumption 假设例如BlueWave Chromebook 比 TechPro Desktop 贵多少用户其实隐含假设BlueWave Chromebook 比 TechPro Desktop 贵因此需要先提取用户的前提是什么再检查它。这种思想不仅适用于客服。例如为什么芯片的 Leakage Current 一定随着 VDD 增大而线性增大里面其实包含一个假设Leakage Current 一定随 VDD 线性增加系统不应该直接解释为什么线性增加而应该先验证这个假设本身是否成立十一、Step 4验证用户假设这一阶段实际上是在做Assumption Verification 假设验证例如用户假设 Chromebook 更贵查数据库Chromebook 249.99 Desktop 999.99比较249.99 999.99得到用户假设错误所以应该先纠正用户 ↓ 再回答问题而不是顺着错误假设继续推理十二、Step 5生成最终回复前面所有步骤完成之后才进入Response to user于是整个处理过程是理解问题 ↓ 检索事实 ↓ 识别假设 ↓ 验证假设 ↓ 修正错误 ↓ 生成回答这实际上已经是一个简单的Reasoning Pipeline 推理流水线十三、教程中的第一个案例用户问BlueWave Chromebook 比 TechPro Desktop 贵多少根据产品信息BlueWave Chromebook $249.99 TechPro Desktop $999.99因此模型应该发现用户假设 Chromebook 更贵 事实 Chromebook 更便宜正确最终结果应该是BlueWave Chromebook 并不比 TechPro Desktop 贵 反而便宜约 750 美元。原教程的英文示例确实按照“识别产品 → 查看价格 → 识别用户假设 → 判断假设错误 → 纠正用户”的结构输出。十四、这里有一个非常值得注意的例子CoT 本身也可能出错原 Datawhale Notebook 的中文输出其实出现了一个很有意思的现象。在某一步中模型说用户的假设是正确的但紧接着又根据249.99 999.99得出了Chromebook 更便宜最后给用户的结论也是Chromebook 比 Desktop 便宜约 750 美元也就是说中间某一步文字 ↓ 出现逻辑矛盾 最终结论 ↓ 反而基本正确这个现象直接出现在该章中文示例的模型输出中。这说明让模型输出 Step 1、Step 2、Step 3 并不意味着推理一定正确。这是学习 CoT 特别需要注意的一点。所以Chain of Thought ≠ Correctness Guarantee即思维链不是正确性的保证。十五、为什么 CoT 仍然有价值虽然不能保证正确但任务分步有几个非常明显的工程价值。例如以前Input ↓ LLM ↓ Answer如果回答错误我们很难知道到底错在哪里而结构化之后Step 1 识别对象 Step 2 获取信息 Step 3 提取假设 Step 4 验证事实 Step 5 回答至少在一些传统提示式工作流中可以更容易观察是识别产品错了 还是获取价格错了 还是比较大小错了 还是最终表达错了所以这里真正有价值的是可分解 可检查 可验证十六、第二个案例用户询问系统没有的产品教程还有一个案例你们有电视吗但系统提供的产品列表只有电脑和笔记本相关产品没有 TV。因此处理过程可以是Step 1 用户询问电视 Step 2 检查产品列表 Step 3 没有找到电视 Step 4 不能凭空补充产品 Step 5 告诉用户当前没有销售电视教程最终也是根据给定产品列表回答没有电视而不是利用模型外部知识虚构商品信息。这和以后 RAG 的原则非常类似不要因为 LLM “知道很多”就允许它脱离提供的数据回答业务事实。十七、什么是 Inner Monologue这一章还有第二个重要概念Inner Monologue 内心独白教程提出一个问题如果我们要求模型输出Step 1 Step 2 Step 3 Step 4 Final Answer是不是一定要把所有中间内容都给用户看不一定。因此旧教程提出一种应用层处理方法模型生成 Step 1 Step 2 Step 3 Step 4 Final Response ↓ 程序处理结果 ↓ 只显示 Final Response也就是说模型生成中间步骤但应用只把最终答案展示给用户。原课程将这种方法称作 Inner Monologue。十八、Inner Monologue 为什么有用假设一个教学系统正在给学生批改数学题。内部可能需要完成判断学生用了什么方法 ↓ 找到计算错误 ↓ 判断错误发生在哪一步 ↓ 确定应该给什么提示但如果系统直接把完整解法都展示出来答案就泄露了用户只需要看到“检查一下你第二步的符号变化。”而不一定需要看到全部内部分析过程。因此内部处理和用户展示最好进行分离。十九、教程中是怎么隐藏中间结果的课程使用了一种很简单的方法先规定分隔符delimiter ####模型输出Step 1 #### ... Step 2 #### ... Step 3 #### ... Step 4 #### ... Response to user #### 最终答案然后利用 Pythonresponse.split(delimiter)将字符串切开。再取[-1]得到最后一部分。概念上final_response response.split(delimiter)[-1].strip()这样显示给用户的就只有最终答案而不是所有中间文本。二十、response.split(delimiter)[-1].strip() 怎么理解这一行对于刚学 Python 时比较容易绕。我们一步一步拆。假设response Step 1####识别产品 Step 2####查询价格 Response####Chromebook 更便宜 然后response.split(####)会按照####把字符串切开。结果类似[ Step 1, 识别产品\nStep 2, 查询价格\nResponse, Chromebook 更便宜 ]然后[-1]表示列表最后一个元素所以得到Chromebook 更便宜最后.strip()去掉前后空格 换行符于是final_response最终只剩真正要给用户看的回答。二十一、这里的 [-1] 为什么表示最后一个Python 中list[0]代表第一个元素例如a [A, B, C]那么a[0]得到A而a[-1]代表最后一个元素所以a[-1]结果就是C因此response.split(delimiter)[-1]就是把 response 分割之后拿最后一段。二十二、为什么还需要 try / except教程这种代码通常还会写成try: final_response response.split(delimiter)[-1].strip() except Exception: final_response 系统暂时无法处理请求。这里try代表尝试执行正常代码。而except代表如果执行过程中出现异常就执行备用方案。原因是我们不能完全保证模型每一次都严格按照Step 1 #### Step 2 #### Response ####输出。如果格式异常程序可能解析失败所以增加异常处理。这实际上是 LLM 应用开发很重要的思想永远不要假设模型输出 100% 符合格式。二十三、现在应该怎样看待“Inner Monologue”这里需要补充一个非常重要的时代差异。这套课程最初的思路是Prompt ↓ 要求模型显式写出推理 ↓ 程序再隐藏这些推理 ↓ 只展示最终答案但现在的 reasoning model 已经会在内部使用 reasoning tokens 完成复杂推理而这些内部 reasoning tokens 并不会作为普通可见回答直接返回。OpenAI 当前文档明确指出对于 reasoning models没有必要通过 Prompt 要求模型“think step by step”或“explain your reasoning”。所以学习这一章时最好区分旧式 CoT Prompt和现代 Reasoning Model二十四、传统 CoT Prompt vs 现代 Reasoning Model可以这样理解对比传统 CoT PromptReasoning Model推理方式Prompt 要求分步输出模型内部进行推理常见提示Think step by step清晰描述任务即可中间推理常以文本形式生成内部 reasoning tokens用户是否必须看到不一定一般不需要主要关注点Prompt 如何分步骤任务、约束、工具、结果当前使用仍有教学和工作流价值更适合复杂推理任务OpenAI 当前针对 reasoning model 的最佳实践明确建议保持提示直接、清晰并指出“要求逐步思考”通常没有必要有时甚至可能妨碍效果。二十五、那 Chain of Thought 现在是不是没用了不是。需要区分两个东西。第一种要求模型把所有内部思考 逐字输出给用户对于现代 reasoning model通常没有必要第二种把业务任务明确拆解依然非常重要。例如1. 找出涉及的产品 2. 查询产品信息 3. 验证用户前提 4. 计算结果 5. 按指定格式回答这种Workflow Decomposition依然是非常重要的工程技巧。因此不要把“不要要求模型暴露完整 Chain of Thought”误解成“不要做任务分解”两者不是一回事。二十六、Reasoning Token 是什么在现代 reasoning model 中还存在一种reasoning tokens它可以理解为模型在生成最终回答之前用于内部复杂推理的 Token。整体可以粗略理解成Input Tokens ↓ Reasoning Tokens ↓ Visible Output Tokens其中Input Tokens是用户和系统给模型的信息。Reasoning Tokens用于模型内部处理。Output Tokens则是最终展示出来的回答。OpenAI 当前文档说明 reasoning model 会产生内部 reasoning tokens这些 Token 会占用上下文空间并计入相应的输出 Token 使用量但不会作为普通推理全文直接通过 API 展示。二十七、这和上一章学的 Context Window 有什么关系前面学过Context Window 模型一次能够处理的信息总空间现代 reasoning model 中还需要考虑输入 Token Reasoning Token 最终输出 Token都需要空间。所以Prompt 很长 任务很复杂可能导致模型留给内部推理和最终回答的空间不足。OpenAI 当前文档也特别指出reasoning tokens 会占用 Context Window因此复杂推理任务要预留足够上下文空间。二十八、Chain of Thought 和 Prompt Chaining 有什么区别Chain of Thought主要是一个问题 ↓ 模型内部/单次任务 ↓ 多个推理步骤 ↓ 最终答案例如识别产品 ↓ 查询价格 ↓ 验证假设 ↓ 回答Prompt Chaining则更加像Prompt 1 ↓ 结果 1 ↓ Prompt 2 ↓ 结果 2 ↓ Prompt 3 ↓ 结果 3也就是说Chain of Thought更偏向一个任务内部的推理结构。而Prompt Chaining更偏向把多个 LLM 调用连接成完整工作流。二十九、举一个 Datasheet 的例子例如 Datasheet 中有Input Leakage Current VIN 0 V to VDD Maximum ±1 μA如果直接问生成测试项模型可能一次性输出结果。如果进行任务分解可以设计Step 1 识别参数名称 Input Leakage Current Step 2 识别 Symbol 如果原文不存在则不自行补充 Step 3 识别 Test Condition VIN 0 V to VDD Step 4 识别 Limit Maximum ±1 μA Step 5 识别 Unit μA Step 6 判断信息是否足够形成 Test Item Step 7 生成结构化输出这样比“帮我分析一下”更加明确。三十、进一步结合 RAG将来如果加入 RAG可以变成用户询问 Datasheet │ ↓ Step 1 识别问题属于哪个参数 │ ↓ Step 2 检索 Datasheet 对应片段 │ ↓ Step 3 检查检索内容是否真正包含答案 │ ↓ Step 4 提取参数 │ ↓ Step 5 验证单位和条件 │ ↓ Step 6 生成答案所以这一章本质上是在教一个很重要的 Agent 思想复杂问题不要一次完成而要拆成多个可验证的小问题。三十一、为什么“先验证再回答”对 Datasheet 特别重要芯片 Datasheet 中经常会出现条件 参数 上下限 单位 模式 温度 电源条件如果漏掉一个条件测试项可能完全不同例如IDD 100 μA不能直接理解成芯片所有状态下电源电流都是 100 μA因为原文可能实际是IDD 100 μA 条件 Standby Mode VDD 3.3 V TA 25°C因此合理流程应该是看到数值 ↓ 不要马上生成 Test Item ↓ 检查对应 Test Condition ↓ 确认模式 ↓ 确认温度 ↓ 确认 Supply ↓ 再输出三十三、现代 Prompt 可以怎样写与其写请一步一步详细展示你的所有思维过程。现代 reasoning model 更推荐写清楚任务本身例如根据给定产品数据库回答用户问题。 要求 1. 只能使用给定数据库中的信息。 2. 检查用户问题是否包含错误前提。 3. 如果前提错误先纠正。 4. 所有价格计算必须使用数据库中的数据。 5. 最终只输出 - 结论 - 关键依据这里仍然进行了任务结构化但是没有要求暴露完整内部推理当前 OpenAI reasoning model 最佳实践也推荐使用简单、直接的 Prompt并明确任务目标和边界。三十四、Structured Reasoning 是更值得学习的工程思维与其关注模型有没有写 Step 1 Step 2 Step 3更值得关注模型有没有完成 ✓ 事实提取 ✓ 前提检查 ✓ 计算验证 ✓ 数据约束 ✓ 输出格式三十七、本章核心流程图用户问题 │ ↓ ┌───────────────┐ │ 理解用户请求 │ └───────────────┘ │ ↓ 是否涉及具体对象 │ ↓ 获取已知事实 │ ↓ 检查用户隐含假设 │ ↓ 验证假设 │ ┌──────────┴──────────┐ ↓ ↓ 正确 错误 │ │ ↓ ↓ 正常回答 先纠正 │ ↓ 再回答 │ ┌──────────────────┘ ↓ Final Response