9.4 详细实现与核心配置(景点票务预约智能体开发)

《扣子编程:从零开始搭建智能体 卢欣欣 清华大学出版社》【摘要 书评 试读】- 京东图书

《扣子编程:从零开始搭建智能体》全书案例持续更新-CSDN博客

9.4.1核心工作流的实现

票务预约的核心业务逻辑通过工作流节点串联实现,在该工作流中包含了“开始”节点、“查询数据”节点、“新增数据”节点、“选择器”节点、“代码”节点、“输出”节点和“结束”节点,完整的工作流如图9-12所示。下面将详细拆解工作流的搭建与参数配置过程。

图9-12 工作流整体预览

1.创建工作流

步骤1:进入扣子编程的资源库页面,单击其右上角的“+ 资源”按钮,在弹出的下拉菜单中选择“工作流”,如图9-13所示。

图9-13 新建工作流

步骤2:在“创建工作流”对话框中,填写工作流名称(如:reservation)及描述,单击“确认”按钮完成创建,如图9-14所示。

图9-14 创建工作流

2.配置开始节点

用户预约时需要提供姓名、联系电话、身份证号码后4位、预约日期、预约时段等关键信息,故需要为“开始”节点配置5个输入参数,以接收用户输入信息。开始节点参数配置如图9-15所示。

图9-15 开始节点的配置

3.查询预约数据

为保证数据的唯一性,在新增预约记录前,需要验证同一联系电话、同一预约日期且同一预约时段是否已提交过预约信息,避免用户重复提交,具体操作说明如下。

步骤1:添加查询数据节点。从“开始”节点右侧的输出端点拖拽出连接线,在弹出的节点类型菜单中,选择数据库分类下的“查询数据”节点,如图9-16所示。

图9-16 添加查询数据节点

步骤2:添加数据表。选中该“查询数据”节点,在右侧参数配置对话框中,单击“数据表”右侧的“+”按钮,为当前节点添加数据表,如图9-17所示。

图9-17 添加数据表

  1. 一个“查询数据”节点只能添加一张数据表。

步骤3:选择数据表。在弹出的“选择数据库”对话框中,单击用户预约信息数据表reservation_record右侧的“添加”按钮,将其添加到当前节点。如图9-18所示。

图9-18 选择数据表

步骤4:选择查询字段。绑定数据表后,在参数面板中会显示“查询字段”配置项,单击其右侧的“+”按钮,从下拉菜单中选择要查询的字段(可多选)。本例中选择查询order_id字段,如图9-19所示。

图9-19 查询字段

步骤5:设置查询条件。判断用户是否重复预约的条件是,查询预约信息表中是否已存在和用户本次输入的联系电话、预约日期、预约时段相同的记录。在参数配置面板的“查询条件”中,默认只有一个查询条件,单击“+ 添加条件”按钮再增加两个条件,并设置三个条件之间是“且”关系(即需要同时满足三个条件)。然后,从条件变量下拉列表中,选择要比较的字段名称phone_number,条件选择“等于”,值引用“开始”节点的phone_number变量。重复此步骤,设置其他两个条件,最终设置效果如图9-20所示。

图9-20 设置查询条件

4.判断是否已预约

步骤1:添加选择器节点。在“查询数据”节点的下游接入一个“选择器”节点,根据查询结果做分支处理。

步骤2:配置分支条件。选中该“选择器”节点,在右侧参数面板中选择“查询数据”节点的输出变量outputList作为判断变量,判断的条件选择“为空”。如图9-21所示。

图9-21 设置分支条件

  1. 如果满足“为空”的条件,则说明未查询到同联系电话、同预约日期、同时段的记录,可以进行后续操作;否则,说明已存在预约信息,应该终止操作。

5.输出重复预约提示信息

步骤1:添加输出节点。从“选择器”节点的“否则”分支(重复预约)拖拽出连接线,在弹出的节点类型菜单中选择“输出”节点。

步骤2:配置输出内容。选中该“输出”节点,将其默认输出变量“output”修改为“visit_date”,并引用绑定“开始”节点的visit_date变量。然后,新增一个名为“time_slot”的变量,引用绑定为“开始”节点的time_slot变量。最后,将输出变量拼接入字符串中,一并作为输出内容,如图9-22所示。

