news 2026/10/14 11:37:02

复合AI系统:从单模型到多组件协同的工程实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
复合AI系统:从单模型到多组件协同的工程实践

这周我把一门AI系统方向研究生课程的CS329Z第一讲阅读材料从头到尾啃了两遍。三篇文章里领头的就是那篇在圈子里流传了很久的Compound AI Systems,另外两篇一篇讲LLM应用走向生产时的工程挑战,一篇讲系统评估与可观测性。读完之后最大的感受是:AI开发的重心,正在从“怎么训出一个更强的大模型”整体转向“怎么把模型、检索、工具、评估这些零件组装成一套可靠运转的系统”。

这个转向对一线开发者的影响非常直接。如果你正在做RAG、Agent、多工具编排,或者只是好奇“一个普通模型加一套好系统能不能打过一个大参数模型”,这三篇材料基本就是为你的问题准备的。这篇文章我会用实战视角把三篇材料拆开揉碎,讲清楚每篇的核心论点、它们之间的逻辑关系,以及我读完以后在项目里实际验证过的一些结论。

1. 这周阅读材料到底在讨论什么

1.1 第一篇:Compound AI Systems——一切讨论的总纲

先把第一篇放在最前面讲,因为它是整个第一讲的总纲。这篇材料给了一个非常朴素的定义:一个Compound AI System,是为了完成一个AI任务,把多个组件组合起来的系统。组件可以是模型本身,也可以是检索器、工具、评估器,甚至是人的反馈。整篇材料要论证的核心论点是:与其花巨大成本训练一个能解决所有问题的“超级模型”,不如花相对较小的成本把现有模型、检索器、工具和评估逻辑组合起来,做出一个行为可靠、成本可控、效果更好的整体系统。

这个概念在2023年之后已经被反复验证。你想想自己实际用过的AI应用,有哪个是只靠调用一个大模型接口就能交付的?一个能查资料、能调用工具、能记住前面对话、能在出错时自我修正的助手,背后至少站着五六个组件的协同。用文章里的话说:真正改变AI应用天花板的关键,正在从“模型能力”迁移到“系统能力”。

提示:读这篇材料时不要只盯着“复合”两个字。它的重点不是把组件堆在一起,而是强调“为了完成一个AI任务”这个目标约束。没有明确任务边界的复合系统,很快就会退化成一个调试地狱。

1.2 第二篇:把LLM放进生产环境,难点到底在哪

第二篇阅读材料讲的是LLM应用工程化过程中那些课本里不会写的现实约束。它开篇就抛出一个让很多开发者头疼的问题:同一套Prompt,在离线测试的时候效果很好,上线之后生产流量一进来,输出质量立刻肉眼可见地下降。为什么?因为离线测试只验证了模型单点能力,而生产环境里多的是上下文干扰、组件竞态、外部依赖抖动、用户输入边界模糊这些综合因素。

这篇文章更像一张“工程挑战地图”。它把LLM应用上线要面对的问题拆成几个维度:延迟预算、成本上限、上下文窗口管理、外部API的不可靠性、用户反馈的闭环周期,以及模型版本频繁更新带来的回归风险。每一个维度单独看都有成熟方案,但它们放在同一个系统里就会互相拉扯。比如你为了压低延迟给检索器加缓存,结果用户输入稍微变形,缓存命中率掉了一半,回答质量又跟着降了。

我读第二篇时最大的收获,是它把“模型问题”和“系统问题”做了清晰切分。模型问题靠换模型、调Prompt解决,系统问题靠架构设计解决。如果混淆这两类问题,就会出现“调了一周Prompt,最后发现是上游数据源字段对不上”这种低效排障。

1.3 第三篇:评估与监控,是复合系统最容易被跳过的部分

第三篇材料把目光聚焦在评估和可观测性上。它的核心观点其实很短:复合AI系统的行为是由多个组件共同决定的,所以任何单点评估都无法反映真实整体效果。你不能只测LLM生成得好不好,你要测检索器有没有把正确文档排到前面、路由规则有没有把问题分到正确的处理器、工具调用有没有在正确的时机触发,以及最终答案有没有真正解决用户的问题。

