LangChain v1.0 的 Agents:让 AI 真正"动起来"

最近在重构项目时升级到了 LangChain v1.0.2,发现新版本的 createAgent() API 确实好用很多。之前写 Agent 需要自己手动处理工具调用的循环,现在一个函数调用就搞定了。今天就来聊聊 Agents 这个核心概念,以及 v1.0 到底改进了什么。

什么是 Agent?

简单来说,Agent 就是让大语言模型"动起来"的东西。它不仅仅是生成文本,还能调用工具、做决策、迭代解决问题。

用公式来表达就是:

ini 复制代码
Agent = Language Model(语言模型) + Tools(工具) + Reasoning(推理能力)

想象一下,你问 ChatGPT:"北京的天气怎么样?"传统的模型只能告诉你它训练数据里的信息,或者告诉你它不知道。但有了 Agent,它就可以:

  1. 理解你的问题
  2. 决定调用天气查询工具
  3. 执行工具获取实时数据
  4. 基于结果生成回答

整个过程是自动的,你不需要手动去调用天气 API,也不需要把结果传回去。Agent 自己会处理这个循环。

为什么需要 Agent?

这个问题其实很简单。语言模型再聪明,它也只是"知道"训练数据里的东西。但现实世界的数据是动态的、实时的。你需要:

  • 查询数据库获取最新订单状态
  • 调用 API 获取实时天气
  • 搜索代码库找到相关代码
  • 执行代码验证结果

这些操作都需要"工具",而 Agent 就是那个能智能选择和使用工具的"大脑"。

v1.0 的改进:createAgent()

之前用 LangChain 0.3.x 的时候,创建 Agent 需要好几步:

typescript 复制代码
import { AgentExecutor, createOpenAIFunctionsAgent } from 'langchain/agents';
import {
  ChatPromptTemplate,
  MessagesPlaceholder,
} from '@langchain/core/prompts';

// 先定义 prompt
const prompt = ChatPromptTemplate.fromMessages([
  ['system', '你是一个有用的助手'],
  ['human', '{input}'],
  new MessagesPlaceholder('agent_scratchpad'),
]);

// 创建 agent
const agent = await createOpenAIFunctionsAgent({
  llm,
  tools,
  prompt,
});

// 再创建 executor
const executor = new AgentExecutor({
  agent,
  tools,
  maxIterations: 15,
});

// 最后才能用
const result = await executor.invoke({ input: '问题' });

说实话,这套流程对新手来说有点复杂。而且每次都要写模板代码,容易出错。

现在 v1.0 的 createAgent() 就简单多了:

typescript 复制代码
import { createAgent } from 'langchain';
import { ChatOpenAI } from '@langchain/openai';
import { tool } from 'langchain';
import { z } from 'zod';

// 定义工具
const weatherTool = tool(
  async ({ city }: { city: string }) => {
    return `天气:${city} 晴天,25°C`;
  },
  {
    name: 'get_weather',
    description: '获取指定城市的天气信息',
    schema: z.object({
      city: z.string().describe('城市名称'),
    }),
  }
);

// 创建模型
const llm = new ChatOpenAI({
  modelName: 'gpt-4',
  temperature: 0,
});

// 创建 Agent - 就这么简单!
const agent = createAgent({
  llm,
  tools: [weatherTool],
  maxIterations: 15,
  systemMessage: '你是一个有用的助手',
});

// 使用
const result = await agent.invoke({
  input: '北京的天气如何?',
});

console.log(result.output);

看,代码量少了一半,而且更直观。这就是 v1.0 "opinionated" 设计理念的体现------提供最佳实践,减少配置负担。

Agent 是怎么工作的?

Agent 的核心是一个循环。理解这个循环机制很重要,它能帮你更好地使用 Agent。

Agent 执行循环详解

让我用图来展示 Agent 的工作流程:

yaml 复制代码
┌─────────────────────────────────┐
│  1. 接收用户输入                │
└────────────┬────────────────────┘
             ↓
┌─────────────────────────────────┐
│  2. LLM 分析任务并决定行动      │
│     - 是否需要调用工具?        │
│     - 调用哪个工具?            │
│     - 使用什么参数?            │
└────────────┬────────────────────┘
             ↓
         ┌───┴───┐
         │需要工具│
         └───┬───┘
             ↓
┌─────────────────────────────────┐
│  3. 执行选定的工具              │
│     - 调用工具函数              │
│     - 获取工具结果              │
└────────────┬────────────────────┘
             ↓
