Prompt 四模式:CoT / Few-shot / ReAct / ToT

W1 · Prompt 四模式:CoT / Few-shot / ReAct / ToT

关键词:Prompt 及格线 / CoT / Few-shot / ReAct / ToT / 代码路由 前置:会流式收答案(见《初识流式输出》) 收尾预告:ReAct 的"Observation"要真工具结果,下一站就是手撸 Function Calling


零、什么样的 prompt 算"过及格线"

先说个反直觉的判断:Prompt 工程有没有及格,和技巧高不高级无关。

一段"请一步步思考"能及格,一段花哨的角色扮演也能及格——判据不是"看起来专业",而是可验证。三个硬指标:

指标白话版怎么检验
角色任务清晰模型知道"你是谁、要干什么"换个人看这段 prompt,也能说出它的用途
输入输出边界明确输入什么、输出什么格式说死了连续跑 3 次,格式稳定
可复用可测试换参数能复用,不是一次性同一个函数换 3 组参数都能跑

及格线 = 角色清晰 + 边界明确 + 可复用可测试。 与技巧花哨与否无关。

为什么 Agent 工程日常做的是 prompt 工程,而不是微调?

微调贵、慢、且改不动"工具调用"这种动态行为。prompt 工程便宜、灵活、可迭代——先 prompt,不够再考虑微调(那是模型工程师的活,不是 Agent 工程师的)。

⚠️ 顺带泼一盆冷水:AI 是加速器,不是替代者。 它能写代码,但架构设计、工具拆分、安全审查、调试评估、部署运维这些工程决策必须由人来做——你学这些,是为了能判断它写得好不好、能在它之上搭产品。


一、先有个统一底座:get_response

后面四种模式都只是"拼不同的 messages",最后都要过一个统一的请求函数。上一篇文章详细拆过流式,这里直接给出完整版作为全篇的地基:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import os
from openai import OpenAI

client = OpenAI(api_key=os.getenv("DEEPSEEK_API_KEY"),
                base_url="https://api.deepseek.com")


def get_response(messages, **kwargs):
    """统一请求入口:流式接收 + 双通道收集(思考 + 正文)。
    注意:如果生成了正式 content,会把 assistant 消息存回 messages(见多轮对话)。"""
    response = client.chat.completions.create(
        model=kwargs.get("model", "deepseek-v4-flash"),
        messages=messages,
        stream=True,                                  # 流式:一截一截收
        reasoning_effort=kwargs.get("reasoning_effort", "low"),
        max_tokens=kwargs.get("max_tokens", 500),
    )
    reasoning_content, content = "", ""
    for chunk in response:
        delta = chunk.choices[0].delta
        if delta.reasoning_content:                   # 草稿纸(思考)
            reasoning_content += delta.reasoning_content
        if delta.content:                             # 正式稿(正文)
            content += delta.content
    if content:
        messages.append({"role": "assistant", "content": content})   # 存回历史
        return content
    return reasoning_content                          # 纯思考题兜底

⚠️ 注意那个副作用:get_response 生成正文后会把 assistant 消息 append 回 messages。这是刻意设计——多轮对话的"记忆"就是这么累积的:每轮 user 进来、assistant 存回去,messages 越来越长,模型越来越"记得"。但它让一个纯函数带了副作用,后面模式工厂里你会看到两种用法打架。先记住这个设计,第七章会回来处理它。


二、CoT:把思考过程写出来

2.1 是什么

CoT(Chain of Thought,思维链)= 别让模型"张口就答",让它先把推理步骤写出来,再给结论。

就像做数学题老师要求"写出解题过程",不许直接填答案。

1
2
3
4
5
6
7
def cot_prompt(question, system_prompt="你是一个逻辑缜密,思维严谨的推理助手"):
    """CoT:要求一步步思考再回答"""
    u = f"请一步步思考,再给出答案。\n问题:{question}"
    return [
        {"role": "system", "content": system_prompt},   # 人设(规则)
        {"role": "user", "content": u},                 # 任务(要求一步步想)
    ]

2.2 解决什么问题

多步推理、数学逻辑题——模型直接答容易"跳步出错":

