1. 为什么单 Agent 会失控
根据样例举个例子说明吧:
周一早上,你收到了这样一条消息:
"上周五提交的《Python数据分析入门》课程需要尽快上线。能不能用你那个AI助手跑一遍标准审核流程?就是:1)所有代码示例要能运行 2)技术概念不能有硬伤 3)难度梯度适合零基础 4)语言风格符合我们的规范。下午3点前要结果。"
你心想,这个任务挺简单的。你的机器人已经能验证代码了,处理这个"组合任务"应该不难。于是你把所有要求塞进一个prompt里:
prompt = """请完成以下课程审核任务:
1. 验证所有Python代码能正确运行
2. 检查技术概念的准确性(特别是pandas和numpy的用法说明)
3. 评估难度曲线是否适合编程新手
4. 按照我们的风格指南调整用词(避免"很简单""超级"等口语)
请给出完整的审核报告。"""
response = agent.run(prompt + course_content)
几分钟后,你打开返回的结果:
Agent确实验证了代码,但在"优化语言"时,它把代码里的super()也改成了parent(),因为它觉得"super太口语化"。
它发现第 3 章对DataFrame的解释有误,改正后却引入了更严重的错误:说"DataFrame是Python内置的数据结构"。至于难度评估?它在处理到第 50 个问题时似乎已经忘了这回事。
你试图让它重来,这次它记住了评估难度,却漏掉了一半的代码验证。第三次,它所有任务都做了,但把原本正确的概念"改错了"。
当你把「代码可运行、概念准确、难度梯度、语言风格」四类要求一次性塞进一个长 Prompt,常见问题是:
问题很明显:让单个Agent同时接管多个复杂任务,就像让一个实习生同时接四个电话——总有一个会出问题。
2. 失败原因(工程化视角)
2.1 注意力机制的遗忘效应
大语言模型在生成回复时,对不同位置信息的"注意力"是不均等的。当Agent处理到第四个任务(润色语言)时,第一个任务(代码验证)的细节已经被大量中间信息稀释。
具体表现:模型在后期修改时"忘记"了前期验证的约束。比如你已经验证super()是正确的Python语法,但在语言润色阶段,模型可能因为"super"这个词看起来口语化而将其替换,导致代码出错。
这不是简单的"记忆力差",而是Transformer架构中self-attention机制的固有限制——token之间的注意力权重会随着序列长度增加而被稀释。
2.2 错误级联放大
在顺序执行多个任务时,早期的错误会成为后续处理的"事实基础"。这个错误会进入后续的上下文导致后续的错误。
2.3 扁平需求 vs 结构化任务图
真实需求通常是图结构:
- 有些任务可以并行(代码检查和风格检查互不干扰)
- 有些任务有依赖(必须先理解概念才能评估难度)
- 有些任务需要全局视角(评估整体难度曲线)
但对模型来说,你的prompt只是一个扁平的token序列。它无法自动识别出这种结构关系,而是试图用一个线性的生成过程去解决一个本质上是图结构的问题。单 Agent 线性生成并不等于图执行。
就像让某人同时玩四个不同规则的游戏,还不告诉他哪些可以轮流玩,哪些必须同时进行。
最终,依赖单个 Agent 执行复杂审阅,就像在没有施工蓝图的情况下建造一栋房子,每砌一块砖都可能影响整栋建筑的结构稳定。
解决方案:
既然让一个 Agent 包办所有事情行不通,那你自然会想到另一种思路:就像你在管理一个项目时,你会把项目拆分成几个子任务,分配给不同的人或在不同时间点完成。这种“分而治之”(Divide and Conquer)的思想,正是解决此类问题的核心。
我们将这种把复杂任务拆解成多个节点,并定义它们之间执行关系的模式,称为工作流 (Workflow)。
构建工作流的关键,是理解业务并做出最合适的任务拆解。下面,我们将从最简单的模式开始,一步步构建出能够处理复杂课程审阅的强大工作流。
3. 工作流五种模式
3.1 模式一:流水线(Pipeline)
流水线说明:它将一个任务分解为多个固定的、按顺序执行的步骤。前一个步骤的输出,严格作为后一个步骤的输入,整个过程像工厂的流水线一样,单向且不可变。你在本课程早期构建的 RAG 问答机器人,就是这种模式的完美体现。
适用:固定流程、顺序不可变。
示例链路:提取代码 -> 执行验证 -> 生成报告。
@Service
public class CoursePipelineService {
private final ChatClient extractor;
private final ChatClient validator;
private final ChatClient reporter;
private final MethodToolCallbackProvider toolProvider;
public CoursePipelineService(
@Qualifier("dashscopeChatModel") ChatModel chatModel,
NotebookSandboxTools sandboxTools) {
this.extractor = ChatClient.create(chatModel);
this.validator = ChatClient.create(chatModel);
this.reporter = ChatClient.create(chatModel);
this.toolProvider = MethodToolCallbackProvider.builder()
.toolObjects(sandboxTools)
.build();
}
public String run(String courseDraft) {
String codeOnly = extractor.prompt()
.system("你是代码提取器。仅提取课程中的代码块,禁止输出解释。")
.user(courseDraft)
.call()
.content();
String verifyResult = validator.prompt()
.system("你是代码验证器。可调用 runSnippetInSandbox 执行代码并返回错误摘要。")
.user(codeOnly)
.toolCallbacks(toolProvider)
.call()
.content();
return reporter.prompt()
.system("你是报告生成器。将验证结果整理成简洁结论+修复建议。")
.user(verifyResult)
.call()
.content();
}
}
优点:
简单、可预测且易于调试。因为流程是固定的,所以当出现问题时,你可以很容易地定位到是哪个环节(提取、验证还是报告)出了问题。
常见使用于:
- 代码初步检查:先提取代码,再运行验证。
- 文档翻译:先提取文本,再进行翻译,最后格式化输出。
- 新员工入职材料分发:先生成欢迎邮件,再附上公司文档,最后发送。
3.2 模式二:分支选择(Branching)
说明:为了克服流水线的僵化,你需要引入决策能力。分支选择模式的核心是在工作流的开始或关键节点设置一个“路由器”或“调度中心”。这个决策节点会分析输入(例如,用户的审阅要求),然后像一个交通警察一样,将任务引导到不同的、预设好的处理路径(即不同的流水线或专家)上去。
适用:同一入口,多条处理路径。
关键点:先做结构化路由,再进入子流程。