这篇文章还提出了一个很精准的分类:按“组件级”和“系统级”两个粒度分别建立指标体系。组件级指标回答“每个零件工作是否正常”,系统级指标回答“整台机器是否完成使命”。两者缺一不可,而且必须形成数据闭环。没有系统级指标,你优化某个组件就可能是自嗨;没有组件级指标,系统级出问题时你根本定位不到是哪个零件在拖后腿。

读到第三篇的时候,我意识到这三篇材料其实是一条完整链路:第一篇告诉你为什么要做复合AI系统,第二篇告诉你做的时候要面对哪些工程现实,第三篇告诉你做完以后怎么证明它真的可靠。三篇合在一起,就是一套从设计到交付的方法论。

2. 深度精讲:Compound AI Systems的四个关键论点

2.1 为什么“模型”退后,“系统”向前

Compound AI Systems这篇文章最有冲击力的地方,不是它发明了什么新概念,而是它把“模型本位”这个隐含假设翻了个面。过去的AI产品研发思路基本是:训练一个更强模型,然后所有能力都从这个模型身上长出来。但文章指出,当模型能力提升到一定程度后,继续在“让模型变强”这条路上投入,边际收益会显著递减,而系统层面的优化还有大量空间可挖。

文章里列举了几个实际案例。比如某个复杂的多步骤推理任务,单独用一个很大的模型硬跑,效果可能只有中等水平,而且推理成本高、延迟长;但把它拆成“规划模型+执行模型+验证模型”的复合结构,每一步用一个小模型,整体效果反而更稳。原因很简单:复杂任务被分解后,每个子任务的评估标准明确,歧义减少,而且可以在每一步插入约束和纠正逻辑。

这一点对我的启发很大。过去我总习惯把Prompt写到“一个提示词塞进所有上下文”,指望模型一步到位;现在会先问自己:这个任务能不能拆?中间需不需要外部知识?如果第一步结果错了,后面能不能发现并修正?这些问题一旦进入设计流程,系统的架构形态就会自然走向复合。

2.2 组件化思维:把模型看成零件而不是神像

文章把复合系统的组件分成几类,每一类都有明确职责。模型组件负责生成和推理,是系统中的“执行器官”;检索组件负责从外部数据源获取相关信息,是“记忆器官”;路由组件负责判断当前该用哪条处理路径,是“决策器官”;工具组件负责与外部世界交互,是“手脚”;评估组件负责对输出质量进行检测,是“免疫系统”。

组件化思维最直接的好处是“可替换性”。如果你把整个应用写成一个巨大的Prompt,那当模型版本升级或者业务需求变化时,你只能整体重构;但如果你定义了清晰的组件接口,替换一个模型组件、换一个检索后端,都只是局部改动。我见过一些团队把“组件化”理解为“多写几个函数”,其实真正的关键是每个组件要有独立的输入输出合约和独立的测试用例。

提示:接口合约不要只定义输入输出格式,还要定义非功能约定,比如超时上限、失败重试策略、上下文预算。否则组件拼起来之后,光是“某个环节超时拖死整个链路”的问题就够你排查一整周。

2.3 三个高频交互模式:RAG、路由、Agent循环

这篇文章虽然没有用代码实现某个系统,但它对交互模式的归纳非常实用。我读完以后把它们整理成三种常见范式,实际开发中70%以上的应用都能套进这三类框架。

第一种是检索增强生成(RAG),适合知识密集型任务,比如客服问答、资料整理、辅助写作。核心流程是:先根据用户问题检索相关内容,再把内容和问题一起交给模型生成答案。做RAG的难点不在“检索+生成”这个流程本身,而在如何判断检索到的内容是否相关、如果检索结果为空该怎么兜底、答案里的信息哪些来自检索内容哪些来自模型幻觉。

第二种是路由分发,适合任务类型多样但每种类型有明确处理方案的应用。核心流程是:先由一个轻量分类器判断请求类型,再分发给不同的专业处理链路。路由的难点在于分类粒度的把握,粒度太粗等于没分,粒度太细每个桶的训练样本都不够。我自己的经验是,路由层先处理“必须区分的少数边界场景”,其余全部走默认链路,比一开始就设计七八条分支要靠谱得多。