1
2
3
4
5
6
7
  小明有 3 个苹果,又买了 2 打(12 个/打),分给 4 个朋友,每人几个?

  ❌ 直接答:5 个            ← 跳步:忘了把"2 打"换算成 24
  ✅ 一步步想:
     1) 3 + 2×12 = 27 个
     2) 27 ÷ 4 = 6.75
     3) 每人 6.75 个

逼它写过程,就能大幅提高正确率——因为每一步都摊开在眼前,跳步会被"自己看见"。

2.3 CoT 的本质:一条指令

CoT 不是某种固定格式,它本质就是一条指令(“请一步步思考”):

  • 放 system → 当规则(全程都这么答)
  • 放 user → 当任务要求(这题这么答)

放哪都行,效果差异不大——选哪个取决于你要"全局生效"还是"单题生效"。

💡 当你已经开了 DeepSeek 的 thinking(reasoning_content)时,还需要 prompt 层的 CoT 吗? 两条路都能让模型"多想一步",但机制不同:thinking 是模型厂商在推理层实现的;CoT 是你在 prompt 层要求的。追求稳妥就两者都开——模型层面多想 + 文本层面要求,双保险。


三、Few-shot:给范例,让模型照葫芦画瓢

3.1 是什么

Few-shot = 在问题前面放几个「输入 → 输出」的例子,让模型模仿。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
DEFAULT_EXAMPLES = [
    {"question": "我明天下午3点约了张医生复诊",
     "answer": "时间:明天下午3点;人物:张医生;事项:复诊"},
    {"question": "周五晚上和李总在望江楼吃饭",
     "answer": "时间:周五晚上;人物:李总;事项:吃饭"},
]

def few_shot_prompt(question, examples=DEFAULT_EXAMPLES,
                    system_prompt="你是擅长信息抽取的助手"):
    """Few-shot:先给 2 个问答范例,再问真问题。"""
    msgs = [{"role": "system", "content": system_prompt}]
    for ex in examples:
        msgs.append({"role": "user", "content": ex["question"]})    # 示例问题
        msgs.append({"role": "assistant", "content": ex["answer"]})  # 示例答案
    msgs.append({"role": "user", "content": question})               # 真问题
    return msgs

类比:新员工入职,先看老员工处理过的几单(输入 → 标准输出),再自己上手。给的是"范例",不是"规则"。

3.2 解决什么问题

格式固定、样本少的任务——比如"把消息分类成 情绪 / 任务 / 闲聊"。规则说不清(什么算"任务"?边界很模糊),但给 2~3 个例子它立刻就会。

1
2
3
4
5
6
  用规则描述:  "判断用户意图,可能是任务、闲聊或情绪表达……"   ← 说不清
  用例子示范:
    user: "帮我订明天去上海的机票"    assistant: 任务
    user: "今天好累啊"                assistant: 情绪
    user: "讲个笑话吧"                assistant: 闲聊
    user: "提醒我晚上买牛奶"          → 模型自然会模仿成: 任务

3.3 🎯 Few-shot 的本质:示例必须组装成消息对

Few-shot 与 CoT 有个关键差别——CoT 是一条指令,Few-shot 是一组"问答对"。

而 API 只认 user/assistant 交替的 messages 结构,所以示例必须拆成多轮消息对:

1
2
3
4
5
# ❌ 错误:把示例塞进一段 user 话里
{"role": "user", "content": "示例:Q:... A:... 示例2:Q:... A:... 现在回答:..."}

# ✅ 正确:示例拆成 user/assistant 交替(见 few_shot_prompt)
[user 示例1问题] [assistant 示例1答案] [user 示例2问题] [assistant 示例2答案] [user 真问题]

🎯 这就是"prompt 必须用代码实现"的第一个理由:文字是 content,代码是组装——API 只接收带 role 的 messages 结构,Few-shot 的"一问一答"格式必须由代码拆成多轮消息,手写文本做不到。

3.4 多轮对话练习:让"记忆"自然发生

把第一节那个"自动存回 assistant"的设计用起来,就得到了天然带记忆的多轮对话:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
def get_response(messages, **kwargs):
    # ……(同第一节:流式收集 + 存回 assistant)……

# system 定义人设:Agent 老师
messages = [{"role": "system", "content":
    "你是一个耐心 Agent 老师,擅长用通俗的语言解释学生提到的问题。"
    "请根据问题一步步分析学生当前的学习阶段,给出最适合当前阶段的回答。"}]

