政安晨【超级AI工作流】—— 以“主题播客工厂”的AI应用为例详细讲述Coze平台的AI工作流应用搭建技巧

政安晨的个人主页:政安晨

欢迎 👍点赞✍评论⭐收藏

希望政安晨的博客能够对您有所裨益,如有不足之处,欢迎在评论区提出指正!

本篇我们以Coze平台上这个同宇宙的“主题播客工厂”的应用为例,详细讲解搭建AI工作流。

目录

体验一下

立即开始

触发器

生成待检索序列

分解检索与必应搜索

编程处理检索

获得播客内容源

提取分类声音文案

声音合成

生成封面

完成


应用地址:

扣子扣子是新一代 AI 大模型智能体开发平台。整合了插件、长短期记忆、工作流、卡片等丰富能力,扣子能帮你低门槛、快速搭建个性化或具备商业价值的智能体,并发布到豆包、飞书等各个平台。https://www.coze.cn/s/YJwyDONPNE4/没有扣子账号的小伙伴可以免费注册一个,很好玩的。

体验一下

我们给一个主题:

以最近的新闻生成一段播客

点击开始生成:

等待半分钟,喝口水......

生成完成,可以下载海报和声音。

点击海报可以放大,点击声音可以播放,点击下载可以下载音频,生成之后可以继续生成)。

点击看大图:

关于一个播客所需要的一切全部准备好(音频2-4分钟,刚合适)。

接下来,跟我一起走一遍这个AI应用的搭建流程需要的小伙伴收藏

立即开始

进入扣子,在个人空间里点击创建应用:

建立您自己的AI应用。

由于我们这个系列重点讲述AI工作流,其它部分不会重点讲,感兴趣的小伙伴自己学习哈。

在主题播客工厂的用户界面旁边,有一个业务逻辑,打开它:

您这里应该是空的,我接下来会详细讲解我的这个工作流(本篇带着大家走一遍,先不着急讲述工作流的搭建思想与设计思路,大家先熟悉,今后慢慢来):

触发器

这个工作流的开始,是一个带有输入变量的触发器。

Coze 平台中的触发器功能允许 Bot 在特定时间或事件下自动执行任务。具体如下:

  • 触发器类型
    • 定时触发器:允许设置 Bot 在指定时间执行任务,无需编写代码。触发时间可以是每日、每周、每月固定时间触发,也可以选择间隔特定天数的固定时间触发。
    • 事件触发器:生成一个 Webhook URL,当向该 URL 发送 HTTPS 请求时,触发任务执行。
  • 任务执行方式
    • Bot 提示词:通过自然语言设置提示词,触发时提示词自动发送给 Bot,Bot 根据提示词向用户发送提醒消息。
    • 调用插件:为触发器添加一个插件,触发时 Bot 会调用该插件获取返回结果并发送给用户。
    • 调用工作流:为触发器添加一个工作流,若工作流有输入参数则需传入参数值,触发时 Bot 会调用该工作流获取返回结果并发送给用户。
  • 使用限制
    • 一个 Bot 内的触发器最多可添加 10 个。
    • 触发器仅当 Bot 发布到飞书时生效。

此外,Coze 支持用户在与 Bot 聊天时设置定时任务,当用户在会话内点击推荐任务后,Bot 将会确认并创建定时任务。

我们这里用到的就是一个调用工作流的触发器。

我用了一个输入的UI控件结合按钮事件将上述工作流的入参给传到工作流里,这就是工作流的开始。

生成待检索序列

这一步就是添加了一个大模型节点,进行了系统及用户提示词的配置,把用户输入的内容转换成适合后续工作流处理的内容。

这里面要注意输出配置:

由于后续工作流基于文字进行,所以输出的数据格式的选择很重要,要匹配。

分解检索与必应搜索

现在,我进入到第一个关键节点。

分解的目的是为了给Bing插件进行搜索:

这个插件会输出合适的数据结构,而用好这个数据结构则是能否成功开发出这套工作流的关键之一,为了用户这些数据,我将使用Python进行编程处理。

编程处理检索

async def main(args: Args) -> Output:
    params = args.params
    outputList = params['outputList'] 
    markdown_str = ""
    message_count = 0
    for item in outputList:
        data = item.get('data', {})
        doc_results = data.get('webPages', [])
        doc_results_2 = doc_results.get('value', [])
        
        for doc in doc_results_2:
            sitename = doc.get('sitename', '')
            summary = doc.get('snippet', '')
            title = doc.get('name', '')
            url = doc.get('url', '')
            
            # 拼接 markdown 格式
            markdown_str += f"##### {title}\n\n"
            markdown_str += f"**网站**: {sitename}\n\n"
            markdown_str += f"**摘要**: {summary}\n\n"
            markdown_str += f"[点击这里查看详情]({url})\n\n\n"
            message_count = message_count + 1
    ret: Output = {
        "markdown_str": markdown_str,
        "message_count": message_count,
    }
    return ret

