01

食谱开张:从一道"加强版 LLM"开始

Anthropic Cookbook 整本书在教什么 · 以及全书的最小可用单元——Augmented LLM

先回答一个问题:你打开 ChatGPT 问"今天上海下雨吗"——会发生什么?

它会说:"抱歉,我没有访问实时数据的能力。" 这一秒,你就触碰到了"裸 LLM" 的边界——它是一颗会说话的大脑,但被困在一个没有窗户、没有电话、没有日历的房间里。

Anthropic Cookbook 这本食谱整本书在教的,就是怎么给这颗大脑配上窗户、电话、日历、还有一个能干活的助手。

🧗
本课的隐喻:户外攀岩者与登山套件

赤手空拳的攀岩者只能爬最简单的路线。给他/她加上四件套——绳索、保护塞、对讲机、教练——他/她突然就能去挑战更难的山壁。一个普通 LLM 调用就是"赤手攀岩",本课要教的 Augmented LLM(加强版 LLM)就是"装备齐全的攀岩"。

Augmented LLM 的"四件套"

Anthropic 工程师在论文 Building Effective Agents 里把"加强版 LLM"定义成基础单元——一个 LLM 配上以下四种装备的某些子集:

🔍

检索(Retrieval)

让 LLM 能从你自己的知识库里"翻书"——产品文档、客服 FAQ、内部 wiki。背后机制是 RAG

🛠️

工具(Tools)

让 LLM 能"叫别人去做事"——查天气、发邮件、调用计算器。LLM 自己不动手,它输出一个"请求工单",你的程序去执行。

💾

记忆(Memory)

让 LLM 能"记住你昨天说过什么"——历史对话、用户偏好、长期事实。否则它每次都像初次见面。

📜

系统提示(System Prompt)

给 LLM 一份"岗位说明书"——你是谁、说什么风格、不能碰哪些话题。本质上是把训练好的通用模型"角色化"成你的专属助手。

💡
关键洞察

整本 cookbook 之后所有的复杂模式(链式、路由、Orchestrator、Agent SDK、SRE 自动修复),归根结底都是多个 Augmented LLM 之间的不同接线方式。先把这个最小单元吃透,整本书就是同一个乐高积木的不同组合。

看一段真实代码:7 行做一个能上网的研究员

这段代码来自 claude_agent_sdk/00_The_one_liner_research_agent.ipynb——整本 cookbook 的 "Hello World"。它是最小可用的 Augmented LLM:LLM + 一件工具(网页搜索)。

CODE · Python
from claude_agent_sdk import ClaudeAgentOptions, query

messages = []
async for msg in query(
    prompt="Research the latest trends in AI agents and give me a brief summary and relevant citations.",
    options=ClaudeAgentOptions(model=MODEL, allowed_tools=["WebSearch"]),
):
    print_activity(msg)
    messages.append(msg)
中文逐行翻译

第 1 行:从 Anthropic 官方 SDK 里把"提问"函数和"配置"工具拿进来。

第 3 行:准备一个空列表,待会儿 agent 跟我们说的每一句话都收进去。

第 4 行:开启异步流式接收——像看直播一样,agent 每说一句、做一步,你都能立刻看到。

第 5 行:我们的"任务订单"——研究 AI agent 最新趋势,给我摘要和引用链接。

第 6 行:关键配置——选用哪个模型,并且 允许它使用一个工具:网页搜索。这就是"Augmented LLM":一个 LLM + 一件工具。

第 8-9 行:把 agent 的每一条思考、每一次搜索、每一段答复都打印出来并存档。

整段共 7 行有效代码——一个能上网做调研的研究员。这就是 cookbook 的 Hello World。

看场对话:裸 LLM vs 加强版 LLM

同一个用户、同一个问题,两次对话——区别是有没有装备。

这本食谱里有什么——给你一张全景地图

整个 cookbook 仓库按"教学价值"重排后是这样的——后续 5 个模块,会按这张地图带你走完最重要的章节:

anthropic-cookbook/ 本食谱根目录
patterns/agents/ 5 大基础编排模式(模块 2、3 主讲)
tool_use/ 让模型动手——function calling 全套(模块 4 主讲)
claude_agent_sdk/ 7 个 notebook 从 one-liner 到 SRE(模块 5 主讲)
capabilities/ RAG / 知识图谱 / 文本转 SQL / 分类 / 摘要
skills/ Claude Skills——可复用的"本领包"(模块 6 涉及)
multimodal/ 视觉 / PDF / 图表理解
extended_thinking/ 让模型有"思考预算"(模块 6 主讲)
misc/ prompt_caching / JSON 模式 / PDF 上传等实用配方
managed_agents/ · observability/ · finetuning/ · tool_evaluation/ 进阶或特定领域配方(本课不展开,你已有钥匙自己读)

小测:你能认出哪一颗 LLM 装备齐了吗?