while True:
    user_input = input("User: ")
    if user_input.lower() in ["exit", "quit"]:
        break
    messages.append({"role": "user", "content": user_input})   # 本轮问题入队
    response = get_response(messages)                          # 内部会把 assistant 存回
    print("Agent导师:", response)

看消息列表怎么自己长胖的:

1
2
3
4
5
  第 1 轮前:  [system, user₁]
  第 1 轮后:  [system, user₁, assistant₁]
  第 2 轮前:  [system, user₁, assistant₁, user₂]
  第 2 轮后:  [system, user₁, assistant₁, user₂, assistant₂]
  …… messages 每轮 +2,模型每轮都"记得"前面聊过什么

💡 这就是最简单的记忆:把历史全塞进上下文。它的上限是 token 窗口——聊长了会爆。怎么在"全记住"和"装不下"之间取舍,是 W3 MemoryManager 要解决的事,这里先建立直觉。


四、ReAct:边想边做(Agent 的前身)

4.1 是什么

ReAct = Reason + Act(边思考边行动)——模型不闷头答,而是"想一步 → 做一步 → 看结果 → 再想下一步"。

1
2
3
4
5
Thought: 我先想清楚要做什么
Action: 调哪个工具
Action Input: 传什么参数
Observation: 工具返回了什么
Answer: 最终答案

4.2 文本版 prompt(第一步:先让模型"假装"会调工具)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def react_prompt(question, system_prompt="你是多种能力的小助手", tools="搜索引擎、计算器"):
    """ReAct 文本版:让模型按 Thought/Action/Observation/Answer 格式回答。
    注意:这里 Observation 是模型自己"编"的——它还没真工具可用。"""
    u = (f"可用工具:{tools}。请严格按格式回答:\n"
         f"Thought: 先根据用户问题想清楚要干什么\n"
         f"Action: 调用哪个工具更适合该问题\n"
         f"Action Input: 参数\n"
         f"Observation: 工具返回结果\n"
         f"Answer: 最终答案\n\n问题:{question}")
    return [{"role": "system", "content": system_prompt},
            {"role": "user", "content": u}]

跑一次你会看到什么——模型确实会按格式输出:

1
2
3
4
5
  Thought: 用户问天气,需要调用天气查询工具
  Action: get_weather
  Action Input: {"city": "北京"}
  Observation: 北京今天晴,26℃          ← ⚠️ 它自己编的!没人真查
  Answer: 北京今天晴,26℃

模型演了一出完整的工具调用戏——但 Observation 是它编的。 它没有真的查天气,它"假装查了"。

🎯 这就是 ReAct 文本版的天花板,也是下一篇的起点:格式已经对了,但"Observation"必须是真工具的真结果——谁来执行 Action、谁来填真的 Observation?答案就是 Function Calling:模型输出 Action 意图,你的代码执行工具,把真结果回填。下一篇《手撸 Function Calling》就是把 ReAct 里那句"假装查了"变成"真查了"。

4.3 为什么说 ReAct 是 Agent 的前身

1
2
3
4
5
  普通对话:  用户 → 模型 → 答案            (一次问答)
  ReAct:     用户 → 想一步 → 做一步 → 看结果 → 再想 → 答案   (循环)

  ReAct 第一次把"行动"和"观察"装进了回答格式里
  → 它差的就是"真能行动"——那就是 Agent

五、ToT:发散 → 评估 → 收敛

5.1 是什么

ToT(Tree of Thoughts,思维之树) 的核心是三步循环:

1
2
3
4
5
  发散:生成多条路径(多个方案)
    ↓
  评估:给每条路径打分(优缺点/风险)
    ↓
  收敛:选出最优路径(并给出实施步骤)

类比:不是只画一条路走到底,而是先在纸上画好几条路,逐一评估,再选最好那条走。

5.2 工程上两种做法

单 prompt 版多轮循环版(真 ToT)
做法让模型一口气走完发散→评估→收敛分三次调用 API,每步一个专家
API 调用1 次3 次
成本低高(约 3 倍)
可控性低(三步混在一次回答里)高(每步可单独调 prompt、可干预)
适合快速出方案关键决策