上面这段代码实现了一个异步函数 main,用于将结构化数据转换为 Markdown 格式的字符串,并统计处理的消息数量。以下是逐层解析:

1. 函数定义与输入

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

  • 异步函数 :使用 async def 定义协程函数,表明该函数可以与其他异步任务并发执行
  • 输入参数 args 是包含输入数据的对象,类型注解 Args 表示其结构需符合特定规范。
  • 返回类型 Output 类型的字典,包含生成的 Markdown 字符串和消息计数。

2. 数据提取与初始化

params = args.params
outputList = params['outputList']
markdown_str = ""
message_count = 0

  • 参数解析 :从 args 中提取 params,并进一步获取 outputList(待处理的数据列表)。
  • 初始化变量 markdown_str 用于累积生成的 Markdown 内容,message_count 统计处理的消息数量。

3. 数据遍历与处理

for item in outputList:
    data = item.get('data', {})
    doc_results = data.get('webPages', [])
    doc_results_2 = doc_results.get('value', [])

  • 嵌套数据结构 :通过多级 get 方法安全访问嵌套字典(如 item['data']['webPages']['value']),避免 KeyError
  • 默认值处理 :若键不存在,返回空字典 {} 或空列表 [],确保后续操作不报错。

4. 生成 Markdown 内容

for doc in doc_results_2:
    sitename = doc.get('sitename', '')
    summary = doc.get('snippet', '')
    title = doc.get('name', '')
    url = doc.get('url', '')
    
    markdown_str += f"##### {title}\n\n"
    markdown_str += f"**网站**: {sitename}\n\n"
    markdown_str += f"**摘要**: {summary}\n\n"
    markdown_str += f"[点击这里查看详情]({url})\n\n\n"
    message_count += 1

  • 字段提取 :从每个文档中提取标题、网站名、摘要和链接,使用 get 避免缺失字段导致的错误。
  • Markdown 拼接 :按固定格式将字段组合为 Markdown 字符串,包含标题(#####)、加粗字段(**)和超链接。
  • 计数更新 :每处理一个文档,message_count 增加 1。

5. 返回结果

ret: Output = {
    "markdown_str": markdown_str,
    "message_count": message_count,
}
return ret

  • 结果封装 :将生成的 Markdown 字符串和消息数量封装为字典,符合 Output 类型的结构要求。

关键点总结

  1. 异步函数的同步执行 :尽管函数用 async def 定义,但内部无 await 调用,实际执行时为同步操作。这可能用于兼容异步框架的接口规范。
  2. 数据安全性 :通过 dict.get() 处理嵌套数据,避免因数据缺失导致崩溃。
  3. 性能优化空间 :频繁使用 += 拼接字符串在大数据量时可能影响性能,可改用列表暂存片段后 join

后续,我也不用这样解释代码,大家通过AI工具自己脑补,我们不断搭建工作流的目的在于训练我们的思想和方案设计能力,未来的具体执行全部交给AI,这个时代给有思想又勤劳的我们!

获得播客内容源

经过编程及相关配置,我们可以得到播客的封面与男女双播的台词脚本:

提取分类声音文案

为了将男女双播的声音分别生成并混合,我们需要先分类提取男声文案与女声文案(依旧是编程处理):

async def main(args: Args) -> Output:
    params = args.params 
    
    lines =  params['input'].strip().split('\n')

    # 初始化两个数组
    male_lines = []
    female_lines = []

    # 遍历每一行,根据前缀将对白添加到对应的数组中
    for line in lines:
        if line.startswith('男:'):
            male_lines.append(line[2:])
        elif line.startswith('女:'):
            female_lines.append(line[2:])
    
    ret: Output = {
        "key0": male_lines,
        "key1": female_lines
    }
    return ret

声音合成

接下来就简单了,分别合成男声与女声,然后再混合:

我分别列出各节点配置,大家放大查看:

其中,人声合成的代码如下:

async function main({ params }: Args): Promise<Output> {
    const mergedUrls = [];
    const maxLength = Math.max(params.audio.length, params.audio_1.length);

    for (let i = 0; i < maxLength; i++) {
        if (i < params.audio.length) {
            mergedUrls.push(params.audio[i].data.url);
        }
        if (i < params.audio_1.length) {
            mergedUrls.push(params.audio_1[i].data.url);
        }
    }
    const ret = {
        "key0": mergedUrls,
    };

    return ret;
}

生成封面

声音完成之后,生成封面就是小Case了。

完成

最后,把这两部分数据同时接入“结束”节点,就完成了这样一个工作流。

结束节点中的数据输出,会在UI中有对应的数据展示:

OK,至此完成,是不是很简单,大家又可以愉快地玩耍啦。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

政安晨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值