┌─────────────────────────────────┐
│  4. 将工具结果返回给 LLM        │
│     - 创建 ToolMessage          │
│     - 添加到消息历史            │
└────────────┬────────────────────┘
             ↓
┌─────────────────────────────────┐
│  5. LLM 基于结果继续推理         │
│     - 分析工具结果              │
│     - 决定下一步行动            │
└────────────┬────────────────────┘
             ↓
    ┌────────┴────────┐
    │  是否有最终答案? │
    └────────┬────────┘
         ┌───┴───┐
    No   │   Yes │
    └───┬─┘   └─┬───┘
        │       │
        ↓       ↓
  返回步骤2   返回最终答案

这个循环会自动重复,直到满足停止条件。整个过程你不需要写任何循环代码,Agent 自己会处理。

停止条件详解

Agent 会在以下情况下停止:

  1. 模型给出最终答案

    • LLM 认为不需要更多工具了
    • 直接返回最终答案
    • 这是最理想的停止方式
  2. 达到迭代限制

    typescript 复制代码
    const agent = createAgent({
      llm,
      tools,
      maxIterations: 15, // 最多执行 15 次迭代
    });
    • 防止无限循环
    • 保护机制,防止资源耗尽
    • 如果达到限制还没完成,会返回当前状态
  3. 错误发生

    • 工具执行失败
    • 或其他错误导致停止
    • Agent 会尝试错误恢复,但严重错误会停止

实际执行示例

让我用一个具体例子说明 Agent 的执行过程:

typescript 复制代码
// 用户输入
const input = '查询北京的天气,如果温度高于25度,就搜索附近的游泳馆';

// Agent 执行过程(自动)

// 迭代 1:
// LLM 决策:需要调用 get_weather 工具
// 执行:get_weather({ city: '北京' })
// 结果:{ temperature: 28, condition: '晴天' }

// 迭代 2:
// LLM 分析:温度是28度,高于25度
// LLM 决策:需要调用 search_nearby 工具
// 执行:search_nearby({ query: '游泳馆', location: '北京' })
// 结果:[{ name: '...', distance: '...' }]

// 迭代 3:
// LLM 分析:已有足够信息
// LLM 决策:生成最终答案,不再调用工具
// 输出:'今天北京天气晴朗,温度28度,适合游泳。附近有以下游泳馆...'

// 停止:模型发出最终答案 ✅

看,Agent 会自动处理这整个流程,你只需要调用一次 invoke() 就行了。

深入理解:Agent 的核心组件

在写实际例子之前,我想先聊聊 Agent 的三个核心组件,这样你能更好地理解它是怎么工作的。

1. Language Model(语言模型)

这是 Agent 的"大脑",负责:

  • 理解用户意图
  • 决定使用哪个工具
  • 分析工具结果
  • 生成最终答案
typescript 复制代码
const llm = new ChatOpenAI({
  modelName: 'gpt-4',
  temperature: 0, // 对于需要确定性的任务,设为 0
});

2. Tools(工具)

这是 Agent 的"双手",能让 Agent 执行实际操作:

typescript 复制代码
// 工具的结构
const tool = tool(
  async (input) => {
    // 实际执行的代码
    return result;
  },
  {
    name: 'tool_name',           // 工具名称
    description: '工具描述',      // 这很重要!
    schema: z.object({...}),      // 参数定义
  }
);

3. Reasoning(推理能力)

这是 Agent 的"思考过程",体现在:

  • 分析任务复杂度
  • 规划执行步骤
  • 决定工具调用顺序
  • 整合多个工具的结果

这三个组件组合在一起,就形成了 Agent 的完整能力。用公式来表达就是:

ini 复制代码
Agent = Language Model(大脑) + Tools(双手) + Reasoning(思考过程)

Agent vs 传统 LLM:什么时候用哪个?

理解 Agent 和传统 LLM 的区别,能帮你更好地判断什么时候用 Agent。

核心区别对比

特性 传统 LLM Agent
能力范围 只能生成文本 能调用工具、执行操作
数据来源 训练数据(静态) 训练数据 + 实时工具数据
解决问题 一次性回答 迭代式解决
工具使用 不支持 自动选择和执行
适用场景 简单问答、文本生成 复杂任务、多步骤操作

什么时候用 Agent?

适合用 Agent 的场景:

  • ✅ 需要查询实时数据(天气、订单、数据库)
  • ✅ 需要执行多个步骤(查询 → 分析 → 生成报告)
  • ✅ 需要调用外部工具(搜索、计算、API)
  • ✅ 任务需要迭代优化(不断尝试直到找到答案)

