Skip to content

02. 快速开始:5分钟创建你的第一个深度代理

从零到一,构建能够自主研究和撰写报告的 AI 助手

本文目标

在这篇教程中,你将:

  1. 安装 DeepAgents 及相关依赖
  2. 创建一个带搜索能力的研究型代理
  3. 理解代理的自动规划和执行流程
  4. 体验 invokestream 两种调用方式

5分钟教程路线图:安装依赖→创建工具→创建代理→运行代理

前置条件

  • Node.js 18+ 环境
  • 一个模型提供商的 API Key(Anthropic、OpenAI 等)
  • (可选)Tavily API Key(用于网络搜索)

第 1 步:安装依赖

bash
# 使用 npm
npm install deepagents langchain @langchain/core @langchain/tavily

# 或使用 yarn
yarn add deepagents langchain @langchain/core @langchain/tavily

# 或使用 pnpm
pnpm add deepagents langchain @langchain/core @langchain/tavily

依赖说明

  • deepagents:DeepAgents SDK 核心包
  • langchain:LangChain 核心库,提供工具定义等能力
  • @langchain/core:LangChain 核心接口
  • @langchain/tavily:Tavily 搜索集成(可选,用于网络搜索)

第 2 步:配置环境变量

bash
# 设置模型 API Key(选择你使用的提供商)
export ANTHROPIC_API_KEY="your-anthropic-api-key"
# 或
export OPENAI_API_KEY="your-openai-api-key"

# 设置 Tavily API Key(用于网络搜索)
export TAVILY_API_KEY="your-tavily-api-key"

💡 提示:没有 Tavily API Key?可以在 tavily.com 免费注册获取。

第 3 步:创建搜索工具

首先,我们需要为代理创建一个"手"——一个可以搜索互联网的工具:

typescript
import { tool } from "langchain";
import { TavilySearch } from "@langchain/tavily";
import { z } from "zod";

const internetSearch = tool(
  async ({
    query,
    maxResults = 5,
    topic = "general",
    includeRawContent = false,
  }: {
    query: string;
    maxResults?: number;
    topic?: "general" | "news" | "finance";
    includeRawContent?: boolean;
  }) => {
    const tavilySearch = new TavilySearch({
      maxResults,
      tavilyApiKey: process.env.TAVILY_API_KEY,
      includeRawContent,
      topic,
    });
    return await tavilySearch._call({ query });
  },
  {
    name: "internet_search",
    description: "运行一次网页搜索,获取互联网上的最新信息",
    schema: z.object({
      query: z.string().describe("搜索查询词"),
      maxResults: z
        .number()
        .optional()
        .default(5)
        .describe("返回结果的最大数量"),
      topic: z
        .enum(["general", "news", "finance"])
        .optional()
        .default("general")
        .describe("搜索主题类别"),
      includeRawContent: z
        .boolean()
        .optional()
        .default(false)
        .describe("是否包含原始内容"),
    }),
  },
);

代码解析

  • tool() 函数来自 LangChain,用于创建结构化工具
  • schema 使用 Zod 定义参数类型,让 LLM 能正确调用
  • description 告诉 LLM 这个工具是干什么的

tool() 的三大组成部分:函数逻辑、参数模式、描述

第 4 步:创建深度代理

现在,让我们创建一个专业的研究型代理:

typescript
import { createDeepAgent } from "deepagents";

const researchInstructions = `你是一名专业研究员。你的工作是进行全面调研,然后撰写一份打磨完善的报告。

你可以使用一个互联网搜索工具,作为收集信息的主要手段。

## 工具说明

### internet_search
使用它对给定查询执行互联网搜索。你可以指定要返回的最大结果数、主题,以及是否应包含原始内容。

## 工作流程

1. 理解用户的研究需求
2. 制定研究计划(使用 write_todos)
3. 执行搜索收集信息
4. 整理并撰写报告
`;

const agent = createDeepAgent({
  tools: [internetSearch],
  systemPrompt: researchInstructions,
});

关键点

  • createDeepAgent() 是创建深度代理的核心 API
  • systemPrompt 定义代理的角色和行为准则
  • 除了我们提供的 internetSearch,代理还自带 write_todosread_filewrite_file 等内置工具

createDeepAgent 的输入与自动获得的内置能力

第 5 步:运行代理

方式一:invoke(同步调用)

typescript
const result = await agent.invoke({
  messages: [{ role: "user", content: "什么是 LangGraph?请给我一份详细的调研报告。" }],
});

console.log(result.messages[result.messages.length - 1].content);

输出示例

# LangGraph 调研报告

## 概述
LangGraph 是 LangChain 团队推出的...

## 核心特性
1. 有状态的多代理协作
2. 循环与条件分支支持
3. 持久化与检查点
...

方式二:stream(流式调用)

如果你想实时观察代理的执行过程:

typescript
const stream = await agent.stream({
  messages: [{ role: "user", content: "什么是 LangGraph?" }],
});

for await (const chunk of stream) {
  console.log(chunk);
}

流式输出的优势

  • 实时观察代理的思考和行动
  • 可以看到工具调用的过程
  • 更好的用户体验(不用等待最终结果)

invoke 同步调用 vs stream 流式调用对比

理解执行流程

当你向代理发送请求后,它会自动执行以下流程:

用户输入 "研究 LangGraph"