步骤3:将输出节点的右侧输出端点与“结束”节点相连接。

 

图9-22 输出节点的配置

6.查询景点的最大承载量

为判断当前景点所选场次是否已满员,需要将景点对应场次的最大承载量和已预约人数进行比较。查询景点的最大承载量操作步骤说明如下。

步骤1:添加查询数据节点。在“选择器”节点的“如果”分支(未重复预约)后接入一个“查询数据”节点。

步骤2:配置数据表和查询字段。选中该查询数据节点,在其右侧参数配置面板中,添加景点基础数据表scenic_spot_info,并选择查询字段为max_capacity(最大承载量)。如图9-23所示。

 

图9-23 配置数据表和查询字段

步骤3:设置查询条件。在查询条件中,设置为入园时段字段time_slot等于“开始”节点用户输入的time_slot,如图9-24所示。

图9-24 设置查询条件

  1. 本例中仅考虑单个景点的情况,如有多个景点,可在查询条件中再增加一个比对景点名称的条件。

7.查询已预约人数

接下来查询当前日期和时段已预约的人数,操作步骤说明如下。

步骤1:添加查询数据节点。在查询景点最大承载量的“数据查询”节点下游继续接入一个“数据查询”节点。

步骤2:添加数据表。选择该查询数据节点,在其右侧参数配置面板中,单击“数据表”右侧的“+”按钮,为当前节点添加预约信息表reservation_record。该节点不需要设置查询字段。

步骤3:设置查询条件。查询预约信息表中与当前用户输入的预约日期和入园时段均相同的记录,如图9-25所示。

图9-25 设置查询条件

8.判断是否满员

步骤1:添加选择器节点。在查询已预约人数的“数据查询”节点下游接入一个“选择器”节点。

步骤2:设置条件分支。判断查询已预约人数节点的输出变量值outputList的长度是否小于查询景点最大承载量节点的输出变量值max_capacity,如图9-26所示。

图9-26 设置条件分支

9.输出满员提示信息

步骤1:添加输出节点。在“选择器”节点的“否则”分支(已满员)接入一个“输出”节点。

步骤2:配置输出内容。选中该节点,为该节点设置visit_date和time_slot两个输出变量,并分别引用绑定开始节点的visit_date和time_slot。最后,将输出变量拼接入字符串中,一并作为输出内容,如图9-27所示。

图9-27 输出节点配置

步骤3:将输出节点的右侧输出端点与“结束”节点相连接。

10.生成预约订单号

为便于后续查询预约订单信息,给每条预约信息生成一个唯一的订单号,订单号由预约时间和随机数构成,实现步骤如下。

步骤1:添加代码节点。在“选择器”节点的“如果”分支(可正常提交预约信息)下游接入一个“代码”节点。

步骤2:编写实现代码。在“代码”节点右侧节点配置对话框中,单击“代码”右侧的“在IDE中编辑”按钮,进入代码编辑窗口。如图9-28所示。

图9-28 进入代码编辑

步骤3:编辑代码。将编程语言选择为“Python”,在代码窗口编写如下代码,实现唯一订单号的生成。

import time

import random

async def main(args: Args) -> Output:

   

# 1. 获取当前时间对象

    now = time.localtime()   

   

# 2. 格式化日期部分:例如 20260502

    date_str = time.strftime("%Y%m%d", now)   

   

# 3. 获取精确时间戳(毫秒级)

    timestamp_ms = int(time.time() * 1000) % 1000000000    

   

# 4. 生成4位随机数 (1000 - 9999)

    random_num = random.randint(1000, 9999)   

   

# 5. 拼接订单号:直接以日期开头

    # 格式示例:202605021234567898821

    order_id = f"{date_str}{timestamp_ms}{random_num}"   

   

return {

        "order_id": order_id

    }

步骤4:设置输出变量。将该节点的输出变量修改为“order_id”,类型为“String”,并删除其他多余输出变量。

11.新增数据

步骤1:添加新增数据节点。在代码节点的下游接入一个“新增数据”节点,用于增加预约信息。

步骤2:添加数据表。选中“新增数据”节点,在其右侧配置面板中,单击数据表右侧的“+”按钮,为当前节点添加预约信息数据表reservation_record。

