> ## Documentation Index
> Fetch the complete documentation index at: https://langchain-zh.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 工作流与智能体

本指南回顾了常见的工作流和智能体模式。

* 工作流具有预定的代码路径，旨在按特定顺序运行。
* 智能体是动态的，定义自己的流程和工具使用。

<img src="https://mintcdn.com/hhh-8c10bf0c/jRI9Uh24bT9O5tSI/oss/images/agent_workflow.png?fit=max&auto=format&n=jRI9Uh24bT9O5tSI&q=85&s=744e94d6e159c56e9ef366c925a20dc8" alt="智能体工作流" width="4572" height="2047" data-path="oss/images/agent_workflow.png" />

LangGraph 在构建智能体和工作流时提供多种优势，包括 [持久化](/oss/javascript/langgraph/persistence)、[流式传输](/oss/javascript/langgraph/streaming)，以及对调试和 [部署](/oss/javascript/langgraph/deploy) 的支持。

## 设置

要构建工作流或智能体，您可以使用支持结构化输出和工具调用的 [任何聊天模型](/oss/javascript/integrations/chat)。以下示例使用 Anthropic：

1. 安装依赖项

<CodeGroup>
  ```bash npm theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  npm install @langchain/langgraph @langchain/core
  ```

  ```bash pnpm theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  pnpm add @langchain/langgraph @langchain/core
  ```

  ```bash yarn theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  yarn add @langchain/langgraph @langchain/core
  ```

  ```bash bun theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  bun add @langchain/langgraph @langchain/core
  ```
</CodeGroup>

2. 初始化 LLM：

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
import { ChatAnthropic } from "@langchain/anthropic";

const llm = new ChatAnthropic({
  model: "claude-sonnet-4-6",
  apiKey: "<your_anthropic_key>"
});
```

## LLM 与增强功能

工作流和智能体系统基于 LLM 以及您添加的各种增强功能。[工具调用](/oss/javascript/langchain/tools)、[结构化输出](/oss/javascript/langchain/structured-output) 和 [短期记忆](/oss/javascript/langchain/short-term-memory) 是定制 LLM 以满足您需求的几个选项。

<img src="https://mintcdn.com/hhh-8c10bf0c/jRI9Uh24bT9O5tSI/oss/images/augmented_llm.png?fit=max&auto=format&n=jRI9Uh24bT9O5tSI&q=85&s=11022c77d40fbf4228c9d49ef94b6a24" alt="LLM 增强功能" width="1152" height="778" data-path="oss/images/augmented_llm.png" />

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}

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

// Schema for structured output
const SearchQuery = z.object({
  search_query: z.string().describe("Query that is optimized web search."),
  justification: z
    .string()
    .describe("Why this query is relevant to the user's request."),
});

// Augment the LLM with schema for structured output
const structuredLlm = llm.withStructuredOutput(SearchQuery);

// Invoke the augmented LLM
const output = await structuredLlm.invoke(
  "How does Calcium CT score relate to high cholesterol?"
);

// Define a tool
const multiply = tool(
  ({ a, b }) => {
    return a * b;
  },
  {
    name: "multiply",
    description: "Multiply two numbers",
    schema: z.object({
      a: z.number(),
      b: z.number(),
    }),
  }
);

// Augment the LLM with tools
const llmWithTools = llm.bindTools([multiply]);

// Invoke the LLM with input that triggers the tool call
const msg = await llmWithTools.invoke("What is 2 times 3?");

// Get the tool call
console.log(msg.tool_calls);
```

## 提示链

提示链是指每个 LLM 调用处理前一个调用的输出。它通常用于执行定义明确的任务，这些任务可以分解为更小的、可验证的步骤。一些示例包括：

* 将文档翻译成不同的语言
* 验证生成内容的一致性

<img src="https://mintcdn.com/hhh-8c10bf0c/nuzu1mnzaCcJfRiZ/oss/images/prompt_chain.png?fit=max&auto=format&n=nuzu1mnzaCcJfRiZ&q=85&s=5e45efa8b729db375689cb5c8edc1ddc" alt="提示链" width="1412" height="444" data-path="oss/images/prompt_chain.png" />