不适合用 Agent 的场景:

  • ❌ 简单的文本生成(翻译、摘要)
  • ❌ 不需要实时数据的问答
  • ❌ 成本敏感的场景(Agent 会多次调用 LLM)
  • ❌ 确定性要求极高的场景(Agent 有一定不确定性)

举个例子:

typescript 复制代码
// ❌ 不需要 Agent:简单的翻译
const llm = new ChatOpenAI({ modelName: 'gpt-4' });
const result = await llm.invoke('把 "Hello" 翻译成中文');
// 直接用 LLM 就够了

// ✅ 需要 Agent:查询实时数据并分析
const agent = createAgent({
  llm,
  tools: [weatherTool, calculatorTool],
});
const result = await agent.invoke(
  '北京的天气如何?如果温度高于20度,计算一下换算成华氏度是多少'
);
// Agent 会自动调用工具、分析结果、生成答案

一个实际例子

让我写个完整的例子,展示 Agent 如何解决一个多步骤的问题:

typescript 复制代码
import { createAgent } from 'langchain';
import { ChatOpenAI } from '@langchain/openai';
import { tool } from 'langchain';
import { z } from 'zod';

// 工具1:查询订单
const queryOrderTool = tool(
  async ({ orderId }: { orderId: string }) => {
    // 假设这是你的数据库查询
    const order = await db.query('SELECT * FROM orders WHERE id = ?', [
      orderId,
    ]);
    return JSON.stringify(order);
  },
  {
    name: 'query_order',
    description: '查询订单详细信息,包括状态、金额、商品等',
    schema: z.object({
      orderId: z.string().describe('订单号'),
    }),
  }
);

// 工具2:查询物流
const trackShippingTool = tool(
  async ({ orderId }: { orderId: string }) => {
    const shipping = await logisticsAPI.track(orderId);
    return JSON.stringify(shipping);
  },
  {
    name: 'track_shipping',
    description: '查询订单的物流信息和配送进度',
    schema: z.object({
      orderId: z.string().describe('订单号'),
    }),
  }
);

// 工具3:搜索FAQ
const searchFAQTool = tool(
  async ({ question }: { question: string }) => {
    const answer = await faqDatabase.search(question);
    return answer;
  },
  {
    name: 'search_faq',
    description: '在常见问题库中搜索答案',
    schema: z.object({
      question: z.string().describe('用户的问题'),
    }),
  }
);

// 创建客服 Agent
const customerServiceAgent = createAgent({
  llm: new ChatOpenAI({
    modelName: 'gpt-4',
    temperature: 0, // 客服需要确定性
  }),
  tools: [queryOrderTool, trackShippingTool, searchFAQTool],
  maxIterations: 10,
  systemMessage: `你是一个专业的客服助手。
  
工作原则:
1. 友好、专业、耐心
2. 使用工具获取准确信息
3. 如果无法解决问题,引导用户联系人工客服`,
});

// 使用
const result = await customerServiceAgent.invoke({
  input: '你好,我想查询订单 #12345 的信息,还有什么时候能到?',
});

console.log(result.output);

当你运行这段代码时,Agent 会自动:

  1. 理解用户想查询订单和物流信息
  2. 调用 queryOrderTool 获取订单详情
  3. 调用 trackShippingTool 获取物流信息
  4. 整合信息生成友好的回答

整个过程你不需要写任何循环代码,Agent 自己会处理。

工具描述的重要性

这里有个很重要的点:工具的描述一定要清晰。Agent 是通过描述来理解工具的用途的,描述越清晰,Agent 选择工具就越准确。

好的描述:

typescript 复制代码
{
  name: 'get_weather',
  description: '获取指定城市的天气信息,包括温度、湿度和天气状况',
  // ...
}

不好的描述:

typescript 复制代码
{
  name: 'tool1',
  description: '获取信息', // 太模糊了
  // ...
}

如果描述不清楚,Agent 可能会选错工具,或者不知道该用哪个。这就像给一个员工分配任务,如果你不说清楚,他可能做错事。

迭代限制和错误处理

Agent 会自动处理错误,这很贴心。如果工具执行失败,Agent 会捕获错误信息,然后尝试其他方案。但你需要设置合理的迭代限制,防止无限循环。

typescript 复制代码
const agent = createAgent({
  llm,
  tools,
  maxIterations: 15, // 最多15次迭代
  // ...
});

一般来说,10-15 次迭代足够解决大多数问题了。如果任务特别复杂,可以适当增加,但也要注意成本。

实际应用场景

我在项目中用 Agent 做了几个场景:

客服机器人:用户问订单状态,Agent 自动查询数据库和物流 API,然后生成回答。这比写一堆 if-else 判断要优雅多了。

数据分析助手:用户用自然语言问数据问题,Agent 自动生成 SQL、执行查询、可视化结果。不需要用户懂 SQL。

代码助手:搜索代码库、读取文件、执行测试、生成代码。Agent 可以自动完成多个步骤。

每个场景都大大简化了代码,而且用户体验更好。

和手动工具调用的对比

之前提到过,v0.3.x 需要手动处理工具调用循环。让我详细对比一下这两种方式的区别。

手动方式(v0.3.x)

typescript 复制代码
import { ChatOpenAI } from '@langchain/openai';
import { HumanMessage, ToolMessage } from '@langchain/core/messages';

const llm = new ChatOpenAI({ modelName: 'gpt-4' });
const llmWithTools = llm.bindTools([weatherTool, databaseTool]);

const messages = [new HumanMessage('问题')];
let response = await llmWithTools.invoke(messages);

while (response.tool_calls?.length > 0) {
  // 手动执行每个工具
  const toolResults = await Promise.all(
    response.tool_calls.map(tc =>
      tools.find(t => t.name === tc.name).invoke(tc.args)
    )
  );

  // 手动创建 ToolMessage
  messages.push(response);
  toolResults.forEach((result, i) => {
    messages.push(
      new ToolMessage({
        content: result,
        tool_call_id: response.tool_calls[i].id,
      })
    );
  });

  // 再次调用
  response = await llmWithTools.invoke(messages);
}

手动方式的问题:

  • ❌ 代码复杂,需要写循环逻辑
  • ❌ 容易出错,消息历史管理麻烦
  • ❌ 需要手动处理错误
  • ❌ 没有迭代限制保护
  • ❌ 每次都要写类似的模板代码

Agent 方式(v1.0)

typescript 复制代码
import { createAgent } from 'langchain';

const agent = createAgent({
  llm,
  tools: [weatherTool, databaseTool],
  maxIterations: 15,
});

const result = await agent.invoke({ input: '问题' });

Agent 方式的优势:

  • ✅ 代码简洁,一行搞定
  • ✅ 自动处理循环和消息历史
  • ✅ 内置错误处理
  • ✅ 自动迭代限制保护
  • ✅ 生产就绪的实现

对比总结

维度 手动方式 Agent 方式
代码量 20-30 行 5-10 行
复杂度
错误处理 手动实现 自动处理
迭代限制 手动管理 自动保护
维护性 难维护 易维护
适用场景 特殊需求 大多数场景

很明显,Agent 方式更简单、更可靠。除非你有特殊需求,否则建议直接用 createAgent()

一些注意事项

使用 Agent 的时候,有几个点需要注意:

  1. 工具描述要清晰:这决定了 Agent 能否正确选择工具
  2. 设置合理的迭代限制:防止无限循环,也控制成本
  3. 错误处理:虽然 Agent 会自动处理,但工具内部最好也有错误处理
  4. 成本考虑:每次迭代都会调用 LLM,复杂的任务成本会比较高

总结

LangChain v1.0 的 createAgent() 确实是个很大的改进。代码更简洁,API 更直观,而且内置了最佳实践。对于需要多步骤交互的场景,Agent 是个很好的选择。

不过它也不是万能的。简单的任务可能直接用 LLM 就够了,不需要 Agent。而且 Agent 需要调用 LLM 多次,成本会比较高。所以要根据实际需求来选择。

总的来说,Agent 让 AI 应用开发变得更简单了。你可以专注于业务逻辑,而不用操心工具调用的循环处理。这就是框架的价值------让复杂的事情变简单。

相关推荐
蛇皮划水怪6 小时前
深入浅出LangChain4J
java·langchain·llm
、BeYourself8 小时前
LangChain4j 流式响应
langchain
、BeYourself8 小时前
LangChain4j之Chat and Language
langchain
qfljg10 小时前
langchain usage
langchain
kjkdd14 小时前
6.1 核心组件(Agent)
python·ai·语言模型·langchain·ai编程
渣渣苏18 小时前
Langchain实战快速入门
人工智能·python·langchain
小天呐18 小时前
01—langchain 架构
langchain
香芋Yu21 小时前
【LangChain1.0】第九篇 Agent 架构设计
langchain·agent·架构设计
kjkdd1 天前
5. LangChain设计理念和发展历程
python·语言模型·langchain·ai编程
ASKED_20191 天前
Langchain学习笔记一 -基础模块以及架构概览
笔记·学习·langchain