步骤3:选择并设置字段。分别为数据表reservation_record中的各个字段指定新增数据的值。其中预约订单号的值引用绑定上游“代码”节点的输出变量order_id,订单状态status为固定字符串“已预约”,其他字段均引用绑定用户通过开始节点输入的对应值,具体配置如图9-29所示。

图9-29 选择并设置字段

12.输出预约成功提示信息

步骤1:添加输出节点。在“新增数据”节点的下游接入一个“输出”节点。

步骤2:配置输出内容。 选中“输出”节点,将其默认输出变量output重命名为order_id,并引用绑定“代码”节点的输出变量order_id。最后,将输出变量拼接入字符串中,一并作为输出内容,以告知用户预约成功后的订单号,如图9-30所示。

图9-30 输出节点配置

步骤3:将输出节点的右侧输出端点与“结束”节点相连接。

13.配置结束节点

该工作流中的输出信息已全部由相应的“输出”节点处理完成,结束节点不需要任何额外输出信息,因此单击默认输出变量output右侧的“-”按钮,将其删除即可。如图9-31所示。

图9-31 结束节点配置

13.测试、发布工作流

步骤1:正常预约测试。单击工作流画布底部工具栏的“试运行”按钮。在试运行对话框的输入框中分别填写身份证号码后4位、联系电话、时段、访客姓名和访问日期后,单击下方“试运行”按钮进行测试,如图9-32所示。

图9-32 试运行输入

  1. 在工作流模式下进行测试时,输出节点配置的输出信息无法正常显示,可以结合工作流的执行走向,判断工作流是否执行成功。

步骤2:重复预约测试。工作流执行一次后,保持测试输入信息不变,再次单击“试运行”按钮,观察工作流是否执行“输出重复预约”提示的分支。

步骤3:满员测试。进入扣子编程资源库页面,单击景点基础数据字典表scenic_spot_info,修改景区最大承载量为“1”。然后,修改测试输入中的“联系电话”或“预约日期”,其他输入可保持不变。再次单击“试运行”按钮启动工作流,观察工作流是否执行“输出满员”提示的分支。

步骤4:发布上线。工作流经多次测试、运行无误后,单击右上角的“发布”按钮进行发布,以便后续供智能体调用。

9.4.2创建智能体

通过工作流预设的、确定性的节点处理步骤,高效地解决了标准化任务的执行问题。但其期待的输入往往是结构化的数据,适合通过API或可视化界面直接调用。为了使其能够理解终端用户的自然语言指令和模糊意图,可将工作流挂载在智能体当中,从而弥补工作流在交互与应变上的不足。二者融合,既实现任务的自动化,又实现能力的智能化。

步骤1:创建智能体。打开扣子编程首页,单击页面右侧下方的“智能体开发”,新建一个智能体,如图9-33所示。

图9-33 创建智能体

步骤2:填写智能体信息。在弹出的窗口中,填入本案例的智能体名称(“期遇”)及其功能描述。然后,单击默认图标右侧的“生成”按钮 ,自动生成一个合适的图标,单击“确认”按钮即可完成智能体的创建,如图9-34所示。

 

图9-34 创建智能体

9.4.3添加工作流

在智能体的编排页面中,为其挂载一个或多个工作流,是赋予智能体实际业务处理能力的首要步骤。具体操作说明如下。

步骤1:在编排页面的“技能”区域,单击“工作流”右侧的“+”按钮,如图9-35所示。

图9-35 添加工作流

步骤2:在弹出的添加工作流窗口中,单击9.4.1节发布的工作流reservation右侧的“添加”按钮,将其添加到智能体中。如图9-36所示。

图9-36 选择工作流

9.4.4设置人设与回复逻辑

“期遇”智能体定位于一款票务预约助手。票务预约业务的核心逻辑完全由工作流来完成,智能体本身不参与预约业务的具体实现。在与用户的自然语言对话中,智能体能够自动识别身份证号码后4位、联系电话、时段、访客姓名和访问日期等关键信息。当以上所需要信息完整时,能够自动调用底层已绑定的reservation工作流,由工作流实现票务预约功能;若上述的输入信息不完整,则引导用户补充完善信息。为该智能体设置的人设与回复逻辑提示词如下。

## 角色

票务预约助手,仅负责理解用户预约门票的业务需求、校验必填信息、交互引导并调用工作流,不参与任何票务库存查询、添加预约等逻辑实现。

