Claude Agent SDK #1:query() 函数全解——三行代码启动一个自主 Agent
整个 Claude Agent SDK 只有一个主入口:query()。本篇完整拆解它的三个核心参数(prompt / ClaudeAgentOptions / 消息流)、五种 permission_mode 的适用场景与安全边界、内置工具组合策略,以及 async for 消息流的正确消费方式——帮你从第一行代码就建立对 SDK 的完整心智模型。
研究速览
用了这么久 Claude Code,你知道它背后的 SDK 怎么用吗?
Anthropic 把驱动 Claude Code 的整个 Agent 引擎开放成了 SDK——Claude Agent SDK。你可以用几行代码,让 Claude 自主读文件、改代码、跑命令,全程不需要你实现工具循环。
今天是新系列第一篇,拆解 SDK 最核心的入口:
query() 函数。🔑 一切从
query() 开始整个 SDK 只有一个主入口:
from claude_agent_sdk import query, ClaudeAgentOptions
async for message in query(
prompt="找出 auth.py 里会崩溃的 bug 并修复",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Glob"],
permission_mode="acceptEdits",
),
):
if hasattr(message, "result"):
print(message.result)就这样。Claude 会自己读文件、分析逻辑、调用工具、写回修复——你只负责消费消息流。
⚙️
query() 的三个核心参数①
prompt——你想让 Agent 做什么,用自然语言描述即可。Claude 根据任务自己决定调哪些工具、用什么顺序。②
options(ClaudeAgentOptions)——控制 Agent 行为边界:allowed_tools:预授权工具列表,列在里面的工具 Claude 可以直接调用,不需要每次询问permission_mode:权限模式(见下)system_prompt:给 Claude 的角色定制指令
③ 返回值:async 消息迭代器——
query() 是异步生成器,async for 消费每一条消息,Claude 思考、工具调用、工具结果、最终输出都会依次流出🛡️ permission_mode:五种权限模式
这是
ClaudeAgentOptions 里最容易踩坑的参数:| 模式 | 行为 | 适用场景 |
|---|---|---|
acceptEdits | 自动批准文件读写,其他操作询问 | 本地开发 |
dontAsk | 只允许 allowed_tools 里的工具,其余全拒 | 锁定式无人值守 |
bypassPermissions | 所有工具直接执行,不询问 | 完全隔离的 CI 沙盒 |
auto(TS 专属) | 模型分类器自动判断每个工具调用 | 带安全防护的自主 Agent |
default | 需要你提供 canUseTool 回调处理审批 | 自定义审批流程 |
生产环境建议:配合
allowed_tools + dontAsk 白名单锁死,绝不用 bypassPermissions 跑在你的真实文件系统上。📦 内置工具一览
allowed_tools 里能填哪些?SDK 内置了一整套:- Read / Write / Edit:读写文件,Edit 可精确按行范围替换
- Bash:执行终端命令、git 操作、跑测试
- Glob / Grep:按模式搜文件路径、正则搜文件内容
- WebSearch / WebFetch:联网搜索 + 抓取页面内容
- Monitor:监听后台脚本输出,逐行触发响应
- AskUserQuestion:向用户提问(带多选选项)
组合示例:
["Read", "Glob", "Grep"]→ 只读分析,最安全["Read", "Edit", "Glob"]→ 分析 + 改代码["Read", "Edit", "Bash", "Glob", "Grep"]→ 全自动化(写代码 + 跑测试 + 修复)
🔄 消息流:async for 里流出什么?
query() 不是等 Claude 跑完才返回——它是流式的,每个阶段都吐出消息:async for message in query(prompt="...", options=...):
if isinstance(message, AssistantMessage):
for block in message.content:
if hasattr(block, "text"):
print(block.text) # Claude 的思考过程
elif hasattr(block, "name"):
print(f"工具调用: {block.name}") # 工具名
elif isinstance(message, ResultMessage):
print(f"完成: {message.subtype}") # 最终结果不过滤的话你会看到系统初始化消息和内部状态——开发调试很有用,生产环境记得按类型过滤。
⚡ 实践建议
① 从最小权限开始:先用
["Read", "Glob"] + dontAsk,确认行为符合预期再逐步开放 Write/Bash②
acceptEdits 是本地开发甜点:既不需要每个操作都手动确认,又保留了对危险命令的询问③ CI/CD 场景:用
bypassPermissions 但必须跑在 Docker 容器里,别直接在宿主机跑④ 流式消费有意义:长任务里实时打印 Claude 的思考过程,有助于快速发现方向跑偏,及时 kill
下一篇:内置工具深度拆解——每个工具的参数细节、边界限制和组合技巧。
参考文档
围绕这条内容继续补充观点或上下文。