创建时间: 2026-08-12最后更新: 2026-08-12作者: yangbo(445bdcbd2)
1. 演变
这个章节,不是为了让大家学会案例代码怎么编写。
而是让大家感受 Agent 从简单对话案例,逐步演变为复杂任务、节点图、多 Agent 协作的完整过程。从而帮助大家对 Agent 开发祛魅。作为初学者,能够直观的感受到 Agent 开发在做什么事情,并且根据需求的变化,多 Agent 还可以变得更加复杂,如下案例所示
出行建议 Agent
偏好、近期对话和天气结果会在本地浏览器中协同工作
尚未保存偏好或对话
LangGraph 多 Agent 运行轨迹
0 / 9 个步骤完成
- 意图识别IntentSchema
- 信息抽取开放事实模型
- 动态澄清场景缺口
- 偏好学习候选偏好
- Supervisor任务分派
- 天气 Agent天气子图
- 偏好 AgentIndexedDB 偏好
- 记忆 AgentIndexedDB 对话
- 建议汇总Supervisor
正在读取本地记忆...
graph.ts
graph-state.ts
understanding.ts
travel-schema.ts
travel-prompt.ts
specialist-agents.ts
memory.ts
preference-memory.ts
model.ts
track-node.ts
status.ts
types.ts
chat.tsx
preferences.tsx
floating-label-field.tsx
001import { END, START, StateGraph } from '@langchain/langgraph'002import { createSubagentModel, createTravelModel } from './model'003import { filterSafePreferenceCandidates } from './preference-memory'004import {005createTravelChannels,006createTravelInput,007formatCompleteTravelInput,008type TravelGraphState,009} from './graph-state'010import {011clarifyInformation,012extractInformation,013recognizeIntent,014} from './understanding'015import {016runMemoryAgent,017runPreferenceAgent,018runSynthesisAgent,019runWeatherAgent,020} from './specialist-agents'021import { trackNode } from './track-node'022import type { TravelStepEvent } from './status'023import type {024TravelAgentInput,025TravelPreferenceCandidate,026TravelSession,027} from './types'028029export interface TravelGraphResult {030reply: string031awaitingUserInput: boolean032session: TravelSession | null033learnedPreferences: TravelPreferenceCandidate[]034}035036interface RunTravelGraphOptions {037onStepEvent: (event: TravelStepEvent) => void038abortSignal?: AbortSignal039}040041export async function runTravelGraph(042input: TravelAgentInput,043{ onStepEvent, abortSignal }: RunTravelGraphOptions,044): Promise<TravelGraphResult> {045const { model, structuredOutputMethod } = await createTravelModel()046const specialistModel = await createSubagentModel()047const graph = new StateGraph<TravelGraphState>({048channels: createTravelChannels(input),049})050.addNode('recognizeIntentNode', trackNode('intent', onStepEvent, async (state, signal) => {051if (state.intent) return { intent: state.intent }052return {053intent: await recognizeIntent(054state.input,055model,056structuredOutputMethod,057signal,058),059}060}))061.addNode('extractInformationNode', trackNode('extract', onStepEvent, async (state, signal) => {062if (state.information) {063return {064information: state.information,065preferenceCandidates: state.preferenceCandidates,066}067}068return extractInformation(069state.input,070state.intent,071model,072structuredOutputMethod,073signal,074)075}))076.addNode('clarifyInformationNode', trackNode('clarify', onStepEvent, async (state, signal) => {077const clarification = await clarifyInformation(078state,079model,080structuredOutputMethod,081signal,082)083const awaitingUserInput = clarification.askUserFor.length > 0084return {085information: clarification.information,086preferenceCandidates: clarification.preferenceCandidates,087awaitingUserInput,088clarificationQuestion: clarification.nextQuestion ?? '',089pendingSession: awaitingUserInput ? {090id: 'default',091intent: state.intent!,092information: clarification.information,093preferenceCandidates: clarification.preferenceCandidates,094updatedAt: Date.now(),095} : null,096}097}))098.addNode('learnPreferencesNode', trackNode('learn', onStepEvent, async state => ({099preferenceCandidates: filterSafePreferenceCandidates(100state.preferenceCandidates,101),102})))103.addNode('returnClarificationNode', async () => ({}))104.addNode('readyForDelegationNode', async () => ({}))105.addNode('supervisor', trackNode('supervisor', onStepEvent, async state => ({106awaitingUserInput: false,107clarificationQuestion: '',108pendingSession: null,109input: formatCompleteTravelInput(state),110})))111.addNode('weather', trackNode('weather', onStepEvent, async (state, signal) => ({112weatherAdvice: await runWeatherAgent(113formatCompleteTravelInput(state),114specialistModel,115onStepEvent,116signal,117),118})))119.addNode('preference', trackNode('preference', onStepEvent, async (state, signal) => ({120preferenceAdvice: await runPreferenceAgent(121formatCompleteTravelInput(state),122state.preferences,123specialistModel,124signal,125),126})))127.addNode('memory', trackNode('memory', onStepEvent, async (state, signal) => ({128memoryAdvice: await runMemoryAgent(129formatCompleteTravelInput(state),130state.conversations,131specialistModel,132signal,133),134})))135.addNode('synthesis', trackNode('synthesis', onStepEvent, async (state, signal) => ({136finalReply: await runSynthesisAgent(state, specialistModel, signal),137})))138.addEdge('clarifyInformationNode', 'learnPreferencesNode')139.addConditionalEdges(140'learnPreferencesNode',141state => state.awaitingUserInput142? 'returnClarificationNode'143: 'readyForDelegationNode',144['returnClarificationNode', 'readyForDelegationNode'],145)146.addEdge(START, 'recognizeIntentNode')147.addEdge('recognizeIntentNode', 'extractInformationNode')148.addEdge('extractInformationNode', 'clarifyInformationNode')149.addEdge('supervisor', 'weather')150.addEdge('supervisor', 'preference')151.addEdge('supervisor', 'memory')152.addEdge(['weather', 'preference', 'memory'], 'synthesis')153.addEdge('synthesis', END)154.addEdge('returnClarificationNode', END)155.addEdge('readyForDelegationNode', 'supervisor')156.compile({ name: 'travel_advice_multi_agent' })157158const result = await graph.invoke(createTravelInput(input), {159signal: abortSignal,160}) as unknown as TravelGraphState161162if (result.awaitingUserInput) {163return {164reply: `为了给出更合适的建议,想再确认一下:${result.clarificationQuestion}`,165awaitingUserInput: true,166session: result.pendingSession,167learnedPreferences: result.preferenceCandidates,168}169}170if (!result.finalReply) throw new Error('出行建议 Agent 没有生成最终结果')171return {172reply: result.finalReply,173awaitingUserInput: false,174session: null,175learnedPreferences: result.preferenceCandidates,176}177}178
这条路线可以压缩成一句话:把「一次对话」逐步变成「可验证的任务」,再把任务变成「可观察的工作流」,最后把工作流拆成「可以协作的专业角色」。
正在加载图示...
图中的每一步都对应前面文章里解决的一类具体问题:信息不完整时先澄清,步骤太多时先规划,流程变长时拆节点,有等待依赖时做串行或并行编排,领域边界稳定后再抽成子图和子 Agent,最后由 Supervisor 负责委派与汇总。
不要把最后的多 Agent 误解成学习的起点。它只是前面所有边界都已经变得清楚之后,系统自然演变出来的组织方式。
订阅后可阅读剩余内容
AI 电子伴侣企业级项目实战
已发布239节计划发布120节目标已完成199%