第三种是Agent循环,适合需要多步推理和外部工具调用的开放任务。核心流程是模型提出行动意图、工具执行、结果反馈给模型、模型继续决策,直到任务完成。Agent循环是所有模式里最难稳定的,因为它每一步都依赖前一步结果,错误会累积,必须设计“主动验证+提前终止”的机制,否则一个看似聪明的Agent会在用户等待时无限循环。

2.4 在“最强大脑”和“理性调度”之间做选择

这篇阅读材料里有一句话我印象很深:一个由中等能力模型组成的精心设计系统,可以在很多任务上超过一个单独的巨大模型,同时成本降低数倍。这句话不是鼓励大家放弃大模型,而是提醒我们:模型不是竞争力本身,模型在系统里发挥什么作用才是。

做这个判断有一个比较实用的决策标准。如果任务是一步到位的,比如翻译、改写、抽取关键词,直接使用大模型可能最简单有效,不需要复合;但如果任务需要外部知识更新、需要多步骤执行、需要对结果进行校验纠错,或者对成本和延迟有硬约束,那就应该认真考虑复合系统。尤其在生产环境里,“单个大模型”通常意味着“把一切不可控因素塞进一个黑盒”,而“复合系统”则意味着“把不可控因素拆成多个可监控、可干预的模块”。

我在这门课的讨论里看到有人问:那到底什么时候才需要自己训练模型?答案很直接:当你已经用复合系统的思路把所有能调的都调过一遍,仍然发现瓶颈在模型本身的参数量或者领域知识上,那时才值得去动训练的念头。绝大多数业务场景,连系统优化的第一步都还没走完。

3. 从论文到代码:搭建一个最小可用的复合AI系统

3.1 先定一个具体场景:带知识库的问答助手

光是讲概念容易飘,这一节我直接演示一个最简复合AI系统的搭建过程。场景是一个支持知识库问答的助手:用户问问题,系统先从本地知识库检索相关片段,再由生成模型基于检索结果作答。这个系统包含三个核心组件:路由组件、检索引擎、生成器,外加一个评估回调函数。整体流程不难,但它能完整呈现复合系统的基本骨架。

在写代码之前,我先定义每个组件的接口。路由组件的输入是用户字符串,输出是一个路径枚举值,决定走“知识库问答”还是“直接对话”。检索引擎的输入是问题字符串,输出是一个文档片段列表,每条带相关性分数。生成器的输入是问题加上检索到的片段,输出是最终回答。评估函数的输入是问题、检索片段、最终回答三件套,输出一个质量评分和一句简短诊断。

接口定义清楚是这一步最关键的地方。很多人在搭建类似系统时喜欢把所有逻辑写在一个大函数里,刚开始百来行挺爽,等到要加监控、加缓存、换检索后端的时候,就发现处处都是硬编码的依赖,改一处牵连一片。接口合约就是给未来的修改留出口。

3.2 先搭路由和检索,再把生成接上来

接下来我给出核心代码。这里不做任何复杂工程化,只用最直白的方式展示每个组件的独立逻辑。

# components.py # 一个最小可用的复合AI系统骨架示例 from dataclasses import dataclass from typing import List, Optional # 组件一:路由组件 # 判断请求应该进入知识库问答链路还是直接闲聊链路 def route_query(query: str) -> str: # 这里用一组很简单的启发式规则,生产环境可以换成模型分类器 kb_markers = ["根据", "查一下", "找找", "文档", "知识库", "手册"] for marker in kb_markers: if marker in query: return "kb" return "chat" # 组件二:检索引擎 # 简化版:基于关键词匹配,配合一个假的知识库切片 @dataclass class RetrievedChunk: content: str score: float def retrieve(query: str, corpus: List[str], top_k: int = 2) -> List[RetrievedChunk]: # 实际项目里这里会调用向量检索或全文检索服务 # 这里用字符重合率做近似匹配 scores = [] query_clean = query.replace("根据", "").replace("知识库", "").strip() for doc in corpus: overlap = len(set(query_clean) & set(doc)) score = overlap / max(len(set(query_clean)), 1) scores.append((doc, score)) ranked = sorted(scores, key=lambda x: x[1], reverse=True) return [RetrievedChunk(doc, score) for doc, score in ranked[:top_k] if score > 0.2] # 组件三:生成器 # 这里模拟调用一个远程模型接口,实际项目替换成对应SDK即可 def generate_answer(query: str, chunks: List[RetrievedChunk]) -> str: if not chunks: return "知识库里没有找到足够相关的内容,建议换个说法再试。" context = "\n---\n".join(c.content for c in chunks) # 真实接入LLM时,把context和query拼进Prompt就完成了 prompt = f"根据以下资料回答问题。\n资料:\n{context}\n问题:{query}\n" # 这里返回模拟结果,演示系统骨架 return f"[模拟生成结果] 已结合检索内容生成回答,上下文长度为{len(prompt)}。"

