ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

私人AI助手平台架构设计:从能力分层到编排调度的工程实践

私人AI助手平台架构设计:从能力分层到编排调度的工程实践

1. 从"工具堆砌"到"统一入口":私人 AI 助手平台到底在解决什么

大多数人接触 AI 的路径是这样的:先用一个网页版对话工具写文案,再换一个工具做图,遇到要处理表格的时候又去开另一个平台,代码报错了再切到某个专门补全代码的编辑器。一圈下来,浏览器标签页开了十几个,每个工具都要单独登录、单独付费、单独记提示词格式。用了一段时间你会发现,真正消耗精力的不是"AI 好不好用",而是"我到底该在哪个窗口里干这件事"。

私人 AI 助手平台要解决的就是这个割裂感。它不是一个单一的模型,也不是一个具体的应用,而是一层"聚合与调度"的中间层——把对话、文档处理、代码辅助、任务自动化这些能力收拢到一个统一的入口里,由平台来决定"这个请求该交给谁处理、用什么方式处理、结果怎么回传给你"。你可以把它理解成家里的配电箱:墙上的插座看起来都一样,但背后哪路走照明、哪路走空调、哪路带漏保,都是配电箱在管。你不需要知道电从哪来,插上就能用。

OpenClaw 这个标题下的"概览",本质上是在讲这类平台的整体设计思路。它适合几类人看:一是自己攒了一堆 AI 工具、想整合成一套工作流的独立开发者;二是在小团队里负责"把 AI 用起来"的技术负责人;三是对平台架构感兴趣、想自己搭一个类似系统的工程师。不管你是哪一类,核心问题都一样——如何让多个能力模块在一个平台里协同工作,而不是各自为政。

这里要先厘清一个常见误解:私人 AI 助手平台不等于"套壳聊天界面"。套壳只是换了个皮肤,底层还是单模型单轮对话。真正的平台级设计要处理的是路由、上下文管理、工具调用、权限隔离、成本控制这一整套问题。下面我会按"能力怎么拆、请求怎么走、上下文怎么管、工具怎么接、坑怎么避"这条线,把这类平台的骨架拆开讲。

2. 能力分层:一个私人 AI 助手平台的内部骨架

2.1 接入层、编排层、能力层、数据层各自管什么

把平台拆开看,通常分成四层,每层的职责边界要划清楚,否则后期维护会非常痛苦。

接入层负责和外界打交道:Web 界面、桌面客户端、API 网关、消息机器人回调都算这一层。它的核心任务是"把请求标准化"——不管用户是从网页来的还是从接口来的,进到平台内部都得变成同一种结构的数据包。这一层最容易被忽视的是鉴权和限流,很多人搭原型时直接裸奔,等到对外提供服务时才发现谁都能调、一调就爆。

编排层是平台的大脑,也是最能体现"平台"和"套壳"区别的地方。它决定一个请求要不要拆成多步、每步交给哪个能力模块、中间结果怎么暂存、失败了要不要重试。举个具体场景:用户说"帮我把这份周报整理成表格,再根据表格生成一段总结"。编排层要做的判断是——先调文档解析能力把周报读成结构化文本,再调数据处理能力转成表格,最后调语言模型生成总结。这三步是有依赖顺序的,不能并行,编排层得管住这个顺序。

能力层就是各种实际干活的模块:对话模型、代码补全、文档解析、图像处理、检索增强等等。每个能力模块应该是可替换的,今天用 A 模型,明天换 B 模型,编排层的逻辑不该跟着改。这就要求能力层对外暴露统一的调用契约,输入输出格式固定。

数据层管三样东西:会话历史、用户配置、以及可选的向量知识库。会话历史决定上下文能不能续上,用户配置决定个性化行为,知识库决定平台能不能回答"你自己的资料"里的问题。

层级核心职责常见失误
接入层请求标准化、鉴权、限流原型阶段不做鉴权,上线后补
编排层任务拆解、路由、重试、结果聚合把业务逻辑写死在路由里
能力层具体 AI 能力执行模块间直接互相调用,形成网状依赖
数据层会话、配置、知识库持久化会话无过期策略,存储无限膨胀

2.2 为什么"可替换"比"最强模型"更重要

新手搭平台时最容易犯的错,是把某个"当前最强"的模型硬编码进核心流程。结果模型一升级、接口一变动、价格一调整,整个平台就得跟着改。我见过一个项目,因为把某模型的特定返回字段直接透传到了前端,后来模型改了字段名,前端全线报错,排查了大半天才定位到是上游变更。

