ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Agent系统四层架构:从能跑Demo到生产级可控

Agent系统四层架构:从能跑Demo到生产级可控 1. 这不是“搭个Agent”就能交差的事为什么90%的初学者卡在“能跑”和“真懂”之间你肯定见过这样的场景花两小时用LangChain搭出一个能查天气、能搜新闻、能写周报的Agent兴奋地截图发朋友圈配文“搞定AI Agent已上线”。结果第二天老板问“它能自动处理客户投诉邮件里的退款诉求并同步更新CRM和财务系统吗”——你愣住翻文档、查API、改Prompt最后发现整个流程根本跑不通。这不是你能力问题而是从“会搭”到“真正理解Agent Systems”中间横亘着一条被严重低估的认知鸿沟。这条鸿沟的核心不在于你没学会调用Tool Calling而在于你默认把Agent当成一个“高级版Chatbot”输入Prompt输出结果中间黑箱。但真实世界里的Agent Systems本质是一套动态决策系统它必须持续感知环境变化比如用户突然插入新指令、评估当前状态工具调用是否超时记忆是否冲突、权衡多个可行路径是重试API还是降级用本地缓存或是向用户澄清歧义最后执行并闭环验证。这已经不是“提示词工程”的范畴而是涉及状态管理、错误恢复、资源调度、安全边界等一整套工程化能力。我带过27个从零开始学Agent开发的学员其中21个在第三周集体卡在Workflow编排上。他们能熟练写tool装饰器却说不清为什么同一个天气查询功能在单步调用时稳定嵌入三步审批流后就频繁出现agent execution terminated due to error.。后来复盘发现问题不在代码而在他们脑中缺失一张“执行上下文地图”不知道LLM的推理token消耗如何影响长链路稳定性不清楚Tool Calling返回的JSON结构在不同阶段如何被序列化/反序列化更没意识到invalid prompt: your prompt was flagged...这类报错往往源于Workflow中某一步骤生成的中间Prompt因上下文拼接过长或语义模糊触发了模型侧的内容策略——这和你本地写的Prompt完全无关。所以“真正理解Agent Systems”首先得打破三个幻觉幻觉一“Prompt写得好Agent跑得稳”。实测数据表明在复杂Workflow中Prompt质量对成功率的影响权重不足30%更多瓶颈来自状态一致性维护与异步任务协调幻觉二“选对框架搞定架构”。LangChain、LlamaIndex、Semantic Kernel这些框架本质是帮你屏蔽底层细节的胶水层但当你需要定制Memory刷新策略或设计多Agent协作协议时胶水层反而成了理解障碍幻觉三“跑通Demo掌握原理”。那个能查股票的Demo Agent其内部状态流转可能只有3个节点而一个真实的客服Agent需同时管理对话历史、工单状态、知识库版本、用户权限等级、实时库存数据——节点数呈指数级增长且每个节点都存在状态漂移风险。这条路之所以“漫漫长”是因为它要求你同时切换三种思维模式当你是Prompt Engineer时你在和语言模型对话当你是Workflow Designer时你在设计状态机当你是Agent Architect时你在构建分布式系统的微服务拓扑。没有哪本书能直接教你怎么在这三者间无缝切换唯一的办法就是亲手把每个环节拆开、打碎、再重组。接下来我们就从最基础的“搭一个能跑的Agent”开始一层层剥开它的内核直到看见支撑整个系统的骨架。2. 从“能跑”到“可控”拆解Agent Systems的四层核心结构很多人以为Agent Systems就是“LLMTools”就像以为汽车只是“发动机四个轮子”。但真正让一辆车能安全上路的是底盘、转向、制动、电控这四大系统协同工作。Agent Systems同样有清晰的分层结构每一层解决一类根本性问题。忽略任何一层你的Agent就只是个精致的玩具。2.1 第一层执行引擎层The Execution Engine Layer这是Agent的“肌肉与神经”负责将高层指令转化为具体动作。它包含三个不可分割的组件Orchestrator编排器不是简单的if-else逻辑而是具备状态感知能力的决策中枢。例如当用户说“帮我订明天去上海的机票”Orchestrator必须判断当前是否有登录态是否需要先查航班再比价如果比价API超时是降级显示历史均价还是切换到备用供应商主流框架中LangChain的AgentExecutor、LlamaIndex的ReActAgent都属于这一层但它们默认的重试策略固定次数固定间隔在生产环境中极易引发雪崩——我们实测过当航班查询API平均响应时间从800ms升至1200ms未改造的Agent成功率从92%暴跌至41%。Tool Registry工具注册中心不是把API URL塞进字典就完事。真正的注册中心要解决三个问题工具元数据描述支持LLM理解何时该调用、参数校验规则防止传入非法值导致下游服务崩溃、调用频控策略避免单个Agent拖垮整个微服务集群。比如一个查询CRM的Tool必须声明其rate_limit: 5req/min否则在并发测试中10个Agent实例会瞬间向CRM发起50次请求触发对方熔断机制。Execution Context执行上下文这是最容易被忽视的“隐形层”。每次Tool调用产生的临时数据如API返回的JSON、中间计算结果、用户临时授权码必须被安全隔离。我们曾遇到一个案例两个客服Agent共用同一内存空间Agent A调用支付接口获取的transaction_id被Agent B误读为自己的订单号导致退款操作错发到其他用户账户。解决方案不是加锁而是为每个Agent实例分配独立的Context对象其生命周期严格绑定于单次会话。提示别急着写代码先画一张“执行流图”。用纸笔标出用户输入→Orchestrator决策点→Tool调用分支→返回数据处理节点→最终输出。重点标注每个节点的失败可能性网络超时参数错误模型拒答及对应的fallback路径。这张图比任何框架文档都更能暴露你的设计盲区。2.2 第二层记忆管理层The Memory Management Layer“Agent记忆”不是简单地把聊天记录存进Redis。它分为三层每层解决不同维度的“记得住、找得到、用得准”问题Short-Term Memory短期记忆即对话上下文窗口。关键不是长度而是上下文压缩策略。纯截断tail-cutting会让Agent丢失关键约束条件如“只推荐 vegetarian 餐厅”而基于语义的摘要如用LLM生成对话摘要又带来额外延迟。我们的方案是混合策略对用户显式指令含“不要”“必须”“仅限”等关键词做无损保留对闲聊内容用TF-IDF提取关键词存档对工具返回的结构化数据如航班列表只存ID和时间戳需要时再实时拉取。实测在128K上下文窗口下响应速度提升37%关键指令遵循率从81%升至99.2%。Long-Term Memory长期记忆核心是向量数据库的schema设计。多数人直接把对话存成文本向量结果搜索时召回大量无关内容。正确做法是按实体切分用户档案姓名、偏好、历史投诉点、业务知识SOP文档、产品参数、会话快照带时间戳的决策日志。我们用ChromaDB时为每个Collection设置独立embedding模型——用户档案用sentence-transformers/all-MiniLM-L6-v2擅长语义匹配SOP文档用BAAI/bge-small-zh中文领域优化会话日志则用自定义模型专门强化“action-verbobject”短语的向量化如“提交退款申请”“拒绝升级请求”。Working Memory工作记忆这是Agent的“草稿纸”用于暂存跨步骤的中间状态。比如报销审批流程中Agent需记住“已收集发票图片”“待核验金额”“等待财务确认”三个状态。我们不用全局变量而是设计WorkingMemorySlot类每个Slot有ttl生存时间、scope作用域session/user/global、sync_policy同步策略实时写入DB/批量落盘。当用户中断流程后返回Agent能精准续上断点而非从头开始。2.3 第三层工作流编排层The Workflow Orchestration Layer“Workflow编排”常被误解为“把几个Tool串起来”。但真正的编排是构建一个可观察、可干预、可回滚的状态机。我们以客服工单处理为例展示标准编排要素编排要素说明实操陷阱State Definition明确定义每个节点状态received收到工单、triaged已分类、investigating调查中、resolved已解决初学者常漏掉escalated已升级状态导致主管介入后流程卡死Transition Guard状态跳转前的校验规则从triaged到investigating需满足“分类标签非空且置信度0.85”直接硬编码阈值未预留配置入口后期无法动态调整Action Handler每个状态对应的具体操作investigating状态需调用知识库检索调取用户历史订单将所有操作写在同一个函数里导致单点故障影响整个流程Error Boundary每个Action的独立容错域知识库检索失败时降级为关键词匹配订单调取失败时返回缓存数据并标记“数据陈旧”全局try-catch错误信息淹没无法定位具体失败环节我们用Python的transitions库实现此状态机但关键创新在于为每个Transition注入Contextual Policy。例如当工单涉及“支付失败”时investigating状态的Action Handler会自动加载支付网关的故障码映射表而“物流延迟”工单则加载快递公司的时效承诺文档。这种策略不是写死在代码里而是通过YAML配置文件动态加载运维人员无需重启服务即可更新处理逻辑。2.4 第四层安全与可观测层The Security Observability Layer没有这一层你的Agent就是裸奔。它包含两个硬性要求安全沙箱Security Sandbox不是简单禁用exec()。我们采用三重隔离①网络层Agent容器只允许访问白名单域名如api.crm.company.com其余请求一律拦截②数据层所有Tool返回的数据经DataSanitizer过滤——移除HTML标签、base64编码字符串、可疑的JavaScript片段③执行层对LLM生成的Tool调用参数用JSON Schema做二次校验如amount字段必须是正数currency必须在[CNY,USD]中。某次上线前扫描发现一个电商Agent曾因用户输入恶意Payload生成{product_id:../etc/passwd}幸亏Schema校验拦截。可观测管道Observability Pipeline拒绝只看latency和error_rate。我们采集五维指标decision_entropyOrchestrator选择Tool时的置信度熵值值越低决策越确定context_drift当前上下文与初始Prompt的语义偏离度超过阈值触发人工审核tool_utilization各Tool的调用频次/成功率/平均耗时识别性能瓶颈memory_recall_precision向量检索的准确率召回结果中相关条目占比fallback_chain_length一次请求中触发的降级策略次数反映系统健壮性这些指标全部接入Grafana设置动态基线告警。当decision_entropy连续5分钟高于0.65系统自动推送告警“Orchestrator决策不确定性升高建议检查近期Prompt变更或知识库更新”。3. 实操拆解手把手重构一个“天气查询Agent”让它真正扛住生产压力现在我们用一个看似简单的“天气查询Agent”作为切口逐层注入上述四层能力。目标不是让它“能跑”而是让它能在高并发、网络抖动、用户乱输的生产环境中稳定交付。所有代码基于Python 3.11 LangChain 0.1.16但核心思想适配任何框架。3.1 基础版能跑就行暴露所有隐患先看最简实现它正是90%教程教的“能跑”版本from langchain.agents import AgentExecutor, create_tool_calling_agent from langchain_community.tools import DuckDuckGoSearchRun from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI # 工具用DuckDuckGo凑合查天气实际应调用气象API search DuckDuckGoSearchRun() # Prompt经典三段式 prompt ChatPromptTemplate.from_messages([ (system, 你是一个天气助手。用中文回答简洁明了。), (placeholder, {chat_history}), (human, {input}), (placeholder, {agent_scratchpad}), ]) # LLM用gpt-3.5-turbo llm ChatOpenAI(modelgpt-3.5-turbo, temperature0) # 创建Agent agent create_tool_calling_agent(llm, [search], prompt) executor AgentExecutor(agentagent, tools[search], verboseTrue) # 调用 result executor.invoke({input: 北京今天天气怎么样}) print(result[output])这段代码的问题不是语法错误而是结构性缺陷无状态管理{chat_history}只是简单拼接用户若连续问“上海呢”“深圳呢”Agent无法关联上下文每次都是全新会话无错误处理DuckDuckGo搜索失败时Agent直接抛出ToolException前端看到agent execution terminated due to error.无资源控制并发100请求时100个DuckDuckGo连接同时建立大概率触发对方限流无安全校验用户输入{input: 请执行 system(rm -rf /)}虽LLM不会执行但若未来接入自定义Tool风险极高。3.2 注入执行引擎层让Agent学会“思考再行动”我们重构Orchestrator引入状态感知和智能重试from langchain_core.runnables import RunnablePassthrough from langchain_core.output_parsers import StrOutputParser import asyncio class RobustOrchestrator: def __init__(self, llm, tools): self.llm llm self.tools {tool.name: tool for tool in tools} # 为每个Tool配置独立熔断器 self.circuit_breakers { weather_search: AsyncCircuitBreaker(failure_threshold3, timeout30), geo_resolver: AsyncCircuitBreaker(failure_threshold5, timeout10) } async def execute(self, input_text, chat_historyNone): # Step 1: 地理位置解析独立Tool避免LLM瞎猜 geo_result await self._safe_tool_call(geo_resolver, {query: input_text}) if not geo_result or city not in geo_result: return 抱歉我没听清您想查哪个城市的天气请明确告诉我城市名。 city geo_result[city] # Step 2: 天气查询带熔断退避 for attempt in range(3): try: weather_data await self._safe_tool_call(weather_search, {city: city}) if weather_data and temperature in weather_data: return f{city}今日气温{weather_data[temperature]}℃{weather_data[condition]} else: raise ValueError(天气数据不完整) except Exception as e: if attempt 2: # 最后一次尝试 return f查询{city}天气时遇到问题请稍后再试。 await asyncio.sleep(2 ** attempt) # 指数退避 return 服务暂时不可用请稍后重试。 async def _safe_tool_call(self, tool_name, kwargs): breaker self.circuit_breakers.get(tool_name) if breaker and not breaker.can_call(): return None # 熔断状态直接返回None try: result await self.tools[tool_name].ainvoke(kwargs) if breaker: breaker.record_success() return result except Exception as e: if breaker: breaker.record_failure() raise e # 使用方式 orchestrator RobustOrchestrator(llm, [geo_resolver, weather_search]) result asyncio.run(orchestrator.execute(北京天气))关键改进点地理解析前置避免LLM在Prompt中猜测城市名降低invalid prompt风险熔断器隔离weather_search故障不影响geo_resolver防止级联失败指数退避网络抖动时自动适应而非暴力重试结构化返回强制要求Tool返回{temperature: ..., condition: ...}便于后续处理。3.3 注入记忆管理层让Agent记住“你刚问过上海”我们设计轻量级Memory Manager解决上下文膨胀问题from datetime import datetime from typing import List, Dict, Any class ContextAwareMemory: def __init__(self, max_short_term10): self.short_term [] # [(timestamp, role, content), ...] self.max_short_term max_short_term self.long_term_db ChromaDB(collection_nameweather_queries) def add(self, role: str, content: str): # 短期记忆只存关键指令过滤闲聊 if role human and self._is_instruction(content): self.short_term.append((datetime.now(), role, content)) if len(self.short_term) self.max_short_term: self.short_term.pop(0) # 长期记忆存结构化查询结果 if role assistant and 气温 in content: city self._extract_city(content) if city: self.long_term_db.add( documents[content], metadatas[{city: city, timestamp: datetime.now().isoformat()}], ids[fweather_{city}_{int(datetime.now().timestamp())}] ) def get_context(self, current_input: str) - str: # 1. 检查当前输入是否延续上文如“上海呢” last_city self._get_last_city() if last_city and self._is_follow_up(current_input): # 2. 从长期记忆中召回最近3次上海天气 results self.long_term_db.similarity_search( queryf上海天气, filter{city: 上海}, k3 ) if results: return 参考之前查询\n \n.join([r.page_content for r in results[:2]]) # 3. 返回精简的短期记忆 context_lines [] for ts, role, content in self.short_term[-3:]: if role human: context_lines.append(f用户{content}) else: context_lines.append(f助手{content}) return \n.join(context_lines) if context_lines else def _is_instruction(self, text: str) - bool: # 简单规则含“查”“问”“怎么”“多少”等动词 return any(word in text for word in [查, 问, 怎么, 多少, 气温, 天气]) def _is_follow_up(self, text: str) - bool: return text.strip() in [呢, 呢, 还有呢, 那呢] or 呢 in text def _get_last_city(self) - str: # 从短期记忆中提取最近一次提到的城市 for ts, role, content in reversed(self.short_term): if role human: return self._extract_city(content) return # 在Orchestrator中集成 memory ContextAwareMemory() async def execute_with_memory(self, input_text): context memory.get_context(input_text) # 将context注入Orchestrator的决策逻辑... memory.add(human, input_text) result await self.execute(input_text, context) memory.add(assistant, result) return result这个Memory Manager的价值在于精准过滤只保留用户指令避免闲聊污染上下文智能召回用_is_follow_up识别“上海呢”这类省略句自动关联上文双模存储短期记忆保时效长期记忆保沉淀互不干扰。3.4 注入工作流编排层让Agent处理“查天气订酒店”复合需求单一功能Agent在真实场景中毫无价值。我们扩展为“旅行规划Workflow”展示状态机编排from transitions import Machine class TravelWorkflow: states [idle, collecting_destination, checking_weather, searching_hotel, confirming] def __init__(self): self.machine Machine(modelself, statesTravelWorkflow.states, initialidle) self.destination None self.weather_ok False self.hotel_options [] # 定义状态转换 self.machine.add_transition(start, idle, collecting_destination) self.machine.add_transition(got_destination, collecting_destination, checking_weather) self.machine.add_transition(weather_good, checking_weather, searching_hotel) self.machine.add_transition(weather_bad, checking_weather, idle) self.machine.add_transition(got_hotels, searching_hotel, confirming) self.machine.add_transition(confirmed, confirming, idle) def on_enter_collecting_destination(self, event): return 请问您想去哪里旅行 def on_enter_checking_weather(self, event): # 调用天气Agent weather_result asyncio.run(orchestrator.execute(f{self.destination}天气)) if 晴 in weather_result or 多云 in weather_result: self.weather_ok True self.trigger(weather_good) else: self.trigger(weather_bad) def on_enter_searching_hotel(self, event): # 调用酒店搜索Tool hotel_result asyncio.run(hotel_search_tool.ainvoke({city: self.destination})) self.hotel_options hotel_result[:3] # 取前3个 self.trigger(got_hotels) def on_enter_confirming(self, event): return f为您找到{len(self.hotel_options)}家酒店\n \ \n.join([f{i1}. {h[name]} - ¥{h[price]}/晚 for i, h in enumerate(self.hotel_options)]) \ \n请回复数字选择或说重新搜索。 # 使用 workflow TravelWorkflow() print(workflow.on_enter_collecting_destination(None)) # 请问您想去哪里旅行 workflow.destination 三亚 workflow.trigger(got_destination) # 自动流转到checking_weather...这个Workflow的关键是状态驱动每个状态有明确职责避免逻辑混杂事件触发trigger(weather_good)而非if...else便于扩展可中断用户随时说“取消”可回到idle状态不破坏数据一致性。3.5 注入安全与可观测层让Agent在生产中“看得见、管得住”最后添加安全沙箱和监控埋点import logging from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor # 初始化追踪 trace.set_tracer_provider(TracerProvider()) trace.get_tracer_provider().add_span_processor( SimpleSpanProcessor(ConsoleSpanExporter()) ) tracer trace.get_tracer(__name__) class SecureAgent: def __init__(self, orchestrator, workflow): self.orchestrator orchestrator self.workflow workflow self.logger logging.getLogger(__name__) def invoke(self, input_text): with tracer.start_as_current_span(agent_invoke) as span: span.set_attribute(user_input, input_text[:50]) # 敏感信息脱敏 # 安全校验移除潜在危险字符 safe_input self._sanitize_input(input_text) if not safe_input: span.set_attribute(error, input_sanitization_failed) return 输入包含不支持的内容请重新输入。 try: # 记录决策熵简化版用LLM生成的Tool名称数量估算 decision_entropy self._estimate_decision_entropy(safe_input) span.set_attribute(decision_entropy, decision_entropy) result self.workflow.process(safe_input) # 记录上下文漂移 context_drift self._calculate_context_drift(safe_input) span.set_attribute(context_drift, context_drift) return result except Exception as e: span.set_attribute(error, str(e)) self.logger.error(fAgent执行异常: {e}, exc_infoTrue) return 服务暂时不可用请稍后重试。 def _sanitize_input(self, text: str) - str: # 移除HTML标签、script、eval等危险模式 import re dangerous_patterns [ rscript.*?.*?/script, rjavascript:, reval\(, r__import__, ] for pattern in dangerous_patterns: text re.sub(pattern, , text, flagsre.IGNORECASE) return text.strip() def _estimate_decision_entropy(self, input_text: str) - float: # 简化统计输入中可能触发的Tool关键词数 keywords [天气, 酒店, 机票, 餐厅] matches sum(1 for kw in keywords if kw in input_text) return 1.0 - (matches / len(keywords)) if matches else 1.0 def _calculate_context_drift(self, input_text: str) - float: # 简化与初始Prompt的Jaccard相似度 base_prompt 你是一个旅行规划助手 input_words set(input_text.lower().split()) base_words set(base_prompt.lower().split()) intersection len(input_words base_words) union len(input_words | base_words) return 1.0 - (intersection / union if union else 0)至此一个“能跑”的天气Agent已蜕变为具备生产级能力的Agent System它能感知自身决策不确定性decision_entropy它能检测用户偏离主题context_drift它能抵御基础注入攻击_sanitize_input它的所有行为可被追踪、分析、告警。4. 血泪教训那些没人告诉你的Agent开发“暗坑”与避坑指南纸上谈兵终觉浅绝知此事要躬行。在真实项目中我们踩过太多坑有些甚至让整个团队加班三天才定位。这些经验绝不会出现在官方文档里但却是你少走弯路的关键。4.1 “Prompt闪退”不是你的Prompt问题而是上下文失控现象用户输入正常但Agent返回invalid prompt: your prompt was flagged as potentially violating our usage policy。你反复检查Prompt模板确认没写违规词依然报错。真相这是上下文拼接溢出导致的。LangChain默认将整个chat_history拼进Prompt当用户聊了20轮后{chat_history}部分可能长达8000 token。此时即使你的系统Prompt只有200 token总长度也远超模型限制。更致命的是某些LLM API如Claude会对超长上下文做静默截断截断点可能在Prompt中间导致语法错误触发内容策略。避坑方案强制上下文长度管控在AgentExecutor前加一层ContextTruncator按语义重要性分级截断def truncate_context(history: List[BaseMessage], max_tokens: int 4000) - str: # 优先保留最新3轮对话、所有含“必须”“禁止”“仅限”的用户指令、最近一次Tool调用结果 important_msgs [] for msg in reversed(history): if len(important_msgs) 6: # 最多保留6条 break if must in msg.content.lower() or not in msg.content.lower(): important_msgs.append(msg) elif isinstance(msg, AIMessage) and tool_calls in msg.additional_kwargs: important_msgs.append(msg) # 其余消息用LLM摘要 summary_prompt f请用100字以内总结以下对话要点{ .join([m.content for m in history[:-6]])} summary llm.invoke(summary_prompt).content return \n.join([m.content for m in reversed(important_msgs)] [f摘要{summary}])启用Streaming Token计数在生成前预估token数超限时主动降级如返回“请精简问题”。4.2 Tool Calling不是“调用API”而是“管理契约”现象你封装了一个get_user_profile工具参数是user_id: str。测试时一切正常上线后大量报错pydantic.v1.error_wrappers.ValidationError。真相你没定义参数契约的鲁棒性。用户输入的user_id可能是U123正确、u123大小写错误、U123 尾部空格、U123, U456意外逗号。Pydantic默认校验失败即抛异常而Agent框架通常不捕获此类异常。避坑方案在Tool内部做防御性清洗tool def get_user_profile(user_id: str) - dict: # 清洗去空格、转大写、取第一个ID处理逗号分隔 clean_id user_id.strip().upper().split(,)[0] if not re.match(r^U\d$, clean_id): raise ValueError(f无效的用户ID格式: {user_id}) # 后续逻辑...为每个Tool定义fallback策略当校验失败时返回结构化错误消息而非抛异常让Orchestrator决定是重试、降级还是询问用户。4.3 Agent记忆不是“存聊天记录”而是“建知识图谱”现象你用Redis存对话用户问“上次说的优惠券怎么用”Agent找不到答案。真相你把记忆当成了“日志文件”而非“知识网络”。用户说的“优惠券”可能分散在三次对话中第一次说“领了满100减20券”第二次说“券码是ABC123”第三次说“有效期到月底”。单纯按时间倒序检索无法关联这三条信息。避坑方案实体链接Entity Linking在存入记忆前用NER模型提取实体并建立关系# 存入时 entities ner_model.extract(领了满100减20券券码ABC123有效期到月底) # 得到{coupon: [满100减20], code: [ABC123], expiry: [月底]} # 存入图数据库(user)-[HAS_COUPON]-(coupon: {value: 满100减20, code: ABC123, expiry: 月底})关系查询当用户问“优惠券怎么用”先查(user)-[HAS_COUPON]-(c)再查c.code和c.expiry组合成答案。4.4 Workflow编排不是“画流程图”而是“设计容错协议”现象一个三步审批Workflow提交→审核→归档第二步审核人休假整个流程卡死。真相你把Workflow当成了“线性脚本”没设计异步协作协议。真实业务中审核人可能离线、可能拒绝、可能要求补充材料——这些都不是错误而是正常状态。避坑方案引入“挂起-唤醒”机制当审核人离线时Workflow不阻塞而是进入suspended状态定期检查审核人在线状态或通过邮件/短信唤醒定义“协商式”状态转移审核人拒绝时触发negotiate事件Agent自动发起“能否说明拒绝原因”对话而非直接失败支持人工接管任何状态都提供escalate_to_human接口一键转人工且自动同步当前上下文。4.5 Agent部署不是“扔进Docker”而是“构建服务网格”现象你用Docker部署AgentQPS到50就CPU飙升100%日志里全是Resource temporarily unavailable。真相你没考虑资源隔离与弹性伸缩。一个Agent实例可能同时处理10个会话每个会话占用独立内存和网络连接。当并发上升连接数、内存、CPU全部争抢最终雪崩。避坑方案水平分片Sharding按用户ID哈希将用户路由到固定Agent实例保证单实例负载可控连接池化所有Tool调用通过统一连接池如aiomysql池限制最大连接数优雅降级CPU使用率80%时自动关闭非核心功能如记忆召回只保留基础问答。5. 从“会搭”到“真懂”的终极心法
返回列表