选型看任务:快速出方案用单 prompt,关键决策用多轮循环。

5.3 单 prompt 版

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
def tot_prompt(system_prompt, question, n=3):
    """ToT 单调用版:把"发散→评估→收敛"全塞进一个问题里"""
    u = (f"请针对以下问题,提供{n}个不同的解决方案,"
         f"然后逐步分析每个解决方案的优缺点,最后给出最优方案,"
         f"并说明理由。\n\n问题:{question}")
    return [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": u},
    ]

# 使用:
msgs = tot_prompt("你是资深的 Agent 架构师,擅长多种角度对比方案", user_input)
response = get_response(msgs, max_tokens=1000)

特点:一次调用、三步混在一次回答里。步骤之间的"节奏"模型自己掌握,你插不上手。适合"随便给个像样的方案就行"的场景。

5.4 多轮循环版(真 ToT)

三个独立调用,每个一个"专家人设":

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def ask(question, system_prompt="你是擅长多种角度对比方案的资深 Agent 架构师",
        max_tokens=500):
    """单次问答:组装 system + user 并调用"""
    msgs = [{"role": "system", "content": system_prompt},
            {"role": "user", "content": question}]
    return get_response(msgs, max_tokens=max_tokens)


def tot_solve(question, n=3):
    """真 ToT:三次调用,三个专家接力。每步的结果喂给下一步。"""
    # ① 发散:规划专家给 n 条思路
    schemes = ask(
        f"请针对以下问题给出{n}种不同解决思路,编号列出:\n{question}\n",
        system_prompt="你是擅长发散思维的规划专家",
        max_tokens=600,
    )
    # ② 评估:评审专家逐条打分(上一步的产出喂进来)
    scores = ask(
        f"请对以下 {n} 个方案逐一打分(1-10分),并各用一句话说明理由:\n{schemes}",
        system_prompt="你是严格的评审专家,打分要客观",
        max_tokens=500,
    )
    # ③ 收敛:决策专家选最优(评分喂进来)
    best = ask(
        f"综合以下评分,选出最优方案,并给出具体实施步骤:\n{scores}",
        system_prompt="你是决策专家,直接给最终选择",
        max_tokens=600,
    )
    return schemes, scores, best


# 使用:
s1, s2, s3 = tot_solve(user_input)
print("方案:", s1)
print("评审:", s2)
print("决策:", s3)

看它的"数据流":schemes 是 ② 的输入,scores 是 ③ 的输入——每一步的产出,是下一步的上下文。这就是"多步 Agent 编排"的最早形态:

1
2
  question ──▶ [规划专家] ──schemes──▶ [评审专家] ──scores──▶ [决策专家] ──▶ best
                发散                   评估                   收敛

💡 每个"专家"其实只是换了个 system_prompt——同一个模型,人设一变,就"扮演"不同角色。角色分离(人设)是编排复杂任务的成本最低的手段。

⚠️ ToT 的 token 陷阱:输出量大(三份长文本),最容易触 max_tokens 上限。判断信号是"结尾突兀 / 结构缺块 / 方案数量不足"。对策三件套:给足 token(max_tokens=600+)、拆多轮循环(每步独立控制)、约束格式。


六、🎯 为什么必须用代码路由,而不是手动粘贴

四种模式都有了,还差一个问题:谁来决定"这题用哪个模式"?

6.1 手动粘贴的局限

手动粘贴 prompt = 单次、人工、不可复用。你在聊天框里试出一个好 prompt,下次还得手动复制——它活在对话里,不活在系统里。

6.2 代码路由的三层价值

1
2
3
4
5
6
  ① 自动化     系统自己判断并调用,不用每次人工选
  ② 执行动作   路由选中的不只是"一段文字",而是一整套执行流程
     —— ReAct 会启动"调 API → 执行工具 → 结果回填"的循环
     —— ToT 是三次调用的编排
     —— 这是手动粘贴永远做不到的
  ③ 可观测    能打日志、能批量测试、能调策略

一句话:单次聊天靠 LLM 自动发挥就够了;做 Agent 系统,必须用代码路由。

6.3 模式注册表 + 路由函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# ── 模式注册表:名字 → prompt 构建函数 ──
BUILDERS = {
    "cot": cot_prompt,
    "few_shot": few_shot_prompt,
    "react": react_prompt,        # 文本版(Observation 还是编的,真工具见 FC 篇)
}