正确的做法是:能力层定义一套自己的内部数据结构,所有外部模型的返回都先转成这个内部结构,再往上层传。这样外部怎么变,内部都稳。这个思路和数据库访问要加一层 ORM 是一个道理——不是为了炫技,是为了隔离变化。

具体到实现,可以定义一个统一的响应对象,至少包含这几个字段:content(文本结果)、tool_calls(需要执行的工具调用)、usage(token 消耗)、finish_reason(结束原因)。不同模型的原始返回各写一个适配器转成这个结构。适配器是唯一需要跟着外部接口变的地方,改动范围被压缩到最小。

提示:适配器里一定要处理"模型返回格式不符合预期"的情况。真实环境里模型偶尔会返回空内容、截断内容或者格式错乱的内容,如果不做兜底,编排层会拿到一个空对象继续往下跑,最后报一个和真实原因八竿子打不着的错。

3. 请求进来之后:编排层如何决定"这一步交给谁"

3.1 意图识别不是分类问题,是路由问题

很多人一上来就想做一个"意图分类器",把用户输入分成"问答""写代码""处理文档"几类,然后按类别分发。这个思路在小规模下能用,但很快会撞墙——真实请求往往是混合意图的,比如"把这段代码里的 bug 修了,然后解释一下为什么错",它同时涉及代码修改和知识解释。

更实用的做法是基于能力的路由,而不是基于意图的分类。编排层不关心"用户想干什么",只关心"当前这一步需要什么能力"。上面那句话可以拆成两步:第一步需要"代码理解与修改"能力,第二步需要"自然语言解释"能力。每一步独立路由,互不干扰。

路由的决策依据通常有三类:显式指令(用户明确说了"用 XX 功能")、上下文推断(根据历史对话判断当前处于什么任务中)、以及默认策略(没有明确信号时走通用对话)。优先级从高到低,显式指令永远压过推断。

3.2 多步任务的中间状态怎么存

多步任务最麻烦的是中间状态。第一步的输出要作为第二步的输入,如果中间某步失败了,是整体回滚还是从失败点重试?这取决于任务是否幂等。

对于只读类操作(解析文档、检索知识库),重试是安全的,直接从头或从失败点重跑都行。对于有副作用的操作(写文件、发消息、改数据库),必须做幂等设计——要么给每个操作分配唯一 ID,重复执行时先查这个 ID 是否已处理过;要么把有副作用的操作放到最后一步,前面全是只读计算,算完了再一次性提交。

我自己的习惯是给每个任务维护一个状态机,状态至少包含:pending(待执行)、running(执行中)、partial(部分完成)、done(完成)、failed(失败)。中间状态持久化到数据层,这样即使服务重启,任务也能从断点恢复。这个设计在调试阶段特别有用——你能清楚看到任务卡在哪一步,而不是面对一个"整体失败"的黑盒。

3.3 超时、重试与降级的实际参数怎么定

超时和重试不能拍脑袋定,要根据能力模块的实际响应分布来设。通用对话类请求,首字节响应通常在几百毫秒到两秒之间,整体完成时间取决于输出长度,设 30 到 60 秒的超时比较合理。文档解析类请求,如果文件较大,可能要几分钟,超时得放宽到 5 分钟以上。

重试策略上,我一般用"指数退避 + 最大次数限制":第一次失败等 1 秒重试,第二次等 2 秒,第三次等 4 秒,最多重试 3 次。超过次数就触发降级——要么换一个备用能力模块,要么返回一个"当前繁忙,请稍后重试"的友好提示,而不是把原始错误直接抛给用户。

降级路径要提前设计好,不能等出事了临时想。比如主对话模型不可用时,降级到备用模型;备用模型也不可用时,降级到"仅返回检索到的知识库内容,不做生成"。每一级降级都保证平台还能提供部分价值,而不是彻底不可用。

4. 上下文管理:决定平台"记性"好坏的关键工程

4.1 会话窗口不是越长越好

上下文窗口是这类平台最容易被误解的地方。很多人觉得"窗口越大越好,把全部历史都塞进去",实际用下来会发现两个问题:一是成本随长度线性上涨,二是模型对超长上下文的注意力会稀释,早期的重要信息反而被淹没。

我的做法是分层管理上下文。近期对话保留完整原文,通常是最近 5 到 10 轮;中期历史做摘要压缩,把更早的对话用模型总结成一段话;长期记忆则抽取成结构化的事实条目,比如"用户偏好简洁回答""用户在做 Python 项目"这类,单独存储,需要时按相关性检索注入。