### 目标

1.识别用户预约门票的业务需求,“身份证后4位、联系电话、时段、访客姓名、访问日期”五项信息全部具备时自动调用工作流{reservation}

2.精准提取并校验身份证号码后4位、联系电话、时段、访客姓名、访问日期五项核心要素,缺失时主动引导用户补充;

3.调用工作流后,直接输出工作流返回的信息,不增加额外输出。

### 技能

1.意图与实体识别:精准识别用户预约意图,从自然语言中提取关键实体(如“明天”、“张三”等);

2.完整性校验:强制校验上述五项必填信息是否齐全;

3.输入信息的格式转换:访问日期为“YYYY-MM-DD”格式,时段为“上午场”或“下午场”

4.流程调度:所有必填信息齐全且合规后,自动触发工作流{reservation}

### 工作流

1.触发条件:当且仅当用户提供身份证号码后4位、联系电话、时段、访客姓名、访问日期全部五项信息时,方可自动调用{reservation}

2.执行规则:票务预约入库的全流程,均由工作流独立完成,智能体不做任何业务逻辑干预;

3.缺省逻辑:若任意一项必填信息缺失或表述模糊,均不触发工作流,直接针对性地提示用户补齐缺失项;

4.结果闭环:同步工作流处理进度,异常时给出简易修改建议。

### 输出格式

1.语言精简正式、服务性强,只做信息核对、信息缺失引导、进度播报、结果告知。

2.缺少信息时提醒:“请补充【缺失字段】,以便为您完成预约。”

### 限制

1.用户输入信息不完整时,禁止私自调用工作流,必须通过多轮对话补全信息;

2.不得自行编造预约成功的假象,不得私自处理预约请求,所有业务逻辑交由工作流完成;

3.不使用晦涩技术术语,回复需要体现服务意识,不进行无关闲聊。

9.4.5设置携带上下文轮数

模型上下文的对话历史轮数默认为“3”。由于本案例中共需要输入5项信息,如果用户每次只输入一项信息,当超出3轮对话后,模型将无法保持之前的对话内容,导致信息丢失,从而重复提示用户补全信息。如图9-37所示。

图9-37 丢失对话信息

为了保持多轮对话的连续性,可以适当调大“携带上下文轮数”的参数值。本例中将其修改为“5”,如图9-38所示。

图9-38 修改携带上下文轮数

9.4.6添加时间技能

智能体本身不具备处理日期时间的能力。在与用户的对话中,如果用户提供“今天”“明天”“后天”等表述,由于智能体无法将其转换为具体的日期,会直接将字符串“明天”作为预约日期字段的值直接存储,如图9-39所示。

图9-39 时间技能测试

为了使其能够处理常见的日期时间表述信息,可为智能体添加相应的插件来拓展其能力,操作步骤说明如下。

步骤1: 在智能体的编排模块中,单击“插件”右侧的“+”按钮,如图9-40所示。

图9-40 时间技能测试

步骤2:在打开的“插件市场”窗口中搜索“时间”关键字。在搜索结果中单击展开官方提供的“时间工具”插件,单击get_current_time工具右侧的“添加”按钮,将其添加到当前智能体。如图9-41所示。

图9-41 添加时间插件

步骤3:在预览与调试面板中,再次输入并发送含有“明天”的时间信息,智能体已经可以正确理解该时间信息,测试结果如图9-42所示。

图9-42 测试时间技能

9.4.7设置开场白

在本案例中,用户需要提供身份证后4位、联系电话、时段、访客姓名、访问日期五项内容,为了引导用户快速上手使用,在智能体编排页面的“对话体验”模块下,设置如下的开场白文案及其预置问题,如图9-43所示。

图9-43 设置开场白文案及其预置问题

nal_edges三组接口允许将多个节点串成有向无环图(DAG, Directed Acyclic Graph),其中并行分支由多条独立的add_edge自然描述;全局状态GlobalState的更新采用合并语义,多个并行分支同时写入不同字段不会发生冲突。

这三项能力的组合,使得本章的11节点工作流可以用相对优雅的代码完整描述,而不需要开发者们手写任何调度逻辑。本节将沿着开发时间线,依次介绍各个节点的实现细节,并展示扣子编程在多模态工作流场景下的工程化能力。

