写点什么

DeepSeek + Function Call:基于 Eino 的“计划——执行”多智能体范式实战

字节跳动CloudWeGo

  • 2025-03-13
    北京
  • 本文字数:10586 字

    阅读完需:约 35 分钟

大小:1.89M时长:11:00
DeepSeek + Function Call:基于 Eino 的“计划——执行”多智能体范式实战

DeepSeek-R1(以下简称 DeepSeek)以其优秀的复杂问题推理能力和规划能力脱颖而出,然而其原生函数调用(Function Call)功能的缺失,无法让大模型去选择不同的工具和程序,以获取对应的信息,使其难以完成以下关键动作:


  • 实时数据获取(天气/票务/交通)

  • 外部服务交互(地图 API/支付接口)

  • 复杂任务拆解执行(多步骤自动化)


这就导致它的应用场景受到限制,大多只能用于简单的对话式问答。有没有一个解决办法,能实现让 DeepSeek 做 Function Call?答案是肯定的,我们提出"计划——执行”多智能体的协同范式:由 DeepSeek 负责“指挥”,由擅长 Function Call 的其他大模型去听指挥进行函数调用。这需要利用“计划——执行”多智能体范式,由“计划”智能体负责推理和生成计划,由“执行”智能体负责执行计划:


“计划——执行”多智能体范式的三大优势:


  1. 专业的“智能体”干专业的事情:比如 DeepSeek 负责推理和计划,豆包大模型负责 Function Call。

  2. “智能体”层面的单一职责原则:每个智能体的职责是明确的,解耦的,方便 Prompt 调优和评测。

  3. 在提供解决问题整体方案的同时,保持灵活性:符合人类解决问题的通用模式。


要实现 “计划 —— 执行” 多智能体,我们必须要解决几个问题:多模型、多工具集成,复杂流程编排,上下文管理以及中间步骤追踪。Eino(文档GitHub 项目页) 框架通过提供开箱即用的模型组件实现和工具执行器、面向抽象接口的灵活流程编排能力、完备的全局状态管理以及回调机制,确保了上述问题的有效解决。


接下来,文章将直观的解释“计划 —— 执行”多智能体范式,介绍如何借助 Eino 框架来实现基于 DeepSeek 的‘计划 —— 执行’多智能体,最后通过一个有趣且靠谱的主题乐园行程规划助手的实战案例,带大家从 0 到 1 搭建一个完整的应用。

“计划——执行”多智能体

基本的 ReAct 单智能体,是由一个 Agent 既负责计划拆解,也负责 Function Call:



可能存在的问题有三个:


  1. 对 LLM 的要求高:既要擅长推理规划,也要擅长做 Function Call。

  2. LLM 的 prompt 复杂:既要能正确规划,又要正确的做 Function Call,还要能输出正确的结果。

  3. 没有计划:每次 Function Call 之后,LLM 需要重新推理,没有整体的可靠计划。


解决的思路,首先是把单个的 LLM 节点拆分成两个,一个负责“计划”,一个负责“执行”:


这样就解决了上面的问题 3,Planner 会给出完整计划,Executor 依据这个完整计划来依次执行。部分解决了问题 1、2,Planner 只需要擅长推理规划,Executor 则需要擅长做 Function Call 和总结,各自的 prompt 都是原先的一个子集。但同时带来一个新的问题:


  1. 缺少纠错能力:最开始的计划,在执行后,是否真的符合预期、能够解决问题?


继续优化多智能体结构,在 Executor 后面增加一个 LLM 节点,负责“反思和调整计划”:



这样就彻底解决了上面列出的问题,Executor 只需要按计划执行 Function Call,Reviser 负责反思和总结。


这就是“计划——执行”多智能体:通过将任务解决过程拆解为负责计划的 Planner 和 Reviser,以及负责执行的 Executor,实现了智能体的单一职责以及任务的有效计划与反思,同时也能够充分发挥 DeepSeek 这种推理模型的长项、规避其短板(Function Call)。

基于 Eino 框架实现“计划——执行”多智能体

实现一个“计划——执行”多智能体,需要:


  • 能够快速简单的集成 DeepSeek、豆包等各种大模型。

  • 能够快速简单的集成和执行各种 Tool。

  • 能够快速实现流程编排,把多个智能体以及工具按设计的流程串联起来,并能随时快速调整。

  • 能够及时的输出各智能体的执行过程,包括 DeepSeek 的推理过程。

  • 能够有效的管理和传递上下文。