Q1. 你想让 Claude 写一首关于秋天的现代诗。最合理的做法是?

Q2. 你的 AI 助手反复说"抱歉我没有实时数据 / 我不知道现在几点 / 我访问不了你公司的内部 wiki"。你应该给它加什么?

Q3. 你公司的客服机器人每次新会话都要让用户重新报姓名、订单号、产品型号——同一个用户上次刚说过这些。最缺的是哪一件装备?

02

三种最基础的工序:链式 · 路由 · 并行

当一个 LLM 一次答不完,你怎么把多个调用编排起来——agentic 架构的第一道分水岭

把多个 LLM 编排起来——形状决定工序

上一模块我们看到 Augmented LLM 是基础单元。但一个单元能干的事有限。现在的问题是:当任务复杂到一个 LLM 一次答不完,你怎么把多个调用编排起来?

Anthropic 工程师在论文里给出了三种最基础的编排方式——本课用一家"现代化奶茶吧台"作贯穿隐喻:

🧋
本课的隐喻:奶茶吧台的三种工序

链式 = 流水线:5 个工位前后接力,前一步的产物喂给下一步。
路由 = 分流员:店员看你点什么,把订单送到对应的专业工位。
并行 = 多窗口同时出杯:4 个工位同时开工,最后一起打包。

⛓️

链式 Chain

何时用:任务能拆成"先 A 再 B 再 C" 的固定步骤。
例子:抽数据 → 转格式 → 排序 → 渲染表格。
不要用:任务步骤会随输入变化。

🚦

路由 Route

何时用:输入分多种类型,每种要不同的专门处理。
例子:客服工单分到账单 / 技术 / 安全三个专员。
不要用:所有输入处理逻辑都一样。

并行 Parallel

何时用:多个独立子任务可以同时进行。
例子:对 100 条评论同时打分;对一篇文章同时做"摘要 / 翻译 / 关键词"。
不要用:后一步依赖前一步结果。

工序一:链式 Chain——前一步的输出喂给下一步

来自 patterns/agents/basic_workflows.ipynb——整个 chain 函数 5 行有效代码:

CODE · Python
def chain(input: str, prompts: list[str]) -> str:
    """Chain multiple LLM calls sequentially, passing results between steps."""
    result = input
    for i, prompt in enumerate(prompts, 1):
        print(f"\nStep {i}:")
        result = llm_call(f"{prompt}\nInput: {result}")
        print(result)
    return result
中文逐行翻译

第 1 行:定义一个叫 chain 的"组装机"——吃进一段输入和一串 prompt 清单。

第 3 行:把"当前结果"初始化为最初的用户输入。

第 4 行:按顺序拿每一个 prompt——步骤 1、步骤 2、步骤 3……

第 6 行(关键):把"当前结果"塞给下一个 prompt 当输入,再调 LLM。前一步的输出 = 后一步的输入——这就是链式的全部魔法。

第 8 行:所有步骤跑完,把最终产物返回。

整个 chain 函数 5 行有效代码——这就是链式工作流的全部。

看一遍真实的链式跑一份业绩报告

cookbook 里给的实际例子:把一段杂乱业绩报告加工成 Markdown 表格,4 步流水线。点"下一步"逐步看:

📥
用户输入
1
抽数字
2
转百分比
3
排序
4
渲染表格
点"下一步"开始

工序二:并行 Parallel——同一份指令,N 份输入同时跑

CODE · Python
def parallel(prompt: str, inputs: list[str], n_workers: int = 3) -> list[str]:
    """Process multiple inputs concurrently with the same prompt."""
    with ThreadPoolExecutor(max_workers=n_workers) as executor:
        futures = [executor.submit(llm_call, f"{prompt}\nInput: {x}") for x in inputs]
        return [f.result() for f in futures]
中文逐行翻译

第 1 行:定义"并发分工机"——吃进 1 个共用 prompt 和 N 个待处理输入。

第 3 行:开 3 个并发工位(线程池)。

第 4 行(关键):把 N 个任务一次性丢给工位——每位工人都拿到同一份 prompt但处理不同的输入。这是并行模式的核心约束。

第 5 行:等所有工位完工,结果按顺序收齐返回。

关键洞察:prompt 不变,input 变。适合"同样的指令处理一堆不同对象"——比如对 100 条评论同时打分、给一篇文章同时生成摘要 / 翻译 / 关键词三种产物。

为什么"并行"快

顺序调 100 次 LLM,每次 2 秒 → 200 秒。开 10 个并发工位 → 约 20 秒。等待 LLM 回复的时间是浪费的,并行就是把这些等待时间叠在一起。账单不变,但用户感觉快了 10 倍。

工序三:路由 Route——分诊台 + 专科医生

路由的核心是两次 LLM 调用:第一次 LLM 当"分诊台"判断输入类型,第二次用对应的"专科 prompt"处理实际工作。