<CodeGroup>
  ```typescript Graph API theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { StateGraph, StateSchema, GraphNode, ConditionalEdgeRouter } from "@langchain/langgraph";
  import { z } from "zod/v4";

  // Graph state
  const State = new StateSchema({
    topic: z.string(),
    joke: z.string(),
    improvedJoke: z.string(),
    finalJoke: z.string(),
  });

  // Define node functions

  // First LLM call to generate initial joke
  const generateJoke: GraphNode<typeof State> = async (state) => {
    const msg = await llm.invoke(`Write a short joke about ${state.topic}`);
    return { joke: msg.content };
  };

  // Gate function to check if the joke has a punchline
  const checkPunchline: ConditionalEdgeRouter<typeof State, "improveJoke"> = (state) => {
    // Simple check - does the joke contain "?" or "!"
    if (state.joke?.includes("?") || state.joke?.includes("!")) {
      return "Pass";
    }
    return "Fail";
  };

  // Second LLM call to improve the joke
  const improveJoke: GraphNode<typeof State> = async (state) => {
    const msg = await llm.invoke(
      `Make this joke funnier by adding wordplay: ${state.joke}`
    );
    return { improvedJoke: msg.content };
  };

  // Third LLM call for final polish
  const polishJoke: GraphNode<typeof State> = async (state) => {
    const msg = await llm.invoke(
      `Add a surprising twist to this joke: ${state.improvedJoke}`
    );
    return { finalJoke: msg.content };
  };

  // Build workflow
  const chain = new StateGraph(State)
    .addNode("generateJoke", generateJoke)
    .addNode("improveJoke", improveJoke)
    .addNode("polishJoke", polishJoke)
    .addEdge("__start__", "generateJoke")
    .addConditionalEdges("generateJoke", checkPunchline, {
      Pass: "improveJoke",
      Fail: "__end__"
    })
    .addEdge("improveJoke", "polishJoke")
    .addEdge("polishJoke", "__end__")
    .compile();

  // Invoke
  const state = await chain.invoke({ topic: "cats" });
  console.log("Initial joke:");
  console.log(state.joke);
  console.log("\n--- --- ---\n");
  if (state.improvedJoke !== undefined) {
    console.log("Improved joke:");
    console.log(state.improvedJoke);
    console.log("\n--- --- ---\n");

    console.log("Final joke:");
    console.log(state.finalJoke);
  } else {
    console.log("Joke failed quality gate - no punchline detected!");
  }
  ```

  ```typescript Functional API theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { task, entrypoint } from "@langchain/langgraph";

  // Tasks

  // First LLM call to generate initial joke
  const generateJoke = task("generateJoke", async (topic: string) => {
    const msg = await llm.invoke(`Write a short joke about ${topic}`);
    return msg.content;
  });

  // Gate function to check if the joke has a punchline
  function checkPunchline(joke: string) {
    // Simple check - does the joke contain "?" or "!"
    if (joke.includes("?") || joke.includes("!")) {
      return "Pass";
    }
    return "Fail";
  }

    // Second LLM call to improve the joke
  const improveJoke = task("improveJoke", async (joke: string) => {
    const msg = await llm.invoke(
      `Make this joke funnier by adding wordplay: ${joke}`
    );
    return msg.content;
  });

  // Third LLM call for final polish
  const polishJoke = task("polishJoke", async (joke: string) => {
    const msg = await llm.invoke(
      `Add a surprising twist to this joke: ${joke}`
    );
    return msg.content;
  });

  const workflow = entrypoint(
    "jokeMaker",
    async (topic: string) => {
      const originalJoke = await generateJoke(topic);
      if (checkPunchline(originalJoke) === "Pass") {
        return originalJoke;
      }
      const improvedJoke = await improveJoke(originalJoke);
      const polishedJoke = await polishJoke(improvedJoke);
      return polishedJoke;
    }
  );

  const stream = await workflow.stream("cats", {
    streamMode: "updates",
  });

  for await (const step of stream) {
    console.log(step);
  }
  ```
</CodeGroup>

## 并行化

通过并行化，LLM 同时处理任务。这可以通过同时运行多个独立的子任务，或者多次运行同一任务以检查不同输出来完成。并行化通常用于：

* 拆分子任务并并行运行它们，从而提高速度
* 多次运行任务以检查不同输出，从而提高置信度

一些示例包括：

* 运行一个处理文档关键词的子任务，以及另一个检查格式错误的子任务
* 多次运行一个根据标准（如引用数量、来源数量及来源质量）对文档进行评分的任务

<img src="https://mintcdn.com/hhh-8c10bf0c/nuzu1mnzaCcJfRiZ/oss/images/parallelization.png?fit=max&auto=format&n=nuzu1mnzaCcJfRiZ&q=85&s=b6b9f904e7037e11e133b21b5ff324ce" alt="并行化" width="1020" height="684" data-path="oss/images/parallelization.png" />