public record RouteChoice(String choice, String extra) {}
@Service
public class CourseBranchingService {
private final ChatClient router;
private final ObjectMapper mapper = new ObjectMapper();
private final CoursePipelineService pipelineService;
private final StyleGuideService styleGuideService;
private final FullReviewService fullReviewService;
public CourseBranchingService(
@Qualifier("dashscopeChatModel") ChatModel chatModel,
CoursePipelineService pipelineService,
StyleGuideService styleGuideService,
FullReviewService fullReviewService) {
this.router = ChatClient.create(chatModel);
this.pipelineService = pipelineService;
this.styleGuideService = styleGuideService;
this.fullReviewService = fullReviewService;
}
public String routeAndRun(String userText) throws JsonProcessingException {
String raw = router.prompt()
.system("""
你是任务路由器。只输出 JSON:
{"choice":"code_check|style_guide|full_review","extra":"..."}
""")
.user(userText)
.call()
.content();
RouteChoice route = mapper.readValue(raw, RouteChoice.class);
return switch (route.choice()) {
case "code_check" -> pipelineService.run(userText);
case "style_guide" -> styleGuideService.run(userText);
case "full_review" -> fullReviewService.run(userText);
default -> fullReviewService.run(userText);
};
}
}
与单一流水线相比,分支选择让系统变得更灵活、更智能。它使得一个应用能够处理多种不同类型的任务,极大地扩展了其适用范围,提升了用户体验。
常见的应用场景有:
- 智能客服:根据用户问题类型(课程内容咨询、平台技术支持、购买建议)转接到不同的处理流程。
- 多工具 Agent:Agent 根据任务需求,决定是调用代码解释器、搜索引擎还是内部知识库。
- 内容处理系统:根据内容类型(视频、文本、交互式 Notebook)调用不同的审核流程。
局限性
分支选择本质上是“多选一”,它依然是串行的。它能处理“代码检查”或“语言润色”,但无法处理“一边检查代码,一边润色语言”的复合请求。
3.3 模式三:并行执行(Parallel Execution)
- 说明:当一个请求可以被分解为多个互不依赖的子任务时,让它们排队等待是极大的浪费。并行执行模式的核心思想是“同时进行”。它首先将一个复杂任务拆解成多个子任务,然后将这些子任务分发到不同的执行单元(Agent或工具)同时处理,最后再将所有结果汇集起来,形成最终的输出。
适用:子任务互不依赖,目标是缩短总耗时。
示例:代码、事实、教学法、风格四路并行,再聚合。