Eino 是字节跳动开源的基于 Golang 的大模型应用开发框架,已在豆包、抖音、扣子等多个业务线广泛使用。我们选择 Eino 作为框架来进行全码开发,因为:


  • Eino 可以用几行代码完成对各种大模型的调用,包括 DeepSeek。

  • Eino 可以用几行代码快速把一个本地 Function 封装成 Tool,且有开箱即用的 Tool 执行器。

  • Eino 的流程编排能力可靠且灵活:分支判断,循环,运行时参数配置等。

  • Eino 的数据流处理能力为大模型应用场景而设计,可配合完整的回调机制实时输出中间结果。

  • Eino 可以通过在图编排时配置和读写全局状态来实现有效的上下文管理和传递。


Eino 的详细信息参见:文档Github 项目页

实战:主题乐园行程规划助手

我们通过实现一个主题乐园行程规划助手,来探索如何用 Eino 实现基于 DeepSeek 的“计划——执行”多智能体。这个多智能体的功能是根据用户的游园需求,规划出具体、符合要求、可操作的行程安排。完整代码仓库地址:https://github.com/cloudwego/eino-examples/tree/main/flow/agent/multiagent/plan_execute

定义多智能体

首先定义多智能体以及需要的配置:


package plan_execute
import ( "github.com/cloudwego/eino/components/model" "github.com/cloudwego/eino/compose" "github.com/cloudwego/eino/schema")
// Config “计划——执行”多智能体的配置.type Config struct { PlannerModel model.ChatModel // planner 智能体使用的大模型 PlannerSystemPrompt string // planner 智能体的 system prompt
ExecutorModel model.ChatModel // executor 智能体使用的大模型 ToolsConfig compose.ToolsNodeConfig // executor 智能体使用的工具执行器配置 ExecutorSystemPrompt string // executor 智能体的 system prompt
ReviserModel model.ChatModel // reviser 智能体使用的大模型 ReviserSystemPrompt string // reviser 智能体的 system prompt
MaxStep int // 多智能体的最大执行步骤数,避免无限循环}
// PlanExecuteMultiAgent “计划——执行”多智能体.type PlanExecuteMultiAgent struct { // 图编排后的可执行体,输入是 Message 数组,输出是单条 Message runnable compose.Runnable[[]*schema.Message, *schema.Message]}
复制代码

多智能体编排逻辑

Eino 的流程编排有“节点(Node)”、“边(Edge)”和“分支(Branch)”组成,数据流转时要求严格的类型对齐。完整的数据流转图如下:



上图中,Planner,Executor,Reviser 都是输入为[]*Message,输出为*Message 的 ChatModel 节点,Branch1 判断 Executor 是否完成了本轮次所有的 Function Call,Branch2 判断 Reviser 是否输出了最终答案,各个 ToList 节点负责连接两个 ChatModel,将输出的 *Message 转化为 []*Message,从而满足类型校验要求。我们实现一个 NewMultiAgent 方法来实现上述编排逻辑:


// NewMultiAgent 根据配置编排一个“计划——执行”多智能体.func NewMultiAgent(ctx context.Context, config *Config) (*PlanExecuteMultiAgent, error) {    var (       toolInfos      []*schema.ToolInfo       toolsNode      *compose.ToolsNode       err            error       plannerPrompt  = config.PlannerSystemPrompt       executorPrompt = config.ExecutorSystemPrompt       reviserPrompt  = config.ReviserSystemPrompt       maxStep        = config.MaxStep    )
if len(plannerPrompt) == 0 { plannerPrompt = defaultPlannerPrompt }
if len(executorPrompt) == 0 { executorPrompt = defaultExecutorPrompt }
if len(reviserPrompt) == 0 { reviserPrompt = defaultReviserPrompt }
if maxStep == 0 { maxStep = defaultMaxStep }
if toolInfos, err = genToolInfos(ctx, config.ToolsConfig); err != nil { return nil, err }
// 为 Executor 配置工具 if err = config.ExecutorModel.BindTools(toolInfos); err != nil { return nil, err }
// 初始化 Tool 执行器节点,传入可执行的工具 if toolsNode, err = compose.NewToolNode(ctx, &config.ToolsConfig); err != nil { return nil, err }
// 创建一个待编排的 graph,规定整体的输入输出类型 graph := compose.NewGraph[[]*schema.Message, *schema.Message]()
// 定义 Executor 后的分支判断用的条件函数。该函数的输出是运行时选中的 NodeKey executorPostBranchCondition := func(_ context.Context, msg *schema.Message) (endNode string, err error) { if len(msg.ToolCalls) == 0 { return nodeKeyExecutorToList, nil } return nodeKeyTools, nil }
// 定义 Reviser 后的分支判断用的条件函数。 reviserPostBranchCondition := func(_ context.Context, sr *schema.StreamReader[*schema.Message]) (endNode string, err error) { defer sr.Close()
var content string for { msg, err := sr.Recv() if err != nil { if err == io.EOF { return nodeKeyReviserToList, nil } return "", err }
content += msg.Content
if strings.Contains(content, "最终答案") { return compose.END, nil }
if len(content) > 20 { return nodeKeyReviserToList, nil } } }
// 添加 Planner 节点 _ = graph.AddChatModelNode(nodeKeyPlanner, config.PlannerModel, compose.WithNodeName(nodeKeyPlanner))
// 添加 Executor 节点 _ = graph.AddChatModelNode(nodeKeyExecutor, config.ExecutorModel, compose.WithNodeName(nodeKeyExecutor))
// 添加 Reviser 节点 _ = graph.AddChatModelNode(nodeKeyReviser, config.ReviserModel, compose.WithNodeName(nodeKeyReviser))
// 添加 Tool 执行器节点 _ = graph.AddToolsNode(nodeKeyTools, toolsNode)
// 添加三个 ToList 转换节点 _ = graph.AddLambdaNode(nodeKeyPlannerToList, compose.ToList[*schema.Message]()) _ = graph.AddLambdaNode(nodeKeyExecutorToList, compose.ToList[*schema.Message]()) _ = graph.AddLambdaNode(nodeKeyReviserToList, compose.ToList[*schema.Message]())
// 添加节点之间的边和分支 _ = graph.AddEdge(compose.START, nodeKeyPlanner) _ = graph.AddEdge(nodeKeyPlanner, nodeKeyPlannerToList) _ = graph.AddEdge(nodeKeyPlannerToList, nodeKeyExecutor) _ = graph.AddBranch(nodeKeyExecutor, compose.NewStreamGraphBranch(executorPostBranchCondition, map[string]bool{ nodeKeyTools: true, nodeKeyExecutorToList: true, })) _ = graph.AddEdge(nodeKeyTools, nodeKeyExecutor) _ = graph.AddEdge(nodeKeyExecutorToList, nodeKeyReviser) _ = graph.AddBranch(nodeKeyReviser, compose.NewStreamGraphBranch(reviserPostBranchCondition, map[string]bool{ nodeKeyReviserToList: true, compose.END: true, })) _ = graph.AddEdge(nodeKeyReviserToList, nodeKeyExecutor)
// 编译 graph,将节点、边、分支转化为面向运行时的结构。由于 graph 中存在环,使用 AnyPredecessor 模式,同时设置运行时最大步数。 runnable, err := graph.Compile(ctx, compose.WithNodeTriggerMode(compose.AnyPredecessor), compose.WithMaxRunSteps(maxStep)) if err != nil { return nil, err }
return &PlanExecuteMultiAgent{ runnable: runnable, }, nil}
复制代码

Tool 实现

我们的主题乐园行程规划助手,需要用到下列工具:


  • query_theme_park_opening_hour: 查询乐园 A 的整体营业时间

  • query_park_ticket_price: 查询乐园 A 的门票价格

  • list_locations: 列出乐园 A 中的所有区域,每个游乐设施都归属于一个区域

  • query_location_adjacency_info: 查询乐园 A 中的一个区域到其他相邻区域的步行时间,以分钟为单位

  • query_attraction_queue_time: 查询游乐设施的排队时间,以分钟为单位

  • query_attraction_info: 查询游乐设施的具体信息

  • query_performance_info: 查询演出的具体信息

  • query_restaurant_info: 查询餐厅的具体信息

  • validate_performance_time_table: 校验安排的表演场次是否符合事实

  • arrange_performances: 根据选中的表演名称,自动根据表演的时间表排程

  • validate_plan_items: 根据一个一日日程安排提案,校验各个计划项内部及之间是否自洽


