告别手动 Loop:借助 Claude Agent SDK 实现 Agent 的工程化闭环
摘要总结:在 Agent 技术快速走向成熟的今天,如何低成本构建具备“自主洞察”能力的智能体?本文拆解 Anthropic 官方推出的 Claude Agent SDK,解析其如何通过托管 Agent Loop、会话持久化等机制,解决 Agent 开发中的状态管理难题。文章通过从无状态交互到具备流式输出能力的 TUI 自动化工具进阶实战,展示了构建低成本、高可用 AI 原生应用的完整路径。
1. 引言
当前,AI Agent 的演进已进入一个崭新的阶段——从需要频繁人工干预的"半自动"模式,进化为能够自主洞察环境变化、动态调整执行策略、实现业务流程自适应编排的智能化系统。Claude Code、Manus、OpenClaw 等代表性产品层出不穷,也标志着 Agent 技术正在快速走向成熟与普及。
近期,笔者在为个人博客引入智能化运营能力(如内容自动校对、审稿与发布),深入研究了多款 Agent 开发框架,如 Claude Agent SDK、Langchain、LangGraph 等。在经过初步的研究对比分析后,Claude Agent SDK 成为了低成本构建高可用 Agent 的首选。
本文将基于 Claude Agent SDK,分享一个从 0 到 1 构建简单 Agent 的实践经验。相关源代码已开源至 GitHub,托管在我与几个好友共同创建的组织 full-stack-workspace 旗下的 agent-playground 仓库中,对应示例项目为:@agent-playground/basic-example
2. 为什么选择 Claude Agent SDK?
Claude Agent SDK(前身为 Claude Code SDK)是 Anthropic 官方推出的开源框架。它的核心价值在于将复杂的“规划-执行-观察”循环(Agent Loop)进行了高度工程化封装,提供简洁的 API 用于构建具有工具使用能力的 AI Agent,让开发者专注于业务逻辑和智能体行为的设计。
对于开发者而言,它解决了以下核心痛点:
| 特性 | 说明 |
|---|---|
| Agent Loop | SDK 内部自动管理多轮交互、规划决策和工具调用,开发者无需再手写复杂的递归或循环逻辑。 |
| 开箱即用的原生技能 | 预置了经过 Anthropic 深度优化的工具,如文件系统操作(Read/Write/Edit)、终端命令执行(Bash)以及网络访问。 |
| 渐进式权限控制 | 提供多级 PermissionMode(如 acceptEdits、dontAsk 等),在安全与效率之间取得了极佳平衡。 |
| 上下文"记忆"管理 | 通过会话 ID 自动处理对话历史和工作状态,支持复杂的长上下文理解。 |
更多了解可参考:Claude Agent SDK 文档
3.快速上手:环境配置与初始化
3.1 安装依赖
由于本项目基于 Node.js 与 TypeScript,首先需要引入核心包:
pnpm install @anthropic-ai/claude-agent-sdk3.2 环境变量的“陷阱”与配置
SDK 默认不会主动扫描 .env 文件。为了确保 API Key 和自定义模型参数生效,我们需要在入口处显式加载:
// 项目入口文件 index.ts
// 显式将 .env 文件中的内容加载到环境变量中
import 'dotenv/config';.env 文件配置建议:在测试阶段,建议配置 ANTHROPIC_DEFAULT_HAIKU_MODEL 处理简单逻辑,使用 SONNET 处理复杂规划,以平衡响应速度与成本。
# .env
ANTHROPIC_BASE_URL=your_custom_model_api_base_url
ANTHROPIC_API_KEY=your_custom_model_api_key
ANTHROPIC_MODEL=your_custom_model_name
ANTHROPIC_DEFAULT_HAIKU_MODEL=your_custom_model_name
ANTHROPIC_DEFAULT_OPUS_MODEL=your_custom_model_name
ANTHROPIC_DEFAULT_SONNET_MODEL=your_custom_model_name4. 核心实践:从无状态交互到自主执行
SDK 的核心交互入口是 query 函数。我们通过两个示例来演示其从“简单对话”到“自主任务处理”的跨越。
Claude Agent SDK 提供了一个与 Agent 交互的主要函数 query,用于直接与 Agent 进行交互。
function query({
prompt,
options
}: {
prompt: string | AsyncIterable<SDKUserMessage>;
options?: Options;
}): QueryOptions 是一个可选参数,类型为 Options 类型,用于配置 Agent 很多方面的行为,如允许的工具、权限模式等。
export declare type Options = {
// 系统提示,可以根据需要自定义系统提示
systemPrompt?: string | {
type: 'preset';
preset: 'claude_code';
append?: string;
};
// 无需用户确认即可自动执行的工具列表
allowedTools?: string[];
// 不允许执行的工具列表
disallowedTools?: string[];
// 会话 ID,用于加载指定会话的历史记录
resume?: string;
// Maximum number of conversation turns before the query stops
// 可以根据需要自定义最大轮数
maxTurns?: number;
// 控制 Agent 使用的模型,可以根据需要自定义模型
model?: string;
/**
* 控制 Agent 输出格式,可以根据需要自定义输出格式
*
* @example
* outputFormat: {
* type: 'json_schema',
* schema: { type: 'object', properties: { result: { type: 'string' } } }
* }
*/
outputFormat?: OutputFormat;
/**
* 控制 Agent 权限模式,可以根据需要自定义权限模式
* - `'default'` - Standard permission behavior, prompts for dangerous operations
* - `'acceptEdits'` - Auto-accept file edit operations
* - `'bypassPermissions'` - Bypass all permission checks (requires `allowDangerouslySkipPermissions`)
* - `'plan'` - Planning mode, no execution of tools
* - `'dontAsk'` - Don't prompt for permissions, deny if not pre-approved
*/
permissionMode?: PermissionMode;
// 控制 Agent 是否允许 bypassPermissions,等价于 Claude Code 的 --allow-dangerously-skip-permissions 参数
allowDangerouslySkipPermissions?: boolean;
// ... 其他更多选项
};4.1 模式一:基础无状态对话
这是最简单的交互模式,用于处理即时性的问答任务。
import {query, Query} from '@anthropic-ai/claude-agent-sdk';
import chalk from 'chalk';
const result = query({
// prompt 可以是一个字符串,也可以是一个 AsyncIterable<SDKUserMessage>
// 这里我们传入一个字符串,作为 prompt
prompt: '分析当前项目的核心架构特征。',
});
for await (const message of result) {
if (message.type === 'assistant') {
message.message.content.forEach(msg => {
if (msg.type === 'text') console.log(chalk.blue(msg.text));
});
}
}4.2 模式二:自主找 Bug 并修复(Agentic Loop)
在此模式下,Agent 会经历“查找文件 -> 阅读内容 -> 发现 Bug -> 构造 Diff -> 应用修改”的闭环,展现了极强的任务导向性:
for await (const message of query({
prompt: "检查 utils.py 中的崩溃隐患并直接修复。",
options: {
// 赋予 Agent 搜索与编辑文件的权力
allowedTools: ["Read", "Edit", "Glob"],
// 开启自动批准模式,无需人工确认修改
permissionMode: "acceptEdits"
}
})) {
// 观察 Agent 的思考路径
if (message.type === "assistant" && "name" in (message.message.content[0] || {})) {
console.log(chalk.yellow(`Agent 正在调用工具: ${message.message.content[0].name}`));
}
}5. 进阶:会话管理与持久化记忆
在实际应用(如智能化审稿流)中,Agent 需要记得前几步的操作结果。Claude Agent SDK 通过 resume 参数实现了完美的会话恢复。
5.1 会话 ID 的捕获与恢复
当启动一个 query 时,系统会在 system 类型的消息中返回一个唯一的 session_id。
let sessionId: string | undefined;
const result = query({
prompt: "开始一个新的校对任务",
options: { resume: sessionId } // 传入 ID 即可恢复上下文
});
for await (const message of result) {
if (message.type === 'system' && message.subtype === 'init') {
sessionId = message.session_id; // 持久化此 ID 以供后续使用
}
}通过保存这个 ID,Agent 能够轻松回答诸如“我刚才让你修改了哪个文件?”这类依赖历史背景的问题,真正具备了“ teammates” 的属性。
6. 实战 TUI 应用:构建流式交互 Agent 终端
为了提供更好的开发体验,我们可以利用 readline 结合 SDK 的流式输出(Stream Event),构建一个简易的命令行聊天工具。
6.1 核心逻辑:流式解析 stream_event
SDK 的流式响应包含多种事件类型,我们需要重点捕获 content_block_delta 来实现打字机效果,并区分“思考(Thinking)”和“文本(Text)”段落。
// 简化后的流式处理逻辑
for await (const message of result) {
if (message.type === 'stream_event') {
const event = message.event;
// 处理思考过程:展示 Agent 的内心独白
if (event.type === 'content_block_delta' && event.delta.type === 'thinking_delta') {
process.stdout.write(chalk.gray(event.delta.thinking));
}
// 处理正式输出:展示 Agent 的最终答复
if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {
process.stdout.write(chalk.yellow(event.delta.text));
}
}
}更多流式输出的细节可参考 Claude Agent SDK 官方指南:Streaming Output
6.2 封装 tuiChat 对话循环
为了方便后续的调用,我们可以封装一个函数,专门来处理对话循环的逻辑,代码示意如下:
interface TuiChatOptions extends Options {
tuiPrompt?: string;
}
export async function tuiChat(options: TuiChatOptions = {}) {
// 会话 ID 缓存,用于恢复会话历史
let sessionId: string | undefined;
// 外层可传入 tuiPrompt 作为 TUI 聊天应用的提示词
// 也传入一些 queryOptions 作为 query 的参数
const {tuiPrompt, ...queryOptions} = options;
const rl = createInterface({
input,
output,
prompt: tuiPrompt || 'User:'
});
rl.prompt();
rl.on('line', async (input: string) => {
const userInput = input.trim();
// 若用户输入 exit,则退出循环
if (userInput === 'exit') {
rl.close();
return;
}
// 注意:离开提示行并暂停 readline,防止其重绘逻辑清除/覆盖写入 stdout 的流式输出
rl.pause();
output.write('\n');
// 调用 chatExample 函数,传入用户输入和会话 ID
// 并将返回的会话 ID 保存起来,用于后续的 query
sessionId = await chatExample(userInput, {
sessionId,
...queryOptions
});
// 恢复 readline,等待用户输入
rl.resume();
// 显示新的提示行
rl.prompt();
});
rl.on('close', () => {
// 当 readline 关闭时,打印一条消息,通知用户 TUI Chat 已关闭
console.log(chalk.green('Goodbye, TUI Chat is closed!\n'));
process.exit(0);
});
}6.3 交互效果展示
通过封装 tuiChat 对话循环,我们就实现了一个具备工具调用和会话记忆能力的终端。我们可以在入口文件中轻松启动交互式 TUI 聊天应用。
// 主入口文件
import chalk from 'chalk';
// 将 .env 文件中的内容加载到环境变量中
import 'dotenv/config';
async function main() {
// 调用 tuiChat 函数,传入 TUI 提示、允许的工具和流式输出选项
await tuiChat({
tuiPrompt: 'User: ',
allowedTools: ['WebSearch', 'WebFetch'],
// 启用流式输出
includePartialMessages: true,
});
}最终效果如下:


7. 结束语
从“调包侠”到“AI 架构师”,迈向更复杂的业务编排。
通过 Claude Agent SDK ,我们仅需少量代码就能构建出具备自主执行能力的 Agent,其背后的设计思想:通过标准化 Skill 和会话管理,将复杂的 AI 交互逻辑转化为可预测的软件工程实践。
深度体验后,我最大的感触是:,Agent 的开发重心也正在转向“如何构建可靠的工程闭环”。通过 SDK 提供的 Agent Loop、会话管理和标准化的工具、Skill 和 MCP 等扩展,我们实际上是在为 AI 搭建一套专属的“操作系统”。它让 AI 的行为变得可观测(通过流式日志)、可追溯(通过会话 ID)且可扩展(通过自定义工具)。
这种转变标志着真正的 AI Native 软件工程的正式到来。掌握这类 SDK,本质上是在学习如何利用 AI 这个“高阶杠杆”去编排复杂的业务流。
目前,我正在尝试将这套理念融入我的博客内容工作流,实现从"多维信源抓取"到"风格化润色"的全流程自动化。如果你对 Agent 在真实业务场景中可能面临的"工程腐化"问题,或是其"效率边界"的探索感兴趣,欢迎持续关注本系列的后续更新。