9.4.2  集成识别与选用

在接到本项目的需求描述后,扣子编程的第一动作仍然是查询集成文档。这一次它并行查询了三个集成:大语言模型集成(含视觉版本与生图版本)、对象存储集成、文件类型支持。查询结果识别出三项关键事实:第一,大语言模型集成提供了doubao-seed-1-8-251228(多模态模型)、doubao-seed-1-6-vision-250815(视觉理解模型)、doubao-seedream-4-5-251128(生图模型)三种能力,分别对应文案生成、图像理解、图片渲染三类需求;第二,对象存储集成提供S3SyncStorage接口,支持单文件上传、多文件批量上传与压缩包打包;第三,开始节点对File类型的支持,使得用户上传的产品白底图可以直接作为多模态模型的输入,而不需要任何中间转换。

基于这三项识别,扣子编程为本章工作流绘制了如表9-3所示的集成-节点映射表。

9-3  集成-节点能力映射

节点类型

使用集成

推荐模型/接口

关键作用

产品解码

多模态视觉模型

doubao-seed-1-6-vision-250815

提取产品视觉特征

三渠道文案

大语言模型

doubao-seed-1-8-251228

生成差异化文案

三渠道提示词优化

多模态视觉模型

doubao-seed-1-6-vision-250815

图+文联合理解

三渠道生图

生图大模型

doubao-seedream-4-5-251128

渲染配图与Banner

素材打包

对象存储

S3SyncStorage

压缩并签名URL

从这张表可以看出,本章工作流之所以能在十一个节点之间稳定协作,并不仅仅因为模型,更是因为不同节点选用了适配各自任务复杂度的不同模型。这种节点级精细选型与第8章经验四“模型选型应当节点级精细化”的原则一脉相承,而且其在多模态场景下表现得尤其明显——视觉理解、文本生成、图像渲染三类能力如果用同一个模型来做,要么质量打折,要么成本翻倍。

9.4.3  节点1:产品解码节点

产品解码节点是整条工作流的起点。它接收开始节点传入的product_image(File类型,产品白底图),调用多模态视觉模型对图片进行结构化分析,输出包含材质特征、色彩定位、设计语言、核心卖点四类信息的产品分析报告。

节点的关键工程细节有三点。第一是输入预处理:产品图通过File对象的url字段传入视觉模型,需要在系统提示词中显式说明请基于这幅产品图进行视觉分析,否则模型会忽略图像而仅基于文字描述作答。第二是输出结构化:要求模型输出严格的JSON对象,包含material(材质)、color_palette(色彩组合)、design_language(设计语言)、key_features(核心卖点列表)四个字段,便于下游节点直接消费。第三是温度控制:本节点温度设为0.3,因为产品视觉特征是客观事实,模型应当尽可能复述而不是创造。节点核心代码如下。

def product_decode_node(state: ProductDecodeInput, config, runtime)

        -> ProductDecodeOutput:

    """产品解码节点:基于多模态模型分析产品白底图"""

    image_url = state.product_image.url

    llm = LLMClient(

        ctx=runtime.context,

        model='doubao-seed-1-6-vision-250815',

        temperature=0.3,

    )

    system = '你是资深产品视觉分析师,请基于上传的产品白底图,提取下列字段并以JSON返回:material(材质)、color_palettedesign_languagekey_features(数组,3-5项)。不要添加任何JSON以外的文字。'

    response = llm.invoke([

        {'role': 'system', 'content': system},

        {'role': 'user', 'content': [

            {'type': 'image_url', 'image_url': {'url': image_url}},

            {'type': 'text', 'text': '请按照系统提示输出JSON'},

        ]},

    ])

    decode = _extract_json(response.content)

    return ProductDecodeOutput(

        product_decode=decode,

        material=decode['material'],

        key_features=decode['key_features'],

    )

值得指出的是,节点中调用了一个_extract_json辅助函数。这一函数的作用是从模型输出中剥离可能出现的Markdown代码块标记(```json ... ```),并做安全的反序列化。这是第8章经验提示中提到的“契约边界防御式编码原则”在本章的延续应用——大模型的JSON输出并不总是干净的,下游必须做好兼容。

9.4.4  节点2/5/8:三渠道文案生成节点