@Service
public class CourseParallelReviewService {
private final ChatClient codeChecker;
private final ChatClient factChecker;
private final ChatClient pedagogyChecker;
private final ChatClient styleChecker;
private final ChatClient summarizer;
private final ExecutorService pool = Executors.newFixedThreadPool(4);
public CourseParallelReviewService(@Qualifier("dashscopeChatModel") ChatModel chatModel) {
this.codeChecker = ChatClient.create(chatModel);
this.factChecker = ChatClient.create(chatModel);
this.pedagogyChecker = ChatClient.create(chatModel);
this.styleChecker = ChatClient.create(chatModel);
this.summarizer = ChatClient.create(chatModel);
}
public String run(String courseContent) {
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(
() -> codeChecker.prompt().system("检查代码正确性并给修复建议").user(courseContent).call().content(), pool);
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(
() -> factChecker.prompt().system("核查技术概念准确性").user(courseContent).call().content(), pool);
CompletableFuture<String> f3 = CompletableFuture.supplyAsync(
() -> pedagogyChecker.prompt().system("评估难度曲线与练习有效性").user(courseContent).call().content(), pool);
CompletableFuture<String> f4 = CompletableFuture.supplyAsync(
() -> styleChecker.prompt().system("检查风格指南一致性").user(courseContent).call().content(), pool);
CompletableFuture.allOf(f1, f2, f3, f4).join();
String merged = String.join("\n\n", f1.join(), f2.join(), f3.join(), f4.join());
return summarizer.prompt()
.system("把多份子报告汇总成一份结构清晰的总审阅报告")
.user(merged)
.call()
.content();
}
}
最显著的优势是效率的大幅提升。工作流的总耗时不再是所有子任务耗时之和,而是取决于耗时最长的那个子任务。这使得 Agent 能够快速响应包含多个步骤的复杂请求。
常见的应用场景有:
- 处理复杂审阅请求:如我们的课程审阅场景,同时处理代码、事实、教学法、风格等多个维度。
- 生成综合报告:同时从不同数据源(用户反馈、市场趋势、竞品分析)拉取信息,并分别进行分析,最后汇总成一份新课程立项报告。
- 批量数据处理:同时对多个课程单元执行相同的格式化或检查操作。
此模式的前提是子任务之间相互独立。如果任务之间存在依赖关系(例如,必须先确认课程的核心知识点,才能评估其案例是否贴切),则无法简单地并行。此外,它假设每个执行单元都能给出“正确”的答案,不适用于需要多方比较、权衡才能得出最佳方案的创造性或决策性任务。
3.4 模式四:混合专家(MoA, Mixture-of-Agents)
说明: 与并行执行旨在提升效率不同,混合专家模式的核心目标是追求极致的质量、鲁棒性和创造性。MoA 的核心理念基于一个关键发现:不同的大语言模型具有各自独特的优势和专长,而当一个模型能够参考其他模型的输出时,往往能生成质量更高的响应——这种现象称为模型的"协作性"(Collaborativeness)。
MoA 的做法是,让多个不同的大语言模型同时处理同一个任务,然后由一个聚合模型对所有输出进行综合、分析和融合,从而产生一个远超任何单个模型水平的最终结果。
适用:高价值场景,优先质量与鲁棒性。
做法:多模型并行提案 + 聚合模型融合。

