☰
Prompt Engineering 进阶:CoT、Few-shot、ReAct、Self-Consistency 推理范式全景与 TaoToken 统一 API 实践
2026/10/1 7:11:56 网站建设 项目流程

1. 从一道数学题说起:为什么同一个模型换个问法准确率差一倍

先看一道题。小明有 5 个苹果,吃了 2 个,又买了 3 袋苹果,每袋 4 个。他现在有几个苹果?

如果你直接问模型"答案是多少",一些中小模型会脱口而出一个错误数字。但如果你在问题后面加一句"让我们一步一步思考",同一个模型、同一个温度参数,它可能会先算 5-2=3,再算 3×4=12,最后算 3+12=15,给出正确答案。

模型没变,变的是引导模型推理的方式。这就是推理范式的威力。大模型本质上是"预测下一个 token"的概率机器,它的推理能力不是没有,而是需要被正确地激发出来。不同的 Prompt 结构,就像不同的思维脚手架,会引导模型走向不同的推理路径。

这篇文章要解决的核心问题是:CoT、Few-shot、ReAct、Self-Consistency 这四种推理范式,在复杂问答和工具调用场景下到底怎么组合使用,怎么用一套统一的 API 通道把它们串起来做可复现的对比测试。我会给出可复制的提示词模板、请求参数配置和逐步验证动作,你可以直接跟着搭一套自己的推理范式测试流程。

适合谁看:已经会调大模型 API、想系统提升 Prompt 效果的工程师;正在做 Agent 或工具调用、需要理解 ReAct 循环怎么落地的人;以及想建立一套"从问对问题到选对范式"决策框架的技术负责人。

先说结论:这四种范式不是互斥的,而是可以叠加的。Few-shot 管格式,CoT 管推理深度,Self-Consistency 管准确率兜底,ReAct 管外部交互。真正难的不是理解它们各自是什么,而是知道什么时候该用哪个、怎么组合、成本怎么算。

2. TaoToken 统一 API 通道:一次配置,多模型对比

做推理范式对比测试,最大的工程障碍不是 Prompt 本身,而是模型切换。你要对比同一个 Prompt 在 GPT、Claude、Gemini 上的表现,传统做法是注册多个平台、维护多套 Key、适配不同的请求格式。光环境搭建就能耗掉半天。

TaoToken 解决的就是这个问题:一个 API Key,一套 OpenAI 兼容的请求格式,背后可以路由到多个主流模型。对于做推理范式对比来说,这意味着你只需要写一份测试代码,改一个 model 字段就能切换模型,其他全部不变。

它的 API 地址是 https://taotoken.net/api,完全兼容 OpenAI 的 /v1/chat/completions 接口。你现有的 OpenAI SDK 代码,只需要改 base_url 和 api_key 两个地方就能跑。

为什么这对推理范式测试特别重要?因为不同范式对模型的敏感度不一样。CoT 在参数量大的模型上效果更明显,Self-Consistency 需要模型有足够的生成多样性,ReAct 则依赖模型对工具描述的理解能力。如果你只有一个模型的访问权限,根本没法判断"效果不好"到底是 Prompt 的问题还是模型的问题。统一通道让你能用同一套测试脚本,快速跑完多个模型的对比矩阵。

另外,做 Self-Consistency 需要同一个 Prompt 采样 N 次,做 ReAct 需要多轮循环调用,这些都会产生大量请求。统一通道在计费和配额管理上省心很多,不用在多个平台之间对账。

如果你还没配好环境,先去控制台创建一个 API Key:https://taotoken.net/console/api-keys 。创建完记下来,后面所有代码都用这一个 Key。

想先直观感受一下不同模型对同一 Prompt 的响应差异,可以直接在模型对话页面测试:https://taotoken.net/models 。把下面第三节的 Prompt 模板粘进去,切换模型看输出变化,比看文档快得多。

3. 可复制配置:四类范式的 Prompt 模板与请求参数

这一节是全文的核心,给出四类范式可以直接复制的配置。每个模板都配了对应的请求参数,你可以直接拿去跑。

3.1 基础环境配置

先建一个配置文件,把统一通道的接入信息写进去。我用 JSON 格式,路径放在项目根目录的 config.json:

{ "base_url": "https://taotoken.net/api", "api_key": "sk-你的Key", "default_model": "gpt-4o", "timeout": 60 }

Python 侧的初始化代码:

import json from openai import OpenAI with open("config.json") as f: cfg = json.load(f) client = OpenAI( base_url=cfg["base_url"], api_key=cfg["api_key"], timeout=cfg["timeout"] ) def chat(messages, model=None, temperature=0.2, n=1): resp = client.chat.completions.create( model=model or cfg["default_model"], messages=messages, temperature=temperature, n=n ) return resp

这段代码是后面所有范式测试的公共底座。注意 base_url 结尾不要加 /v1,SDK 会自动补全路径。

3.2 Few-shot 模板:用例子框定输出格式

Few-shot 的核心是在 Prompt 里给 2 到 5 个"输入→输出"示例。场景选一个后端开发天天干的活:自然语言转 SQL。

FEWSHOT_PROMPT = """请将用户的中文问题转换为 SQL 查询。 示例1: 问题:查询所有状态为已支付的订单 SQL:SELECT * FROM orders WHERE status = 'paid'; 示例2: 问题:统计每个用户的订单总金额,按金额降序 SQL:SELECT user_id, SUM(amount) AS total FROM orders GROUP BY user_id ORDER BY total DESC; 现在请转换: 问题:查询最近7天注册且下单超过3次的用户 SQL:""" messages = [{"role": "user", "content": FEWSHOT_PROMPT}] resp = chat(messages, temperature=0.0) print(resp.choices[0].message.content)

参数要点:temperature 设 0.0,因为 Few-shot 要的是稳定复现示例格式,不需要创造性。示例数量控制在 2 到 5 个,太少学不到模式,太多浪费上下文窗口。示例顺序有讲究,模型对最后的示例记忆最强,把最贴近目标任务的示例放最后。

3.3 CoT 模板:结构化思维链

CoT 的关键是让模型把中间推理过程显式写出来。生产环境里为了让输出可解析,通常用标签包裹推理和答案:

COT_PROMPT = """请按照以下格式回答: <thinking> 在这里写出你的逐步推理过程 </thinking> <answer> 这里只写最终答案 </answer> 问题:一个水池有甲乙两个进水管,甲管单独注满需要6小时,乙管单独注满需要4小时。两管同时打开,多少小时能注满水池?""" messages = [{"role": "user", "content": COT_PROMPT}] resp = chat(messages, temperature=0.2) content = resp.choices[0].message.content print(content)

下游代码可以用正则提取<answer>标签里的结果,同时保留<thinking>用于调试和溯源。temperature 设 0.2 左右,太低会让推理链僵化,太高容易跑偏。

如果你用的是自带思考过程的推理模型,不需要手动加 CoT 提示,它本来就会深度推理。强行加反而可能干扰它自己的思考节奏。CoT 对这些模型的价值主要在于可解释性——让思考过程对你可见、可审计。

3.4 Self-Consistency 配置:多路采样加投票

Self-Consistency 的做法是对同一个 CoT Prompt 独立采样 N 次,然后对最终答案投票。关键是 temperature 要调高,让多次生成有足够的多样性:

import re from collections import Counter def self_consistency(question, n=5, temperature=0.7): prompt = COT_PROMPT.replace("问题:一个水池有甲乙两个进水管,甲管单独注满需要6小时,乙管单独注满需要4小时。两管同时打开,多少小时能注满水池?", f"问题:{question}") messages = [{"role": "user", "content": prompt}] resp = chat(messages, temperature=temperature, n=n) answers = [] for choice in resp.choices: text = choice.message.content m = re.search(r"<answer>(.*?)</answer>", text, re.DOTALL) if m: answers.append(m.group(1).strip()) counter = Counter(answers) return counter.most_common(1)[0][0], counter result, dist = self_consistency("一件商品先涨价20%,再降价20%,最终价格是原价的百分之几?", n=5) print("投票结果:", result) print("分布:", dist)

参数要点:temperature 建议 0.4 到 0.8,太低路径太雷同投票没意义,太高容易胡说。n 通常取 5 到 20。注意投票只投最终答案,不投推理文本,因为多条链的推理表述千差万别没法直接比较。所以它天生适合答案离散可枚举的题,不适合开放式长文本生成。

3.5 ReAct 模板:推理与行动交替

ReAct 让模型在推理和行动之间来回切换。下面是一个带工具调用的完整模板:

REACT_PROMPT = """你可以使用以下工具: 工具1:search[query] 用途:搜索信息,返回相关文本 工具2:calculator[expression] 用途:计算数学表达式 请严格按照以下格式回答: Thought: 你的思考过程 Action: 工具名[参数] Observation: 工具返回结果 ...(重复 Thought/Action/Observation 直到能给出答案) Final Answer: 最终答案 问题:李安的处女作电影的拍摄地,和他后来的《少年派的奇幻漂流》取景地是同一个国家吗?""" messages = [{"role": "user", "content": REACT_PROMPT}] resp = chat(messages, temperature=0.0) print(resp.choices[0].message.content)

模型会输出类似这样的轨迹:

Thought: 我需要先找出李安的处女作电影是什么。 Action: search[李安 导演 处女作 第一部电影] Observation: 李安的导演处女作是 1993 年的《推手》。 Thought: 现在需要查《推手》的拍摄地。 Action: search[电影《推手》拍摄地点] Observation: 《推手》主要在美国华盛顿州拍摄。 ... Final Answer: 不是同一个国家。

实际工程中,你需要写一个解析器把 Action 提取出来、执行对应工具、把 Observation 拼回对话历史,然后再次调用模型。这个循环就是 Agent 的核心。工具描述的质量决定整个 Agent 的上限——描述写得含糊,模型就会选错工具、传错参数、陷入死循环。

4. 逐步验证:从单次请求到完整测试流程

配置写好了,接下来验证每一步是否真的跑通。我按从简到繁的顺序给验证动作。

4.1 验证基础连通性

先跑一个最简单的请求,确认 Key 和 base_url 没问题:

resp = chat([{"role": "user", "content": "回复OK两个字"}]) print(resp.choices[0].message.content)

如果这一步报 401,说明 Key 有问题,去控制台重新确认。如果报连接超时,检查网络和 base_url 拼写。

4.2 验证 Few-shot 格式稳定性

用 3.2 的模板跑三次,看输出的 SQL 格式是否一致。正常情况下三次都应该输出SELECT ... FROM ... WHERE ...的结构,不会跑偏成自然语言解释。如果格式不稳定,检查示例是否够清晰、temperature 是否设成了 0。

4.3 验证 CoT 标签解析

用 3.3 的模板跑一次,然后用正则提取:

import re content = resp.choices[0].message.content thinking = re.search(r"<thinking>(.*?)</thinking>", content, re.DOTALL) answer = re.search(r"<answer>(.*?)</answer>", content, re.DOTALL) print("推理过程:", thinking.group(1).strip() if thinking else "未找到") print("最终答案:", answer.group(1).strip() if answer else "未找到")

如果标签没被正确输出,可能是模型没理解格式要求。可以在 Prompt 里加一句"必须严格使用上述标签格式,不要省略标签"。

4.4 验证 Self-Consistency 投票分布

用 3.4 的代码跑一道有确定答案的题,观察投票分布。理想情况下正确答案应该占多数。如果分布很分散,说明 temperature 太高或者题目本身有歧义。如果所有答案都一样,说明 temperature 太低,需要调高。

4.5 验证 ReAct 循环

ReAct 的验证需要你实现工具执行逻辑。先写一个假的 search 函数返回固定结果,确认模型能正确解析 Action 并继续循环:

def fake_search(query): if "处女作" in query: return "李安的导演处女作是 1993 年的《推手》。" if "推手" in query and "拍摄" in query: return "《推手》主要在美国华盛顿州拍摄。" if "少年派" in query: return "该片主要在印度和中国台湾取景。" return "未找到相关信息" # 解析模型输出中的 Action,执行工具,拼回对话 # 循环直到出现 Final Answer 或达到最大轮数

跑通后你会看到模型经过 4 轮 Thought/Action/Observation 循环,最终给出"不是同一个国家"的答案。

4.6 多模型对比矩阵

基础验证都通过后,用同一套 Prompt 跑多个模型,记录每个模型在每类范式下的表现。建议记录这几个维度:答案正确率、输出格式合规率、平均 token 消耗、平均延迟。这张对比表才是你做技术选型的依据。

5. 常见报错排查:401、local proxy failed、reading choices 怎么解

这一节列出实际跑测试时最常撞到的几个报错,以及对应的排查路径。

5.1 401 Unauthorized

最常见的报错。原因通常是 Key 写错、Key 过期、或者 base_url 和 Key 不匹配。排查步骤:先确认 config.json 里的 api_key 是完整的,没有多余空格;再去控制台确认 Key 状态正常;最后确认 base_url 是 https://taotoken.net/api 而不是其他地址。如果用了环境变量,检查环境变量是否被正确加载。

