Skip to content

告别手动 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 LoopSDK 内部自动管理多轮交互、规划决策和工具调用,开发者无需再手写复杂的递归或循环逻辑。
开箱即用的原生技能预置了经过 Anthropic 深度优化的工具,如文件系统操作(Read/Write/Edit)、终端命令执行(Bash)以及网络访问。
渐进式权限控制提供多级 PermissionMode(如 acceptEdits、dontAsk 等),在安全与效率之间取得了极佳平衡。
上下文"记忆"管理通过会话 ID 自动处理对话历史和工作状态,支持复杂的长上下文理解。

更多了解可参考:Claude Agent SDK 文档

3.快速上手:环境配置与初始化

3.1 安装依赖

由于本项目基于 Node.js 与 TypeScript,首先需要引入核心包:

bash
pnpm install @anthropic-ai/claude-agent-sdk

3.2 环境变量的“陷阱”与配置

SDK 默认不会主动扫描 .env 文件。为了确保 API Key 和自定义模型参数生效,我们需要在入口处显式加载:

typescript
// 项目入口文件 index.ts
// 显式将 .env 文件中的内容加载到环境变量中
import 'dotenv/config';

.env 文件配置建议:在测试阶段,建议配置 ANTHROPIC_DEFAULT_HAIKU_MODEL 处理简单逻辑,使用 SONNET 处理复杂规划,以平衡响应速度与成本。

bash
# .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_name

4. 核心实践:从无状态交互到自主执行

SDK 的核心交互入口是 query 函数。我们通过两个示例来演示其从“简单对话”到“自主任务处理”的跨越。

Claude Agent SDK 提供了一个与 Agent 交互的主要函数 query,用于直接与 Agent 进行交互。

typescript
function query({
  prompt,
  options
}: {
  prompt: string | AsyncIterable<SDKUserMessage>;
  options?: Options;
}): Query

Options 是一个可选参数,类型为 Options 类型,用于配置 Agent 很多方面的行为,如允许的工具、权限模式等。

typescript
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 模式一:基础无状态对话

这是最简单的交互模式,用于处理即时性的问答任务。

typescript
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 -> 应用修改”的闭环,展现了极强的任务导向性

typescript
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。

typescript
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)”段落。

typescript
// 简化后的流式处理逻辑
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 对话循环

为了方便后续的调用,我们可以封装一个函数,专门来处理对话循环的逻辑,代码示意如下:

typescript
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 聊天应用。

typescript
// 主入口文件
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 在真实业务场景中可能面临的"工程腐化"问题,或是其"效率边界"的探索感兴趣,欢迎持续关注本系列的后续更新。