这段代码故意写得非常简单,目的不是为了直接上线,而是为了展示“组件之间如何解耦”。路由不依赖检索的索引细节,检索不依赖生成器的模型版本,生成器也不关心路由是怎么决策的。每一个组件都可以单独改、单独测。

3.3 组装主线,并把评估架子搭起来

有了三个组件之后,组装逻辑只是一个透明的主流程。下一步要做的关键工作是把评估挂上去,也就是把前面第三篇阅读材料里强调的“组件级+系统级”双轨指标落到系统里。

# main.py import time import json from typing import Dict def run_compound_system(query: str, corpus: List[str]) -> Dict: # 记录每个阶段的耗时,作为可观测性原始数据 timestamps = {} t0 = time.time() route = route_query(query) timestamps["route_ms"] = round((time.time() - t0) * 1000, 2) if route == "kb": t1 = time.time() chunks = retrieve(query, corpus) timestamps["retrieve_ms"] = round((time.time() - t1) * 1000, 2) timestamps["retrieved_count"] = len(chunks) else: chunks = [] t2 = time.time() answer = generate_answer(query, chunks) timestamps["generate_ms"] = round((time.time() - t2) * 1000, 2) # 系统级输出:一次调用的完整记录 record = { "query": query, "route": route, "retrieved_chunks": [c.content for c in chunks], "answer": answer, "timings": timestamps, } # 组件级评估:如果走了知识库链路,检索结果为空就是一个值得告警的信号 if route == "kb" and len(chunks) == 0: record["warnings"] = ["retriever_empty_result"] # 系统级评估:后续可以接入一个打分模型,对answer整体质量打分 record["assessment"] = evaluate_quality(query, chunks, answer) return record def evaluate_quality(query: str, chunks: List[RetrievedChunk], answer: str) -> str: # 简化评估逻辑,真实场景可以用LLM-as-judge或规则集打分 if "[模拟生成结果]" in answer: return "pass: answered_with_context" return "review: fell_back_to_generic"

这段演示里最值得关注的不是评估函数本身,而是它揭示的“观测点设计”思路。我在record结构里同时记录了三类信息:路由结果、组件耗时与成分、系统最终输出。这些信息串起来就是一条行为轨迹,将来系统出了任何问题,都能顺着这条轨迹回放全程。

3.4 一个小实验:看看复合系统怎么“自我管理”

有了上面的骨架,我们做一个简单的实验。造一个迷你知识库,里面放两条关于“部署注意事项”的文档片段,然后输入一个包含“根据知识库部署"的需求,观察整个调用链路。

if __name__ == "__main__": corpus = [ "部署时建议先配置环境变量,再启动服务。", "启动失败时优先检查日志文件中的错误码。", ] test_queries = [ "根据知识库说说部署的建议", "你好,介绍一下你自己", ] for q in test_queries: result = run_compound_system(q, corpus) print(json.dumps(result, ensure_ascii=False, indent=2))

运行以后你会发现,第二条“闲聊”查询走了chat路径,完全没有触发检索和生成器,系统只在必要环节消耗资源。这正是复合系统的价值之一:它不是把“检索+生成+工具”这些能力永远挂载在主链路上,而是通过路由层按需调度,把延迟和成本用在最需要的地方。

4. 踩坑实录:读完材料之后在生产环境里的验证心得