CODE · Python
def route(input: str, routes: dict[str, str]) -> str:
    selector_prompt = f"""
    Analyze the input and select the most appropriate support team
    from these options: {list(routes.keys())}
    First explain your reasoning, then provide your selection in this XML format:
    <reasoning>...</reasoning>
    <selection>The chosen team name</selection>
    Input: {input}""".strip()

    route_response = llm_call(selector_prompt)
    route_key = extract_xml(route_response, "selection").strip().lower()

    selected_prompt = routes[route_key]
    return llm_call(f"{selected_prompt}\nInput: {input}")
中文逐行翻译

第 2-8 行:构造"分诊 prompt"——告诉 LLM 有哪些可选窗口、要先讲推理、再用 XML 标签 给出最终选择。

第 10 行:第一次 LLM 调用——分诊台开工。

第 11 行:用 extract_xml 把 <selection>标签里的内容拎出来,作为路由 key。

第 13-14 行:用 key 取出对应的"专科 prompt",第二次 LLM 调用——专员处理。

核心:两次 LLM 调用,第一次决定"去哪",第二次干活。

看一场真实的路由:客户报修工单

💡
关键洞察:三种工序可以嵌套

真实生产系统经常是 route → chain → parallel 的嵌套——先按工单类型路由,进了"账单专员"窗口后再走 "查订单 → 算金额 → 出退款单" 的链式,每个客户的退款邮件还可以并行批量发。先按形状判断,再按需要叠在一起。

小测:判断任务的形状

Q1. 你要做一个程序:客户上传 PDF 后自动生成"摘要 → 关键词 → 翻译成英文"。最适合的工序?

Q2. 你要给一条推文同时打 5 个独立维度的标签:情绪 / 话题 / 国家 / 是否广告 / 风险等级。最佳模式?

Q3. 用户上传一张图,可能是发票、可能是身份证、可能是收据——你要先判断类型,再用对应模板提取信息。最佳模式?

03

高阶工序:调度官 与 评审官

当任务的形状要看到才知道——动态拆解 与 互相博弈打磨的两种模式

现实里,有时候你看到任务的瞬间才知道该怎么拆

上一模块的三种工序都有一个共同假设——你提前知道任务的形状。但 chain 的步骤、parallel 的子任务清单、route 的窗口列表,都是在写代码时就敲死了的(俗称写死)。

现实世界里,很多任务一来你才知道要怎么拆。这一模块教两种处理"未知形状"任务的最重要工序——它们都比基础工序多了一层"元认知"。

🎬
本课的隐喻:纪录片摄制组

Orchestrator-Workers(调度官 + 工人)= 总导演 + 摄影组:导演拿到选题后不预先写好剧本——看现场情况决定这场戏值得拍特写、空镜还是延时,再分别派摄影 A、B、C 去拍各自的镜头,最后剪辑成片。
Evaluator-Optimizer(评审官 + 优化器)= 编剧 + 责编:编剧写一稿初稿交给责编。责编不动笔,只给反馈:"角色动机不清楚 / 第二幕太拖"。编剧拿反馈再改一稿,再交。来回三五次直到 PASS。

调度官的核心 = 一个会现场拆任务的 prompt

看 cookbook 里的 orchestrator prompt——它的精髓是把"导演的元认知"用 XML 结构强约束出来:

PROMPT · 给 Orchestrator
ORCHESTRATOR_PROMPT = """
Analyze this task and break it down into 2-3 distinct approaches:

Task: {task}

Return your response in this format:

<analysis>
Explain your understanding of the task and which variations would be valuable.
</analysis>

<tasks>
    <task>
    <type>formal</type>
    <description>Write a precise, technical version that emphasizes specifications</description>
    </task>
    <task>
    <type>conversational</type>
    <description>Write an engaging, friendly version that connects with readers</description>
    </task>
</tasks>
"""
中文逐句解读

"Analyze this task and break it down into 2-3 distinct approaches"——让 Claude 当导演:看完任务后给我列 2-3 种切入角度。"distinct" 是关键词——必须有差异。

<analysis> 标签——强制导演先讲"为什么这么拆",避免它跳过思考直接出方案。这是 CoT 的一种实现。

<tasks> / <task> / <type> / <description> 嵌套——用 XML 强约束输出结构,方便程序解析成"工单清单"。

{task} 占位符——运行时把实际任务("为环保水壶写产品文案")填进去。

核心:具体拆几个 task、每个 task 是什么风格,全由 Claude 看到 task 那一刻自己决定——不是程序员写死的。这就是"动态拆任务"。

调度官的主循环:1 次导演 + N 次工人

1
导演看任务

第 1 次 LLM 调用——orchestrator 读 task,输出 <analysis> + <tasks> 工单清单。

2
解析工单

用 extract_xml + parse_tasks 把 LLM 吐出来的 XML 转成程序能用的结构化清单。

