创见博客
用 createAgent 创建智能体:创建与调用
七崽爱吃小饼干2026/10/15阅读 0

前面几篇讲了工具(tool)和结构化输出。把它们串起来,就组成了 Agent(智能体):让模型自己「思考 → 调用工具 → 看结果 → 再思考」,直到解决问题。手动实现这个循环要写 bindTools、执行工具、塞回 ToolMessage……很啰嗦。LangChain 提供了 createAgent(Python 里叫 create_agent),把整个循环打包成一个对象。这篇讲清楚它怎么创建、怎么调用。

一、Agent 与 createAgent

Agent 的本质是一个 ReAct 循环:

用户提问
  -> 模型决策(可能需要调用工具,输出 tool_calls)
  -> 执行工具,把结果塞回消息历史
  -> 模型再决策(继续调用 or 给出最终答案)
  -> 重复,直到不再调用工具

createAgent 做的事情,就是把这个循环封成一个「可以 invoke 的对象」。你只需要提供模型、工具、系统提示词,剩下的编排它全包了:

js
import { createAgent, tool } from "langchain";

const agent = createAgent({
  model: "deepseek:deepseek-chat",
  tools: [getWeather],
  systemPrompt: "你是一个简洁的中文助手,需要实时信息时请调用工具。",
});

对比一下:手动循环(见 demo-09)要自己 bindTools、遍历 tool_calls、构造 ToolMessage、再循环调用;createAgent 之后只剩这一处配置。

二、创建:createAgent 的参数

js
const agent = createAgent({
  model: "deepseek:deepseek-chat",  // 模型:字符串或模型实例
  tools: [getWeather],              // 工具数组,用 tool() 定义
  systemPrompt: "你是简洁的中文助手", // 系统提示词(字符串或 SystemMessage)
  checkpointer: new MemorySaver(),  // 可选:多轮记忆
});
参数作用
model模型。可以是 "provider:model" 字符串,也可以是配置好的模型实例
tools工具数组,每个工具用 tool(fn, { name, description, schema }) 定义
systemPrompt系统提示词,设定 agent 的角色和行为规范
checkpointer可选,传入记忆存储后支持多轮对话(见第五节)
responseFormat可选,让 agent 直接产出结构化结果(见 demo-10)

一个工具长这样(和 demo-09 完全一致):

js
const getWeather = tool(
  ({ city }) => `${city} 今天晴,气温 25℃`,
  {
    name: "get_weather",
    description: "查询指定城市今天的天气",
    schema: z.object({ city: z.string().describe("城市名,例如 北京") }),
  }
);

三、调用:invoke 与 stream

创建好之后,用 invoke 或 stream 调用。两者输入相同:一个 { messages: [...] } 的 state。

3.1 invoke:一次性拿到完整结果

js
const res = await agent.invoke({
  messages: [{ role: "user", content: "北京今天天气怎么样?" }],
});

console.log(res.messages.map((m) => m.type).join(" -> "));
// human -> ai -> tool -> ai

console.log(res.messages.at(-1).content);
// 北京今天天气晴朗,气温 25℃。适合外出,记得做好防晒。

返回值是一个 state,核心是 messages 数组,里面记录了整个循环过程:

  • human:用户输入;
  • ai:模型的决策(可能带 tool_calls);
  • tool:工具执行结果;
  • ai:最终的纯文本答案。

中间那条 ai 消息里的 tool_calls 就是模型「请求调用工具」的证据:

js
// res.messages[1].tool_calls
[{ name: "get_weather", args: { city: "北京" }, id: "call_xxx", type: "tool_call" }]

3.2 stream:流式拿到结果

stream 返回一个异步可迭代对象,适合做打字机效果或观察执行过程。常用的两种 streamMode:

streamMode: "messages"——逐 token 流式输出:

js
const stream = await agent.stream(
  { messages: [{ role: "user", content: "用一句话介绍你自己" }] },
  { streamMode: "messages" }
);

for await (const [chunk] of stream) {
  if (chunk.content) process.stdout.write(chunk.content);
}

每个 chunk 是 [消息, 元数据],把 chunk.content 拼起来就是完整回复。

streamMode: "updates"——逐节点返回,观察 ReAct 循环:

js
const stream = await agent.stream(
  { messages: [{ role: "user", content: "上海今天天气怎么样?" }] },
  { streamMode: "updates" }
);

for await (const step of stream) {
  console.log(Object.keys(step)); // ["model_request"] -> ["tools"] -> ["model_request"]
}

可以看到节点按 model_request → tools → model_request 推进,正是 ReAct 循环的每一步。

需要更细粒度的事件(单个 token、工具调用开始/结束等)可以用 agent.streamEvents(...)。

四、调用:多轮对话(记忆)

默认情况下每次 invoke 都是独立的,agent 不记得上一轮。 要让它记住,需要两步:

  1. 创建时挂一个 checkpointer(记忆存储);
  2. 调用时用 thread_id 区分会话。
js
import { createAgent } from "langchain";
import { MemorySaver } from "@langchain/langgraph";

const agent = createAgent({
  model: "deepseek:deepseek-chat",
  tools: [],
  systemPrompt: "你是助手,请记住用户告诉你的信息。",
  checkpointer: new MemorySaver(),   // 挂上记忆
});

const config = { configurable: { thread_id: "user-1" } };

await agent.invoke(
  { messages: [{ role: "user", content: "我叫小明,住在杭州。" }] },
  config
);

const res = await agent.invoke(
  { messages: [{ role: "user", content: "我叫什么?住在哪?" }] },
  config
);

console.log(res.messages.at(-1).content);
// 你叫小明,住在杭州。

要点:

  • 同一个 thread_id = 同一段会话,历史会自动累积,agent 能记住上下文;
  • 换一个 thread_id 就是另一段独立会话,互不影响;
  • MemorySaver 存在内存里,进程结束就没了;生产环境换成数据库/Redis 等持久化 checkpointer。

五、Python 对应写法

Python 里函数名是 create_agent,参数名基本一致(model / tools / system_prompt),调用方式也一样:

python
from langgraph.checkpoint.memory import InMemorySaver
from langchain.agents import create_agent

agent = create_agent(
    model="deepseek:deepseek-chat",
    tools=[get_weather],
    system_prompt="你是一个简洁的中文助手,需要实时信息时请调用工具。",
    checkpointer=InMemorySaver(),
)

result = agent.invoke({"messages": [{"role": "user", "content": "北京今天天气怎么样?"}]})
print(result["messages"][-1].content)

六、小结

创建:createAgent({ model, tools, systemPrompt, checkpointer })——给「模型 + 工具 + 系统提示词」,它自动完成整个 ReAct 循环。

调用:

  • agent.invoke(input[, config]):一次性拿到完整 state,看 res.messages;
  • agent.stream(input, { streamMode }):流式。"messages" 逐 token,"updates" 逐节点;
  • agent.streamEvents(...):更细粒度的事件流。

多轮:挂 checkpointer + 用 config.configurable.thread_id 区分会话。

一句话:createAgent = 把「模型决策 + 工具执行」的循环编排打包成一个可 invoke 的对象,你负责给配置、给输入,它负责把 ReAct 循环跑完。

评论
0/100