@Service
public class CourseMoaService {
private final ChatClient proposerA;
private final ChatClient proposerB;
private final ChatClient proposerC;
private final ChatClient aggregator;
private final ExecutorService pool = Executors.newFixedThreadPool(3);
public CourseMoaService(
@Qualifier("qwen3MaxChatModel") ChatModel qwen3Max,
@Qualifier("deepseekChatModel") ChatModel deepseek,
@Qualifier("kimiChatModel") ChatModel kimi) {
this.proposerA = ChatClient.create(qwen3Max);
this.proposerB = ChatClient.create(deepseek);
this.proposerC = ChatClient.create(kimi);
this.aggregator = ChatClient.create(qwen3Max);
}
public String run(String task) {
String proposerPrompt = "你是课程分析师,请提炼课程核心卖点与宣传文案。";
CompletableFuture<String> a = CompletableFuture.supplyAsync(
() -> proposerA.prompt().system(proposerPrompt).user(task).call().content(), pool);
CompletableFuture<String> b = CompletableFuture.supplyAsync(
() -> proposerB.prompt().system(proposerPrompt).user(task).call().content(), pool);
CompletableFuture<String> c = CompletableFuture.supplyAsync(
() -> proposerC.prompt().system(proposerPrompt).user(task).call().content(), pool);
CompletableFuture.allOf(a, b, c).join();
String merged = """
模型1:
%s
模型2:
%s
模型3:
%s
""".formatted(a.join(), b.join(), c.join());
return aggregator.prompt()
.system("""
你是聚合器。批判性评估多个候选回答,
提取优点、修复问题,输出一个高质量最终版本。
""")
.user(merged)
.call()
.content();
}
}
多层 MoA:把第一层聚合结果再送入第二层提议者,最后二次聚合。
成本建议:常规任务用 2 层即可;3 层以上只给关键环节。
3.4.1 Mixture-of-Agents(MoA) 工作原理:
MoA 将参与的模型分为两类角色:
- 提议者(Proposers):多个不同的模型并行处理同一任务,各自生成响应。这些模型可能在某些方面表现出色(如逻辑推理、创意表达、事实准确性等)。
- 聚合器(Aggregator):接收所有提议者的输出,通过批判性评估、比较和融合,生成一个质量更高的最终响应。
关键: 聚合器并非简单地选择最好的答案,而是能够从多个响应中提取各自的优点,综合产生一个超越任何单一模型的结果。
3.4.2 MoA 的优势:
- 利用模型多样性:不同模型有不同的训练数据、架构和优化目标,导致它们在不同任务上表现各异。MoA 能够同时利用多个模型的长处。
- 增强鲁棒性:即使某个模型在特定输入上表现不佳,其他模型的高质量输出也能保证最终结果的质量下限。
- 质量的涌现效应:研究表明,即使提议者模型的单独输出质量较低,聚合后的结果仍可能超越任何单一模型——这是"模型协作性"的直接体现。
3.4.3 适用的场景
MOA 适用于那些没有唯一标准答案、对结果质量要求极高、价值巨大的开放性或创造性任务。
- 核心文案撰写:如课程Slogan、推广文案、品牌故事。
- 复杂决策分析:综合不同模型的分析报告,形成更全面的新课程方向决策建议。
- 代码生成与优化:让不同模型生成一段示例代码,再由评审 Agent 择优或进行融合重构,以达到最佳的教学效果。
3.4.5 主要的局限性:
不过,MOA 最主要的制约是成本。调用 N 个专家 Agent 会带来 N 倍的计算成本和相应的延迟。这是一种用资源换质量的策略,因此必须用在"好钢用在刀刃上"的关键环节,不适合用于常规的、对成本敏感的日常任务。
3.4.6 进阶:多层 MoA (Multi-Layer MoA)
前面展示的 MoA 是一个"2层结构":第一层有多个专家并行处理任务,第二层由一个聚合器综合所有专家的输出。然而,MoA 也可以扩展到 3 层或更多层,通过多轮迭代不断提炼和优化结果,从而获得比单层 MoA 更卓越的输出质量。

