

























核心摘要 (TL;DR)
- 架构进阶:从传统的 ReAct 循环升级为 LlamaIndex Workflow,掌握基于“事件驱动”的现代智能体编排范式。
- 算力自由:摆脱本地 GPU 显存与运行时间的限制,实战接入 Groq 与硅基流动的高性能免费大模型 API。
- 实战目标:利用 Workflow 重构博客监控程序,将其拆解为“检查员 (Checker)”与“通知官 (Notifier)”,实现多智能体的解耦与协作。
在上一篇博客,我们用本地加载的huggingface模型来定义的ReActAgent完成了任务。其实对于LlamaIndex而言,更规范的用法是用WorkFlow来定义Agent,用API来调用而不是用本地加载模型,所以本篇博客的主要内容就是介绍一下LlamaIndex的workflow流程。

之前咱们的用法是一种QueryEngine的用法,就是将大模型当成一个查询的工具在使用,而workflow是LlmaIndex的新一代编排引擎。
LlamaIndex的workflow,本质上是一个事件驱动(Event-driven)的状态机,如果各位友人们经常做开发的话,一定一下就理解。 咱们可以将其流程想象成一场"接力赛":
@step装饰函数,这个函数就是step,负责具体的逻辑。Event,用于在Step间传递数据。Event一样,只是作为最后一棒,某个Step返回StopEvent就意味着"接力赛"结束了,咱们将结果返回给用户。
1 | from llama_index.core.workflow import Event |
@step
是逻辑处理单元。一个Step可以通过返回值来“发射”事件。
Event实例。Event实例。StartEvent & StopEvent
是流程的"起跑线"和"终点线"。一般我们只用定义StopEvent,当调用workflow.run()自动会触发StartEvent,任何Step只要返回了StopEvent,整个workflow就会停止并输出结果。
结合起来,就是这样一个极简的Workflow模板
1 | from llama_index.core.workflow import Workflow, step, StartEvent, StopEvent, Event |
通常来讲,咱们会把step定义给一个调用llm处理的函数. 我们待会儿就用Workflow重写咱们上一篇中的Agent。
咱们这次给大家换换口味,不用本地加载模型,而是用API的方式去调用大模型,所以本篇博客的代码可以在没有显卡的电脑上运行,可以脱离Kaggle的显卡环境。
PS: 虽然调用API更方便,但是本地加载或者本地部署更安全
(阿尔周末也尝试过在kaggle上直接去用vllm/ollama部署,然后调用,但是遇到了太多没法解决的问题,本次就直接用现成的API了。如果能解决,到时候再出一篇教程吧,如果还记得这个事儿的话,哈哈哈)
接下来介绍两个可以用免费模型的API: Groq和硅基流动。
Groq并不是模型开发者,只是大模型的搬运工,是一个推理加速平台,其核心是自研的LPU(Language Processing Unit),所以它的推理速度那是相当惊人,这也是阿尔推荐它的很重要的一个理由。
| 模型系列 | 模型 ID (API 调用名) | 厂商 | 上下文窗口 | 特点与优势 |
|---|---|---|---|---|
| Llama 3.3 | llama-3.3-70b-versatile | Meta | 128k | 最强逻辑,性能对标 GPT-4o |
| Llama 3.1 | llama-3.1-8b-instant | Meta | 128k | 极速响应,适合简单逻辑与翻译 |
| Llama 3.2 | llama-3.2-11b-vision-preview | Meta | 128k | 多模态支持,可识别并理解图片 |
| Gemma 2 | gemma2-9b-it | 8k | 指令遵循强,结构化输出更稳定 | |
| Mixtral | mixtral-8x7b-32768 | Mistral | 32k | 经典的混合专家模型,长文本表现好 |
| Whisper | whisper-large-v3 | OpenAI | - | 极速语音转文字 (STT) |
Groq的限制
Groq的免费层级给的非常慷慨,堪称大善人,但是为了防止滥用,还是设置了很多限制。通常对每个模型独立计算
通常从RPM(Requets Per Minute)每分钟请求数,RPD(Requests Per Day)每天请求数,TPM(Tokens Per Minute)每分钟消耗Token数三个维度限制,当然对于咱们来说是完全够用的
注册Groq Api Key
Start BuildingAPI KEYS
生成API Key
硅基流动是咱们要介绍的二号大模型的搬运工,国内开发者使用比较多,可以在上面找到很多便宜大碗的模型,也有不少免费的模型可以用,咱们今天就要用它的免费模型。
| 模型系列 | 最新代表型号 (API 调用名) | 核心优势 | 上下文窗口 | 状态 |
|---|---|---|---|---|
| DeepSeek | deepseek-ai/DeepSeek-V3.2 | 性能对标顶级闭源模型,极强逻辑 | 128k | 旗舰收费 |
| DeepSeek | deepseek-ai/DeepSeek-R1 | 推理增强模型,擅长复杂数学与逻辑 | 64k | 部分免费 |
| Qwen | Qwen/Qwen3-30B-A3B | 阿里最新一代模型,中文语境指令遵循极强 | 128k | 免费/收费 |
| Qwen-VL | Qwen/Qwen3-VL-72B | 顶级视觉理解能力,支持视频分析 | 32k | 旗舰收费 |
| GLM | Z.ai/GLM-5 | 智谱旗舰,专注于长周期 Agent 任务 | 205k | 旗舰收费 |
| Kimi | moonshotai/Kimi-K2.5 | 原生多模态智能体模型,长文本处理极佳 | 262k | 旗舰收费 |
| Step | stepfun-ai/Step-3.5-Flash | 极高性价比的轻量模型,推理速度极快 | 262k | 低成本/免费 |
| MiniMax | MiniMaxAI/MiniMax-M2.5 | 擅长角色扮演与情感交互 | 197k | 旗舰收费 |
| Llama 3 | meta-llama/Llama-3.3-70B-Instruct | 国际最强开源模型,适配各类 Agent 框架 | 128k | 旗舰收费 |
硅基流动的限制
硅基流动有着比Groq更多的可用模型,有不少永久免费的模型, 甚至还有推广(阿尔这里就不贴推广码了,大家自行注册即可)和新用户赠金,但是其免费版的并发数很低,具体的模型也有RPM和TPM限制。
注册硅基流动API Key
我们待会儿使用Qwen/Qwen3-8B这个免费模型
这次和此前不同,诶,咱们今天用API不用自己加载模型,不用开GPU加速,Accelerator选择None即可。
然后老样子,先装依赖库
1 |
|
注意,这里咱们硅基流动其实也是有专门的定制库的,llama-index-llms-siliconflow,只是这里咱们为了通用性用了llama-index-llms-openai-like。(实际上是因为最开始试了Groq效果不好,觉得换中文模型会好一点,然鹅效果也不好,这次主要还是介绍这个WorkFlow架构吧)
和上篇博客一样,咱们在Add-ons->Secrets中添加上Groq和硅基流动的API Key,命名为GROQ_API_KEY和SILICON-API_KEY(当然,名字无所谓,和代码匹配就好)
Tools和之前一样,咱们就不赘述了。
1 | import os |
1 | from llama_index.llms.openai_like import OpenAILike |
可以看出来,定制的接口只用定义对应的API KEY在环境变量里,通用的接口需要补充清楚模型名,api-key,api的url等等。
我们打算定义两个Agent
当有新的博客的时候,Checker向Notifer发送事件,告知notifier新博客的标题和链接。然后结束。
整体流程如下:

1 | from llama_index.core.workflow import Workflow, step, StartEvent, StopEvent, Context, Event |
由于Checker流转向Notifer的时候,只需要给它标题和链接即可,咱们的NewBlogPostEvent只用包含title和link字段。
我们先定义Checker
1 | from llama_index.core.agent.workflow import ReActAgent |
然后咱们再来定义Notifier
1 | NOTIFIER_SYSTEM_PROMPT = """ |
StartEvent开始到StopEvent结束这里因为模型的指令跟随能力比较差,格式化输出不了,咱们用了一个正则来兜底。
1 | import os |
1 | async def main(): |
这里咱们运行两遍,确认全局变量会同步更新到新状态,咱们实际使用的时候,可以将其持久化存储下来,而不是用变量global_last_title将状态保存在内存中
本篇博客代码示例可在Kaggle笔记本
Q1: 为什么不让 Agent 直接判断是否有更新,而是要在 Python 代码里写 if current_title != global_last_title:?
A: 为了系统的绝对稳定性!(划重点)
大模型在 ReAct 模式下有时会产生“幻觉”或者表现得过于“客气”。
Q2: 为什么一定要强制模型输出 JSON 格式?之前用 | 这种自定义分隔符不行吗?
A: 因为自然语言的边界太模糊,且极易与真实数据冲突。
这是本次开发多智能体协作时遇到的最大痛点!
split("|") 直接报错。| 符号。正则匹配遇到这种情况会产生严重的边界歧义。re.search(r"(\{.*\})") 专门抓取大括号之间的内容,就能彻底免疫模型的“废话”。Q3: 运行 Workflow 时碰到了 WorkflowValidationError: The following events are produced but never consumed 报错是怎么回事?
A: 这是 LlamaIndex 工作流引擎的一种“管道安全检查”机制。
它的意思是:咱们的 check_step 辛辛苦苦生产了一个 NewBlogPostEvent,但是工作流里没有任何一个 Step 声明要接收并处理这个事件,导致事件“无家可归”。
notify_step)。async def notify_step(self, ev: NewBlogPostEvent)。这样引擎就能自动把上一步产生的数据路由到这里,完成闭环。Q4: 调用 Groq 或硅基流动 API 时,频繁遇到 429 Too Many Requests 怎么办?
A: 这是因为多智能体循环请求过快,触发了并发限制。
在开发 ReAct Agent 时,模型需要反复执行“思考-行动-观察”的循环,短时间内会产生高密度的 API 请求。
await asyncio.sleep(2) 进行冷却。Q5: 在生产环境中,我还应该使用 global global_last_title 这种全局变量来管理状态吗?
A: 非常不建议。
本教程使用全局变量仅为了降低代码阅读门槛和方便演示。
Context 对象。咱们应该在 @step 中通过 ctx.set("last_title", title) 和 ctx.get("last_title") 来在不同的步骤之间安全地传递状态,或者引入外部数据库(如 Redis、本地 JSON 文件)进行持久化。此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。