这样一套下来,实际送进模型的上下文长度能控制在合理范围,既保留了关键信息,又不会让成本和延迟失控。摘要压缩的触发时机可以按轮数(比如超过 10 轮触发一次)或按 token 数(比如超过窗口的 60% 触发)来定,后者更精确。

4.2 知识库检索与对话上下文的融合顺序

当平台接了知识库(RAG)之后,一个关键问题是:检索到的内容和对话历史,谁先谁后、怎么拼?

常见的错误做法是把检索结果直接追加到对话末尾,这样模型容易把检索内容当成"用户刚说的话",产生混淆。更稳的做法是在系统提示里明确区分区块,比如用清晰的分隔标记把"对话历史""检索到的参考资料""当前用户问题"分成三段,并在系统提示里说明每段的用途。

检索的时机也有讲究。不是每轮对话都需要检索——闲聊、追问、确认类的问题检索了反而是噪音。我的经验是做一个轻量的判断:如果当前问题和上一轮高度相关(比如只是追问细节),就复用上一轮的检索结果;如果是全新话题,才触发新检索。这个判断可以用简单的关键词重叠度来做,不必上模型,省时省力。

4.3 会话持久化的存储选型与清理策略

会话数据的特点是"写多读少、近期热远期冷"。选型上,如果只是单机部署,SQLite 完全够用,别一上来就上分布式数据库,运维成本不划算。如果是多实例部署,需要共享会话状态,那就得用支持并发写的存储,关系型数据库或者带持久化的键值存储都行。

清理策略必须提前定。我一般设两级:活跃会话保留 30 天,超过 30 天未访问的会话归档到冷存储或直接删除;归档数据再保留 90 天后彻底清除。这个策略要写进配置,不能硬编码,方便按实际合规要求调整。

注意:会话里可能包含用户粘贴的敏感信息。如果平台要长期存储会话,务必在文档里明确告知用户数据保留策略,并提供手动删除入口。这不是可选项,是基本要求。

5. 工具调用:让平台从"会聊天"变成"能干活"

5.1 工具描述写得好不好,直接决定调用成功率

工具调用(function calling / tool use)是私人 AI 助手平台的核心能力。模型能不能正确调用一个工具,很大程度上取决于工具描述写得清不清楚。

一个合格的工具有三个要素:名称要语义明确,get_weather比gw好一万倍;描述要说清楚"什么时候用、什么时候不用",而不只是"这个工具干什么";参数要给出类型、是否必填、以及取值范围或示例。

我踩过的一个坑是:工具描述里只写了"查询天气",没写"仅支持城市名,不支持经纬度"。结果模型传了经纬度进来,工具直接报错。后来在描述里补了一句"参数必须是城市中文名,例如'北京'",调用成功率立刻上去了。工具描述本质上是写给模型看的文档,得按"模型会怎么误解"来写。

5.2 参数校验与失败回传的正确姿势

模型生成的参数不可信,必须校验。校验分两层:格式校验(类型对不对、必填项有没有)和业务校验(值合不合法,比如日期不能是未来、ID 必须存在)。

校验失败时,不要直接抛异常中断整个流程。更好的做法是把错误信息结构化后回传给模型,让它自己修正参数重试。比如返回{"error": "city 参数不能为空,请提供城市名"},模型看到后通常会重新生成一个带正确参数的调用。这个"失败—回传—重试"的循环一般设 2 到 3 次上限,避免模型陷入死循环。

5.3 危险操作的确认机制怎么设计

有些工具是有副作用的:删文件、发邮件、改配置。这类工具绝不能让它"静默执行"。我的做法是给工具加一个requires_confirmation标记,带这个标记的工具在真正执行前,先把"即将执行的操作"展示给用户确认,用户点了确认才继续。

确认信息要具体,不能只说"即将执行删除操作",而要说"即将删除文件 report_2024.csv,此操作不可撤销"。信息越具体,用户越能做出正确判断。这个机制看起来增加了交互步骤,但能避免大量误操作,长期看是省事的。

6. 部署与成本:把平台跑起来之后才会遇到的现实问题

6.1 本地部署还是云端托管,判断依据是什么

这个选择没有标准答案,取决于三个因素:数据敏感度、使用规模、以及你的运维能力。

数据敏感度高、不允许出本地的场景,只能本地部署。本地部署的好处是数据可控,代价是硬件成本和你得自己维护。使用规模小(比如就自己或几个人用)时,本地部署一台普通机器就能跑,没必要上云。使用规模大、需要弹性扩容时,云端托管更合适,但要接受数据经过第三方这个前提。