<CodeGroup>
  ```typescript Graph API theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { StateGraph, StateSchema, GraphNode } from "@langchain/langgraph";
  import * as z from "zod";

  // Graph state
  const State = new StateSchema({
    topic: z.string(),
    joke: z.string(),
    story: z.string(),
    poem: z.string(),
    combinedOutput: z.string(),
  });

  // Nodes
  // First LLM call to generate initial joke
  const callLlm1: GraphNode<typeof State> = async (state) => {
    const msg = await llm.invoke(`Write a joke about ${state.topic}`);
    return { joke: msg.content };
  };

  // Second LLM call to generate story
  const callLlm2: GraphNode<typeof State> = async (state) => {
    const msg = await llm.invoke(`Write a story about ${state.topic}`);
    return { story: msg.content };
  };

  // Third LLM call to generate poem
  const callLlm3: GraphNode<typeof State> = async (state) => {
    const msg = await llm.invoke(`Write a poem about ${state.topic}`);
    return { poem: msg.content };
  };

  // Combine the joke, story and poem into a single output
  const aggregator: GraphNode<typeof State> = async (state) => {
    const combined = `Here's a story, joke, and poem about ${state.topic}!\n\n` +
      `STORY:\n${state.story}\n\n` +
      `JOKE:\n${state.joke}\n\n` +
      `POEM:\n${state.poem}`;
    return { combinedOutput: combined };
  };

  // Build workflow
  const parallelWorkflow = new StateGraph(State)
    .addNode("callLlm1", callLlm1)
    .addNode("callLlm2", callLlm2)
    .addNode("callLlm3", callLlm3)
    .addNode("aggregator", aggregator)
    .addEdge("__start__", "callLlm1")
    .addEdge("__start__", "callLlm2")
    .addEdge("__start__", "callLlm3")
    .addEdge("callLlm1", "aggregator")
    .addEdge("callLlm2", "aggregator")
    .addEdge("callLlm3", "aggregator")
    .addEdge("aggregator", "__end__")
    .compile();

  // Invoke
  const result = await parallelWorkflow.invoke({ topic: "cats" });
  console.log(result.combinedOutput);
  ```

  ```typescript Functional API theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { task, entrypoint } from "@langchain/langgraph";

  // Tasks

  // First LLM call to generate initial joke
  const callLlm1 = task("generateJoke", async (topic: string) => {
    const msg = await llm.invoke(`Write a joke about ${topic}`);
    return msg.content;
  });

  // Second LLM call to generate story
  const callLlm2 = task("generateStory", async (topic: string) => {
    const msg = await llm.invoke(`Write a story about ${topic}`);
    return msg.content;
  });

  // Third LLM call to generate poem
  const callLlm3 = task("generatePoem", async (topic: string) => {
    const msg = await llm.invoke(`Write a poem about ${topic}`);
    return msg.content;
  });

  // Combine outputs
  const aggregator = task("aggregator", async (params: {
    topic: string;
    joke: string;
    story: string;
    poem: string;
  }) => {
    const { topic, joke, story, poem } = params;
    return `Here's a story, joke, and poem about ${topic}!\n\n` +
      `STORY:\n${story}\n\n` +
      `JOKE:\n${joke}\n\n` +
      `POEM:\n${poem}`;
  });

  // Build workflow
  const workflow = entrypoint(
    "parallelWorkflow",
    async (topic: string) => {
      const [joke, story, poem] = await Promise.all([
        callLlm1(topic),
        callLlm2(topic),
        callLlm3(topic),
      ]);

      return aggregator({ topic, joke, story, poem });
    }
  );

  // Invoke
  const stream = await workflow.stream("cats", {
    streamMode: "updates",
  });

  for await (const step of stream) {
    console.log(step);
  }
  ```
</CodeGroup>

## 路由

路由工作流处理输入，然后将其定向到特定上下文的任务。这允许您为复杂任务定义专用流程。例如，构建用于回答产品相关问题的流程可能会先处理问题类型，然后将请求路由到定价、退款、退货等的特定流程。

<img src="https://mintcdn.com/hhh-8c10bf0c/nuzu1mnzaCcJfRiZ/oss/images/routing.png?fit=max&auto=format&n=nuzu1mnzaCcJfRiZ&q=85&s=7aa7337912c23624fea8bff9ce78b783" alt="路由" width="1214" height="678" data-path="oss/images/routing.png" />

<CodeGroup>
  ```typescript Graph API theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { StateGraph, StateSchema, GraphNode, ConditionalEdgeRouter } from "@langchain/langgraph";
  import * as z from "zod";

  // Schema for structured output to use as routing logic
  const routeSchema = z.object({
    step: z.enum(["poem", "story", "joke"]).describe(
      "The next step in the routing process"
    ),
  });

  // Augment the LLM with schema for structured output
  const router = llm.withStructuredOutput(routeSchema);

  // Graph state
  const State = new StateSchema({
    input: z.string(),
    decision: z.string(),
    output: z.string(),
  });

  // Nodes
  // Write a story
  const llmCall1: GraphNode<typeof State> = async (state) => {
    const result = await llm.invoke([{
      role: "system",
      content: "You are an expert storyteller.",
    }, {
      role: "user",
      content: state.input
    }]);
    return { output: result.content };
  };

  // Write a joke
  const llmCall2: GraphNode<typeof State> = async (state) => {
    const result = await llm.invoke([{
      role: "system",
      content: "You are an expert comedian.",
    }, {
      role: "user",
      content: state.input
    }]);
    return { output: result.content };
  };

  // Write a poem
  const llmCall3: GraphNode<typeof State> = async (state) => {
    const result = await llm.invoke([{
      role: "system",
      content: "You are an expert poet.",
    }, {
      role: "user",
      content: state.input
    }]);
    return { output: result.content };
  };

  const llmCallRouter: GraphNode<typeof State> = async (state) => {
    // Route the input to the appropriate node
    const decision = await router.invoke([
      {
        role: "system",
        content: "Route the input to story, joke, or poem based on the user's request."
      },
      {
        role: "user",
        content: state.input
      },
    ]);

    return { decision: decision.step };
  };

  // Conditional edge function to route to the appropriate node
  const routeDecision: ConditionalEdgeRouter<typeof State, "llmCall1" | "llmCall2" | "llmCall3"> = (state) => {
    // Return the node name you want to visit next
    if (state.decision === "story") {
      return "llmCall1";
    } else if (state.decision === "joke") {
      return "llmCall2";
    } else {
      return "llmCall3";
    }
  };

  // Build workflow
  const routerWorkflow = new StateGraph(State)
    .addNode("llmCall1", llmCall1)
    .addNode("llmCall2", llmCall2)
    .addNode("llmCall3", llmCall3)
    .addNode("llmCallRouter", llmCallRouter)
    .addEdge("__start__", "llmCallRouter")
    .addConditionalEdges(
      "llmCallRouter",
      routeDecision,
      ["llmCall1", "llmCall2", "llmCall3"],
    )
    .addEdge("llmCall1", "__end__")
    .addEdge("llmCall2", "__end__")
    .addEdge("llmCall3", "__end__")
    .compile();

  // Invoke
  const state = await routerWorkflow.invoke({
    input: "Write me a joke about cats"
  });
  console.log(state.output);
  ```

  ```typescript Functional API theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import * as z from "zod";
  import { task, entrypoint } from "@langchain/langgraph";

  // Schema for structured output to use as routing logic
  const routeSchema = z.object({
    step: z.enum(["poem", "story", "joke"]).describe(
      "The next step in the routing process"
    ),
  });

  // Augment the LLM with schema for structured output
  const router = llm.withStructuredOutput(routeSchema);

  // Tasks
  // Write a story
  const llmCall1 = task("generateStory", async (input: string) => {
    const result = await llm.invoke([{
      role: "system",
      content: "You are an expert storyteller.",
    }, {
      role: "user",
      content: input
    }]);
    return result.content;
  });

  // Write a joke
  const llmCall2 = task("generateJoke", async (input: string) => {
    const result = await llm.invoke([{
      role: "system",
      content: "You are an expert comedian.",
    }, {
      role: "user",
      content: input
    }]);
    return result.content;
  });

  // Write a poem
  const llmCall3 = task("generatePoem", async (input: string) => {
    const result = await llm.invoke([{
      role: "system",
      content: "You are an expert poet.",
    }, {
      role: "user",
      content: input
    }]);
    return result.content;
  });

  // Route the input to the appropriate node
  const llmCallRouter = task("router", async (input: string) => {
    const decision = await router.invoke([
      {
        role: "system",
        content: "Route the input to story, joke, or poem based on the user's request."
      },
      {
        role: "user",
        content: input
      },
    ]);
    return decision.step;
  });

  // Build workflow
  const workflow = entrypoint(
    "routerWorkflow",
    async (input: string) => {
      const nextStep = await llmCallRouter(input);

      let llmCall;
      if (nextStep === "story") {
        llmCall = llmCall1;
      } else if (nextStep === "joke") {
        llmCall = llmCall2;
      } else if (nextStep === "poem") {
        llmCall = llmCall3;
      }

      const finalResult = await llmCall(input);
      return finalResult;
    }
  );

  // Invoke
  const stream = await workflow.stream("Write me a joke about cats", {
    streamMode: "updates",
  });

  for await (const step of stream) {
    console.log(step);
  }
  ```
</CodeGroup>

## 编排器 - 工作者

在编排器 - 工作者配置中，编排器：

* 将任务分解为子任务
* 将子任务委托给工作者
* 将工作者输出综合为最终结果

<img src="https://mintcdn.com/hhh-8c10bf0c/nuzu1mnzaCcJfRiZ/oss/images/worker.png?fit=max&auto=format&n=nuzu1mnzaCcJfRiZ&q=85&s=397d3873538efc9f3fbf3b7995eea34a" alt="工作者" width="1486" height="548" data-path="oss/images/worker.png" />

编排器 - 工作者工作流提供更灵活性，通常在子任务无法像 [并行化](#parallelization) 那样预先定义时使用。这在编写代码或需要在多个文件中更新内容的流程中很常见。例如，需要更新多个 Python 库的安装说明的流程，且涉及未知数量的文档，可能会使用此模式。

<CodeGroup>
  ```typescript Graph API theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}

  type SectionSchema = {
      name: string;
      description: string;
  }
  type SectionsSchema = {
      sections: SectionSchema[];
  }

  // Augment the LLM with schema for structured output
  const planner = llm.withStructuredOutput(sectionsSchema);
  ```

  ```typescript Functional API theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import * as z from "zod";
  import { task, entrypoint } from "@langchain/langgraph";

  // Schema for structured output to use in planning
  const sectionSchema = z.object({
    name: z.string().describe("Name for this section of the report."),
    description: z.string().describe(
      "Brief overview of the main topics and concepts to be covered in this section."
    ),
  });

  const sectionsSchema = z.object({
    sections: z.array(sectionSchema).describe("Sections of the report."),
  });

  // Augment the LLM with schema for structured output
  const planner = llm.withStructuredOutput(sectionsSchema);

  // Tasks
  const orchestrator = task("orchestrator", async (topic: string) => {
    // Generate queries
    const reportSections = await planner.invoke([
      { role: "system", content: "Generate a plan for the report." },
      { role: "user", content: `Here is the report topic: ${topic}` },
    ]);

    return reportSections.sections;
  });

  const llmCall = task("sectionWriter", async (section: z.infer<typeof sectionSchema>) => {
    // Generate section
    const result = await llm.invoke([
      {
        role: "system",
        content: "Write a report section.",
      },
      {
        role: "user",
        content: `Here is the section name: ${section.name} and description: ${section.description}`,
      },
    ]);

    return result.content;
  });

  const synthesizer = task("synthesizer", async (completedSections: string[]) => {
    // Synthesize full report from sections
    return completedSections.join("\n\n---\n\n");
  });

  // Build workflow
  const workflow = entrypoint(
    "orchestratorWorker",
    async (topic: string) => {
      const sections = await orchestrator(topic);
      const completedSections = await Promise.all(
        sections.map((section) => llmCall(section))
      );
      return synthesizer(completedSections);
    }
  );

  // Invoke
  const stream = await workflow.stream("Create a report on LLM scaling laws", {
    streamMode: "updates",
  });

  for await (const step of stream) {
    console.log(step);
  }
  ```
</CodeGroup>

### 在 LangGraph 中创建工作者

编排器 - 工作者工作流很常见，LangGraph 内置支持它们。`Send` API 允许您动态创建工作节点并向其发送特定输入。每个工作者都有自己的状态，所有工作者输出都写入共享状态键，编排器图可访问该键。这使编排器能够访问所有工作者输出，并将其综合为最终输出。下面的示例遍历章节列表，并使用 `Send` API 将每个章节发送给每个工作者。

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
import { StateGraph, StateSchema, ReducedValue, GraphNode, Send } from "@langchain/langgraph";
import * as z from "zod";

// Graph state
const State = new StateSchema({
  topic: z.string(),
  sections: z.array(z.custom<SectionsSchema>()),
  completedSections: new ReducedValue(
    z.array(z.string()).default(() => []),
    { reducer: (a, b) => a.concat(b) }
  ),
  finalReport: z.string(),
});

// Worker state
const WorkerState = new StateSchema({
  section: z.custom<SectionsSchema>(),
  completedSections: new ReducedValue(
    z.array(z.string()).default(() => []),
    { reducer: (a, b) => a.concat(b) }
  ),
});

// Nodes
const orchestrator: GraphNode<typeof State> = async (state) => {
  // Generate queries
  const reportSections = await planner.invoke([
    { role: "system", content: "Generate a plan for the report." },
    { role: "user", content: `Here is the report topic: ${state.topic}` },
  ]);

  return { sections: reportSections.sections };
};

const llmCall: GraphNode<typeof WorkerState> = async (state) => {
  // Generate section
  const section = await llm.invoke([
    {
      role: "system",
      content: "Write a report section following the provided name and description. Include no preamble for each section. Use markdown formatting.",
    },
    {
      role: "user",
      content: `Here is the section name: ${state.section.name} and description: ${state.section.description}`,
    },
  ]);

  // Write the updated section to completed sections
  return { completedSections: [section.content] };
};

const synthesizer: GraphNode<typeof State> = async (state) => {
  // List of completed sections
  const completedSections = state.completedSections;

  // Format completed section to str to use as context for final sections
  const completedReportSections = completedSections.join("\n\n---\n\n");

  return { finalReport: completedReportSections };
};

// Conditional edge function to create llm_call workers that each write a section of the report
const assignWorkers: ConditionalEdgeRouter<typeof State, "llmCall"> = (state) => {
  // Kick off section writing in parallel via Send() API
  return state.sections.map((section) =>
    new Send("llmCall", { section })
  );
};

// Build workflow
const orchestratorWorker = new StateGraph(State)
  .addNode("orchestrator", orchestrator)
  .addNode("llmCall", llmCall)
  .addNode("synthesizer", synthesizer)
  .addEdge("__start__", "orchestrator")
  .addConditionalEdges(
    "orchestrator",
    assignWorkers,
    ["llmCall"]
  )
  .addEdge("llmCall", "synthesizer")
  .addEdge("synthesizer", "__end__")
  .compile();

// Invoke
const state = await orchestratorWorker.invoke({
  topic: "Create a report on LLM scaling laws"
});
console.log(state.finalReport);
```

