ACP大模型应用开发之构建工作流:五种编排模式应用的工作流汇总学习

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)

说明:为了克服流水线的僵化,你需要引入决策能力。分支选择模式的核心是在工作流的开始或关键节点设置一个“路由器”或“调度中心”。这个决策节点会分析输入(例如,用户的审阅要求),然后像一个交通警察一样,将任务引导到不同的、预设好的处理路径(即不同的流水线或专家)上去。

适用:同一入口,多条处理路径。
关键点:先做结构化路由,再进入子流程。

image.png

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或工具)同时处理,最后再将所有结果汇集起来,形成最终的输出。

适用:子任务互不依赖,目标是缩短总耗时。
示例:代码、事实、教学法、风格四路并行,再聚合。

image.png

@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 的做法是,让多个不同的大语言模型同时处理同一个任务,然后由一个聚合模型对所有输出进行综合、分析和融合,从而产生一个远超任何单个模型水平的最终结果。

适用:高价值场景,优先质量与鲁棒性。
做法:多模型并行提案 + 聚合模型融合。

image.png

@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 将参与的模型分为两类角色:

    1. 提议者(Proposers):多个不同的模型并行处理同一任务,各自生成响应。这些模型可能在某些方面表现出色(如逻辑推理、创意表达、事实准确性等)。
    1. 聚合器(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 更卓越的输出质量。


image.png

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 系统的关键模式。

适用:高风险操作、概念争议、关键发布审批。
做法:在工作流中显式“暂停”,等待人类确认后继续。

image.png
/**
 * 模式五:人机协作(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. 总结

记住一个核心原则:没有“最好”的模式,只有“最适合”的模式。你的选择应该由任务的内在属性决定,例如任务的复杂度、子任务间的依赖关系、对成本和效率的要求,以及对结果质量和风险的容忍度。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容