AI 应用为什么需要 Workflow?不要把复杂任务写成一串函数调用 上一篇文章讨论了 Prompt 管理。Prompt 管理解决的是模型输入如何组织的问题。它让 Prompt 不再散落在业务代码里而是成为可以维护、复用和版本化的项目资产。但当 Prompt 和 LLM 抽象层都准备好以后AI 应用还会继续变复杂。一开始一个功能可能只是这样messagesprompt_manager.render_messages(summary,{text:text})resultllm.chat(messages)returnresult.content这很清楚。但真实项目往往不是一次模型调用就结束。比如一个文章处理任务可能需要清洗输入文本。判断文章类型。选择合适 Prompt。调用模型生成摘要。校验摘要长度。如果不符合要求再调用模型重写。再生成标题。再提取关键词。最后组合成结构化结果。如果把这些全部写在一个函数里代码很快就会变成很长的一串调用。这时候就需要 Workflow。一、为什么简单函数调用一开始够用在 Demo 阶段简单函数调用是最自然的写法。例如defrun(text:str)-str:cleaned_textclean_text(text)promptbuild_prompt(cleaned_text)resultllm.chat(prompt)returnresult.content这段代码没有问题。它短、直观、容易调试。如果任务只有三四步这样写完全可以。但问题是AI 应用一旦进入真实业务就很少停留在三四步。业务会不断增加新的要求。比如输入为空时要返回提示。文本太长时要切分。模型调用失败时要重试。输出格式不对时要重新生成。不同用户场景要走不同 Prompt。有些任务需要调用外部工具。有些任务需要保存中间结果。有些任务需要记录每一步耗时。这些需求一加进来简单函数就会开始膨胀。最后可能变成一个很长的函数里面充满if else、try except和临时变量。这不是某个开发者写得不好。而是任务复杂度已经超过了普通函数链条适合表达的范围。二、复杂 AI 任务为什么容易写乱复杂 AI 任务容易写乱主要有几个原因。第一步骤多。一次完整任务可能包含输入处理、Prompt 渲染、模型调用、结果解析、校验、重试、工具调用和最终输出。第二中间状态多。每一步都会产生数据。例如原始输入、清洗后输入、Prompt、模型响应、解析结果、校验结果、错误信息。第三分支多。不同输入可能走不同路径。例如短文本直接总结长文本先切分再总结。第四失败场景多。模型可能超时。返回内容可能为空。JSON 可能解析失败。工具调用可能失败。第五调试困难。当最终结果不符合预期时需要知道到底是哪一步出了问题。如果所有逻辑都写在一个函数里排查会很痛苦。所以复杂 AI 任务需要一种更清晰的组织方式。Workflow 的价值就在这里。三、Workflow 解决的不是炫技问题提到 Workflow有些人会觉得这是把简单问题复杂化。如果任务只有一次模型调用确实不需要 Workflow。但 Workflow 不是为了炫技。它解决的是复杂任务的组织问题。一个合理的 Workflow 至少应该带来几个好处。第一步骤清晰。每个节点只负责一件事。第二状态清晰。所有中间结果都放在统一上下文里。第三分支清晰。不同条件对应不同执行路径。第四错误清晰。每一步失败时都能知道失败位置和失败原因。第五调试清晰。可以记录每个节点的输入、输出、耗时和状态。第六扩展清晰。新增一个步骤不一定要改动整个大函数。所以Workflow 的本质不是把代码写得更复杂。而是让复杂任务的结构变得可见。四、AI Workflow 通常有哪些节点AI Workflow 可以把任务拆成多个节点。常见节点包括Input 节点 - 接收用户输入。 - 做基础校验。 - 标准化输入格式。 Preprocess 节点 - 清洗文本。 - 截断文本。 - 分段处理。 Prompt 节点 - 选择 Prompt 模板。 - 注入变量。 - 生成 messages。 LLM 节点 - 调用模型。 - 获取生成结果。 - 记录 token 和耗时。 Tool 节点 - 调用外部工具。 - 查询数据库。 - 检索知识库。 Condition 节点 - 判断是否继续执行。 - 判断走哪个分支。 - 判断是否需要重试。 Validator 节点 - 校验模型输出格式。 - 校验 JSON 字段。 - 校验长度和业务规则。 Output 节点 - 整理最终结果。 - 返回给调用方。 - 写入日志或数据库。这些节点不是每个项目都必须有。但它们代表了 AI 应用里常见的任务步骤。Workflow 的作用是把这些步骤组织起来。五、不要让每个函数随便传参数复杂任务里最容易乱的地方是参数传递。例如cleanedclean_text(raw_text)promptbuild_prompt(cleaned,user_id,scene,lang)responsecall_llm(prompt,model,timeout)parsedparse_response(response,scene)validatedvalidate_result(parsed,raw_text,user_id)刚开始还能接受。但步骤越来越多时每个函数都要传一堆参数。有些参数只在某一步使用。有些参数会被后续多个步骤使用。有些参数是中间结果。最后整个调用链会变得很难看。更合理的方式是设计统一的WorkflowContext或WorkflowState。例如fromdataclassesimportdataclass,fielddataclassclassWorkflowState:raw_input:strcleaned_input:str|NoneNoneprompt_messages:list[dict]|NoneNonellm_output:str|NoneNoneparsed_result:dict|NoneNoneerrors:list[str]field(default_factorylist)每个节点接收 state处理后更新 state。defclean_node(state:WorkflowState)-WorkflowState:state.cleaned_inputstate.raw_input.strip()returnstate这样状态流转会更清楚。不是所有参数都在函数之间到处飞。而是每一步都围绕同一个 state 进行处理。六、一个最简单的 Workflow 可以怎么写第一版 Workflow 不需要很复杂。可以先从顺序执行开始。例如classWorkflow:def__init__(self):self.nodes[]defadd_node(self,node):self.nodes.append(node)returnselfdefrun(self,state):fornodeinself.nodes:statenode(state)returnstate然后定义节点defclean_node(state):state.cleaned_inputstate.raw_input.strip()returnstatedefprompt_node(state):state.prompt_messagesprompt_manager.render_messages(namesummary,variables{text:state.cleaned_input},)returnstatedefllm_node(state):responsellm.chat(state.prompt_messages)state.llm_outputresponse.contentreturnstate组合起来workflow(Workflow().add_node(clean_node).add_node(prompt_node).add_node(llm_node))stateWorkflowState(raw_input一段文章内容)resultworkflow.run(state)这个版本很简单。但它已经比一个巨大函数更清楚。因为每个节点都有明确职责。七、顺序 Workflow 适合哪些场景顺序 Workflow 适合步骤固定的任务。例如文章摘要生成。标题生成。简单问答处理。文本分类。关键词提取。固定格式报告生成。这类任务的特点是执行顺序比较稳定。分支不多。每一步都依赖上一步结果。例如文章摘要可以是输入文本 ↓ 清洗文本 ↓ 渲染 Prompt ↓ 调用 LLM ↓ 校验摘要 ↓ 输出结果这种任务不需要一开始就上复杂 DAG。一个简单的顺序 Workflow 就足够。脚手架应该先支持这种基础能力。因为大多数 AI 应用的第一批功能都可以从顺序流程开始。八、什么时候需要条件分支当不同输入需要走不同路径时就需要条件分支。例如如果文章很短直接总结。如果文章很长先分段总结再合并总结。可以表示成输入文本 ↓ 判断长度 ├── 短文本直接总结 └── 长文本分段总结 - 合并总结代码里可以先用简单方式实现。例如defroute_node(state):iflen(state.cleaned_input)5000:state.routelong_textelse:state.routeshort_textreturnstate然后根据 route 执行不同节点。第一版不一定要做得很抽象。但要让分支逻辑有明确位置。不要让分支散落在每个节点里。如果每个节点都自己判断一堆条件Workflow 也会变乱。九、失败重试也应该进入 Workflow 视角AI 任务里失败很常见。模型调用可能失败。输出格式可能不符合要求。工具调用可能超时。JSON 可能解析失败。如果每个地方都自己写重试逻辑项目会很乱。Workflow 可以把失败重试看成流程的一部分。例如调用 LLM ↓ 校验输出 ├── 通过进入下一步 └── 失败重新生成代码可以先写成defvalidate_summary_node(state):ifnotstate.llm_output:state.errors.append(empty summary)state.need_retryTruereturnstateiflen(state.llm_output)200:state.errors.append(summary too long)state.need_retryTruereturnstate state.need_retryFalsereturnstate然后 Workflow 根据need_retry决定是否再调用一次 LLM。这样失败处理就不是临时补丁。而是流程设计的一部分。十、Workflow 需要可观测性复杂 AI 任务很难只靠最终结果调试。因为最终结果不好不代表最后一步错了。可能是输入清洗错了。可能是 Prompt 变量错了。可能是模型输出格式错了。可能是某个工具返回了空结果。所以 Workflow 需要记录每个节点的执行信息。至少包括节点名称。开始时间。结束时间。是否成功。错误信息。关键输入摘要。关键输出摘要。例如{workflow:summary_workflow,node:llm_node,success:true,latency_ms:1200}这些日志对调试非常重要。开发环境可以记录更多细节。生产环境要注意脱敏。尤其是用户输入、API Key、隐私信息不应该随意进入日志。可观测性不是后期才做的事情。Workflow 层一开始就应该预留记录能力。十一、Workflow 和 Prompt、LLM 的关系Workflow 不是替代 Prompt 管理也不是替代 LLM 抽象层。它们的职责不同。Prompt 管理层负责构造模型输入。LLM 抽象层负责调用模型。Workflow 层负责任务编排。例如defprompt_node(state):state.messagesprompt_manager.render_messages(namesummary,variables{text:state.cleaned_input},)returnstatedefllm_node(state):state.llm_outputllm.chat(state.messages).contentreturnstate这里 Workflow 只是把 Prompt 和 LLM 组织起来。它不应该把 Prompt 字符串写死在节点里。也不应该直接依赖某个模型供应商 SDK。否则前面做的 Prompt 管理和 LLM 抽象都会失去意义。好的 Workflow应该建立在前面这些基础模块之上。十二、Workflow 和 Agent 有什么区别Workflow 和 Agent 很容易被混在一起。它们确实有关系但重点不同。Workflow 更偏确定性流程。也就是说开发者预先设计好步骤和顺序。例如清洗输入 - 渲染 Prompt - 调用模型 - 校验结果 - 输出Agent 更偏动态决策。也就是说系统根据目标、上下文和工具结果动态决定下一步做什么。例如分析问题 - 选择工具 - 调用工具 - 观察结果 - 决定下一步简单理解Workflow 适合流程明确的任务。Agent 适合路径不固定、需要动态决策的任务。但它们不是对立关系。Agent 内部也可以使用 Workflow。Workflow 的某个节点也可以调用 Agent。对于 AI Scaffold 来说可以先把 Workflow 作为确定性任务编排层做好。后续再讨论 Agent 层会更自然。十三、Workflow 在 AI Scaffold 里的位置在 AI Scaffold 里Workflow 可以作为核心模块之一。项目结构可以这样设计app/ ├── main.py ├── config/ │ └── settings.py ├── llm/ │ ├── base.py │ └── factory.py ├── prompts/ │ └── summary/ │ └── v1.md ├── workflows/ │ ├── __init__.py │ ├── base.py │ ├── state.py │ └── summary_workflow.py └── tools/ └── search_tool.py其中workflows/base.py放基础 Workflow 类。workflows/state.py放状态对象。summary_workflow.py放具体业务流程。CLI 创建项目时可以默认生成一个示例 Workflow。例如workflows/summary_workflow.py这样开发者创建项目后就能看到一个完整链路配置系统提供运行参数。Prompt 管理层生成模型输入。LLM 抽象层调用模型。Workflow 层组织任务步骤。这比只生成一个main.py更适合真实项目。十四、总结当 AI 应用只是一次模型调用时不一定需要 Workflow。但当任务开始包含多个步骤、多个中间状态、多个分支和多个失败场景时Workflow 就变得非常重要。一个合理的 AI Workflow至少应该做到把复杂任务拆成清晰节点。使用统一 state 管理中间状态。支持顺序执行。支持条件分支。支持失败校验和重试。能记录每个节点的执行状态。和 Prompt 管理层保持边界。和 LLM 抽象层保持边界。为后续 Agent 层打基础。对于 AI Scaffold 来说Workflow 是从 Demo 走向工程化的重要一步。它让 AI 任务不再是一串临时拼起来的函数调用而是变成结构清晰、状态可追踪、失败可处理、后续可扩展的执行流程。下一篇文章可以继续讨论 Agent当任务路径不再完全固定需要系统根据目标、上下文和工具结果动态决定下一步时Agent 应该如何在脚手架中设计。