┌───────────────────────────────────────┐
│  1. 规划阶段 (write_todos)            │
│     - 搜索 LangGraph 官方文档          │
│     - 了解核心概念和架构               │
│     - 收集使用案例                     │
│     - 整理并撰写报告                   │
└───────────────────────────────────────┘

┌───────────────────────────────────────┐
│  2. 执行阶段 (internet_search)        │
│     - 搜索 "LangGraph official docs"  │
│     - 搜索 "LangGraph architecture"   │
│     - 搜索 "LangGraph examples"       │
└───────────────────────────────────────┘

┌───────────────────────────────────────┐
│  3. 上下文管理 (write_file)           │
│     - 将搜索结果保存到虚拟文件         │
│     - 避免上下文窗口溢出               │
└───────────────────────────────────────┘

┌───────────────────────────────────────┐
│  4. 综合生成                          │
│     - 整合所有信息                     │
│     - 生成结构化报告                   │
└───────────────────────────────────────┘

    最终报告输出

这就是 DeepAgent 的魔力:你只需要告诉它目标,它会自动规划、执行、管理上下文,最后交付结果。

DeepAgent 四阶段自动执行流程:规划、执行、上下文管理、综合生成

完整代码示例

typescript
import { tool } from "langchain";
import { TavilySearch } from "@langchain/tavily";
import { createDeepAgent } from "deepagents";
import { z } from "zod";

const internetSearch = tool(
  async ({
    query,
    maxResults = 5,
    topic = "general",
    includeRawContent = false,
  }) => {
    const tavilySearch = new TavilySearch({
      maxResults,
      tavilyApiKey: process.env.TAVILY_API_KEY,
      includeRawContent,
      topic,
    });
    return await tavilySearch._call({ query });
  },
  {
    name: "internet_search",
    description: "运行一次网页搜索",
    schema: z.object({
      query: z.string().describe("搜索查询词"),
      maxResults: z.number().optional().default(5),
      topic: z.enum(["general", "news", "finance"]).optional().default("general"),
      includeRawContent: z.boolean().optional().default(false),
    }),
  },
);

const researchInstructions = `你是一名专业研究员。
你的工作是进行全面调研,然后撰写一份打磨完善的报告。
你可以使用 internet_search 工具来搜索信息。`;

const agent = createDeepAgent({
  tools: [internetSearch],
  systemPrompt: researchInstructions,
});

async function main() {
  console.log("🚀 启动研究代理...\n");
  
  const result = await agent.invoke({
    messages: [{ role: "user", content: "什么是 LangGraph?请给我一份简要的调研报告。" }],
  });

  console.log("📝 研究报告:\n");
  console.log(result.messages[result.messages.length - 1].content);
}

main().catch(console.error);

不使用搜索工具的简化版本

如果你暂时没有 Tavily API Key,也可以创建一个简单的代理:

typescript
import { createDeepAgent } from "deepagents";
import { tool } from "langchain";
import * as z from "zod";

const getWeather = tool(
  ({ city }) => {
    const weathers = {
      "北京": "晴,温度 25°C",
      "上海": "多云,温度 28°C",
      "东京": "小雨,温度 22°C",
    };
    return weathers[city] || `${city} 天气数据暂无`;
  },
  {
    name: "get_weather",
    description: "获取指定城市的天气",
    schema: z.object({
      city: z.string().describe("城市名称"),
    }),
  },
);

const agent = createDeepAgent({
  tools: [getWeather],
  systemPrompt: "你是一个天气助手,可以查询各城市的天气情况。",
});

async function main() {
  const result = await agent.invoke({
    messages: [{ role: "user", content: "北京和上海的天气怎么样?" }],
  });
  
  console.log(result.messages[result.messages.length - 1].content);
}

main();

小结

恭喜!你已经成功创建了第一个深度代理。让我们回顾一下关键点:

步骤内容关键 API
安装依赖deepagents + langchainnpm install
创建工具定义代理可用的能力tool()
创建代理组合工具和系统提示词createDeepAgent()
运行代理同步或流式调用invoke() / stream()

DeepAgent 自动完成的工作

  • ✅ 任务规划(write_todos)
  • ✅ 工具调用(你提供的工具 + 内置工具)
  • ✅ 上下文管理(文件系统工具)
  • ✅ 结果综合

开发者提供 vs DeepAgent 自动处理的职责划分

下一步

在下一篇文章中,我们将深入探索 createDeepAgent() 的所有配置选项,学习如何:

  • 切换不同的模型提供商
  • 配置中间件扩展能力
  • 添加子代理实现任务委托
  • 启用长期记忆

实践任务

  1. 运行本文的完整代码示例
  2. 修改 systemPrompt,让代理成为一个"新闻编辑"或"代码审查员"
  3. 尝试添加更多工具,比如计算器、翻译等
  4. 使用 stream() 方式调用,观察代理的执行过程

常见问题

Q: 为什么我的代理没有使用 write_todos?

A: DeepAgent 会根据任务复杂度自动决定是否需要规划。简单任务可能直接执行。

Q: 如何查看代理调用了哪些工具?

A: 使用 stream() 方式可以看到每一步的工具调用。或者检查返回结果中的 messages 数组。

Q: 支持哪些模型?

A: 支持所有实现了工具调用的模型,包括 Claude、GPT-4、Gemini 等。下一篇文章会详细介绍模型配置。

参考资源

读文档、看源码、写代码,理解 AI Agent 本质 🤖