def auto_select(question: str) -> str:
    """让 LLM 判断这题适合哪种模式,返回模式名。
    规则写在 prompt 里;识别用关键词兜底(tot→react→few_shot→cot)。
    匹配顺序从长到短,避免 'cot' 误吞 'react'。"""
    content = (
        f"判断下面用户的问题适合哪种回答模式,输出:tot 或 react 或 few_shot 或 cot\n"
        f"规则:需要一步步推理/数学解题/公式推导的输出 cot;"
        f"固定模板化抽取信息的输出 few_shot;"
        f"需要调工具(天气/计算等)的输出 react;"
        f"开放性问题/多方案对比找最优的输出 tot\n"
        f"问题:{question}"
    )
    text = get_response([{"role": "user", "content": content}],
                        max_tokens=50).lower()
    for mode in ["tot", "react", "few_shot", "cot"]:   # 先长后短
        if mode in text:
            return mode
    print("[警告] 未识别到模式名,兜底 cot")
    return "cot"


def run_mode(mode: str, question: str, **kw):
    """按模式执行。tot 特判(要拼三段输出),其余走 BUILDERS。"""
    if mode == "tot":
        schemes, scores, best = tot_solve(question, n=kw.get("n", 3))
        return f"【方案】\n{schemes}\n\n【评审】\n{scores}\n\n【决策】\n{best}"
    if mode not in BUILDERS:
        raise ValueError(f"未知模式:{mode},可选 {list(BUILDERS) + ['tot']}")
    msgs = BUILDERS[mode](question, **kw)
    return get_response(msgs, **kw)


# ── 主循环:选模式 → 执行 → 输出(Agent 的第一版驾驶舱)──
while True:
    user_input = input("User: ")
    if user_input.lower() in ["exit", "quit"]:
        break
    mode = auto_select(user_input)
    print(f"[使用模式] {mode}")
    result = run_mode(mode, user_input)
    print("Agent导师:", result)

看主循环那三行——不再是"你选模式",而是模型看问题自己选:

1
2
  以前:你写死一种方式 → 调用
  现在:模型看问题 → 自己选 cot/few_shot/react/tot → 执行

🎯 这就是"会选模式"的 Agent 雏形。它和《手撸 Function Calling》里那套 fc_loop 合体后,就是能"自己选怎么答 + 真调工具"的完整 Agent——下一篇收这个口。

⚠️ 诚实提醒:auto_select 用关键词兜底而非纯靠 LLM,是有意的。纯靠 LLM 选模式,选错一次整个回答就废了;关键词兜底虽笨,但可预测、可调试。先跑通规则,再放开给模型。


七、踩坑记

坑 1:把 Few-shot 示例堆进一段 user 话 ⚠️

  • 现象:给了示例模型还是不按格式走
  • 原因:API 只认 user/assistant 交替的 messages——示例得拆成"一问一答"的消息对
  • 解法:示例逐个 user(问题) + assistant(答案) 交替插入,真问题放最后

坑 2:CoT 的"一步步思考"放错层 ⚠️

  • 现象:想让全局按 CoT,结果只对单题生效(或反之)
  • 原因:指令放 system 是规则(全局),放 user 是任务(单题)
  • 解法:想清楚作用域再放。多数场景放 user 更干净——不至于让所有回答都啰嗦

坑 3:get_response 的"自动存回"副作用踩多轮 ⚠️

  • 现象:纯函数场景(如 auto_select 只问一句话)messages 被悄悄 append 了 assistant
  • 原因:get_response 把存回历史写死在函数里——多轮对话需要它,一次性问答不需要
  • 解法:要么拆出 ask_once(不存回)和 ask_chat(存回)两个版本;要么用参数 save=True/False 控制

坑 4:ToT 输出被 max_tokens 截断 🔴

  • 现象:方案列到一半没了 / 结尾突兀 / 结构缺块
  • 原因:ToT 输出量大,token 上限不够
  • 解法:给足 token(600+)、拆多轮循环(每步独立)、约束格式(编号列出)
  • 自检信号:结尾突兀 / 结构缺块 / 方案数量不足——三选一即中招