5.2 local proxy failed 或连接被拒绝

这个报错通常出现在本地网络环境有额外配置的情况下。排查方向:确认没有额外的网络层拦截请求;检查系统代理设置是否影响了 SDK 的连接;如果是公司网络,确认出口策略允许访问 API 地址。最直接的验证方式是用 curl 手动发一个请求:

curl https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer sk-你的Key" \ -H "Content-Type: application/json" \ -d '{"model":"gpt-4o","messages":[{"role":"user","content":"hi"}]}'

如果 curl 能通但 SDK 不通,问题在 SDK 配置;如果 curl 也不通,问题在网络层。

5.3 reading choices 相关报错

典型报错是KeyError: 'choices'或者AttributeError: 'NoneType' object has no attribute 'choices'。这说明响应体里没有 choices 字段,通常是请求本身失败了但 SDK 没有正确抛出异常。排查步骤:先打印完整的 response 对象看返回了什么;检查 model 字段是否拼写正确(模型名写错会返回错误信息而不是 choices);检查 messages 格式是否符合要求。一个稳妥的做法是在 chat 函数里加一层错误处理:

def chat(messages, model=None, temperature=0.2, n=1): try: resp = client.chat.completions.create( model=model or cfg["default_model"], messages=messages, temperature=temperature, n=n ) if not resp.choices: raise ValueError(f"响应无 choices 字段:{resp}") return resp except Exception as e: print(f"请求失败:{e}") raise

5.4 OAuth 或认证方式不匹配

如果你用的是某些需要 OAuth 流程的工具(比如 Claude Code 的某些接入方式),可能会遇到认证方式不匹配的报错。这类问题的核心是确认你用的认证方式(API Key 还是 OAuth token)和工具期望的一致。用统一 API 通道时,统一走 API Key 认证,不要混用其他认证方式。

5.5 模型名不存在

报错信息通常是model not found或类似提示。解决方法是去模型列表页面确认可用的模型 ID,注意大小写和连字符。不同提供商的模型命名规则不一样,比如有的是gpt-4o,有的是claude-3-5-sonnet-20241022,不能想当然。

5.6 超时或响应截断

做 Self-Consistency 采样 10 次时,如果并发太高可能触发限流或超时。解决方法是加并发控制,或者把 n 拆成多次请求。另外 CoT 和 ReAct 的输出比较长,确认 max_tokens 设置够大,否则推理链会被截断,导致标签解析失败。

6. 工程落地经验与统一通道 CTA

跑完上面所有验证,你应该已经有一套可复现的推理范式测试流程了。最后分享几条实战中反复验证过的经验。

第一,从最简单的范式开始,逐级加码。先试 Zero-shot,不行加 Few-shot,还不行上 CoT,准确率不够再叠 Self-Consistency,涉及外部世界就切 ReAct。每加一级都是在用成本换准确率,你要清楚这笔账是否划算。别一次上全家桶,多一层就多一份成本和故障面。

第二,Few-shot 和 CoT 往往要一起用。最好的 CoT 通常是 Few-shot CoT——用几个带完整推理过程的例子,同时教会模型任务格式和推理方式。单独用 Zero-shot CoT 虽然省事,但在复杂领域模型自己生成的推理链质量参差不齐。

第三,ReAct 的工程难点在鲁棒性。模型生成的 Action 格式可能不合法,工具可能失败,循环可能陷入死胡同。生产级 ReAct 需要严格的输出格式解析和重试、工具失败的兜底策略、最大循环次数限制,以及对每一环的观测。

第四,做对比测试时,统一 API 通道能省掉大量环境切换成本。你只需要维护一份测试脚本,改 model 字段就能跑完整个模型矩阵。对于需要频繁切换模型做 A/B 对比的场景,这个效率提升是实打实的。

如果你要长期做编码类 Agent 或者需要频繁调用多种模型做推理范式实验,可以了解一下 Coding Plan:https://taotoken.net/coding-plan 。对于需要接入 Claude Code 做代码辅助的场景,接入文档在这里:https://taotoken.net/doc 。

现在就可以动手:去 https://taotoken.net/console/api-keys 创建一个 Key,把第三节的配置复制到你的项目里,先跑通 4.1 的基础连通性验证,然后按 4.2 到 4.5 逐步验证四类范式。跑通之后,用 4.6 的多模型对比矩阵,找出在你的具体任务上性价比最高的范式组合。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询