下面这套内容基于 Anthropic 公开 API 和官方 claude-cookbooks 仓库整理,所有代码都能直接运行。如果你也想知道 Claude 到底能干什么、代码怎么写、坑在哪里,这篇应该能省你不少时间。
前言
Anthropic 有个 GitHub 仓库叫 claude-cookbooks,里面塞了 30 多个 Notebook,工具调用、扩展思考、多模态、RAG、Agent 都覆盖了。
我自己翻过一遍,感觉有两个地方不太顺手:
一是太散。每个能力一个独立文件,看完记得住语法,串不起主线。
二是太碎。不少例子只给片段,复制到本地跑不通,坑得自己踩。
后来我按"能直接用"的思路重排了一遍,把主线捋顺,每段都补上能跑的代码。下面就是整理后的结果。读到后面,你应该能自己拼出一个会查资料、会算账、能看图、还能多步推理的 Agent。
前置:会一点 Python(函数、字典、循环够用),有一个 Anthropic API Key。不用懂机器学习。
读完能动手做这些:
- 工具调用:让 Claude 去调你写的任意函数,比如查天气、算账、查数据库
- 扩展思考:开起来处理复杂推理和多步任务
- 视觉:让 Claude 读图、读图表、读文档
- RAG:把自己的文档接进 Claude 做问答
- 多智能体:用编排器、评估-优化这些模式搭一套系统
0. 环境准备
装 SDK 和配 Key
bash
pip install anthropic
export ANTHROPIC_API_KEY="sk-ant-..." # macOS / Linux
# set ANTHROPIC_API_KEY=sk-ant-... # Windows PowerShell
提醒:别把 Key 写进会提交到 Git 的代码里。用 .env 加 python-dotenv,或者直接用系统环境变量。泄露了马上去控制台吊销。
封装一个好用的 client
官方 SDK 调用很直白,但每次写一堆参数有点啰嗦。教程里统一用下面这个封装,之后所有示例都基于它。
python
import os
import anthropic
# 模型名随版本更新;3.7 Sonnet 支持扩展思考,4 系也支持。
# 用最新模型时替换为 claude-sonnet-4-... / claude-opus-4-... 等。
MODEL = "claude-3-7-sonnet-latest"
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
def chat(prompt, system=None, max_tokens=1024):
"""最简单的对话:发一句话,拿回文字。"""
messages = [{"role": "user", "content": prompt}]
kwargs = {"model": MODEL, "max_tokens": max_tokens, "messages": messages}
if system:
kwargs["system"] = system
resp = client.messages.create(**kwargs)
return resp.content[0].text
print(chat("用一句话解释什么是大模型。"))
能打印出一段中文解释,说明 Key、网络、SDK 都没问题。报错的话:401 是 Key 不对,429 是额度或限流,404 多半是模型名拼错。
1. 核心概念
写工具调用前,先把三个概念理顺,后面代码都围绕它们:
| 概念 | 是什么 | 在代码里长啥样 |
|---|---|---|
| Messages | 一次对话由多条 message 组成,每条带 role(user/assistant)和 content | [{"role":"user","content":"你好"}] |
| Content Blocks | 一条 message 的 content 可以是字符串,也可以是多个结构化块:text / tool_use / tool_result / thinking / image | [{"type":"text","text":"..."}] |
| Tools | 你声明的"函数清单",含名称、描述、JSON Schema 参数。Claude 决定何时调用 | tools=[{"name":...,"input_schema":{...}}] |
工具调用真正关键的地方在于它是一个来回的过程:你把 tools 给模型,模型返回 tool_use 块(只说想调哪个函数、参数是什么,不会真去执行),你执行完函数,把结果用 tool_result 块喂回去,模型再接着回答。后面所有 Agent 都是这个骨架。
2. Tool Use 工具调用
Tool Use 是 Claude 最核心的能力:把你自己写的真实函数交给模型,模型在需要的时候用正确的参数去调用。下面从最小例子一路讲到并行、记忆、精确计算。
2.1 你的第一个工具:查天气
流程分六步:声明工具(名字+描述+参数 Schema),把工具和用户问题一起发给模型,模型返回 tool_use 块,你执行函数,把结果作为 tool_result 回传,模型给出最终回答。
python
import anthropic, os
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
MODEL = "claude-3-7-sonnet-latest"
weather_tool = {
"name": "get_weather",
"description": "获取指定城市的当前天气",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名,如 '北京'"}
},
"required": ["city"]
}
}
def get_weather(city):
# 真实场景这里会请求天气 API;此处用模拟数据演示
return {"city": city, "temp_c": 22, "condition": "晴"}
messages = [{"role": "user", "content": "北京今天天气怎么样?"}]
resp = client.messages.create(
model=MODEL, max_tokens=1024,
tools=[weather_tool], messages=messages
)
# 取出模型想调用的工具
tool_use = next(b for b in resp.content if b.type == "tool_use")
result = get_weather(**tool_use.input) # 真正执行函数
# 把结果回传:assistant 原样保留,user 补上 tool_result
messages.append({"role": "assistant", "content": resp.content})
messages.append({"role": "user", "content": [{
"type": "tool_result",
"tool_use_id": tool_use.id,
"content": str(result)
}]})
final = client.messages.create(
model=MODEL, max_tokens=1024,
tools=[weather_tool], messages=messages
)
print(final.content[0].text)
坑:回传时 assistant 这条必须原样放整个 resp.content(包括 tool_use 块),不能只留文字。不然模型不知道自己在等哪个工具的结果。
2.2 控制工具选择:tool_choice
默认 tool_choice 是 {"type":"auto"},模型自己决定调不调、调哪个。另外两个模式:
| 模式 | 行为 | 用途 |
|---|---|---|
| auto | 模型自由决定 | 常规对话 |
| any | 本轮必须调用某个工具(不确定哪个) | 强制走工具流程 |
| tool | 强制调用指定工具:{"type":"tool","name":"get_weather"} | 确定性流程 / 评测 |
python
# 强制调用指定工具(用于结构化抽取、评测等确定场景)
resp = client.messages.create(
model=MODEL, max_tokens=1024,
tools=[weather_tool],
tool_choice={"type": "tool", "name": "get_weather"},
messages=[{"role": "user", "content": "上海"}]
)
print(resp.content[0].input) # 直接拿到结构化参数 {"city": "上海"}
2.3 结构化 JSON 抽取(Pydantic)
把 Pydantic 模型当抽取模板用:模型的字段生成工具的 input_schema,拿到 tool_use 之后直接 model_validate 成对象,类型安全还能顺带校验。
python
from pydantic import BaseModel
from typing import List
class Person(BaseModel):
name: str
age: int
skills: List[str]
# 由 Pydantic 模型生成工具定义
extract_tool = {
"name": "extract_person",
"description": "从文本中抽取人物信息",
"input_schema": Person.model_json_schema()
}
text = "李雷,28 岁,会 Python 和 SQL。"
resp = client.messages.create(
model=MODEL, max_tokens=1024,
tools=[extract_tool],
tool_choice={"type": "tool", "name": "extract_person"},
messages=[{"role": "user", "content": text}]
)
block = next(b for b in resp.content if b.type == "tool_use")
person = Person.model_validate(block.input) # 带校验地转成对象
print(person.name, person.age, person.skills)
这比让模型直接吐 JSON 再用 json.loads 稳。字段缺了、类型错了,Pydantic 会直接拦下来,而且你拿到的是对象,不是字符串。
2.4 并行工具调用
模型可以在一次回复里发出多个 tool_use 块。处理方式和单次差不多,只是要把每个工具都跑一遍,再一次性把所有 tool_result 回传。
python
tools = [weather_tool] # 假设还有 get_stock、get_news 等多个工具
def dispatch(name, args):
if name == "get_weather": return get_weather(**args)
# ... 其它工具
return {"error": f"unknown tool {name}"}
messages = [{"role": "user", "content": "北京天气和腾讯股价分别是多少?"}]
resp = client.messages.create(model=MODEL, max_tokens=1024, tools=tools, messages=messages)
tool_results = []
for b in resp.content:
if b.type == "tool_use":
tool_results.append({
"type": "tool_result",
"tool_use_id": b.id,
"content": str(dispatch(b.name, b.input))
})
messages.append({"role": "assistant", "content": resp.content})
messages.append({"role": "user", "content": tool_results})
final = client.messages.create(model=MODEL, max_tokens=1024, tools=tools, messages=messages)
print(final.content[0].text)
2.5 持久化记忆(Memory)
长对话会变长、变贵,模型也容易"忘事"。两个办法比较实用:把旧消息压成摘要,或者把关键事实抽出来存库,要用的时候再塞回 system。
python
def compress_history(messages, keep_last=4):
"""把较早的消息压缩成一段摘要,保留最近 keep_last 轮。"""
if len(messages) <= keep_last:
return messages
old, recent = messages[:-keep_last], messages[-keep_last:]
summary = chat(
"请把以下对话压缩成 3 句话的关键信息摘要:\n" + str(old),
max_tokens=300
)
return [{"role": "user", "content": f"[历史摘要] {summary}"}] + recent
def extract_facts(text):
"""把用户刚说的话里的事实抽成列表(很简单的关键信息提取)。"""
facts = chat(
"从下面文字抽取关键事实,每行一条,不要解释:\n" + text,
max_tokens=300
)
return [line for line in facts.splitlines() if line.strip()]
# 用法示例
memory = []
memory += extract_facts("用户叫 tuo,在做 AI 助手开发。")
messages = compress_history(messages)
system = "已知用户背景:" + ";".join(memory)
真实产品里 memory 通常落库(SQLite / 向量库)。这里只给最小可运行骨架,存储你照着接就行。
2.6 计算器工具:补上模型的数学短板
大模型做精确算术、大数运算容易出错。把计算交给真正的 Python,模型只负责决定算什么。
python
calc_tool = {
"name": "calculator",
"description": "精确计算数学表达式,支持 + - * / 和括号",
"input_schema": {
"type": "object",
"properties": {"expression": {"type": "string", "description": "如 '(12+8)*3/2'"}},
"required": ["expression"]
}
}
def calculator(expression):
# 仅允许安全字符,避免 eval 风险
allowed = set("0123456789+-*/(). ")
if not set(expression) <= allowed:
return {"error": "非法字符"}
try:
return {"result": eval(expression, {"__builtins__": {}})}
except Exception as e:
return {"error": str(e)}
# 与 2.4 的 dispatch 思路一致:模型产出表达式 -> 你 eval -> 回传结果
这里用白名单字符加清空 builtins 来降低 eval 风险。真要上生产,建议用 asteval 或 sympy 这类安全表达式库。
3. Extended Thinking 扩展思考
扩展思考让模型在回答之前先想一会儿,把推理过程写进 thinking 块。数学、规划、多步推理这类任务开着会明显更稳。注意两点:开了之后 max_tokens 必须大于 budget_tokens,而且 thinking 块要原样回传。
3.1 基础用法
python
resp = client.messages.create(
model=MODEL,
max_tokens=4096, # 必须 > budget_tokens
thinking={"type": "enabled", "budget_tokens": 2048},
messages=[{"role": "user",
"content": "一个游泳池长 25 米、宽 10 米、深 2 米,注满需要多少吨水?(1 立方米水=1 吨)"}]
)
for b in resp.content:
if b.type == "thinking":
print("【思考】", b.thinking)
elif b.type == "text":
print("【答案】", b.text)
budget_tokens 越大,思考越深、越慢、也越贵。简单题给小一点(512
1024),难题给大(20488000)。不是越大越好。
3.2 思考 + 工具调用(Agent 核心)
让模型边想边调工具,是高级 Agent 的关键写法。回传时有个坑:把 tool_result 发回去的时候,上一轮 assistant 的完整 content(包括 thinking 块)必须原样带上,否则直接报错。
python
tools = [weather_tool, calc_tool]
messages = [{"role": "user",
"content": "北京比上海平均气温高几度?查天气后算差值。"}]
for _ in range(5): # 最多 5 轮,防止死循环
resp = client.messages.create(
model=MODEL, max_tokens=4096,
thinking={"type": "enabled", "budget_tokens": 2048},
tools=tools, messages=messages
)
messages.append({"role": "assistant", "content": resp.content}) # 含 thinking 块,原样保留
# 没有工具调用 = 已得出最终答案
if not any(b.type == "tool_use" for b in resp.content):
break
results = []
for b in resp.content:
if b.type == "tool_use":
fn = get_weather if b.name == "get_weather" else calculator
results.append({"type": "tool_result", "tool_use_id": b.id,
"content": str(fn(**b.input))})
messages.append({"role": "user", "content": results})
print(messages[-1].content[0].text)
必须原样保留 thinking 块,这是 90% 报错的地方。只要开了 thinking,assistant 这条就放整个 resp.content,别只挑 tool_use 放。
4. 多模态 Vision
Claude 能直接看图片:把图片以 base64 放进 content 块就行。支持的图片类型:png / jpeg / gif / webp。
4.1 图片输入
python
import base64
def load_image(path):
with open(path, "rb") as f:
data = base64.b64encode(f.read()).decode()
# 按实际类型改 media_type:image/png / image/jpeg / image/gif / image/webp
return {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": data}}
resp = client.messages.create(
model=MODEL, max_tokens=1024,
messages=[{"role": "user", "content": [
{"type": "text", "text": "图里有什么?请详细描述。"},
load_image("example.png")
]}]
)
print(resp.content[0].text)
4.2 读图表 / 文档
图表、PPT、扫描件都能喂给模型做视觉理解。几个让准确率上去的习惯:图要清晰、对比度高;prompt 里说清你要什么(只要表格数据,还是要结论);多页文档分页传,逐页处理完再汇总。
python
def read_chart(path, ask="请提取图中的关键数据并简要说明趋势。"):
resp = client.messages.create(
model=MODEL, max_tokens=1500,
messages=[{"role": "user", "content": [
{"type": "text", "text": ask},
load_image(path)
]}]
)
return resp.content[0].text
# 多页文档:逐页抽文字后拼接
pages_text = [read_chart(f"doc_p{i}.png", "只抽取本页全部文字,保留段落。") for i in range(1, 4)]
full = "\n".join(pages_text)
summary = chat(f"请总结以下文档要点:\n{full}", max_tokens=800)
5. RAG 检索增强生成
RAG 的思路是先检索相关资料,再让 Claude 基于资料回答,解决模型不知道你私有数据的问题。四步:分块、嵌入、检索、拼装。
Anthropic 官方已经不提供通用文本 Embedding 接口。检索环节的向量化得用第三方,官方自己推荐 Voyage AI(pip install voyageai)。下面用可插拔的 embed() 演示,你换成任意提供商都行。
python
import math, re
def chunk_text(text, size=500, overlap=50):
"""简单按字符滑动窗口分块。生产可用按句子/段落切。"""
step = size - overlap
return [text[i:i+size] for i in range(0, len(text), step)]
def embed(text):
"""占位:替换为 Voyage / OpenAI 等真实嵌入。返回向量 list[float]。"""
# 真实调用示例(需装 voyageai 并设 VOYAGE_API_KEY):
# import voyageai; v = voyageai.Client(); return v.embed(text, model="voyage-3").embeddings[0]
return [float(hash(text[i:i+4]) % 1000) / 1000 for i in range(0, 256)] # 演示用伪向量
def cosine(a, b):
dot = sum(x*y for x, y in zip(a, b))
na = math.sqrt(sum(x*x for x in a)); nb = math.sqrt(sum(y*y for y in b))
return dot / (na * nb)
# 建库
docs = chunk_text(open("手册.txt", encoding="utf-8").read())
index = [(c, embed(c)) for c in docs]
def retrieve(query, top_k=3):
qv = embed(query)
ranked = sorted(index, key=lambda x: cosine(x[1], qv), reverse=True)
return [c for c, _ in ranked[:top_k]]
# 问答
def rag_answer(question):
ctx = "\n\n".join(retrieve(question))
prompt = f"仅根据下面的资料回答问题,资料里没有就回答'不知道'。\n\n资料:\n{ctx}\n\n问题:{question}"
return chat(prompt, max_tokens=800)
print(rag_answer("退货政策是怎样的?"))
几个让检索更准的小习惯:分块带重叠,避免切断语义;top_k 取 3~5 段;最相关的放最前面;提示模型只依据资料,减少编造。
6. 多智能体模式(Agents)
单次 Claude 调用能做的事有限。把多次调用按套路编排起来,才谈得上"Agent 系统"。三个最实用的模式:
6.1 基础工作流:路由 + 顺序 + 循环
用模型当路由器,判断该走哪条分支,再顺序或循环执行。
python
def router(user_msg):
"""判断用户意图,返回分支名。"""
decision = chat(
"用户这句话属于哪类?只回一个词:sales / support / other。\n" + user_msg,
max_tokens=20
).strip().lower()
return decision
def handle(user_msg):
branch = router(user_msg)
if branch == "sales":
return chat("你是销售助手,回答:" + user_msg)
if branch == "support":
return chat("你是客服助手,回答:" + user_msg)
return chat("通用回答:" + user_msg)
# 循环:反复处理,直到模型说"完成"
def loop_until_done(task, max_iter=5):
msgs = [{"role": "user", "content": task}]
for _ in range(max_iter):
r = client.messages.create(model=MODEL, max_tokens=1024, messages=msgs)
text = r.content[0].text
msgs.append({"role": "assistant", "content": text})
if "完成" in text:
return text
msgs.append({"role": "user", "content": "继续,直到任务结束再说'完成'。"})
return msgs[-1]["content"]
6.2 编排器-工作者(Orchestrator-Workers)
主 Agent 把大任务拆成子任务,分发给多个工作者并行处理,最后汇总。调研、代码生成、长文写作都适合这套。
python
def orchestrate(big_task):
# 1) 编排器拆解任务
plan = chat(f"把下面这个任务拆成 3-5 个独立子任务,每行一个:\n{big_task}", max_tokens=500)
subtasks = [t for t in plan.splitlines() if t.strip()]
# 2) 工作者并行执行(真实可用 concurrent.futures 并发)
results = []
for st in subtasks:
results.append(chat(f"请完成这个子任务并给出结果:\n{st}", max_tokens=800))
# 3) 汇总
joined = "\n\n".join(f"子任务{i+1}: {r}" for i, r in enumerate(results))
return chat(f"根据下列子任务结果,整合成最终交付物:\n{joined}", max_tokens=1000)
print(orchestrate("写一份'AI 客服系统'的技术方案,含架构、技术栈、排期。"))
6.3 评估-优化(Evaluator-Optimizer)
一个生成器出结果,一个评估器打分、给修改建议,生成器照着改,直到通过。写代码、写文案、做翻译都用得上。
python
def generate(task, feedback=""):
extra = f"\n\n评审反馈(请据此改进):{feedback}" if feedback else ""
return chat(f"完成任务:{task}{extra}", max_tokens=1000)
def evaluate(task, draft):
return chat(
f"请评审下面的成果是否达成任务要求,给出'通过/不通过'和具体改进点。\n"
f"任务:{task}\n成果:{draft}", max_tokens=400)
def improve(task, rounds=3):
draft = generate(task)
for _ in range(rounds):
review = evaluate(task, draft)
if review.strip().startswith("通过"):
return draft, review
draft = generate(task, feedback=review)
return draft, "已达轮次上限"
final, note = improve("写一段产品发布会开场白,热情、简洁、不超过 80 字。")
print(final, "\n---评审---", note)
怎么选:能一次做对就直接调;要分流用路由;任务大而能拆用编排器-工作者;质量要反复打磨用评估-优化。它们也能组合起来用。
7. 其他能力速查
| 能力 | 核心做法 | 关键代码片段 |
|---|---|---|
| 文本摘要 | 长文分段摘要再聚合;用 max_tokens 控制粒度 | chat(f"用3句话总结:{text}") |
| 文本分类 | few-shot 加限定标签;用 tool_choice 强制结构化输出 | tool_choice={"type":"tool","name":"classify"} |
| Text-to-SQL | 把数据库 Schema 放进 prompt,让模型生成 SQL 再由你执行 | 见下 |
| 知识图谱 | 抽取实体/关系,存图库(如 Neo4j),再图查询 | 见下 |
python
# Text-to-SQL:把建表语句喂给模型,让它生成可执行的 SQL
SCHEMA = """
CREATE TABLE orders(id INT, user_id INT, amount DECIMAL, created_at DATE);
CREATE TABLE users(id INT, name TEXT, city TEXT);
"""
sql = chat(
f"数据库 Schema:\n{SCHEMA}\n请只生成一条 SQL 回答:'北京用户的总消费是多少?'",
max_tokens=300
).strip()
# 拿到 sql 后,用你的数据库驱动(sqlite3 / psycopg2)执行,不要把模型输出直接当命令跑
# 知识图谱抽取(最小骨架)
kg_triples = chat(
"从下面文本抽取 (实体, 关系, 实体) 三元组,每行一个:\n" + text,
max_tokens=500
)
模型生成的 SQL 或命令,永远别直接执行。至少做白名单校验、只读权限、参数化查询,最好人工复核一遍。
8. 上下文工程(Context Engineering)
最近圈子里总提"上下文工程",听着玄,说的事其实挺朴素:别再往系统提示里堆一大堆死规则,而是把对的事例、对工具、对的历史,在需要的时候动态塞进上下文,剩下的交给模型的判断力。
我自己踩下来,体感是这样的:
系统提示能短就短。细节留给工具描述和 few-shot 示例,比写一堆"如果......就......"管用。
历史要会扔。长对话按 2.5 节那样压一压,不相关的干脆删掉,别舍不得。
记忆和知识按需取。别一上来把全部资料怼进 prompt,用到再检索。
敢信模型。把目标和安全边界说清就行,别用几十条规则把它捆死。
回过头看,前面写的记忆压缩、RAG 检索、工具选择,干的其实都是同一件事:把对的上下文在对的时机喂进去。把它们当工具箱用,别当教条。
总结
到这儿,你已经能用 Claude API 搭出一个会查资料、会算账、能看图、还能多步推理的 Agent 了。剩下的事不复杂:把示例里的模拟函数,换成你自己的真实业务逻辑就行。
想继续往下挖,这几个地方值得看:
- 官方 Cookbook 仓库:github.com/anthropics/...
- API 文档:docs.anthropic.com
- 提示词工程指南:anthropic.com/engineering...
觉得有用就点个赞,或者收藏起来下次照着敲。哪一块想让我展开讲(比如完整的 RAG 工程、Agent 并发框架),评论区说一声,下篇可以安排。