## 评估器 - 优化器

在评估器 - 优化器工作流中，一个 LLM 调用创建响应，另一个评估该响应。如果评估器或 [人工介入](/oss/javascript/langgraph/interrupts) 确定响应需要改进，则提供反馈并重新创建响应。此循环持续进行，直到生成可接受的响应。

当任务有特定的成功标准但需要迭代才能满足时，通常使用评估器 - 优化器工作流。例如，在两种语言之间翻译文本时，并不总是能完美匹配。可能需要几次迭代才能生成在两种语言中具有相同含义的翻译。

<img src="https://mintcdn.com/hhh-8c10bf0c/jRI9Uh24bT9O5tSI/oss/images/evaluator_optimizer.png?fit=max&auto=format&n=jRI9Uh24bT9O5tSI&q=85&s=cb386495693b909e89766ae0d0f137df" alt="评估器 - 优化器" width="1004" height="340" data-path="oss/images/evaluator_optimizer.png" />

<CodeGroup>
  ```typescript Graph API theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { StateGraph, StateSchema, GraphNode, ConditionalEdgeRouter } from "@langchain/langgraph";
  import * as z from "zod";

  // Graph state
  const State = new StateSchema({
    joke: z.string(),
    topic: z.string(),
    feedback: z.string(),
    funnyOrNot: z.string(),
  });

  // Schema for structured output to use in evaluation
  const feedbackSchema = z.object({
    grade: z.enum(["funny", "not funny"]).describe(
      "Decide if the joke is funny or not."
    ),
    feedback: z.string().describe(
      "If the joke is not funny, provide feedback on how to improve it."
    ),
  });

  // Augment the LLM with schema for structured output
  const evaluator = llm.withStructuredOutput(feedbackSchema);

  // Nodes
  const llmCallGenerator: GraphNode<typeof State> = async (state) => {
    // LLM generates a joke
    let msg;
    if (state.feedback) {
      msg = await llm.invoke(
        `Write a joke about ${state.topic} but take into account the feedback: ${state.feedback}`
      );
    } else {
      msg = await llm.invoke(`Write a joke about ${state.topic}`);
    }
    return { joke: msg.content };
  };

  const llmCallEvaluator: GraphNode<typeof State> = async (state) => {
    // LLM evaluates the joke
    const grade = await evaluator.invoke(`Grade the joke ${state.joke}`);
    return { funnyOrNot: grade.grade, feedback: grade.feedback };
  };

  // Conditional edge function to route back to joke generator or end based upon feedback from the evaluator
  const routeJoke: ConditionalEdgeRouter<typeof State, "llmCallGenerator"> = (state) => {
    // Route back to joke generator or end based upon feedback from the evaluator
    if (state.funnyOrNot === "funny") {
      return "Accepted";
    } else {
      return "Rejected + Feedback";
    }
  };

  // Build workflow
  const optimizerWorkflow = new StateGraph(State)
    .addNode("llmCallGenerator", llmCallGenerator)
    .addNode("llmCallEvaluator", llmCallEvaluator)
    .addEdge("__start__", "llmCallGenerator")
    .addEdge("llmCallGenerator", "llmCallEvaluator")
    .addConditionalEdges(
      "llmCallEvaluator",
      routeJoke,
      {
        // Name returned by routeJoke : Name of next node to visit
        "Accepted": "__end__",
        "Rejected + Feedback": "llmCallGenerator",
      }
    )
    .compile();

  // Invoke
  const state = await optimizerWorkflow.invoke({ topic: "Cats" });
  console.log(state.joke);
  ```

  ```typescript Functional API theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import * as z from "zod";
  import { task, entrypoint } from "@langchain/langgraph";

  // Schema for structured output to use in evaluation
  const feedbackSchema = z.object({
    grade: z.enum(["funny", "not funny"]).describe(
      "Decide if the joke is funny or not."
    ),
    feedback: z.string().describe(
      "If the joke is not funny, provide feedback on how to improve it."
    ),
  });

  // Augment the LLM with schema for structured output
  const evaluator = llm.withStructuredOutput(feedbackSchema);

  // Tasks
  const llmCallGenerator = task("jokeGenerator", async (params: {
    topic: string;
    feedback?: z.infer<typeof feedbackSchema>;
  }) => {
    // LLM generates a joke
    const msg = params.feedback
      ? await llm.invoke(
          `Write a joke about ${params.topic} but take into account the feedback: ${params.feedback.feedback}`
        )
      : await llm.invoke(`Write a joke about ${params.topic}`);
    return msg.content;
  });

  const llmCallEvaluator = task("jokeEvaluator", async (joke: string) => {
    // LLM evaluates the joke
    return evaluator.invoke(`Grade the joke ${joke}`);
  });

  // Build workflow
  const workflow = entrypoint(
    "optimizerWorkflow",
    async (topic: string) => {
      let feedback: z.infer<typeof feedbackSchema> | undefined;
      let joke: string;

      while (true) {
        joke = await llmCallGenerator({ topic, feedback });
        feedback = await llmCallEvaluator(joke);

        if (feedback.grade === "funny") {
          break;
        }
      }

      return joke;
    }
  );

  // Invoke
  const stream = await workflow.stream("Cats", {
    streamMode: "updates",
  });

  for await (const step of stream) {
    console.log(step);
    console.log("\n");
  }
  ```