首先定义核心的领域模型:


type ActivityType string
const ( ActivityTypeAttraction ActivityType = "attraction" ActivityTypePerformance ActivityType = "performance" ActivityTypeRestaurant ActivityType = "restaurant" ActivityTypeOther ActivityType = "other")
// Activity 主题乐园中的一个项目,可以是游乐设施、表演或餐厅.type Activity struct { Name string `json:"name"` Desc string `json:"desc"` Type ActivityType `json:"type"` Location string `json:"location" jsonschema:"description:项目所属的区域"` MinHeight int `json:"min_height,omitempty" jsonschema:"description:参加游乐设施需要的最小身高,单位是厘米。如果为空,则没有身高要求"` Duration int `json:"duration,omitempty" jsonschema:"description:一个项目参加一次需要的时间,注意不包括排队的时间。如果为空,则缺少具体的时间信息"` TimeTable []string `json:"time_table,omitempty" jsonschema:"description:一个演出的时间表。如果为空,则使用 OpenTime 和 CloseTime 来表示这个项目的运营时间范围"` OpenTime string `json:"open_time,omitempty" jsonschema:"description:一个项目开始运营的时间"` CloseTime string `json:"close_time,omitempty" jsonschema:"description:一个项目结束运营的时间"` RequireBooking bool `json:"require_booking,omitempty" jsonschema:"description:一个餐厅是否需要提前预约"` HasPriorityAccess bool `json:"has_priority_access,omitempty" jsonschema:"description:一个项目是否有高速票服务"` PriorityAccessCost int `json:"priority_access_cost,omitempty" jsonschema:"description:一个项目如果有高速票服务,则一个人的高速票需要花多少钱"` QueueTime int `json:"queue_time,omitempty" jsonschema:"description:一个项目常规需要的排队时间,单位是分钟。如果为空,则这个项目一般不需要排队"`}
复制代码


注意大多数字段中都有 jsonschema:"description:xxx" 的 go struct tag。Eino 框架可抽取这个信息以及其他的 tag 给到大模型。实现工具列表中需要的本地 function,如:


// GetAttractionInfo 获取游乐设施信息.func GetAttractionInfo(_ context.Context, in *ListAttractionRequest) (out *ListAttractionResponse, err error) {    if len(in.Name) > 0 && in.Name != "all" {       for _, a := range attractions {          if a.Name == in.Name {             return &ListAttractionResponse{                Attractions: []Activity{                   a,                },             }, nil          }       }    }
if len(in.Location) > 0 { locationAttractions := make([]Activity, 0) for _, a := range attractions { if a.Location == in.Location { locationAttractions = append(locationAttractions, a) return &ListAttractionResponse{ Attractions: locationAttractions, }, nil } } }
return &ListAttractionResponse{ Attractions: attractions, }, nil}
复制代码


完整的领域模型及服务定义参见代码链接。数据来源:可以是主题乐园提供的 API,也可以是外置的数据库,在我们的场景中,直接在项目中维护结构化的信息(完整代码链接)。将本地 function 封装成 Tool:


func GetTools(ctx context.Context) (tools []tool.BaseTool, err error) {    queryTimeTool, err := utils.InferTool("query_theme_park_opening_hour", "查询乐园 A 的整体营业时间", GetParkHour)    if err != nil {       return nil, err    }
tools = append(tools, queryTimeTool) // 以下省略多个 Tool return}
复制代码


完整的 Tool 封装代码参见代码链接

上下文管理

针对每个智能体的一次执行,它的上下文应当包括:


  • 用户输入的任务。

  • 之前执行的智能体(包括自身)的输出。

  • 之前执行的智能体的 Function Call,以及对应的结果。

  • 自身的 System Prompt。


为了保存多智能体的上下文,我们为 graph 增加全局状态,并在各智能体执行前以及 Tool 执行前,向这个全局状态中读写上下文:


// state 以多智能体一次运行为 scope 的全局状态,用于记录上下文type state struct {    messages            []*schema.Message}
func NewMultiAgent(ctx context.Context, config *Config) (*PlanExecuteMultiAgent, error) { // ... 省略 N 行 ... // 创建一个待编排的 graph,规定整体的输入输出类型,配置全局状态的初始化方法 graph := compose.NewGraph[[]*schema.Message, *schema.Message](compose.WithGenLocalState(func(ctx context.Context) *state { return &state{} })) // 在大模型执行之前,向全局状态中保存上下文,并组装本次的上下文modelPreHandle := func(systemPrompt string, isDeepSeek bool) compose.StatePreHandler[[]*schema.Message, *state] { return func(ctx context.Context, input []*schema.Message, state *state) ([]*schema.Message, error) { for _, msg := range input { state.messages = append(state.messages, msg) }
if isDeepSeek { return append([]*schema.Message{schema.SystemMessage(systemPrompt)}, convertMessagesForDeepSeek(state.messages)...), nil }
return append([]*schema.Message{schema.SystemMessage(systemPrompt)}, state.messages...), nil }} // ... 省略 N 行 ... // 添加 Planner 节点,同时添加 StatePreHandler 读写上下文 _ = graph.AddChatModelNode(nodeKeyPlanner, config.PlannerModel, compose.WithStatePreHandler(modelPreHandle(plannerPrompt, true)), compose.WithNodeName(nodeKeyPlanner)) // 添加 Executor 节点,同时添加 StatePreHandler 读写上下文 _ = graph.AddChatModelNode(nodeKeyExecutor, config.ExecutorModel, compose.WithStatePreHandler(modelPreHandle(executorPrompt, false)), compose.WithNodeName(nodeKeyExecutor)) // 添加 Reviser 节点,同时添加 StatePreHandler 读写上下文 _ = graph.AddChatModelNode(nodeKeyReviser, config.ReviserModel, compose.WithStatePreHandler(modelPreHandle(reviserPrompt, true)), compose.WithNodeName(nodeKeyReviser)) // 添加 Tool 执行器节点,同时添加 StatePreHandler 读写上下文 _ = graph.AddToolsNode(nodeKeyTools, toolsNode, compose.WithStatePreHandler(func(ctx context.Context, in *schema.Message, state *state) (*schema.Message, error) { state.messages = append(state.messages, in) return in, nil })) // ... 省略 N 行 ...}
复制代码


完整编排代码见链接

main 函数:多智能体执行

多智能体执行逻辑需要实现下列功能:


  • 实例化 DeepSeek 和豆包的模型,并放到多智能体的配置中。

  • 获取 Tool 列表。

  • 依据配置编排和初始化多智能体。

  • 将多智能体的各中间步骤及时输出。


在 main 函数中:利用 Eino 框架提供的组件实现,实例化需要的大模型,获取 Tool,初始化多智能体:


func main() {    ctx := context.Background()
deepSeekModel, err := deepseek.NewChatModel(ctx, &deepseek.ChatModelConfig{ Model: os.Getenv("DEEPSEEK_MODEL_ID"), APIKey: os.Getenv("DEEPSEEK_API_KEY"), BaseURL: os.Getenv("DEEPSEEK_BASE_URL"), }) if err != nil { log.Fatalf("new DeepSeek model failed: %v", err) }
arkModel, err := ark.NewChatModel(ctx, &ark.ChatModelConfig{ APIKey: os.Getenv("ARK_API_KEY"), Model: os.Getenv("ARK_MODEL_ID"), }) if err != nil { log.Fatalf("new Ark model failed: %v", err) }
toolsConfig, err := tools.GetTools(ctx) if err != nil { log.Fatalf("get tools config failed: %v", err) }
// 创建多智能体的配置,system prompt 都用默认值 config := &Config{ // planner 在调试时大部分场景不需要真的去生成,可以用 mock 输出替代 PlannerModel: &debug.ChatModelDebugDecorator{ Model: deepSeekModel, }, ExecutorModel: arkModel, ToolsConfig: compose.ToolsNodeConfig{Tools: toolsConfig}, ReviserModel: &debug.ChatModelDebugDecorator{ Model: deepSeekModel, }, }
planExecuteAgent, err := NewMultiAgent(ctx, config) if err != nil { log.Fatalf("new plan execute multi agent failed: %v", err) }
printer := newIntermediateOutputPrinter() // 创建一个中间结果打印器 printer.printStream() // 开始异步输出到 console handler := printer.toCallbackHandler() // 转化为 Eino 框架的 callback handler
// 以流式方式调用多智能体,实际的 OutputStream 不再需要关注,因为所有输出都由 intermediateOutputPrinter 处理了 _, err = planExecuteAgent.Stream(ctx, []*schema.Message{schema.UserMessage("我们一家三口去乐园玩,孩子身高 120 cm,园内预算 2000 元,最爱的是各种表演,游乐设施比较偏爱刺激项目,希望能在一天内尽可能多体验不同的活动,帮忙规划一个行程。我们会在园区开门之后立刻入园,在园区关闭之后再离开。")}, agent.WithComposeOptions(compose.WithCallbacks(handler)), // 将中间结果打印的 callback handler 注入进来 // 给 planner 指定 mock 输出 //agent.WithComposeOptions(compose.WithChatModelOption(debug.WithDebugOutput(schema.AssistantMessage(debug.PlannerOutput, nil))).DesignateNode(nodeKeyPlanner)), // 给 reviser 指定 mock 输出 //agent.WithComposeOptions(compose.WithChatModelOption(debug.WithDebugOutput(schema.AssistantMessage("最终答案", nil))).DesignateNode(nodeKeyReviser)), ) if err != nil { log.Fatalf("stream error: %v", err) }
printer.wait() // 等待所有输出都处理完再结束}
复制代码


完整 main 函数代码实现链接

流式输出中间过程

在上面的 main 函数中可以看到,我们通过 printer 这个“中间结果打印器”,把各智能体的流式输出异步打印了出来。这利用了 Eino 框架的 callback 机制,在 ChatModel 输出时和 Tool 起止时触发执行切面逻辑。

调试与优化

在上面的 main 函数中,通过 ChatModelDebugDecorator把 Planner 智能体封装起来,这是因为调试过程中,我们经常需要固定 Planner 的输出,单独调试后续流程。在 Eino 框架中,能够很方便的实现类似的装饰者,因为所有的组件如 ChatModel 等都是 interface,从编排角度看,原始的 ChatModel 实现和对应的装饰者可以无缝替换。完整调试代码实现见链接。如果你更习惯可视化调试,可以安装 Eino Dev IDE 插件(已支持 Golang 和 VSCode),把多智能体的编排拓扑在 IDE 中直观的展示出来,还可以指定中间的某个智能体开始调试。在实战过程中,对 system prompt 的优化占据了相当多的时间,有关优化的最佳实践还在总结之中,后续会在 Eino 项目中发布,可以关注我们的 Github 项目获取最新的进展。

实际效果

以下为 Reviser 智能体的最终输出:最终答案:


开始时间表演开始时间表演时长项目名称预计耗时区域类型费用单价总费用备注
09:00--入园0入口大街入园00开园即入
09:20--派斯音速太阳系营救15分钟未来世界游乐设施00早间低峰(排队5分钟+体验10分钟)
10:1510:1515唐式太极15分钟奇幻园林表演00步行至未来世界需7分钟
11:0011:0015复仇者小分队培训行动15分钟未来世界表演00就近体验刺激项目
11:30--星露谷餐厅(午餐)45分钟未来世界餐厅80元/人240正餐(汉堡套餐)
12:30--抱抱熊飞天赛车50分钟玩具的故事游乐设施180元540午间低峰排队20分钟(原40分钟),购买高速票节省时间
13:3013:2020梦幻故事会20分钟幻想世界表演00步行10分钟至幻想世界
14:00--八个大高人矿山车72分钟幻想世界游乐设施00午间排队时间减少20%(原90分钟→72分钟)
15:3015:4514童话专列14分钟奇幻园林表演00提前15分钟占位
16:3016:3020金色童话盛典20分钟奇幻园林表演00就近安排快餐
17:30--家勒比海贼——沉船宝贝之战20分钟宝贝港湾游乐设施00傍晚低峰排队10分钟(原20分钟)
18:2018:2015奇幻冬日巡游15分钟奇幻园林表演00灯光秀版本,步行5分钟至入口大街
19:00--好伙伴美味市集(晚餐)30分钟入口大街餐厅60元/人180快餐边走边吃
19:30--飞吧地平线40分钟冒险岛游乐设施00晚间低峰排队30分钟(原60分钟)
21:0021:0020奇梦之光幻影秀20分钟奇幻园林表演00普通占位(无需尊享卡)


总费用:门票 1100 元 + 高速票 540 元 + 餐饮 420 元 = **2060 元**(超支 60 元,可通过午餐降级为蓝莓熊餐盒节省 60 元)




关键优化点:


  1. 高速票精准投放:仅在“抱抱熊飞天赛车”午间时段使用(性价比最高),其他项目利用排队低峰期

  2. 表演全覆盖:新增“复仇者小分队培训行动”,保留所有核心表演场次

  3. 动线优化:区域集中化(未来世界→玩具的故事→幻想世界→奇幻园林→入口大街)

  4. 预算控制:通过调整午餐为快餐(蓝莓熊餐盒人均 50 元)可使总费用降至 2000 元以内

  5. 刺激项目最大化:包含 3 个过山车类项目(抱抱熊/矿山车/飞吧地平线)+ 2 个黑暗骑乘(家勒比海贼/派斯音速)




执行效果:在保证所有热门表演的前提下,实现 5 个高刺激项目体验,时间利用率达 92%,区域移动时间占比仅 8%。


完整执行过程见链接

相关链接

Eino 框架 Github 仓库地址:


  • 核心仓库:https://github.com/cloudwego/eino

  • 扩展仓库,含本文用到的 DeepSeek 和豆包模型实现:https://github.com/cloudwego/eino-ext

  • 示例仓库,含本文内的主题乐园行程规划助手:https://github.com/cloudwego/eino-examples


项目官网:https://www.cloudwego.cn

项目文档:https://cloudwego.cn/zh/docs/eino/


2025-03-13 18:148310

评论

发布
暂无评论

大话设计模式 | 2. 策略模式

Puran

C# 设计模式

愚蠢写作术(4):怎么让写作从开始到放弃

史方远

读书笔记 个人成长 写作 随笔杂谈

ARTS Week4

丽子

小师妹学JavaIO之:用Selector来发好人卡

程序那些事

io nio 「Java 25周年」 小师妹 selector

软件设计原则作业

qihuajun

架构师训练营总结-20200614

caibird1984

使用 Docker 镜像 | Docker 系列

AlwaysBeta

Docker 容器 虚拟私有云

官方源、镜像源汇总

JackTian

镜像源 官网源

ARTS打卡计划_第二周

叫不醒装睡的人

ARTS 打卡计划

程序员陪娃系列——叛逆小娃回归

孙苏勇

程序员 陪伴

ARTS|Week 3 本周的主题可能是乱

Puran

ARTS 打卡计划

JVM学习笔记——JVM类加载机制

王海

Java 面试 JVM

Shell的技巧小总结(MIT Missing Semester)

Henny

Shell MIT 计算机 Computer Science 计算机工具

推荐几款有意思的小众 App(06.13)

静陌

产品 App

1. 版本管理工具及 Ruby 工具链环境

Edmond

rubygems CocoaPods VersionControl PackageManager Git Submodule

利用工作日志提高效率

Janenesome

思考 工作方式

GoF 23种设计模式

无心水

设计模式 GoF 23种设计模式

Flink 源码分析之写给大忙人看的 Flink Window原理

shengjk1

flink flink源码 flink window

架构师训练营第一讲-学习总结

索隆

架构师训练营作业1-食堂就餐卡系统设计

索隆

为什么软件交付要快?因为要有赢的感觉!

刘华Kenneth

DevOps 敏捷 MVP 最小可用产品 持续交付

你了解 SpringBoot java -jar 的启动原理吗?

猴哥一一 cium

面试 Spring Boot Fat-JAR JAR URL Java 25 周年

硬核!30 张图解 HTTP 常见面试题

小林coding

https 计算机网络 计算机基础 HTTP

架构训练营作业-20200614

caibird1984

个人编程技能全景图

南山

编程基础

南山

国内首个区块链电子档案平台上线

CECBC

区块链技术 防伪 溯源 电子档案

软件设计原则学习总结

qihuajun

【在云端 001】欢迎来到云原生

Bora.Don

云计算 云原生

ARTS Week 3

时之虫

ARTS 打卡计划

仓储控制系统(WCS)软件可靠性设计

申扬科技

仓储控制系统 WCS 可靠性设计 容错性 易恢复性

DeepSeek + Function Call:基于 Eino 的“计划——执行”多智能体范式实战_生成式 AI_InfoQ精选文章