3.4.6.1 进阶:多层 MoA (Multi-Layer MoA)
何时使用多层 MoA:
- 极高价值任务:如公司年度战略报告、重要产品发布文案、核心课程体系设计等,这些任务的成败可能直接影响业务结果,值得投入更多资源。
- 创造性要求极高:如品牌故事创作、教学方法创新设计等,需要多轮思想碰撞才能激发出最佳创意的场景。
- 容错要求极高:如法律文书、技术白皮书等,任何错误都可能带来严重后果,需要多层审核来确保准确性。
3.4.7 成本权衡:
多层 MoA 的成本随层数线性增长。以上面的 3 层架构为例:每层 3 个提议者模型 + 1 个聚合器,意味着至少调用 (3+1) + (3+1) = 8 次模型,相比单层的 3+1=4 次,成本增加了一倍多。因此,只有在任务的价值明显高于成本时,才应考虑使用多层 MoA。
扩展阅读:工作流的成本优化与资源管理
差异化模型分配:工作流中的不同节点,其任务复杂度和重要性天差地别。你可以为简单的任务(如意图识别、格式转换)分配轻量、廉价的模型,而只为最关键的核心任务(如最终决策、文案生成)保留昂贵的高级模型。研究表明,通过合理的优化策略,根据具体实施情况,企业可以节省 40-70% 的 Token 成本。
系统性缓存:仔细观察你的工作流,你会发现许多节点的计算是可重复的。例如,对同一份公司风格指南的检索、对同一篇课程的审阅请求解析等。通过为这些节点增加缓存机制,你可以存储中间结果。当下次遇到相同的输入时,系统可以直接返回缓存的结果,完全绕过模型调用,从而大幅降低成本和延迟。
智能批处理 (Batching):并非所有任务都需要立即响应。对于课程质量报告生成、用户反馈分析等非实时性任务,你可以设计工作流来智能地聚合一批相似的请求,然后通过一次模型调用进行“批量处理”,而不是为每个请求都单独调用一次。这能在成本和响应时间之间找到一个更优的平衡点。
3.5 模式五:人机协作(HITL)
说明: 设计的所有工作流都是全自动的。然而,在现实世界中,将所有决策权完全交给 AI 存在风险,尤其是在处理模糊不清的教学概念或高价值的课程内容时。人机协作模式不再追求完全的自动化,而是有意地在工作流中设计一个或多个“暂停节点”,将控制权交还给人类,由人类进行决策、审批或质量把关后,再将任务交还给工作流继续执行。这是一种构建可信、安全 AI 系统的关键模式。
适用:高风险操作、概念争议、关键发布审批。
做法:在工作流中显式“暂停”,等待人类确认后继续。