</CodeGroup>

## 智能体

智能体通常实现为使用 [工具](/oss/javascript/langchain/tools) 执行操作的 LLM。它们在连续反馈循环中运行，用于问题和解决方案不可预测的情况。智能体比工作流拥有更多自主权，可以决定使用哪些工具以及如何解决问题。您仍然可以定义可用的工具集以及智能体行为的指导方针。

<img src="https://mintcdn.com/hhh-8c10bf0c/jRI9Uh24bT9O5tSI/oss/images/agent.png?fit=max&auto=format&n=jRI9Uh24bT9O5tSI&q=85&s=f41b192d859cefcfa2e0649abd61afec" alt="智能体" width="1732" height="712" data-path="oss/images/agent.png" />

<Note>
  要开始使用智能体，请参阅 [快速入门](/oss/javascript/langchain/quickstart) 或阅读更多关于 [它们如何工作](/oss/javascript/langchain/agents) 的信息。
</Note>

```typescript Using tools theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
import { tool } from "@langchain/core/tools";
import * as z from "zod";

// Define tools
const multiply = tool(
  ({ a, b }) => {
    return a * b;
  },
  {
    name: "multiply",
    description: "Multiply two numbers together",
    schema: z.object({
      a: z.number().describe("first number"),
      b: z.number().describe("second number"),
    }),
  }
);

const add = tool(
  ({ a, b }) => {
    return a + b;
  },
  {
    name: "add",
    description: "Add two numbers together",
    schema: z.object({
      a: z.number().describe("first number"),
      b: z.number().describe("second number"),
    }),
  }
);

const divide = tool(
  ({ a, b }) => {
    return a / b;
  },
  {
    name: "divide",
    description: "Divide two numbers",
    schema: z.object({
      a: z.number().describe("first number"),
      b: z.number().describe("second number"),
    }),
  }
);

// Augment the LLM with tools
const tools = [add, multiply, divide];
const toolsByName = Object.fromEntries(tools.map((tool) => [tool.name, tool]));
const llmWithTools = llm.bindTools(tools);
```