3
派工人

对每张工单调一次 worker LLM——每个工人独立完成自己那一份。

4
汇总产物

把 N 个 worker 的结果收齐,作为最终产出返回。整个流程 = 1 次导演 + N 次工人 = N+1 次 LLM 调用

CODE · Python(节选)
class FlexibleOrchestrator:
    def process(self, task: str, context: dict | None = None) -> dict:
        # Step 1: Get orchestrator response
        orchestrator_input = self._format_prompt(self.orchestrator_prompt, task=task, **context)
        orchestrator_response = llm_call(orchestrator_input, model=self.model)

        # Parse orchestrator response
        analysis = extract_xml(orchestrator_response, "analysis")
        tasks_xml = extract_xml(orchestrator_response, "tasks")
        tasks = parse_tasks(tasks_xml)

        # Step 2: Process each task
        worker_results = []
        for i, task_info in enumerate(tasks, 1):
            worker_input = self._format_prompt(self.worker_prompt, original_task=task,
                task_type=task_info["type"], task_description=task_info["description"])
            worker_response = llm_call(worker_input, model=self.model)
            worker_results.append({"type": task_info["type"], "result": worker_response})

        return {"analysis": analysis, "worker_results": worker_results}
中文逐行翻译

第 5 行:第 1 次 LLM 调用——导演看任务、决定怎么拆。

第 8-10 行:把导演吐出来的 XML 解析成程序能用的"工单清单"。

第 13 行:对每张工单派一个工人。

第 16 行:第 N 次 LLM 调用(N = 工单数)——每个工人独立完成自己那一份。

第 19 行:把所有产物加上 analysis(导演的解读)一起返回。

关键对比:parallel 的工人清单程序员写死。orchestrator 的工人清单导演现场决定。这一字之差,让系统从"流水线"变成了"团队"。

💡
Aha! Orchestrator vs Parallel——一字之差

两个模式都是"同时跑多个 LLM"。差别在哪?parallel 的工人任务清单是写死的,orchestrator 的工人任务清单是导演现场决定的。如果你能提前列清楚要做哪几件事 → 用 parallel 省一次 LLM 调用;如果要做哪几件事得看具体输入 → 用 orchestrator。

评审官的循环:两个 LLM 互相博弈

这个模式叫 evaluator-optimizer——一个 LLM 写,一个 LLM 评,循环直到 PASS。

CODE · Python
def loop(task, evaluator_prompt, generator_prompt):
    memory = []
    chain_of_thought = []

    thoughts, result = generate(generator_prompt, task)
    memory.append(result)
    chain_of_thought.append({"thoughts": thoughts, "result": result})

    while True:
        evaluation, feedback = evaluate(evaluator_prompt, result, task)
        if evaluation == "PASS":
            return result, chain_of_thought

        context = "\n".join(["Previous attempts:",
            *[f"- {m}" for m in memory], f"\nFeedback: {feedback}"])

        thoughts, result = generate(generator_prompt, task, context)
        memory.append(result)
中文逐行翻译

第 2 行:准备一本"草稿本"——记下每一稿。

第 5 行:编剧(generator)先写第一稿。

第 9 行:进入打磨循环。

第 10 行:责编(evaluator)看稿,吐出"通过 / 还要改"以及具体反馈。

第 11-12 行:责编满意了就交付,整个循环结束。

第 14-15 行:把所有历史草稿和最新反馈打包——告诉编剧"这些你已经写过了,现在按这个反馈改"。注意 memory 的累积——避免编剧在原地打转。

第 17 行:编剧带着批注再写一稿。循环直到 PASS。两个 LLM 互相博弈,自动改稿。

看一场真实的博弈:写一个 Min-Stack

cookbook 里给的实际例子——编剧(generator)和责编(evaluator)在写一个所有操作 O(1) 的栈:

⚠️
生产坑:循环不收敛

真实生产里这个循环最大的危险是——evaluator 一直说 "NEEDS_IMPROVEMENT" 跑了 20 次还没 PASS,账单爆炸。必须设最大轮数,并且检测"反馈是否在重复"——如果第 5 次和第 3 次反馈几乎一样,说明陷入死循环,应该 break 出去交人工。

小测:架构决策题

Q1. 你要给同一个产品生成 3 种固定风格的营销文案:技术控版、文艺版、网红版。三种风格清单是产品经理写死的。最佳模式?

Q2. 你要让 AI 写一篇高质量的长文,并且严格控制语调("专业但不冷淡")。最适合的模式?

Q3. 你的 evaluator-optimizer 跑了 20 多轮还没 PASS,账单爆炸。最该做的两件事?

04

工具调用:让模型动手

Claude 自己不动手——它输出"工单"叫你的程序去做。这是 agent 唯一真的能改变外部世界的方式

Claude 不能查数据库、不能发邮件——但能"叫别人去做"

