高级特性

掌握了基础之后,LangGraphGo 还提供了一系列高级特性,帮助你构建更复杂、更健壮、更易于维护的 AI 系统。

1. 并行执行 (Parallel Execution)

背景与功能

在许多任务中,多个步骤是可以同时进行的。例如,在写一篇文章时,可以同时搜索三个不同的主题。并行执行可以显著减少总的延迟。

实现原理

LangGraphGo 的运行时会自动检测并行机会。如果一个节点有多个出边指向不同的节点(Fan-out),或者多个节点没有依赖关系且都满足执行条件,运行时会将它们放入 Goroutine 中并发执行。

并发执行的结果需要合并。这就是为什么 State Schema 中的 Reducer 如此重要。Reducer 定义了如何安全地将并发产生的部分状态合并到主状态中。

代码展示

// 简单的 Fan-out 模式
g.AddEdge("start", "search_topic_a")
g.AddEdge("start", "search_topic_b")
g.AddEdge("start", "search_topic_c")

// Fan-in 模式:所有搜索完成后,汇总结果
g.AddEdge("search_topic_a", "aggregator")
g.AddEdge("search_topic_b", "aggregator")
g.AddEdge("search_topic_c", "aggregator")

// 运行时会自动并行执行 search_topic_a, b, c
// 只有当它们都完成后(或者根据具体逻辑),aggregator 才会执行

2. 子图 (Subgraphs)

背景与功能

随着应用变得复杂,单张大图会变得难以管理。子图允许你将图模块化。你可以像调用普通节点一样调用另一个编译好的图。

这不仅有助于代码组织,还支持多 Agent 协作模式,其中每个 Agent 都是一个独立的子图。

实现原理

编译后的图(CompiledGraph)实现了与节点函数相同的接口(接收 Context 和 State,返回 State)。因此,它可以直接被添加为父图的一个节点。

需要注意的是,父图和子图的状态 Schema 需要兼容,或者需要进行转换。

代码展示

// 1. 定义子图 (Researcher Agent)
researchGraph := graph.NewStateGraph(...)
// ... 构建 researchGraph ...
researchRunnable := researchGraph.Compile()

// 2. 定义父图 (Main Assistant)
mainGraph := graph.NewStateGraph(...)

// 3. 将子图作为节点添加到父图
mainGraph.AddNode("research_agent", researchRunnable)

// 4. 定义流程
mainGraph.AddEdge("classify_input", "research_agent")

3. 可视化 (Visualization)

背景与功能

“一图胜千言”。对于复杂的逻辑图,代码往往不如图形直观。LangGraphGo 内置了 Mermaid.js 格式的导出功能,让你能直接看到图的结构。

实现原理

图对象遍历其内部的节点和边结构,生成符合 Mermaid 语法的字符串描述。

代码展示

exporter := graph.NewExporter(g)
mermaidChart := exporter.DrawMermaid()
fmt.Println(mermaidChart)
// 输出示例:
// graph TD
//   start --> node_a
//   node_a --> node_b
//   ...

你可以将输出复制到 Mermaid Live Editor 中查看图表。

4. 运行时配置 (Configuration)

背景与功能

在不改变图结构和代码的情况下,我们经常需要调整运行时的行为。例如,为不同的用户使用不同的 LLM 模型,或者传递 User ID 以便在日志中追踪。

Config 对象提供了一种标准的方式来传递这些元数据。

实现原理

Config 对象在图的执行上下文中传递。任何节点都可以通过 graph.GetConfig(ctx) 获取当前的配置。

代码展示

// 调用时传递配置
config := &graph.Config{
    Configurable: map[string]interface{}{
        "user_id": "123",
        "model":   "gpt-4",
    },
}
runnable.InvokeWithConfig(ctx, input, config)

// 在节点中访问配置
func myNode(ctx context.Context, state interface{}) (interface{}, error) {
    config := graph.GetConfig(ctx)
    userID := config.Configurable["user_id"]
    // ...
}