三个渠道的文案生成节点是本章工作流的内容生产主力,三者结构同构、参数差异化。下面以小红书文案生成节点为例展开介绍。

小红书文案节点的输入是产品解码结果(material、color_palette、key_features等),输出是包含title(标题)、body(正文)、hashtags(话题标签)3个字段的JSON。系统提示词的核心结构是:角色(你是有10万粉丝的小红书户外博主)+风格(生活仪式感、温馨治愈) +受众(25~35岁城市女性中产)+表达约束(中文+大量Emoji、长段落+短句穿插、不出现专业术语)+输出格式(严格JSON)。整个系统提示词约500字,确保大模型在写作过程中始终保持小红书博主的人格。

LinkedIn文案节点的系统提示词在角色(you are a senior outdoor product marketer publishing on LinkedIn)、风格(professional, parameter-driven, industrial)、表达约束(English, business terminology, with hashtags like #OutdoorTech)等维度上做了对应的差异化设置。邮件营销文案节点则在角色(你是品牌邮件营销专家)+风格(FOMO、稀缺、紧迫)+行动指令(明确的Shop Now/立即抢购)等维度上做了差异化。

三个节点的模型选型为同一款doubao-seed-1-8-251228,但温度参数进行了差异化:小红书0.85(强调情绪表达自由度)、LinkedIn 0.5(强调专业稳定性)、邮件0.7(兼顾情绪与确定性)。

9.4.5  节点3/6/9:三渠道生图提示词优化节点

生图提示词优化节点是本章相较于第8章工作流最重要的工程改进。在最初版本的工作流中,文案生成节点的输出直接被送入生图节点,结果是生图模型只能依靠产品白底图与一段简短指令——例如把这款蓝色背包放到温馨的窗台场景——去渲染配图。这种简单调用方式存在三个问题:其一,生图模型不知道文案的具体氛围(清晨阳光、慵懒午后、还是雨夜室内);其二,生图模型不知道文案强调的具体卖点(防泼水?人体工学?还是大容量?);其三,生图模型不知道生成图片的最终用途(小红书封面/LinkedIn配图/邮件Banner,分辨率与构图截然不同)。最终结果就是文案与配图各说各话。

引入生图提示词优化节点后,工作流的视觉规划变成了一个两阶段过程:阶段一,提示词优化节点同时接收产品白底图与已生成的文案,调用多模态模型从两者交叉分析,输出一段精确的英文生图提示词;阶段二,生图节点拿着这段优化后的提示词去渲染图片。这种两阶段视觉规划的效果立竿见影——生图模型不再需要猜测文案氛围,因为它拿到的是已经把氛围翻译成视觉语言的Brief。

以小红书生图提示词优化节点为例,节点的系统提示词大致结构如下:你是一名资深视觉总监,请基于产品图与下面这段小红书文案,输出一段适合生图模型的英文Prompt,要求:(1)保留产品的形态特征(材质、颜色);(2)匹配文案的情绪基调(温馨、治愈);(3)显式描述场景细节(光线、构图、配饰);(4)禁止出现真实品牌Logo、夸张数据、低质素材;(5)输出长度150~250词,纯英文,不要任何中文。

3个优化节点的提示词模板高度一致,但在以下两个维度上做了差异化:其一是目标平台(小红书 → 4:5竖图/LinkedIn → 16:9横图/邮件营销 → 16:9 Banner+CTA区域);其二是视觉风格关键词(warm, cinnamon morning light vs cool grey, modern office vs clean white background, high-contrast Shop Now button)。三组关键词分别构成了三条渠道的视觉锚点。

【经验】 如果你的工作流中存在文案与配图协同生成的需求,强烈推荐在两者之间插入一个独立的提示词优化节点。这一节点的开销很低(仅调用一次多模态模型),却能显著提升图文一致性,是少有的低成本高回报工程改进。

9.4.6  节点4/7/10:三渠道图片渲染节点

图片渲染节点的实现相对简单:接收上游传入的优化后提示词,调用生图模型进行渲染,并把生成的图片URL写入全局状态。3个节点的核心差异在于分辨率与图片比例的设置。

具体来说,小红书场景图渲染节点采用4:5的竖图比例(典型分辨率3200×4000),契合小红书信息流的展示规范;LinkedIn场景图渲染节点采用16:9的横图比例(典型分辨率3840×2160),契合LinkedIn动态卡片的展示规范;邮件营销Banner渲染节点同样采用16:9,但视觉构图刻意保留右下角空白区域,便于后期叠加Shop Now按钮。这些细节差异都通过节点配置文件中的size字段精确指定,无需修改业务代码。

生图节点的另一项工程细节是分辨率边界守卫。生图大模型的SDK要求自定义分辨率必须落在[2560, 4096]的区间内,超出范围会被直接拒绝。在第一次试运行时,扣子编程曾经把分辨率设为4500×4500,导致SDK报错,随即自动修正为3200×4000与3840×2160。

9.4.7  节点11:素材打包节点

素材打包节点是整条工作流的终局节点。它的职责是把全局状态中的所有素材(3条文案、3幅配图)整理为一个zip压缩包,并上传到对象存储,最终返回一个带签名的URL。节点本身不调用大模型,仅依赖对象存储集成中的S3SyncStorage接口。

打包节点的关键工程考量有三点。第一是命名规范:压缩包内的每个文件都按照{渠道}/{资源类型}.{扩展名}的层级命名,例如xiaohongshu/copy.txt、xiaohongshu/cover.jpg、linkedin/post.txt等,便于下游运营快速定位。第二是元信息保留:除了文案与配图,还会附带一个README.md,记录本次工作流的运行时间戳、关键词、产品解码摘要,便于追溯与审计。第三是签名URL有效期:默认24小时,避免长期暴露内部存储路径,但又给运营留出充裕的下载时间。

9.4.8  主图编排:让11个节点协同流动

11个节点的实现完成后,需要在主图(src/graphs/graph.py)中通过add_node与add_edge把它们连接起来。主图编排是工作流的全局视角,决定了节点之间的依赖关系与执行顺序。本章主图的核心代码如下。

from langgraph.graph import StateGraph, END

 

builder = StateGraph(GlobalState)

 

# 注册节点

builder.add_node('product_decode', product_decode_node)

for ch in ['xiaohongshu', 'linkedin', 'email']:

    builder.add_node(f'{ch}_content', globals()[f'{ch}_content_node'])

    builder.add_node(f'{ch}_image_prompt',

                     globals()[f'{ch}_image_prompt_node'])

    builder.add_node(f'{ch}_image', globals()[f'{ch}_image_node'])

builder.add_node('package', package_materials_node)

 

# 入口与出口

builder.set_entry_point('product_decode')

builder.add_edge('package', END)

 

# 三条并行渠道,每条内部串行

for ch in ['xiaohongshu', 'linkedin', 'email']:

    builder.add_edge('product_decode', f'{ch}_content')

    builder.add_edge(f'{ch}_content', f'{ch}_image_prompt')

    builder.add_edge(f'{ch}_image_prompt', f'{ch}_image')

    builder.add_edge(f'{ch}_image', 'package')

 

graph = builder.compile()

这段编排代码用了不到20行就完整描述了一个11节点的工作流。其中for ch in ['xiaohongshu', 'linkedin', 'email']这一循环优雅地表达了3条并行渠道的对称结构,每一条渠道内部的“product_decode → content → image_prompt → image → package”依赖关系也清晰可见。如果不使用循环,而是手写每条渠道的所有连接,代码量会翻三倍且容易出错。表9-4给出了11个节点的关键配置。

9-4  十一节点关键配置一览

节点名

节点类型

能力

关键输入

关键输出

开始

input

product_image

产品解码

agent

多模态模型

product_image

product_decode等

小红书文案

agent

大语言模型

product_decode

xhs_content

小红书提示词优化

agent

多模态模型

image+content

xhs_image_prompt

小红书生图

task

生图模型

xhs_image_prompt

xhs_image

LinkedIn文案

agent

大语言模型

product_decode

linkedin_content

LinkedIn提示词优化

agent

多模态模型

image+content

linkedin_image_prompt

LinkedIn生图

task

生图模型

linkedin_image_prompt

linkedin_image

邮件文案

agent

大语言模型

product_decode

email_content

邮件Banner提示词优化

agent

多模态模型

image+content

email_banner_prompt

邮件Banner

task

生图模型

email_banner_prompt

email_banner

素材打包

tool

对象存储

全部素材

package_url

结束

output

GraphOutput

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值