到上一模块为止,所有工序都还停留在"LLM 之间互相讲话"。Claude 自己看不见时间、查不了数据库、发不了邮件。但你可以教它"叫别人去做这些事"——这就是 tool use 的全部秘密。

♟️
本课的隐喻:国际象棋大师 + 棋钟

大师(Claude)只能"想棋",不能离开桌子去查棋谱。你给他配几张"工具卡"——查开局库、查残局库、问引擎评分。每张卡上写清楚这张牌能干什么、需要什么参数。他想用哪张就抬手按下棋钟、说出工具名和参数。他不亲自查,他叫你去查——你查完把结果递回去,他接着想下一步。整盘棋下来按好几次钟——这就是 agentic loop

📋

Description 决定生死

Claude 看着工具的 description 决定"什么时候用 / 怎么用"。说明书写不清楚,工具就用不对。

📐

JSON Schema 是合同

用 JSON Schema 描述参数形状——必填字段、类型、举例。这是 Claude 和你的程序之间的格式合同。

↩️

tool_result 必须回喂

工具执行完拿到结果后,必须把结果作为 tool_result 角色塞回对话历史,再调一次 Claude——否则 Claude 永远不知道工具结果。

🛑

max_iterations 是救命稻草

agent loop 可能跑飞——加个上限。同时检测"是不是反复调同一个工具"——这往往是死循环征兆。

第一步:写一份"工具说明书"

来自 tool_use/calculator_tool.ipynb——给 Claude 配一个简单计算器:

CODE · Python
tools = [
    {
        "name": "calculator",
        "description": "A simple calculator that performs basic arithmetic operations.",
        "input_schema": {
            "type": "object",
            "properties": {
                "expression": {
                    "type": "string",
                    "description": "The mathematical expression to evaluate (e.g., '2 + 3 * 4').",
                }
            },
            "required": ["expression"],
        },
    }
]
中文逐行翻译

第 1 行:tools 是一个列表——意味着你可以一次给 Claude 配多张卡。

"name": "calculator"——工具的"卡名",Claude 会用这个名字来召唤它。

"description"(关键):这是 tool use 里最重要的一行——Claude 是看着这句话决定"要不要用这个工具"的。说明书写不清楚,Claude 就会用错或干脆不用。要写得像在跟一个聪明但没上下文的实习生交代任务。

"input_schema"——用 JSON Schema 描述参数形状:要一个叫 expression 的字符串。

"required": ["expression"]——强制 Claude 必须填这个参数,不许偷懒。

给 vibe coder 的一句话:tool 的 description 不是写给程序员看的,是写给 Claude 看的。

第二步:跑通 agentic loop

当 Claude 决定要用工具时,它不直接给答案——而是停下来,输出一段"工单",等你执行。然后你把结果回喂,它再继续。看一遍这个 loop 的 7 步动画:

👤
用户
🤖
Claude
⚙️
你的程序
🧮
Calculator
点"下一步"开始
CODE · Python(agentic loop 简化版)
message = client.messages.create(
    model=MODEL_NAME,
    messages=[{"role": "user", "content": user_message}],
    tools=tools,
)

if message.stop_reason == "tool_use":
    tool_use = next(b for b in message.content if b.type == "tool_use")
    tool_result = process_tool_call(tool_use.name, tool_use.input)

    response = client.messages.create(
        model=MODEL_NAME,
        messages=[
            {"role": "user", "content": user_message},
            {"role": "assistant", "content": message.content},
            {"role": "user", "content": [{
                "type": "tool_result",
                "tool_use_id": tool_use.id,
                "content": tool_result,
            }],
        }],
        tools=tools,
    )
中文逐行翻译

第 1-5 行:第一次调 Claude,把"工具说明书清单"一起递过去。

第 7 行:Claude 没直接回答,stop_reason == "tool_use" 表示它要用工具——停下来等你执行。

第 8 行:从 Claude 的回复里挑出"要用工具的那块"——拿到工具名和参数。

第 9 行(真正干活):你的程序按 Claude 给的工具名和参数去执行——拿到结果。

第 11-22 行(关键):第二次调 Claude——把工具结果用 tool_result 这个特殊角色塞回对话历史。这一步是关键——必须保留完整对话上下文,Claude 才知道"刚才让查的结果回来了"。

真实场景里这个过程可能循环多次——直到 stop_reason ≠ "tool_use",才算完。

Spot the Bug:找出这段代码哪行写错了

下面是一段错误的 agentic loop。Claude 调用了工具但 agent 永远不会给最终答复——找出关键 bug 行:

1 message = client.messages.create(model=MODEL, messages=msgs, tools=tools)
2 if message.stop_reason == "tool_use":
3     tool_use = next(b for b in message.content if b.type == "tool_use")
4     tool_result = process_tool_call(tool_use.name, tool_use.input)
5     print(tool_result)  # 拿到结果,打印就完事
6     return tool_result
🐛
这是 vibe coder 用 Cursor / Claude Code 时最常见的 bug 根因

