通用Agent工程实践:四层解耦架构与七道落地关卡

发布时间:2026/6/24 11:25:02
通用Agent工程实践:四层解耦架构与七道落地关卡 1. 这不是一篇讲“AI未来”的空泛文章而是一份来自一线团队的Agent工程实录“Manus 团队在构建通用 Agent 过程中的经验总结”——这个标题里没有炫技的术语堆砌没有模糊的愿景描述只有一个非常具体的主语Manus团队、一个明确的动作构建、一个被反复验证仍具挑战性的目标通用Agent以及最珍贵的部分经验总结。我接触过太多团队从高校实验室到大厂创新组再到独立创业小队几乎所有人都在谈Agent但真正把“通用性”当硬指标来拆解、压测、迭代、推翻重来的不到十分之一。Manus团队属于那不到十分之一。他们不靠PPT讲故事靠日志、监控、用户反馈和失败用例说话。所谓“通用Agent”不是指能同时订咖啡又写周报的演示Demo而是指在未预设任务类型、未提前注入领域知识、仅凭自然语言指令就能稳定调用工具链、处理多跳推理、维持长程状态、并在结果偏差时自主诊断修正的系统能力。这背后是工程化程度的分水岭一边是“能跑通”另一边是“敢上线”。本文所有内容都锚定在这个分水岭上展开。如果你正卡在Agent从PoC走向MVP的临界点如果你的Agent在测试环境表现惊艳、一进真实用户场景就频繁失焦或工具调用错乱如果你的团队还在为“记忆该存哪”“工具该谁调度”“错误该向谁汇报”争论不休——那么这篇总结不是参考而是你接下来两周应该打印出来贴在显示器边上的操作手册。它不讲LLM原理不比模型参数只讲人怎么在算力、延迟、成本、可控性之间做取舍只讲代码、配置、日志和凌晨三点改完的第十版提示词。2. 内容整体设计与思路拆解为什么“通用”必须从架构反推而非提示词堆砌2.1 通用性的本质不是“什么都能做”而是“什么都能学得会、做得稳”Manus团队在内部复盘会上反复强调一个观点把Agent做成“万能瑞士军刀”是工程灾难的起点。他们早期版本曾尝试用一个超大提示词模板覆盖所有已知任务类型——查天气、订机票、分析Excel、生成PPT大纲、调试Python代码……结果是每个功能单独测试时准确率超92%但一旦混合使用比如用户说“先查北京明天天气再根据温度推荐三套穿搭最后把结果发给张经理”成功率断崖式跌至37%。根本原因在于这种设计把“通用性”错误地等同于“功能枚举完备性”忽略了三个底层矛盾状态耦合矛盾查天气需要实时API调用而推荐穿搭依赖本地风格库缓存两者对网络稳定性、响应超时、重试策略的要求完全不同。强行塞进同一执行流必然互相拖累。认知粒度矛盾分析Excel需要细粒度单元格操作而发邮件只需粗粒度收件人正文填充。用同一套思维链Chain-of-Thought模板驱动要么让Excel分析过度冗余要么让邮件发送缺乏必要校验。失败传播矛盾天气API超时失败本应降级为“暂无数据”却因提示词强绑定逻辑导致后续穿搭推荐直接编造温度值再污染邮件内容——错误像病毒一样跨任务传染。因此Manus团队彻底放弃“单一大脑全功能提示词”的路线转向“分层可插拔架构”。核心思想是把“通用”拆解为“可组合性”与“可适应性”两个正交维度。前者解决“如何把已有能力拼成新能力”后者解决“遇到没见过的任务如何快速学会并稳定交付”。这个转变直接决定了后续所有技术选型。2.2 架构分层四层解耦每一层都承担明确的“通用性”责任Manus团队最终落地的架构分为四层每层有清晰边界、独立演进路径和明确SLA服务等级协议层级名称核心职责“通用性”贡献关键约束L1能力原子层Capability Atom封装最小、最稳定的可执行单元如get_weather(city, date)、parse_excel(file_path, sheet_name)。每个原子有明确定义的输入Schema、输出Schema、超时阈值、重试次数、错误码映射表。提供“可组合性”基础原子越小、契约越严组合时出错概率越低。原子不可包含业务逻辑不可跨网络域如不能同时调用内部API和外部SaaS必须自带健康检查接口。L2编排引擎层Orchestration Engine接收用户原始指令解析意图→匹配可用原子→规划执行序列→注入上下文→调度执行→聚合结果→生成终态响应。核心是轻量级DAG有向无环图运行时非LLM驱动。提供“可适应性”骨架当新任务出现只需注册新原子更新意图识别规则无需改动引擎核心。引擎不参与任何语义理解不存储长期记忆所有决策基于结构化元数据原子描述、用户历史行为标签、当前会话上下文摘要。L3记忆与上下文层Memory Context Hub统一管理三类状态① 短期会话上下文5轮② 中期用户偏好如“张经理”邮箱zhangxxx.com“偏好简约风穿搭”③ 长期知识快照如公司组织架构、产品文档最新版哈希值。采用分层存储内存Cache Redis 向量DB。解耦状态管理使L1/L2专注执行避免状态污染导致的“通用”失效。所有写入必须带TTL生存时间读取需声明所需上下文类型避免过度加载向量检索仅用于知识快照匹配不用于实时推理。L4交互适配层Interaction Adapter负责将L2输出的结构化结果转换为不同终端所需的格式Web端渲染为富文本操作按钮App端转为卡片消息快捷操作语音端转为TTS友好文本语调标记。实现“通用”交付同一能力无缝适配多端避免为每个渠道重复开发逻辑。适配器无业务逻辑仅做格式转换错误时返回标准化错误码如ERR_CONTEXT_EXPIRED由L2统一处理降级。这个分层不是理论设计而是被线上事故逼出来的。一次生产事故中天气API持续超时导致L2编排引擎因等待响应而阻塞进而拖垮整个会话队列。复盘发现问题根源在于L1原子未定义超时熔断机制L2引擎又把“等待”当作正常流程。此后他们强制规定L1原子必须自带熔断开关L2引擎必须将“超时”视为一类独立错误事件触发预设降级策略如返回缓存值、切换备用API、向用户说明。这种“错误即数据”的设计哲学成为保障通用性的隐形支柱。2.3 为什么拒绝“LLM as Orchestrator”一次真实的性能测算当前主流方案中“用LLM直接做任务规划与工具调用”如ReAct、Toolformer因其简洁性广受欢迎。Manus团队也深度测试过结论是在追求通用性与稳定性的生产环境中LLM不适合作为编排中枢。这不是技术偏见而是基于三组硬数据延迟不可控性在同等硬件A10G GPU下调用开源Qwen2-7B进行单次工具选择输入用户指令可用工具列表输出JSON格式工具名参数P95延迟为842ms而L2编排引擎Rust编写执行同等逻辑P95延迟为23ms。更关键的是LLM延迟波动极大标准差±310ms而引擎延迟标准差仅±1.2ms。对于需要串联3~5个原子的复杂任务LLM编排的端到端P95延迟可能突破4秒远超用户耐心阈值1.5秒。错误不可追溯性当LLM错误选择工具如把“查航班”误判为“查天气”日志中只有输入文本和错误输出无法定位是提示词缺陷、上下文截断、还是模型固有幻觉。而L2引擎的每一步决策都有结构化日志[orchestration] intentFLIGHT_SEARCH, matched_atoms[get_flight_status, search_flights_by_route], selectedget_flight_status, reasonroute_not_specified_in_query。运维可直接关联到意图识别模型的bad case快速优化。成本不可收敛性按日均10万次任务计算若全部由LLM编排Qwen2-7B的token消耗约为1200万/天平均输入800token输出150tokenGPU资源成本约$320/天而L2引擎CPU占用率峰值15%服务器成本$15/天。节省的不仅是钱更是可预测的资源水位——这对容量规划至关重要。因此Manus团队将LLM严格限定在两个角色① L1原子内部的“智能增强模块”如parse_excel原子内嵌小型MoE模型提升表格理解精度② L4交互层的“文案润色器”将结构化结果转为自然语言。把LLM当作“专业工具里的智能螺丝刀”而非“整栋楼的承重墙”——这是他们保障通用性落地最务实的技术取舍。3. 核心细节解析与实操要点从“能用”到“敢用”的七道关卡3.1 关卡一意图识别——不用BERT微调用规则小模型混合方案通用Agent的第一道门槛是听懂用户到底想干什么。“我要查张三的报销进度”和“帮我查张三的报销进度”对人来说没区别但对机器前者是陈述句后者是祈使句隐含的执行意愿强度不同。Manus团队发现纯大模型意图识别如用ChatGLM3-6B做few-shot分类在长尾任务上F1值骤降且难以解释错误原因。他们的解法是“三层漏斗”第一层正则与关键词硬匹配Rule-based Filter覆盖高频、高确定性指令如“查.*进度” → INTENT_REIMBURSEMENT_STATUS“导出.*为.*xlsx” → INTENT_EXPORT_TO_EXCEL。这部分用DFA确定性有限自动机实现毫秒级响应零误报。他们维护了一个动态规则库运营同学可随时添加/禁用规则无需发版。第二层轻量级语义相似度Tiny-BERT Embedding FAISS对规则层未命中的指令提取其Sentence-BERTdistiluse-base-multilingual-cased-v2向量化表示在预置的127个标准意图向量库中检索Top-3相似项。关键技巧不直接取最高分而是计算Top-3的分数方差。若方差0.05如0.82, 0.81, 0.83说明语义模糊需进入第三层若方差0.15如0.91, 0.32, 0.28则直接采纳最高分项。这避免了模型在边界案例上的“自信误判”。第三层微调小模型兜底DistilRoBERTa 32分类头仅处理前两层无法决断的5%长尾case。模型在内部标注的2.3万条真实用户指令上微调特别强化了“否定意图”如“别查进度直接打钱”和“复合意图”如“先看李四的报销再对比王五的”的识别能力。上线后整体意图识别准确率从89.7%提升至96.4%且99%的case可在200ms内完成。提示他们严禁在规则层使用模糊匹配如“查.*”因为会导致“查一下天气”和“查一下我的银行卡余额”全部命中同一规则。所有规则必须包含至少两个确定性要素如“查.*报销.*进度”或“导出.*为.*xlsx”。3.2 关卡二工具调度——不是“选哪个”而是“怎么组合、何时调、失败后怎么办”意图识别只是开始真正的工程挑战在调度。Manus团队将工具调度抽象为三个子问题组合问题Composition用户指令“把销售部Q3报表发给总监并标红亏损项”需组合export_report(deptsales, quarterQ3)highlight_loss_items(file_path)send_email(todirectorxxx.com, file_path)。他们的解法是预定义组合模式库Pattern Library。例如[EXPORT] [HIGHLIGHT] [SEND]是一个标准模式L2引擎根据意图识别结果自动匹配无需LLM实时规划。模式库由资深产品经理和工程师共同梳理覆盖83%的复合任务新增模式只需配置JSON无需改代码。时序问题Sequencing并非所有组合都是线性。“先备份数据库再升级版本最后验证”是严格串行“查北京和上海的天气”是并行“如果库存100发货否则通知采购”是条件分支。Manus团队采用轻量DAG DSL领域特定语言描述时序{ type: parallel, steps: [ {atom: get_weather, params: {city: beijing}}, {atom: get_weather, params: {city: shanghai}} ] }DSL解析器用Rust编写启动时编译为高效状态机执行开销可忽略。容错问题Fault Tolerance这是区分“能用”和“敢用”的关键。他们为每个原子定义三级容错策略原子内自愈如get_weather原子内置重试最多2次 备用API当主API超时自动切至气象局公开接口编排层降级若highlight_loss_items失败L2引擎不中断流程而是记录highlight_failed:true继续执行send_email并在邮件正文末尾自动追加【注】报表亏损项标红失败详见附件原始报表用户层兜底若整个DAG失败如网络分区L2引擎立即返回结构化错误包包含error_code、suggested_action如“请稍后重试”或“点击此处手动下载报表”、estimated_recovery_time基于历史故障统计。这套容错体系让P0级任务如财务付款的端到端成功率从92.1%提升至99.97%且95%的故障无需人工介入。3.3 关卡三记忆管理——不是“存多少”而是“存什么、何时存、谁有权读”通用Agent必须记住用户说过的话、做过的事、偏好的风格否则每次对话都是“第一次见面”。但全量记忆不仅成本高昂更会引发隐私与一致性风险。Manus团队的记忆设计遵循“三权分立”原则写入权Write Authority只有L1原子在成功执行后才能向记忆层写入结构化事实。例如send_email原子执行成功后写入{type:email_sent, to:zhangxxx.com, subject:Q3报表, timestamp:2024-06-15T10:23:45Z}。禁止原子写入主观判断如“用户很着急”或未验证信息如“用户电话是138****1234”。读取权Read AuthorityL2编排引擎读取记忆时必须声明上下文作用域session_scope仅读取当前会话ID下的短期记忆默认开启user_scope读取该用户ID下的中期偏好需用户显式授权如首次使用时弹窗global_scope读取全系统共享的知识快照如公司政策文档需管理员审核发布。生命周期权Lifecycle Authority所有记忆条目强制携带TTL。短期记忆TTL30分钟会话结束后自动清理中期偏好TTL90天静默期超时自动归档知识快照TTL7天每日凌晨校验哈希值过期则触发更新流程。注意他们用Redis Streams实现会话记忆确保写入顺序与消费顺序严格一致用PostgreSQL的JSONB字段存储用户偏好支持高效的部分更新用ChromaDB管理知识快照支持语义检索但禁止在实时编排中调用——所有知识匹配必须在L2引擎调度前完成避免阻塞。3.4 关卡四工具原子化——不是“封装API”而是“定义契约、注入可观测性、预留演进接口”L1能力原子是整个架构的基石。Manus团队制定了原子开发的“铁律”违反任一条代码不予合并契约先行Contract First开发者必须先用OpenAPI 3.0规范编写原子接口定义YAML包含paths、components/schemas、x-execution-hints如timeout_ms: 3000,retryable: true,rate_limit: 100/minute。CI流水线会自动校验YAML语法、Schema完整性并生成SDK代码。可观测性内置Observability Built-in每个原子必须暴露/health返回{status:ok,latency_ms:12,error_rate_5m:0.02}和/metricsPrometheus格式含atom_execution_total{atomget_weather,statussuccess} 1245。这些指标直接接入Grafana大盘运维可实时看到每个原子的P95延迟、错误率、QPS。演进接口预留Evolution Interface原子版本号必须遵循MAJOR.MINOR.PATCH。PATCH升级如修复bug兼容所有旧调用MINOR升级如新增可选参数向后兼容MAJOR升级如改变必填参数必须并行部署新旧版本通过x-versionHeader路由并设置30天灰度期。他们甚至为每个原子配置了“废弃倒计时”在API响应Header中返回X-Deprecation-Warning: This version will be retired in 14 days。这套规范让原子平均上线周期从2周缩短至3天且上线后0次因兼容性问题导致的线上事故。3.5 关卡五提示词工程——不是“写得更长”而是“分层注入、动态裁剪、效果可量化”尽管LLM不作为编排中枢但在L1原子内部如parse_excel和L4交互层文案润色提示词质量直接影响用户体验。Manus团队摒弃了“写万字提示词”的做法转向“提示词即配置”的工程化管理分层注入Layered Injection提示词拆为三部分静态层Static Layer原子能力描述、输出格式要求如“必须返回JSON字段包括items[]、summary”存于Git仓库版本化管理上下文层Context Layer从记忆层读取的用户偏好、会话历史摘要由L2引擎在调用原子前动态注入动态层Dynamic Layer根据当前任务难度实时调整如简单查询注入请用一句话回答复杂分析注入请分三步1. 识别关键数据 2. 计算趋势 3. 给出建议。动态裁剪Dynamic Trimming为防止上下文超长他们开发了语义感知裁剪器Semantic Trimmer。不简单按token数截断而是用小型分类模型识别句子重要性如“用户说‘必须今天发’”比“天气不错”重要10倍保留所有带数字、专有名词、动词的句子对长段落用TextRank算法提取核心句。实测在保持95%关键信息的前提下平均压缩上下文长度42%。效果可量化Quantifiable Effectiveness每个提示词变体上线前必须通过A/B测试框架验证。核心指标不是“准确率”而是用户任务完成率Task Completion Rate, TCR和用户主动修正率User Correction Rate, UCR。例如优化parse_excel提示词后TCR从78%升至89%UCR从12%降至4.3%证明用户更少需要手动修改结果。3.6 关卡六安全与合规——不是“加个防火墙”而是“在每层埋入检查点”通用Agent直面用户安全不是附加功能而是架构基因。Manus团队的安全设计贯穿四层L1原子层所有原子执行前调用统一security_guard服务。该服务基于规则引擎Drools实时检查输入是否含敏感词如身份证号、银行卡号用正则模糊匹配双重校验请求是否越权如普通员工调用delete_user_account原子输出是否泄露敏感信息如Excel解析结果中自动脱敏手机号。L2编排层DAG执行前进行数据血缘扫描Data Lineage Scan。若指令涉及“导出客户名单”引擎会自动检查① 当前用户是否有该客户数据权限② 导出格式是否符合GDPR如CSV需禁用明文邮箱③ 是否触发审计日志。任一不满足流程终止并返回合规提示。L3记忆层所有写入记忆的数据自动打上privacy_level标签如P1公开P2部门内P3仅本人。读取时L2引擎必须声明所需隐私级别记忆层按策略过滤。例如user_scope读取只返回P2及以下数据。L4交互层所有生成的自然语言响应经content_moderator服务过滤。该服务融合关键词、语义模型FinBERT微调版和规则对歧视、暴力、违法内容实时拦截并提供可解释的拦截理由如“检测到地域歧视表述依据《内容安全准则》第3.2条”。这套设计让上线6个月以来0起安全事件且所有合规审计均一次性通过。3.7 关卡七监控与告警——不是“看Dashboard”而是“用异常模式反推架构弱点”Manus团队的监控体系不追求“大屏好看”而追求“故障未发生预警已到位”。他们定义了三类黄金信号原子健康信号Atom Health Signal每个原子的error_rate_5m 5%且latency_p95_ms 2 * baseline触发P1告警。Baseline非固定值而是过去7天同时间段的移动平均自动适应业务峰谷。编排异常信号Orchestration Anomaly SignalL2引擎检测到非预期DAG模式。例如历史数据显示get_weather原子99.8%被用于[GET_WEATHER]单节点DAG若某时段突然出现大量[GET_WEATHER] - [GENERATE_REPORT]组合且GENERATE_REPORT错误率飙升则判定为上游天气数据格式变更自动触发weather_api_schema_changed事件通知L1原子负责人。用户挫败信号User Frustration Signal从交互层采集用户行为连续2次发送相似指令如“查张三报销”、“再查张三报销”、点击“重试”按钮、手动编辑Agent返回结果。当某用户在5分钟内触发3次挫败信号系统自动标记为high_risk_session并将完整会话日志推送给体验优化小组。实操心得他们发现80%的“通用性”问题最早暴露在编排异常信号中。例如一次search_flights_by_route原子因航司API变更返回新字段未及时更新原子契约导致下游generate_itinerary原子解析失败。但编排层早在首例失败前2小时就监测到search_flights_by_route的输出结构变异new_field_detected:true只是当时未配置对应告警。此后他们将所有原子的Schema变更纳入必告警项。4. 实操过程与核心环节实现从0到1搭建可扩展Agent系统的完整路径4.1 第一阶段定义你的第一个能力原子以get_weather为例不要一上来就搞“通用”先做出一个能稳定交付的原子。Manus团队的标准流程如下步骤1契约定义15分钟创建atoms/get_weather/openapi.yamlopenapi: 3.0.0 info: title: Weather API version: 1.0.0 paths: /current: get: summary: Get current weather for a city parameters: - name: city in: query required: true schema: type: string - name: units in: query required: false schema: type: string enum: [celsius, fahrenheit] default: celsius responses: 200: description: Current weather data content: application/json: schema: type: object properties: city: type: string temperature: type: number condition: type: string humidity: type: integer timestamp: type: string format: date-time x-execution-hints: timeout_ms: 3000 retryable: true rate_limit: 100/minute步骤2SDK生成与原子骨架10分钟运行openapi-generator-cli generate -i openapi.yaml -g rust-server -o ./src/atoms/get_weather生成Rust骨架代码。修改handler.rs注入真实API调用他们用reqwesttokiopub async fn get_current_weather( city: String, units: OptionString, ) - ResultWeatherResponse, AtomError { let client reqwest::Client::new(); let url format!( https://api.weatherapi.com/v1/current.json?key{}q{}aqino, std::env::var(WEATHER_API_KEY).unwrap(), city ); // 添加熔断器使用tokio::sync::Semaphore控制并发 let _permit WEATHER_SEMAPHORE.acquire().await?; let resp client .get(url) .timeout(Duration::from_millis(3000)) .send() .await .map_err(|e| AtomError::Network(e.to_string()))?; if !resp.status().is_success() { return Err(AtomError::Api(resp.status().as_u16().to_string())); } let json: serde_json::Value resp.json().await.map_err(|e| AtomError::Parse(e.to_string()))?; Ok(WeatherResponse { city: json[location][name].as_str().unwrap_or().to_string(), temperature: json[current][temp_c].as_f64().unwrap_or(0.0), condition: json[current][condition][text].as_str().unwrap_or().to_string(), humidity: json[current][humidity].as_i64().unwrap_or(0) as i32, timestamp: json[current][last_updated].as_str().unwrap_or().to_string(), }) }步骤3可观测性注入5分钟在main.rs中初始化Prometheus注册器use prometheus::{register_int_counter_vec, IntCounterVec}; lazy_static::lazy_static! { pub static ref ATOM_EXECUTION_TOTAL: IntCounterVec register_int_counter_vec!( atom_execution_total, Total number of atom executions, [atom, status] ).unwrap(); } // 在handler结尾处记录 ATOM_EXECUTION_TOTAL.with_label_values([get_weather, success]).inc();步骤4健康检查与本地测试10分钟实现/health端点返回结构化状态。用curl http://localhost:8080/health验证。然后用cargo test跑单元测试覆盖超时、错误码、重试逻辑。注意他们要求每个原子的单元测试必须包含“混沌测试”用例如模拟网络延迟tokio::time::sleep(Duration::from_secs(4))验证熔断器是否生效。这是保证通用性的第一道防线。4.2 第二阶段搭建L2编排引擎Rust Actix WebL2是大脑必须快、稳、可观察。Manus团队选择Rust核心考量是① 零成本抽象性能极致② 所有权模型天然防内存泄漏③ 生态成熟Actix Web、Tokio、Serde。步骤1定义DAG执行器30分钟创建orchestrator/src/executor.rs核心是execute_dag函数pub async fn execute_dag( dag: DagDefinition, context: Context, ) - ResultExecutionResult, OrchestratorError { let mut state ExecutionState::new(context); // 并行执行叶子节点 let futures: Vec_ dag.leaves().iter().map(|node| { let node_clone node.clone(); let state_clone state.clone(); async move { execute_node(node_clone, state_clone).await } }).collect(); let results join_all(futures).await; // 汇总结果处理错误 let mut final_result ExecutionResult::default(); for result in results { match result { Ok(r) final_result.merge_success(r), Err(e) final_result.add_error(e), } } Ok(final_result) }步骤2集成意图识别服务20分钟在orchestrator/src/main.rs中调用已部署的意图识别APIHTTPlet intent_response client .post(http://intent-service:8000/recognize) .json(json!({query: user_input})) .send() .await?; let intent_data: IntentResponse intent_response.json().await?; // 根据intent_data.intent匹配预置DAG模板 let dag DAG_TEMPLATES.get(intent_data.intent).cloned().ok_or_else(|| { OrchestratorError::UnknownIntent(intent_data.intent) })?;步骤3实现容错策略40分钟为每个原子调用包裹with_fallbackasync fn execute_atom_with_fallback( atom_name: str, params: JsonValue, context: Context, ) - ResultJsonValue, AtomError { // 尝试主原子 match execute_atom(atom_name, params.clone(), context).await { Ok(res) Ok(res), Err(e) { // 主失败检查是否可降级 if let Some(fallback) FALLBACK_STRATEGIES.get(atom_name) { execute_atom(fallback.atom, fallback.params, context).await } else { Err(e) } } } }FALLBACK_STRATEGIES是一个全局HashMap配置在config/fallbacks.toml中[get_weather] atom get_weather_cached params { city {{city}} }步骤4暴露监控端点10分钟添加/metrics端点暴露自定义指标use prometheus::{register_int_gauge_vec, IntGaugeVec}; lazy_static::lazy_static! { pub static ref ORCHESTRATOR_DAG_QUEUE_LENGTH: IntGaugeVec register_int_gauge_vec!( orchestrator_dag_queue_length, Current length of DAG execution queue, [status] // status: pending, running, failed ).unwrap(); } // 在DAG入队/出队时更新 ORCHESTRATOR_DAG_QUEUE_LENGTH.with_label_values([pending]).dec();4.3 第三阶段构建记忆与上下文层Redis PostgreSQL ChromaDB步骤1会话记忆Redis Streams20分钟在memory/src/session.rs中pub struct SessionMemory { stream_key: String, redis_client: redis::Client, } impl SessionMemory { pub async fn append_event(self, event: SessionEvent) - Result(), MemoryError { let mut conn self.redis_client.get_async_connection().await?; redis::cmd(XADD) .arg(self.stream_key) .arg(*) .arg(event_type).arg(event.event_type) .arg(payload).arg(serde_json::to_string(event.payload)?) .query_async(mut conn) .await?; Ok(()) } }Stream Key格式为session:{session_id}自动过期EXPIRE session:{session_id} 1800。步骤2用户偏好PostgreSQL JSONB15分钟建表CREATE TABLE user_preferences ( user_id VARCHAR PRIMARY KEY, preferences JSONB NOT NULL DEFAULT {}, updated_at TIMESTAMP WITH TIME