4.1 上下文管理是最容易被低估的工程问题

课堂上讨论材料时,大家聊得最多的是模型能力,但我实际做项目时发现,复合系统里最经常出问题的反而是上下文管理。这里的上下文不止是“给模型的Prompt有多少字”,还包括:检索器带回来的文档片段有多少冗余、中间结果花了多少上下文额度、历史对话保留多少轮、上一轮的错误信息要不要传给下一轮。

我踩过最典型的一个坑是:把检索出的TopK个文档全部塞进上下文,以为“信息越多越安全”。结果答案质量不但没有提升,还经常被长尾碎片带偏,同时延迟上升了40%。后来我把检索结果按相关性分数做截断、只保留真正高相关的前两段,再在生成器的Prompt里加一句“如果没有足够信息,直接说明不知道”,整体准确率反而升了一截。

这个教训对应到阅读材料里,就是那句“上下文也是系统资源”的论断。复合系统里,上下文窗口像一条共享总线,模型、检索器、路由、工具返回结果全都要在它上面跑。谁占了不该占的份额,谁就把别的组件的表达能力挤掉了。设计阶段必须给每个组件分配明确的上下文预算,就像给微服务分配内存一样严肃。

提示:观察上下文使用率,不要只看Prompt总字数。要看最终生成结果里,有多少内容真的来自外部上下文,有多少是模型自己“脑补”的。后者占比过高,基本可以判断检索或提示结构出了问题。

4.2 组件测试和端到端评估缺一不可

我记得有一段时间,团队的测试重点全部放在端到端评估上,也就是拿一批标准问题跑完整链路,计算回答准确率。效果确实有提升,但得到的反馈非常粗糙:整体分数涨了,你不知道是检索变好了还是生成Prompt改对了;整体分数跌了,更不知道要去查哪一环。

后来按照第三篇材料里的思路,改成组件级和系统级双轨并行。组件级测试专门盯每个部件的输入输出指标。比如路由层的分类准确率、检索层的TopK命中率、生成层的幻觉率。系统级测试则盯最终用户体验。这样拆开以后,回归定位速度快了很多。有一次端到端分数异常下跌,组件级数据马上暴露是检索目标的索引没有同步导致的,而生成侧完全没有变化。

组件测试的写法其实不难,就是给每个组件固化一组带标准答案的测试样本。检索组件需要一套“问题-期望文档”对,路由组件需要一组“输入-期望路径”样本,评估组件也要固定金标答案。这些样本不要只选“顺风局”,必须包含边界情况:问题模糊、知识库无答案、多轮指代等等。没有这些边界样本,组件测试测了跟没测差不多。

4.3 可观测性要做到“能回放”,而不是“能报警”

很多监控体系的问题在于只做了指标监控,比如延迟升高、错误率变多,但没有保存请求级别的轨迹数据。坏消息是,复合AI系统的故障往往隐藏在高维交互里,单看延迟曲线你根本看不出是文档检索返回了垃圾,还是路由把问题分给了错误的处理链。

我现在的做法是:为每一次完整请求保存一条trace记录,包含路由决策、检索片段的具体内容、上下文窗口使用情况、模型输出原文、以及最终评估结果。平时这些数据躺着不动,一旦线上出现badcase,直接按trace把当时系统“看到的一切”完整回放。你会发现大部分问题只看一眼就能定位,比自己对着日志盲猜效率高出一个量级。

这个思路还能带来一个附加收益:积累一段时间的trace之后,就能对badcase做聚类,提炼出高频问题模式。哪类问题总是被路由错误、哪类文档总是被检索出来但没派上用场,这些模式可以直接反馈给团队调整组件参数。可观测性从此从“被动排查”变成“主动优化”的工具。

4.4 复合系统不是越“复合”越好

有了第一篇材料的背书,初学者很容易走向另一个极端:不管什么任务,都先加检索、加路由、加Agent、加反思循环,好像组件越多越先进。我见过一个内部工具项目,本来只需要一个很简单的规则判断加一次模型调用,结果技术上堆了一大堆Agent工具调用,宣称要“智能决策”。结果是调试成本、维护成本、成本预算全面上涨,效果并没有比简单方案更好。