"我让 AI 调一个工具,它好像调了,但最终答复还是没用工具的结果"——99% 是这个 bug:少了第二次 messages.createtool_result 回喂给 Claude。print 工具结果不是答案——把结果塞回对话历史,再调一次 Claude,才有最终答复。

小测:调试 agent 的真实场景

Q1. 你给 Claude 配了一个 send_email 工具,但它从来不用——反而经常自己编邮件内容。最可能的原因?

Q2. 你的 agent 跑了 30 多次工具调用还没结束——账单爆了。最该加的两件事?

Q3. 用户问"订单 ABC123 怎么样了"。Claude 调用 get_order_details(order_id="ABC123"),但 ABC123 不存在。Claude 接下来最可能做的合理动作?

💡
Aha! 模型动嘴,你动手

Tool use 是 Claude 唯一真的能改变外部世界的方式。它写一段文字 ≠ 它发了一封邮件——只有当你真的在 process_tool_call 里调用了发邮件的代码,邮件才会发出去。你才是动手的那个,Claude 只是动嘴。这一点理解了,你就理解了为什么所有 agent 框架的核心都是"工具循环",而不是"模型本身"。

05

Claude Agent SDK:从一行代码到 SRE 值班员

Anthropic 把 Claude Code 的内核以库的形式开放——同一个 SDK,从入门到生产

上一模块手写 70 行才能让 Claude 用一个计算器——Anthropic 自己也觉得太麻烦

所以他们把 agentic loop 打包成了 SDK——从 70 行变 7 行。但 SDK 真正的厉害不是省代码,而是它把 Claude Code 这个产品里所有的 agent 工程经验都开放给了你。

🎹
本课的隐喻:钢琴学习的进阶

Notebook 00 = 第一首练习曲——右手单音、左手 do-mi-sol,5 分钟弹会。
Notebook 01 = 巴赫小品——左右手协奏,加上踏板(CLAUDE.md / Output Styles / Plan Mode / Hooks / Subagents)。
Notebook 03 = 拉赫玛尼诺夫——八度大跳、复杂踏板、还要现场即兴(MCP 工具 / 安全 hook / 远程修配置)。
同一架琴(Claude Agent SDK),同一双手,难度从入门到大师级。

1
Research Agent · 一行 query()

WebSearch + 一句任务订单。能上网做调研。

2
Chief of Staff · 长记忆 + 子 agent

ClaudeSDKClient + CLAUDE.md + Subagents + Output Styles + Plan Mode + Hooks。能当一家 50 人公司的参谋长。

3
Observability Agent · 接外部系统

+ MCP 服务器(Git / GitHub)+ 审计 hook。能监控 CI/CD、识别故障。

4
SRE Agent · 写权限 + 安全围栏

+ 写权限 + PreToolUse 安全钩子 + Prometheus + Docker 控制。能值守生产、自动诊断 + 修复 + 写 post-mortem。

第一首练习曲:7 行的 Research Agent

来自 claude_agent_sdk/00_The_one_liner_research_agent.ipynb——把模块 4 手写的 70 行 agentic loop 替换成这个:

CODE · Python
from claude_agent_sdk import ClaudeAgentOptions, query

messages = []
async for msg in query(
    prompt="Research the latest trends in AI agents and give me a brief summary and relevant citations.",
    options=ClaudeAgentOptions(model=MODEL, allowed_tools=["WebSearch"]),
):
    print_activity(msg)
    messages.append(msg)
中文逐行翻译

第 1 行:从官方 SDK 拿"提问"和"配置"两件事。

第 4 行:async for 流式接收 agent 的每一条动作和输出——像看直播一样。

第 5 行:任务订单(prompt)。

第 6 行(关键):allowed_tools 是 SDK 的安全围栏——你能精确控制 agent 能动什么、不能动什么。

第 8-9 行:把 agent 的所有动作打印 + 存档。

对比模块 4 手写 70 行的 agentic loop——SDK 把 while loop / tool dispatch / 对话历史管理全包圆了。

巴赫小品:Chief of Staff + 长期记忆

来自 claude_agent_sdk/01_The_chief_of_staff_agent.ipynb——给 50 人初创公司当 AI 参谋长:

CODE · Python
async with ClaudeSDKClient(
    options=ClaudeAgentOptions(
        model=MODEL,
        cwd="chief_of_staff_agent",  # Points to subdirectory with our CLAUDE.md
        setting_sources=["project"],
    )
) as agent:
    await agent.query("What's our current runway?")
    async for msg in agent.receive_response():
        print_activity(msg)
        messages.append(msg)
中文逐行翻译

第 1 行:用 ClaudeSDKClient——和上一段的 query() 不同,这个是有状态会话,能记住一整轮对话。