一个折中方案是混合:敏感数据相关的处理放本地,通用对话走云端。这要求平台的能力层支持"按能力指定执行位置",编排层根据请求内容决定路由到本地还是云端。这个设计复杂度高一些,但灵活度也高。

6.2 token 成本失控的三个常见原因

成本失控通常不是单一原因,而是几个小问题叠加。

第一是上下文无节制增长。前面讲过分层管理,如果没做,每轮对话都把全部历史塞进去,成本会随对话轮数平方级上涨。

第二是重试没有上限。模型偶尔抽风返回空内容,如果代码里写的是"while 没结果就重试",遇到持续失败就会疯狂烧 token。重试必须有硬上限。

第三是工具调用结果全量回传。有些工具返回的数据很大(比如一次检索返回几十条记录),如果全量塞回模型,token 消耗会非常夸张。正确做法是先在工具侧做截断或摘要,只把最相关的几条回传。

我一般会在平台里加一个成本监控面板,按天统计 token 消耗,设一个阈值告警。这样异常增长能第一时间发现,而不是月底看账单才傻眼。

6.3 日志与可观测性:出问题时你能看到什么

平台跑起来之后,最怕的是"出问题了但不知道问题在哪"。可观测性要覆盖三个层面:请求级日志(每个请求的输入、路由决策、各步耗时、最终输出)、能力级指标(每个能力模块的调用次数、成功率、平均延迟)、错误聚合(同类错误归并,避免被海量重复日志淹没)。

请求级日志里,我特别建议记录"路由决策的理由"。比如日志里写"路由到代码能力,因为检测到代码块标记",这样排查时能快速判断是路由错了还是能力执行错了。没有这个信息,你只能看到"结果不对",但不知道是哪一环出的问题。

日志的保留周期和会话数据类似,也要有清理策略。全量日志保留 7 到 14 天用于排查,聚合后的指标数据可以保留更久用于趋势分析。

7. 我在搭这类平台时踩过的几个真实坑

第一个坑是过早抽象。一开始就想着"要支持多种模型、多种存储、多种部署方式",结果接口设计得极其复杂,实际只用了其中一种。后来我改成"先跑通一条最短路径,等真的需要第二种方案时再抽象",代码量少了一半,可维护性反而更好。抽象是为了应对已经出现的变化,不是为了应对想象中的变化。

第二个坑是忽视冷启动。本地部署的模型第一次加载要几十秒,如果平台没有预热机制,第一个请求的用户会等到怀疑人生。解决办法是服务启动时先跑一个空请求把模型加载进内存,或者用一个定时任务保持模型常驻。

第三个坑是错误信息太技术化。早期版本里,模型调用失败时直接把原始错误抛给用户,用户看到一堆堆栈信息完全不知道该怎么办。后来改成"当前服务繁忙,请稍后重试,如持续失败请联系管理员",同时在后台日志里保留完整错误。用户体验和排查效率两头都照顾到了。

第四个坑是配置散落各处。模型名、超时时间、重试次数这些参数一开始硬编码在各个模块里,改一个参数要翻好几个文件。后来统一收拢到一个配置文件,按环境(开发/生产)分节,改配置不用动代码,省了大量时间。

8. 从概览到落地:给不同起点的读者几条实在建议

如果你只是想自己用,别一上来就搭平台。先用现成工具把需求跑清楚,明确自己到底高频用哪些能力,再决定要不要整合。很多时候你会发现,两三个工具组合起来就够用了,搭平台的投入产出比并不高。

如果你是要在团队里推这套东西,先解决"统一入口"这一个问题就够了。把大家常用的能力收拢到一个界面,统一鉴权和计费,这一步的价值就已经很大。编排、工具调用这些可以后续迭代,不要想着一次到位。

如果你是想深入平台架构,建议从编排层入手。编排层是这类平台最有技术含量、也最能体现设计功力的部分。先把单步路由做扎实,再逐步加多步编排、工具调用、降级策略。每加一层能力,都要配套相应的可观测性和错误处理,否则系统会越来越难维护。

这类平台的演进方向,我个人判断是"能力越来越强,但入口越来越简单"。用户最终感知到的应该是一个"什么都能问、什么都能干"的助手,而背后有多少模块、多少模型、多少层调度,用户不需要知道。把复杂性留给自己,把简单留给用户,这是所有工具类产品的共同追求。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进