
1. 为什么现在谈 AI Native 架构正当时过去两年我参与过三个从零起步的 AI 项目也接手过两个“传统系统加挂 AI 模块”的改造项目。这两类项目的体感差异非常大前者像在高速公路上边跑边换轮胎后者像给一栋老楼加装电梯——结构上处处受限最后往往只能做到“能用”离“好用”差得很远。这也是我越来越坚定一个判断的原因AI Native 不是把 AI 塞进系统而是让系统从第一天起就围绕 AI 的能力边界和运行特征来设计。所谓 AI Native 架构核心就一句话把模型推理、上下文管理、工具调用、记忆与反馈回路当作系统的一等公民而不是把它们当成某个业务模块里的一个函数调用。它解决的问题很具体——传统架构里业务逻辑是确定的、状态是显式的、延迟是可预测的而 AI 系统里输出是概率性的、上下文是动态膨胀的、延迟是波动的、成本是按 token 计费的。这两套世界观硬拼在一起就会出现提示词散落在业务代码里、会话状态和数据库事务打架、模型换了要改十几个文件这类典型症状。这篇文章适合三类人看一是准备从零搭一个 AI 应用的开发者二是正在做传统系统 AI 化改造的架构师三是对 Agent、RAG、LLM 编排感兴趣但还没动手的工程师。我会把架构分层、核心模块、实操步骤、参数取舍和踩过的坑都摊开讲尽量做到你读完能直接照着搭一个最小可用的骨架。2. AI Native 架构的整体分层与设计思路2.1 从“业务为中心”到“能力为中心”的思维切换传统分层架构通常是 Controller → Service → DAO业务逻辑是主干数据是支撑。AI Native 架构里我更倾向于把系统看成一条能力流水线输入进来先经过理解层意图识别、实体抽取再进入编排层决定是直接回答、检索增强还是调用工具然后到执行层模型推理、工具执行最后经过后处理层校验、格式化、落库。业务逻辑不再是一条写死的 if-else 链而是编排层根据上下文动态决定的路径。这个切换带来的最大好处是可替换性。当模型从 A 换成 B或者从纯对话换成带工具调用的 Agent你只需要改编排层的策略配置而不是翻遍整个代码库。我实测过一个项目把底层模型从一个小参数模型换成另一个厂商的大模型改动量控制在两个配置文件加一个适配器类半天完成灰度。2.2 四层架构的职责划分我习惯把 AI Native 系统拆成四层每层职责单一、边界清晰层级核心职责典型组件不该做的事接入层协议适配、鉴权、限流API 网关、SSE 通道不碰业务逻辑和提示词编排层意图路由、流程控制、上下文组装编排引擎、状态机不直接调模型 SDK能力层模型推理、工具执行、检索模型适配器、工具注册表、向量库不感知具体业务场景数据层会话存储、向量存储、审计日志关系库、向量库、对象存储不做业务判断这么分的原因很实际能力层是最容易变的模型版本、工具接口、检索策略几乎每周都在动而数据层的 schema 一旦定下来就尽量别动。把易变的部分隔离在上层把稳定的部分沉在下层是控制维护成本的关键。我见过太多项目把提示词硬编码在 Service 里结果一次提示词优化要发一次全量版本回滚还特别麻烦。2.3 为什么不用微服务一把梭有朋友会问那是不是每个能力都拆成微服务我的经验是初期不要。AI 系统的调用链本来就长一次请求可能涉及意图识别、检索、重排、生成、校验五六个步骤如果每步都是跨网络调用光是网络抖动和序列化开销就能把 P99 延迟推到不可接受。我建议初期用模块化单体把编排层和能力层放在同一个进程里用清晰的接口隔离等某个能力真的成为瓶颈比如向量检索 QPS 打满再单独拆出去。这个判断标准很简单当某个模块的扩容需求和主进程不一致时才拆。3. 核心模块的细节拆解与实操要点3.1 模型适配器把模型当成可插拔的零件模型适配器是整个架构里最值得先写好的东西。它的职责是屏蔽不同模型厂商的 API 差异对上暴露统一的接口。我通常定义三个方法chat(messages, tools)、embed(texts)、count_tokens(text)。前两个好理解第三个经常被忽略但它直接决定了你的上下文裁剪策略和成本预估。写适配器时有几个坑要避开。第一不要假设所有模型都支持 function calling有些模型只支持纯文本这时候工具调用要靠提示词模拟适配器里要做能力探测。第二流式输出的分片格式各家不同有的按字符有的按 token有的会在最后补一个 usage 字段适配器要统一成一种事件格式再往上抛。第三错误码要归一化限流、超时、内容过滤这三类错误在上层要能区分处理不能笼统抛一个 Exception。class ModelAdapter: def __init__(self, config): self.model config[model] self.timeout config.get(timeout, 30) self.max_retries config.get(max_retries, 2) def chat(self, messages, toolsNone, streamFalse): # 统一入参格式内部做厂商差异适配 payload self._build_payload(messages, tools) for attempt in range(self.max_retries 1): try: return self._invoke(payload, stream) except RateLimitError: time.sleep(2 ** attempt) except ContentFilterError as e: return self._safe_fallback(e)3.2 上下文管理比模型选型更影响体验很多人把精力全花在选模型上结果上线后发现体验差问题往往出在上下文管理。AI Native 系统里上下文不是简单地把历史消息拼起来而是要做分层管理系统提示词稳定、长期记忆半稳定、近期对话易变、检索结果按需注入。这四类内容的生命周期完全不同混在一起管理必然出问题。我的做法是给每类内容打上标签和优先级组装上下文时按优先级填充超出预算就从低优先级开始裁剪。预算怎么算假设模型上下文窗口是 128K token我会预留 20% 给输出剩下 80% 里再留 10% 给工具返回结果实际可用于输入的约 90K。这个数字不是拍脑袋是因为工具返回的内容长度不可控留足余量能避免请求直接被拒。提示裁剪上下文时优先保留系统提示词和最近三轮对话中间的检索结果可以按相关性分数截断。千万别用简单的“保留最近 N 条”那样会丢掉关键的系统约束。3.3 工具注册与调用让模型安全地“动手”Agent 架构里工具调用是最容易出安全事故的地方。我的原则是工具必须显式注册、参数必须强校验、执行必须有沙箱。注册表里每个工具要声明名称、描述、参数 schema、超时时间和是否需要人工确认。模型返回的工具调用请求先过 schema 校验再判断权限最后才执行。参数校验这块我强烈建议用 JSON Schema 而不是手写 if-else。模型偶尔会返回缺字段或者类型不对的参数Schema 校验能在执行前就拦下来避免脏数据进到下游。对于写操作类工具比如发消息、改数据我一般会加一道确认机制模型生成调用意图后先返回给用户确认确认通过才真正执行。这个设计在早期能挡掉大量误操作。3.4 记忆与状态会话不是一条直线传统 Web 系统的会话状态通常存在 Redis 里key 是 session_idvalue 是一个扁平的对象。AI 系统的会话要复杂得多它可能有多条分支用户中途切换话题、有摘要长对话压缩、有实体槽位记住用户提到的关键信息。我一般用事件溯源的思路来存会话每次交互追加一条事件记录当前状态由事件回放得出。这样既能支持分支又方便做审计和回放调试。摘要的触发时机也有讲究。我试过按轮次触发每 10 轮压缩一次和按 token 触发超过阈值压缩实测下来按 token 触发更稳因为不同轮次的内容长度差异太大。压缩时用一个小模型做摘要成本低且够用摘要结果要保留原始事件的引用 ID方便需要时回溯细节。4. 从零搭建的完整实操流程4.1 环境准备与依赖选型假设你要搭一个最小可用的 AI Native 服务我建议的技术栈是这样Python 3.11 起步异步生态成熟Web 框架用 FastAPI原生支持异步和 SSE向量库初期用轻量的本地方案比如基于文件的索引关系库用 PostgreSQLJSONB 字段存会话事件很方便缓存用 Redis。模型侧先接一个通用对话模型加一个 embedding 模型即可。依赖安装没什么特别的但有两个细节要注意。一是锁定版本AI 生态的库更新极快不锁版本今天能跑明天就崩。二是把模型 SDK 的调用封装在适配器里业务代码不直接 import 厂商 SDK这样换厂商时改动面最小。pip install fastapi uvicorn httpx pydantic psycopg[binary] redis pip freeze requirements.txt4.2 编排引擎的最小实现编排引擎的核心是一个决策循环拿到用户输入后先判断意图再决定走哪条路径执行后判断是否需要继续循环比如工具调用后要再生成一次回答。我用状态机来实现状态包括UNDERSTAND、RETRIEVE、PLAN、ACT、RESPOND每个状态有明确的进入条件和退出条件。class Orchestrator: def run(self, session_id, user_input): ctx self.context_manager.load(session_id) ctx.append_user(user_input) state UNDERSTAND while state ! DONE: if state UNDERSTAND: intent self.understand(ctx) state RETRIEVE if intent.needs_knowledge else PLAN elif state RETRIEVE: docs self.retriever.search(ctx.last_query) ctx.inject_docs(docs) state PLAN elif state PLAN: plan self.planner.decide(ctx) state ACT if plan.has_tool_call else RESPOND elif state ACT: result self.tool_executor.run(plan.tool_call) ctx.append_tool_result(result) state PLAN # 回到规划判断是否还要继续 elif state RESPOND: answer self.generator.generate(ctx) ctx.append_assistant(answer) state DONE self.context_manager.save(session_id, ctx) return ctx.last_answer这个循环里最关键的是最大迭代次数限制。我一般设 5 次超过就强制进入 RESPOND用当前已有信息生成回答。没有这个限制模型可能在工具调用和规划之间无限循环既烧钱又拖延迟。4.3 检索增强的落地细节RAG 这块我踩过的坑最多。第一个坑是切分粒度切太碎语义不完整切太大检索不准。我的经验是按语义段落切每段控制在 300 到 500 token相邻段落保留 50 token 重叠。第二个坑是只做向量检索实测下来纯向量检索对关键词类查询效果一般我一般会加一路关键词检索两路结果做融合排序。融合排序用 RRF倒数排名融合就够了不需要上复杂的重排模型。RRF 的公式很简单每个文档的得分是它在各路检索中排名的倒数之和。这个方法的优点是不需要调参对两路检索的分数尺度不敏感实测效果稳定。检索策略适用场景优点缺点纯向量语义相似查询泛化好关键词命中差纯关键词精确术语查询准确无法处理同义混合RRF通用场景兼顾两者实现稍复杂4.4 可观测性没有日志的 AI 系统等于裸奔AI 系统的调试难度远高于传统系统因为同样的输入可能得到不同的输出。所以全链路日志是刚需。我一般记录这几类信息每次请求的完整上下文脱敏后、模型返回的原始响应、工具调用的入参和结果、每步的耗时和 token 消耗。这些数据存到关系库里用 JSONB 字段存结构化部分方便后续查询和分析。成本监控也要从第一天就做。按 token 计费的模型一次请求的成本可能从几分钱到几块钱不等不做监控很容易月底收到账单才发现异常。我的做法是在适配器层统一记录 token 用量按会话、按用户、按天聚合设一个阈值告警。5. 常见问题与排查技巧实录5.1 输出不稳定怎么排查模型输出不稳定是最常见的问题表现是同样的输入有时答得好有时答得差。排查顺序我一般是这样的先看温度参数如果设得偏高比如 0.8 以上先降到 0.2 试试再看上下文里有没有冲突信息比如检索结果和系统提示词矛盾模型会摇摆最后看提示词结构把关键约束放在开头和结尾中间放参考资料这个位置效应实测有效。还有一个隐蔽的原因是上下文超长被静默截断。有些模型在超长时会悄悄丢掉中间部分导致关键信息丢失。解决办法是在适配器里主动做 token 计数超预算就按优先级裁剪而不是依赖模型自己处理。5.2 工具调用失败的典型原因工具调用失败我整理过一张速查表覆盖了八成以上的情况现象可能原因排查方法模型不调用工具工具描述不清检查 description 是否说明用途和时机参数缺字段schema 太宽松加 required 约束参数类型错模型理解偏差在描述里给示例值调用超时工具本身慢加超时和降级重复调用循环没退出条件加最大迭代限制注意工具描述里一定要写清楚“什么时候用”和“什么时候不用”只写功能说明模型经常在不该调用的时候调用。5.3 延迟优化的几个实用手段AI 系统的延迟大头在模型推理但也不是没有优化空间。我常用的手段有流式输出让用户先看到部分结果感知延迟大幅降低并行化独立的检索和意图识别缓存高频问题的回答和 embedding 结果小模型前置用便宜快的小模型做意图识别和路由只把复杂请求交给大模型。这几个手段叠加实测能把 P95 延迟压下来一半左右。5.4 成本控制的经验成本控制的核心是分级处理。不是所有请求都需要大模型简单问答用小模型复杂推理才升级。检索结果做去重和截断别把十篇文档全塞进去。摘要用便宜模型生成用贵模型。我还会给每个用户设一个日 token 预算超了就降级到小模型或者排队避免单个用户把额度吃光。6. 我踩过的几个印象深刻的坑第一个坑是把会话状态存在内存里。早期图省事用进程内字典存会话单机测试没问题一上多实例就出现会话丢失和串号。后来改成 Redis 加数据库双写Redis 做热数据数据库做持久化才稳定下来。第二个坑是提示词版本管理混乱。提示词改了没记录出问题不知道回滚到哪版。后来我把提示词抽成独立文件用版本号管理每次改动记录变更原因和效果对比才算可控。第三个坑是忽略内容安全过滤。模型可能生成不合适的内容也可能被诱导执行危险操作。我在适配器层加了输入输出双向过滤工具执行前加权限校验虽然增加了一点延迟但这是必须的底线。第四个坑是过早优化架构。一开始就上微服务、上消息队列、上复杂的编排框架结果业务还没跑通光维护基础设施就耗掉大半精力。后来我坚持先单体跑通闭环再按瓶颈拆效率高很多。7. 后续可以这样扩展这套骨架跑通之后扩展方向其实很多。想做多 Agent 协作可以在编排层加一个 Agent 注册表让不同 Agent 负责不同领域由一个协调者分发任务。想做个性化可以在记忆层加用户画像把长期偏好注入上下文。想做离线评估可以把线上请求采样存下来定期用新模型跑一遍对比效果。这些扩展都不需要推翻现有架构因为它们都建立在清晰的分层边界之上——这也是我一开始坚持分层的原因好的架构不是预测未来而是让未来容易改。