第 4 行(关键):cwd 把 agent 的"工作目录"指到一个子文件夹。关键魔法:那个文件夹里有一个 CLAUDE.md,agent 启动时会自动读它当背景知识。

第 5 行:告诉 SDK:去那个项目目录里把 .claude/output-styles/、.claude/commands/ 也一起加载。

第 8 行:像跟同事问话一样发问——"runway 还有多久?"

第 9 行:流式接收每一句回话。

核心洞察:CLAUDE.md = 项目级长期记忆。把公司财务数据、团队规则、历史决策写进去,agent 每次启动都自带这份"入职 onboarding 文档"——不用每次 prompt 重复。

看一场 Chief of Staff 内部分工

真实的 CoS 不是一个 agent 干所有事——它派子 agent (subagent) 去做专业领域的工作,自己只做汇总。看这场 CEO 让团队重组的对话:

SDK 的 6 大模块——你的"乐高积木"

query()

无状态一次性问答。最简单的入口,研究 agent / one-shot 任务用它。

💬

ClaudeSDKClient

有状态会话——多轮对话、上下文累积。CoS 这种长会话场景必用。

⚙️

ClaudeAgentOptions

配置中枢:model / allowed_tools / cwd / hooks / mcpServers / settings 全在这里。

📚

CLAUDE.md

项目级长期记忆。把公司情况、规则、历史决策写进去——agent 自动加载。

👥

Subagents

派生子 agent 处理专业领域。财务分析师、招聘官、法务顾问——每个有自己的 prompt 和工具。

🪝

Hooks

工具调用前后的拦截器——做审计、安全检查、限流。SRE agent 的"删数据库前必须人工确认"靠它。

💡
Aha! Claude Agent SDK 不是新发明——是 Claude Code 的内核开放

你每天用 Claude Code 时见到的所有"魔法"——自动用工具、记得对话、规划再执行——其实就是这套 SDK。Anthropic 把内核拿出来开源后,意味着:你能把 Claude Code 那套"通用 agent 内核"复制到任何领域——AI 律师、AI 销售、AI 数据分析师……拿 SDK 嫁接,最快 1 天有 demo。

小测:从 SDK 选什么

Q1. 你想让 agent 在用一个"删数据库"工具前必须暂停让你确认。SDK 里用什么机制?

规则归规则文件,任务归 prompt。" data-explanation-wrong="想清楚:'每次都忘'是因为 prompt 没传到位?还是因为这种规则本来就该用持久化方式而不是每次重述?">

Q2. 你的 agent 经常忘记公司的"绝不直接联系客户"规则。最干净的解法?

Q3. 你看到 SRE agent demo 后想做"AI 律师助手"——查法规、起草合同、提交客户审批。最适合从哪个 notebook 起步?

06

进阶火候:思考 · 缓存 · Skills

三件训练外挂——把同一个 agent 从"能用"推到"生产可用"

前 5 个模块教的是 agent 的骨架——这一模块是训练外挂

到这里你已经能理解 cookbook 大部分章节。但实战里同一个 agent 经常被三个问题卡住:推理太浅 / 调用太贵 / 本领太散。这一模块的三件外挂分别治这三个症。

🏃
本课的隐喻:长跑选手的三件训练外挂

Extended Thinking = 起跑前的呼吸调整——赛前那 30 秒深呼吸,让大脑先预热再开跑。
Prompt Caching = 训练后的肌肉记忆——同一段路跑过 100 次,肌肉自动反应,不用再思考动作。
Skills = 教练给的训练计划包——一份现成的、能直接套用的 SOP("全马备赛 16 周计划")。
三件外挂对应三种"提速":思考更深、重复更快、本领更广。每一件都是任何 agent 都能加挂的。

🧠

Extended Thinking

治什么病:复杂推理一次想不清。
怎么打开:API 调用加一个 thinking 参数。
适合场景:数学 / 多步规划 / 风险分析。
注意:会增加输出 token 消耗。

💾

Prompt Caching

治什么病:长前缀重复花钱。
怎么打开:API 调用加一个 cache_control 参数。
适合场景:固定 system prompt / 长文档反复问 / 工具列表。
效果:第二次起 input token 价格降到 1/10、延迟降一半。

📦

Skills

治什么病:本领太散,复用难。
怎么打开:把"代码 + 提示词 + 资源"打包成 Skill。
适合场景:做 PPT / Excel / PDF 等专业产物。
意义:本领能跨项目、跨客户端复用。

第一件外挂:Extended Thinking——给模型一段不被打扰的草稿纸

Extended Thinking 不是模型变聪明了,是给它一段独立的草稿空间——它把推理过程写在 thinking 块里,最后才给结论。复杂推理任务直接受益。

CODE · Python
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=4000,
    thinking={
        "type": "enabled",
        "budget_tokens": 2000
    },
    messages=[{
        "role": "user",
        "content": "Solve this puzzle: Three people check into a hotel..."
    }]
)
中文逐行翻译