/**
* 模式五:人机协作(HITL)—「Human as a Tool」的 Spring AI(通义 OpenAI 兼容)等价实现。
* <p>
* 与 Python AgentScope 示例一致的两段式管线:
* <ol>
* <li>疑难点分析师:对课程摘录给出一条修改建议;</li>
* <li>内容改写器:带 {@code ask_human_decision} 工具,由模型自主决定是否先向人类请示再定稿。</li>
* </ol>
* <p>
* 运行前:配置 {@code DASHSCOPE_API_KEY}(或 {@code PROMPT_DEBUG_API_KEY})。<br>
* 人类工具行为:
* <ul>
* <li>推荐:设 {@code HITL_HUMAN_REPLY=...} 模拟专家答复(CI / 无终端场景);</li>
* <li>本地演示:不设该变量且存在 {@link System#console()} 时,会在控制台阻塞读取一行作为专家意见。</li>
* </ul>
* 可选:{@code HITL_SUGGEST_MODEL}(默认 qwen-plus)、{@code HITL_REWRITE_MODEL}(默认 qwen-max)。
*
* @see com.baoma.ai.debug.PromptDebugPlaygroundTest#buildOpenAiApi 同源 URL 处理逻辑(本类内复制最小子集,避免测试间耦合)
*/
class CourseHitlHumanAsToolSpringAiTest {
private static final String COURSE =
"在Python中,装饰器本质上是一个接收函数作为参数并返回一个新函数的函数...";
@Test
@DisplayName("HITL:分析师建议 + 改写器可选 ask_human_decision 工具定稿")
void runHitlCourseReviewPipeline() {
String apiKey = firstNonBlank(
System.getenv("PROMPT_DEBUG_API_KEY"),
System.getenv("DASHSCOPE_API_KEY")
);
Assumptions.assumeTrue(apiKey != null && !apiKey.isBlank(),
"请配置 DASHSCOPE_API_KEY 或 PROMPT_DEBUG_API_KEY 后重跑");
String baseUrl = firstNonBlank(
System.getenv("PROMPT_DEBUG_BASE_URL"),
System.getenv("BASE_URL"),
"https://dashscope.aliyuncs.com/compatible-mode"
);
String suggestModel = firstNonBlank(System.getenv("HITL_SUGGEST_MODEL"), "qwen-plus");
String rewriteModel = firstNonBlank(System.getenv("HITL_REWRITE_MODEL"), "qwen-max");
ChatClient suggester = buildChatClient(baseUrl, apiKey, suggestModel, 0.3);
String suggestion = suggester.prompt()
.system("""
你是一名资深教学设计师。请找出课程中对初学者可能最难理解的一个概念,
并提供一个更通俗易懂的解释作为修改建议。只输出建议正文,不要前缀标题。""")
.user(COURSE)
.call()
.content();
Assertions.assertNotNull(suggestion);
Assertions.assertFalse(suggestion.isBlank(), "分析师未返回建议");
System.out.println("=== AI 建议 ===");
System.out.println(suggestion);
HumanExpertTools humanTools = new HumanExpertTools();
var toolProvider = MethodToolCallbackProvider.builder().toolObjects(humanTools).build();
ChatClient rewriter = buildChatClient(baseUrl, apiKey, rewriteModel, 0.2);
String task = """
下面是课程摘录与 AI 的修改建议。根据系统提示完成最终修改:
[课程内容]
%s
[AI 建议]
%s
""".formatted(COURSE, suggestion);
String finalText = rewriter.prompt()
.system("""
你是课程内容改写器。基于提供的 AI 建议完成最终修改。
- 若你有把握,请直接完成修改并给出确认信息;
- 若存在不确定、歧义或高风险,请调用工具 ask_human_decision 先向人类专家请示,
再据此完成修改;
- 在最终结果中简要说明是否咨询了人类及原因。""")
.user(task)
.toolCallbacks(toolProvider)
.call()
.content();
System.out.println("=== HITL 最终输出 ===");
System.out.println(finalText);
Assertions.assertFalse(finalText == null || finalText.isBlank(), "改写器未返回内容");
}
/**
* 将人类介入封装为 Spring AI 可调用的工具(对应 Python {@code ask_human_decision})。
*/
static final class HumanExpertTools {
@Tool(
name = "ask_human_decision",
description = "向人类专家征求决策或意见。当比喻是否恰当、术语取舍、合规风险等无法自决时调用。"
)
public String askHumanDecision(String question) {
String simulated = firstNonBlank(System.getenv("HITL_HUMAN_REPLY"));
if (simulated != null) {
return simulated;
}
Console console = System.console();
if (console != null) {
console.printf("%n[教学专家] 模型提问:%n%s%n请输入您的意见(单行):%n", question);
String line = console.readLine();
return line == null || line.isBlank() ? "(专家未补充,请模型在保守策略下自行定稿)" : line;
}
return "(无控制台且未设置 HITL_HUMAN_REPLY;请模型在保守策略下完成修改并注明未获实时人工输入)";
}
}
private static ChatClient buildChatClient(String baseUrl, String apiKey, String model, double temperature) {
OpenAiApi api = buildOpenAiApi(baseUrl, apiKey);
OpenAiChatOptions options = OpenAiChatOptions.builder().model(model).temperature(temperature).build();
OpenAiChatModel chatModel = OpenAiChatModel.builder().openAiApi(api).defaultOptions(options).build();
return ChatClient.create(chatModel);
}
private static OpenAiApi buildOpenAiApi(String baseUrl, String apiKey) {
String b = (baseUrl == null || baseUrl.isBlank())
? "https://dashscope.aliyuncs.com/compatible-mode"
: baseUrl.trim().replaceAll("/+$", "");
boolean isDashScopeCompatible = b.contains("dashscope.aliyuncs.com") && b.contains("compatible-mode");
OpenAiApi.Builder apiBuilder = OpenAiApi.builder().apiKey(apiKey);
if (isDashScopeCompatible && b.endsWith("/compatible-mode/v1")) {
apiBuilder.baseUrl(b).completionsPath("/chat/completions");
} else {
apiBuilder.baseUrl(b);
}
return apiBuilder.build();
}
private static String firstNonBlank(String... values) {
if (values == null) {
return null;
}
for (String v : values) {
if (v != null && !v.isBlank()) {
return v.trim();
}
}
return null;
}
}
常见的应用场景有:
- 处理模糊需求:当需求不明确时(如“让课程更有趣”),由 AI 提供多个教学设计方案,人类做出选择。
- 高价值操作审批:在执行任何涉及课程内容发布、删除旧版本等操作前,必须由课程负责人进行审批。
- 关键产出质量审核:在“混合专家”生成一份重要的课程大纲初稿后,工作流的最后一步应是将其发送给教学总监进行最终审核,而不是直接投入开发。
局限性
引入人类会显著降低工作流的自动化程度和执行速度。因此,它不适用于追求高吞吐量和毫秒级响应的全自动化场景。HITL 节点的设计需要精心考虑,只在绝对必要的环节介入,避免过多的人工干预拖慢整个流程。
如何快速上手接入
你无需从零开始实现这些复杂的模式。业界已经有成熟的框架来帮助你构建和管理 Agent 工作流,也内置了异常处理和状态管理工具。
代码框架:AgentScope-java、LangGraph 等库允许你用 JAVA、Python 代码灵活地定义节点和边,构建任意复杂的图结构工作流,提供了最高的定制化能力。
可视化编排平台:阿里云百炼、Dify 等低代码/无代码平台,允许你通过拖拽组件、连接线条的方式,像绘制流程图一样构建工作流。这极大地降低了开发门槛,适合快速原型验证和业务流程相对固定的场景。
6. 总结
记住一个核心原则:没有“最好”的模式,只有“最适合”的模式。你的选择应该由任务的内在属性决定,例如任务的复杂度、子任务间的依赖关系、对成本和效率的要求,以及对结果质量和风险的容忍度。