<CodeGroup>
  ```typescript Graph API theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { StateGraph, StateSchema, MessagesValue, GraphNode, ConditionalEdgeRouter } from "@langchain/langgraph";
  import { ToolNode } from "@langchain/langgraph/prebuilt";
  import {
    SystemMessage,
    ToolMessage
  } from "@langchain/core/messages";

  // Graph state
  const State = new StateSchema({
    messages: MessagesValue,
  });

  // Nodes
  const llmCall: GraphNode<typeof State> = async (state) => {
    // LLM decides whether to call a tool or not
    const result = await llmWithTools.invoke([
      {
        role: "system",
        content: "You are a helpful assistant tasked with performing arithmetic on a set of inputs."
      },
      ...state.messages
    ]);

    return {
      messages: [result]
    };
  };

  const toolNode = new ToolNode(tools);

  // Conditional edge function to route to the tool node or end
  const shouldContinue: ConditionalEdgeRouter<typeof State, "toolNode"> = (state) => {
    const messages = state.messages;
    const lastMessage = messages.at(-1);

    // If the LLM makes a tool call, then perform an action
    if (lastMessage?.tool_calls?.length) {
      return "toolNode";
    }
    // Otherwise, we stop (reply to the user)
    return "__end__";
  };

  // Build workflow
  const agentBuilder = new StateGraph(State)
    .addNode("llmCall", llmCall)
    .addNode("toolNode", toolNode)
    // Add edges to connect nodes
    .addEdge("__start__", "llmCall")
    .addConditionalEdges(
      "llmCall",
      shouldContinue,
      ["toolNode", "__end__"]
    )
    .addEdge("toolNode", "llmCall")
    .compile();

  // Invoke
  const messages = [{
    role: "user",
    content: "Add 3 and 4."
  }];
  const result = await agentBuilder.invoke({ messages });
  console.log(result.messages);
  ```

  ```typescript Functional API theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { task, entrypoint, addMessages } from "@langchain/langgraph";
  import { BaseMessageLike, ToolCall } from "@langchain/core/messages";

  const callLlm = task("llmCall", async (messages: BaseMessageLike[]) => {
    // LLM decides whether to call a tool or not
    return llmWithTools.invoke([
      {
        role: "system",
        content: "You are a helpful assistant tasked with performing arithmetic on a set of inputs."
      },
      ...messages
    ]);
  });

  const callTool = task("toolCall", async (toolCall: ToolCall) => {
    // Performs the tool call
    const tool = toolsByName[toolCall.name];
    return tool.invoke(toolCall.args);
  });

  const agent = entrypoint(
    "agent",
    async (messages) => {
      let llmResponse = await callLlm(messages);

      while (true) {
        if (!llmResponse.tool_calls?.length) {
          break;
        }

        // Execute tools
        const toolResults = await Promise.all(
          llmResponse.tool_calls.map((toolCall) => callTool(toolCall))
        );

        messages = addMessages(messages, [llmResponse, ...toolResults]);
        llmResponse = await callLlm(messages);
      }

      messages = addMessages(messages, [llmResponse]);
      return messages;
    }
  );

  // Invoke
  const messages = [{
    role: "user",
    content: "Add 3 and 4."
  }];

  const stream = await agent.stream([messages], {
    streamMode: "updates",
  });

  for await (const step of stream) {
    console.log(step);
  }
  ```
</CodeGroup>

***

<div className="source-links">
  <Callout icon="edit">
    [Edit this page on GitHub](https://github.com/langchain-ai/docs/edit/main/src/i18n\zh-CN\oss\langgraph\workflows-agents.mdx) or [file an issue](https://github.com/langchain-ai/docs/issues/new/choose).
  </Callout>

  <Callout icon="terminal-2">
    [Connect these docs](/use-these-docs) to Claude, VSCode, and more via MCP for real-time answers.
  </Callout>
</div>