第 1-3 行:普通的 API 调用——Sonnet 模型,最终输出最多 4000 token

第 4-7 行(关键开关):打开扩展思考,并给它 2000 token 的"草稿纸预算"。模型会把推理过程写进一个独立的 thinking 块,再写最终答案。

第 8-11 行:你的实际问题。

调用回来后response.content 里会有两类块:thinking 块(推理过程)和 text 块(最终答案)。

对调试 agent 行为价值巨大——你能看到模型的"内心独白",立刻知道它哪里想错了,是 prompt 没写好还是模型推理偏了。

看一遍模型的"内心独白"

cookbook 里给的经典例题——旅馆账单悖论。看 Claude 怎么用 thinking 块把推理过程摊开:

第二件外挂:Prompt Caching——一行参数省 90% 的输入 token

Prompt Caching 不是新模型,是 API 的一个 flag——把长的、不变的前缀(一本书、一份代码库、一份 system prompt)缓存住。第二次调用同一前缀时,输入 token 价格降到 1/10、延迟降一半。

CODE · Python
write_response = client.messages.create(
    model=MODEL_NAME,
    max_tokens=300,
    cache_control={"type": "ephemeral"},  # <-- one-line change
    messages=[
        {
            "role": "user",
            "content": str(TIMESTAMP)
            + "<book>"
            + book_content   # 整本《傲慢与偏见》约 187k token
            + "</book>"
            + "\n\nWhat is the title of this book? Only output the title.",
        }
    ],
)
中文逐行翻译

第 4 行(关键):就这一行!cache_control={"type": "ephemeral"}。意思是"我允许系统把这次输入的可缓存部分缓存起来"。ephemeral 表示短期缓存。

第 9-11 行:把整本《傲慢与偏见》(约 187k token)塞进 prompt 里。如果不缓存,每次问问题都要重新输入这 187k token——账单会爆炸。

第 12 行:实际问题——只占几十 token。

第一次调用:缓存被写入,时间和不缓存差不多(baseline)。

第二次调用相同前缀:API 直接从缓存读,输入 token 价格降到 1/10、延迟降一半以上

真实生产场景:你的 agent 每次都带相同的 system prompt(几千 token)和工具列表?打开 caching,立刻省钱。

📉
数字感受一下

假设你的 agent 系统每次带 10000 token 的 system prompt,每天 100 万次调用。
不开 caching:每次按全价付 10000 token 输入费 → 一天烧掉 100 亿 token 输入费。
开 caching:第一次写入按全价,之后命中按 1/10 → 一天烧掉约 10 亿 token 输入费。账单立省 90%。这是 CTO 级别的对话词汇——产品经理说"AI 太贵",你能立刻问"接 prompt caching 了吗?"

练习:把场景拖到对应的外挂上

把左边的"外挂方案"拖到右边对应的"真实场景"。

Extended Thinking
Prompt Caching
两个一起开
两个都不需要

复杂数学推理 / 多步规划任务(一次答不准,需要深度思考)

把外挂拖到这里

客服 agent,每次对话开头都贴 5000 token 的产品 KB 当 system prompt

把外挂拖到这里

RAG agent:长文档(缓存友好)+ 复杂多跳问答(推理重)

把外挂拖到这里

一个超简单的"今天星期几" 一次性问答

把外挂拖到这里

小测:给真实场景挑外挂

Q1. 你的 agent 每次对话开头都要贴一份 8000 token 的 system prompt + 工具说明,对话本身只有几百 token。账单很贵。最优一招?

Q2. 你的 agent 在做"分析三季度财务报告,识别 5 个潜在风险"。回答经常浅尝辄止——只点 1-2 个明显的风险。最该试的开关?

Q3. 你想让 Claude 在网页应用里直接生成 PowerPoint 文件。最适合的机制?

🎯
这门课结束了——但 Cookbook 还在更新

整本食谱的脉络其实很简单——先认识 Augmented LLM 这个最小单元(模块 1),学会三种基础工序(模块 2)和两种高阶工序(模块 3),把"动手"机制(模块 4)打通后,用 SDK 把所有这些封装成产品级 agent(模块 5),最后用三件训练外挂(模块 6)把 agent 推到生产可用。

回到 cookbook 仓库后,你不再是看 random 一堆 notebook——你能认出每个 notebook 在这张地图上的坐标。看到 customer_service_agent → 这是 tool use 的实战。看到 contextual-embeddings → 这是 RAG 的优化变体。看到 sub-agents → 这是 orchestrator 的具体实现。

作为 vibe coder,你拿到的不只是知识——是和工程师对话的词汇:你能说出"这部分用 evaluator-optimizer 太重了,改成 chain 加 spot-check"或者"这个 agent 应该把规则放 CLAUDE.md 不要每次塞 prompt"。这就是这门课最大的价值。