复合系统的价值取向是“按需组合”而不是“堆砌摆设”。判断要不要让系统更复杂,有一个简单标准:新增一个组件后,能否给系统级核心指标带来可测的提升?如果答案是没有,那就先不加。给系统做“减法”是一个持续动作:每次优化时都值得问一句,哪些组件是真正不可缺少的,哪些只是让你觉得“手段很先进”。

我在实操中会定期给系统做一次组件清理:检查检索命中率低于阈值的知识库、替代掉没有触达率的工具、删除永远走不到的分支路由。清理之后,系统往往反而更稳定,因为链路短了,故障面小了,每多一个组件就多一层失败可能。阅读材料里有一句话反复强调:系统越复杂,越需要更强的纪律性来约束每个组件的行为边界。

5. 写在这篇精讲之后的一点个人体会

把这三篇阅读材料连起来读,其实是在回答一个很现实的问题:当大模型的参数规模已经不能成为绝对壁垒时,我们这些做应用的人靠什么在市场上立足?答案是靠对系统的理解。

我个人在做实际项目的过程中体会最深的一点是,掌控感变了。过去用一个超大模型直接做输出,效果好不好总有点看天吃饭的意思,出了问题除了重新调Prompt、换个更强的模型,没有太好的抓手。而采用复合系统的思路以后,系统里每一个环节都有了明确的观察点、测试用例和干预手段,我可以很清楚地知道问题出在哪里,也可以很有针对性地去修。

最后再分享一个这段时间养成的习惯:每读完一篇AI系统相关的材料,不急着记笔记,而是先想一下“这篇文章如果变成一段最小代码,我该怎么写”。动手跑过一个最简实现之后,你对文字论述的理解深度会和在段落下面画横线完全不同。CS329Z这门课第一讲的三篇材料,就是那种值得你为它们各写一遍最小代码的文本。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 11:36:32

4G显存也能跑7B大模型:llama.cpp与GGUF量化实战指南

这几年本地模型的热度一直没退,但每次看教程,开头都是“推荐配置:XX GB 显存起步”。手里只有 4G 显存老卡的玩家,很容易在第一步就被劝退。我自己就差点被劝退——从开源模型社区下载了一个 7B 级别的模型文件,双击运…

作者头像 李华
网站建设 2026/10/14 11:36:10

fast-drools-spring-boot-starter:Spring Boot 3.2+ 轻量规则引擎启动器

简介:fast-drools-spring-boot-starter 是一款面向 Spring Boot 开发者的轻量级规则引擎集成组件,专为需动态规则管理的业务系统(如风控、营销、审批流)设计,帮助 Java 中高级开发者快速落地 Drools 规则能力&#xff…

作者头像 李华
网站建设 2026/10/14 11:34:42

前端技术架构设计指南:分层、模块拆分与状态管理实战

1. 前端技术架构到底在解决什么问题前端技术架构这个词,听起来像是只有大厂架构师才需要关心的事情。但我做了十多年一线开发,带过不少中小团队的项目之后,越来越确信一件事:只要你的项目前端代码超过五千行、参与开发的人超过两个…

作者头像 李华
网站建设 2026/10/14 11:34:35

【计算机单片机毕业设计指导(内含开题报告参考)】基于单片机的婴儿床体温心率监测与定时喂奶系统设计,基于STM32的婴儿监护尿床哭泣检测与生理参数监测装置设计(032704)

文章目录20 个相关毕业设计备选题目项目研究背景摘要总体方案核心功能技术路线开题报告一、选题依据(一)研究背景(二)研究的意义(三)国内外研究现状(四)参考文献二、设计或研究内容、…

作者头像 李华
网站建设 2026/10/14 11:33:15

186个AI专家人格从零落地:分层设计、路由调度与工程实践

很多朋友看到“186个AI专家人格”的第一反应是堆砌角色设定:写一堆“你是XX领域的专家”放进提示词,以为就能让模型自动变强。实测下来完全不是这么回事。人设只是入口,真正的工程量在于角色体系怎么分层、知识边界怎么隔离、任务路由怎么判定…

作者头像 李华