坑 5:ReAct 文本版把"编的 Observation"当真的 ⚠️

  • 现象:模型输出 Observation: 北京晴 26℃,你当真了
  • 原因:文本版没有真工具,Observation 是模型自己编的(幻觉的温床)
  • 解法:记住 Observation 必须来自真工具执行——这正是下一站 Function Calling 要解决的。在接真工具前,别把文本版 ReAct 用于任何需要真实数据的场景

坑 6:auto_select 匹配顺序反了 ⚠️

  • 现象:模型输出 “react_prompt” 却被匹配成 “cot”("cot" in "react_prompt" → False?对,但 "cot" in "few_shot_cot..." 会误伤)
  • 注意:子串匹配的坑在于短模式是长模式的子串(如 cot ⊂ scotland)
  • 解法:从长到短匹配(tot → react → few_shot → cot),或要求模型输出纯模式名后做精确匹配

坑 7:react 返回字符串、其他模式返回消息 ⚠️

  • 现象:run_mode 里 react 特判,其他走 BUILDERS——接口不齐
  • 原因:react 直接进 fc_loop 拿最终答案,其余返回消息列表
  • 解法:演进过程中先跑通、后统一(把 react 也包成"返回字符串"的一致接口)。接口不齐是演进的常态,别为了好看卡住进度

八、速查卡片(复习直接看这)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# ===== 三种模式一句话 =====
# CoT      要求一步步思考 → 适合数学/推理(本质:一条指令)
# Few-shot 给范例照葫芦画瓢 → 适合格式固定任务(本质:user/assistant 问答对)
# ReAct    想一步做一步看一步 → Agent 前身(Observation 要真工具,见 FC 篇)

# ===== 模式构建函数 =====
def cot_prompt(q, sys="你是逻辑缜密的推理助手"):
    return [{"role": "system", "content": sys},
            {"role": "user", "content": f"请一步步思考,再给出答案。\n问题:{q}"}]

def few_shot_prompt(q, examples=[("小明约了张医生", "时间:明天;人物:张医生")], sys="..."):
    msgs = [{"role": "system", "content": sys}]
    for question, answer in examples:
        msgs.append({"role": "user", "content": question})       # 一问
        msgs.append({"role": "assistant", "content": answer})     # 一答
    msgs.append({"role": "user", "content": q})                   # 真问题
    return msgs

def react_prompt(q, tools="搜索引擎、计算器"):
    u = (f"可用工具:{tools}。请严格按格式回答:\nThought:...\nAction:...\n"
         f"Action Input:...\nObservation:...\nAnswer:...\n\n问题:{q}")
    return [{"role": "system", "content": "你是多种能力的小助手"},
            {"role": "user", "content": u}]

# ===== ToT 两种做法 =====
# 单调用:tot_prompt 一发带走(发散→评估→收敛 混在一次回答)
# 多轮:  tot_solve 三连调(规划→评审→决策,每步产出喂下一步)→ 关键决策用这个

# ===== Prompt 及格线 =====
# 角色任务清晰 + 输入输出边界明确 + 可复用可测试(与技巧高级无关)

九、一句话总结

Prompt 四模式不是四种"写法技巧",而是四种"思考方式":CoT 让模型把推理摊开、Few-shot 让模型按范例模仿、ReAct 让模型边想边做、ToT 让模型多条路评估后择优。及格的标准永远是"角色清晰 + 边界明确 + 可复用可测试"。

而你这一篇真正学会的是:

1
2
3
4
5
6
  ① 文字(prompt 内容)和代码(messages 组装)缺一不可
     —— API 只收带 role 的结构,Few-shot 的问答对必须代码拆
  ② 模式可以注册成表(BUILDERS),用路由(auto_select)选
     —— 代码路由 = 自动化 + 执行动作 + 可观测,手动粘贴做不到
  ③ ReAct 的 Observation 必须是真工具的真结果
     —— 文本版只是"演戏",接真工具才是 Agent

下一篇《手撸 Function Calling》:把 ReAct 里那句"假装查了"变成"真查了"——模型输出 Action 意图,代码执行工具,把真 Observation 回填,再让模型基于真结果作答。到那时,你从"让模型按格式说话"(本篇)进到"让模型驱动真实世界"(下一篇)。


Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 Stack 由 Jimmy 设计