AutoGen与CrewAI核心差异:任务建模、状态管理与可观测性对比 1. 项目概述当两个主流多智能体框架站在同一张对比表上“AutoGen vs CrewAI”这个标题一出来我手边刚泡好的第三杯咖啡还没凉透就下意识点开了终端——不是去跑代码而是先翻了翻最近三个月在 Slack 社区、GitHub Issues 和 Discord 频道里被反复顶上热帖的几条讨论“用 CrewAI 做客户支持流程编排第三天就卡在 agent 间 context 传递上”“AutoGen 的 group chat manager 看似灵活但 debug 一次 message flow 要画三张时序图”“我们上线前一周把 AutoGen 换成 CrewAI不是因为更好是因为文档里真有‘怎么让两个 agent 不互相抢话’这一节”。这些不是段子是真实团队踩出来的坑。今天这篇不讲谁“赢了”也不做评分式总结而是以一个连续三年用多 agent 系统落地过 7 个生产级项目的从业者身份把 AutoGen 和 CrewAI 拆开、摊平、对照着电路板焊点一样逐层看它们各自在任务建模粒度、通信契约设计、状态持久化机制、错误恢复路径、调试可观测性这五个硬指标上到底做了什么取舍又为这些取舍付出了什么隐性成本。如果你正站在技术选型十字路口——比如要搭建一个能自动分析销售邮件、调用 CRM API、生成周报草稿、再由主管 agent 审核修订的闭环系统——那么你真正需要的不是“哪个更火”而是“当我把‘让销售助理 agent 主动追问客户未明确的交付时间’写进 prompt 时框架底层会如何解析这句话并在失败时告诉我哪一层断了”。这篇文章就是给你准备的那套万用示波器。2. 核心设计哲学与架构分野从“消息总线”到“角色剧本”2.1 AutoGen基于对话流的轻量级协作协议AutoGen 的核心不是“创建 agent”而是“定义对话参与者及其响应规则”。它的设计原点非常朴素把 multi-agent 问题还原为一个可配置的、带记忆的、支持工具调用的多轮对话系统。你声明一个ConversableAgent本质上是在注册一个“能听、能说、能调外部函数”的对话节点而GroupChatManager则是一个运行时调度器负责按预设策略如 round-robin、manager-first、或自定义 function call把上一条消息路由给下一个该说话的 agent。这里的关键在于——AutoGen 不管理 agent 的“内部状态”只管理“消息流”。它默认假设agent 的所有决策依据都应显式编码在当前收到的 message content、history、以及 tools 的返回结果中。这意味着如果你希望 agent A 在第三次收到客户询价后才触发价格计算你不能靠“给 A 设个 counter0 的实例变量”而必须把 counter 值作为 system message 的一部分注入或通过 tool call 的返回字段显式携带。我去年在一个跨境物流报价系统里试过前者结果发现当对话历史超过 12 轮LLM 开始对“system message 里那个 counter2”的指令产生幻觉误判为新会话起点。后来改用后者——让一个专用的state_trackertool 每次返回 JSON 包含step_count,last_intent,pending_action才稳住逻辑。AutoGen 的优势正在于此它强迫你把业务逻辑显式暴露在消息层debug 时只要 dump 出 message list就能复现整个决策链。但它也埋下隐患所有状态都得靠 LLM 从文本中 parse一旦 prompt 写得不够鲁棒整个链条就脆如薄冰。2.2 CrewAI基于角色驱动的任务分解引擎CrewAI 的出发点截然不同。它不把 multi-agent 当作“对话”而是当作“剧组拍戏”——每个 agent 是一个有固定role角色、goal目标、backstory背景设定的演员而Crew是导演Task是分镜脚本。当你定义一个Task(分析客户邮件情绪倾向, agentanalyst, expected_output正面/中性/负面 关键理由)CrewAI 并不立即发消息而是先做三件事1检查 analyst 是否具备执行此 task 所需的 tools比如 sentiment analysis API key2验证 task 的context字段是否提供了足够输入比如是否绑定了前一个 task 的 output3将 task 封装为一个带超时、重试、输出 schema 的可执行单元。这才是 CrewAI 的核心抽象agent 是能力容器task 是原子工作单元crew 是调度中枢。它天然支持 task 依赖A 的 output 是 B 的 input并内置了SequentialProcess和HierarchicalProcess两种执行流。我在做电商客服工单分类系统时用SequentialProcess让triage_agent先判断工单类型物流/售后/咨询再根据类型把context动态路由给logistics_specialist或returns_coordinator。这种设计让业务逻辑高度可视化——打开 crew 的.json配置就能看清整个 pipeline。但代价是CrewAI 把 agent 的“思考过程”黑盒化了。你无法像 AutoGen 那样直接看到“agent 在第 5 轮说了什么导致下一步跳转失败”只能看到“task X failed with error: output does not match expected schema”。要定位问题你得进到 agent 的_execute_task方法里加 log或者用verboseTrue看海量中间日志。这就像导演只告诉你“演员忘词了”却不给你看排练录像。2.3 架构分野的本质状态管理权的归属之争把两者放一起看分歧根源在于一个根本问题谁来负责维护跨 agent 协作中的“共享上下文”AutoGen 说“交给 message historyLLM 自己 parse。” —— 这是轻量、透明、但脆弱的方案。CrewAI 说“交给 task context 和 crew state框架统一管理。” —— 这是厚重、可控、但抽象层更深的方案。这个选择直接决定了它们的适用边界。AutoGen 更适合探索性强、逻辑常变、需要快速迭代 prompt 和 message flow 的场景比如研究团队做 AI for Science 的假设验证CrewAI 更适合流程固化、输出确定、需对接企业级监控和告警的场景比如银行风控团队部署反欺诈工单分派系统。我见过最典型的误用案例一个教育科技公司用 CrewAI 做个性化学习路径推荐结果因为每个学生的历史数据格式不一context注入时频繁触发 schema validation error团队花了两周才搞懂怎么写output_pydantic的嵌套 validator。如果当时选 AutoGen他们可以直接在 message 里传 raw JSON让 LLM 自己 extract虽然 prompt 工程量大点但至少不会卡在框架校验层。提示不要被“AutoGen 更底层”“CrewAI 更高级”的说法误导。真正的差异是“控制粒度”——AutoGen 让你控制每一句 message 的字节CrewAI 让你控制每一个 task 的语义。选哪个取决于你的团队是更擅长写 prompt还是更擅长写 schema。3. 实操细节深度拆解从初始化到生产部署的七道关卡3.1 初始化成本从 pip install 到第一个可运行 demo两者的安装命令都是pip install开头但背后隐藏的初始化成本天差地别。AutoGen 的初始化路径pip install pyautogen # 然后你需要手动处理 # 1. OpenAI API key 环境变量设置必须 # 2. 可选配置 LLM config list 支持多模型 fallback # 3. 必须手写第一个 ConversableAgent定义 llm_config、system_message、tools我实测过从pip install到跑通一个双 agent 对话agent A 提问agent B 查天气 API 后回答平均耗时 23 分钟。难点不在代码而在理解llm_config里cache_seed、max_tokens、temperature如何影响 message routing。比如cache_seedNone会导致每次 run 都生成不同 response看似随机实则是 LLM 在“自由发挥”而非“按指令执行”这会让调试变得极其痛苦。我建议新手起步时强制设cache_seed42等逻辑跑通再放开。CrewAI 的初始化路径pip install crewai # 然后你需要 # 1. 设置 OPENAI_API_KEY必须 # 2. 可选配置 SERPER_API_KEY用于搜索工具 # 3. 必须定义 Agentrole/goal/backstory、Taskdescription/expected_output、Crewagents/tasks/process同样 demoCrewAI 平均耗时 18 分钟快 5 分钟但这是“表面快”。因为 CrewAI 的Agent类里backstory字段不是装饰用的——它直接影响 LLM 对 role 的理解深度。我试过把backstory写成“你是一个资深天气预报员”LLM 回答准确率 82%改成“你有 15 年气象局工作经验熟悉 ECMWF 模型输出能识别卫星云图异常”准确率升到 94%。这意味着CrewAI 的初始化成本很大一部分花在了backstory 的工程化打磨上而这部分工作 AutoGen 是分散在每个system_message里的。注意CrewAI 的Task.expected_output不是提示词而是强校验 schema。如果你写expected_output天气情况它会严格比对 LLM 输出是否完全等于这四个字。正确写法是expected_outputJSON 格式包含 temperature、condition、humidity 三个字段并配合output_pydanticWeatherReport使用。这个细节90% 的新手在第一个 demo 里就会栽跟头。3.2 工具集成方式API 调用的封装哲学工具Tool是 multi-agent 系统的“手脚”两者对工具的抽象层级完全不同。AutoGen 的工具集成它采用标准 OpenAI Function Calling 协议。你定义一个 Python 函数加上tool装饰器再把它注册进llm_config[functions]。关键点在于AutoGen 不修改你的函数签名也不帮你处理错误。比如你写了一个get_weather(city: str) - dict当 city 是空字符串时函数抛出ValueErrorAutoGen 会原样把 traceback 传给 LLM然后 LLM 可能生成一句“抱歉城市名不能为空”也可能直接 hallucinate 一个虚构城市天气。我在线上环境吃过亏一个支付查询工具因网络超时抛出requests.TimeoutAutoGen 把整段 stack trace 塞进 messageLLM 误以为这是“成功返回的加密数据”试图 base64 decode结果触发下游解析错误。解决方案是所有工具函数必须做防御性包装把异常转化为结构化 error messagetool def get_weather(city: str) - str: try: # real api call return json.dumps({temperature: 25, condition: sunny}) except requests.Timeout: return {error: network_timeout, retry_after: 30} except Exception as e: return f{{error: unknown, message: {str(e)}}}CrewAI 的工具集成它用Tool类封装要求你提供func执行函数、name工具名、description供 LLM 理解用途。CrewAI 的优势在于它会在调用前后自动注入 context并提供基础重试机制。比如你定义search_tool Tool(funcsearch_web, nameWebSearch, descriptionSearch the web for latest info)当 LLM 决定调用它时CrewAI 会自动把当前 task 的description和expected_output作为 context 传入search_web函数。更关键的是它支持max_iter3参数失败时自动重试。但陷阱在于CrewAI 的重试是“整个 tool call 重试”不是“网络请求重试”。如果search_web函数里用了requests.get(url, timeout5)第一次 timeout 后CrewAI 会立刻重试第二次而不是等 5 秒再试。这可能导致对下游服务的雪崩式冲击。我的做法是在search_web函数内部实现指数退避而把 CrewAI 的max_iter设为 1避免双重重试。3.3 错误处理与可观测性debug 时你最先看到什么这是决定长期维护成本的核心维度。我统计过自己过去一年 debug 多 agent 系统的日志量AutoGen 平均每次故障需查看 127 行 message historyCrewAI 平均需查看 438 行 verbose log。AutoGen 的可观测性它的 debug 友好性来自极致的透明。GroupChatManager的run_chat()方法会返回完整的chat_history每条记录包含roleuser/assistant/function、content、function_call如果有、name调用的 tool 名。你可以直接print(chat_history[-3:])看最后三步发生了什么。更狠的是它支持register_function时传入function_map让你能 hook 到每个 tool call 的前后。我在一个金融报告生成系统里用这个 hook 记录了每次get_stock_price调用的入参、耗时、返回值做成一张实时监控表。但短板也很明显它不告诉你“为什么 LLM 选择了这个 tool”。比如 history 显示 LLM 调用了calculate_roi但没调用get_market_data你只能猜是 prompt 里缺少 market data 的重要性描述还是 LLM 误判了依赖关系。CrewAI 的可观测性它用Crew.process(..., verbose2)输出详细日志包括task start/end timestamp、agent name、tool call name、tool input/output、output validation result。这很爽但问题在于日志是线性的而实际执行流可能是分支的。比如一个HierarchicalProcess中manager agent 根据条件把 task 分发给 A 或 B日志里只会显示“task sent to A”不会显示“B 为何未被选中”。要搞清这个你得去看 manager agent 的llm调用原始 response。我最终的解决方案是在 crew 初始化时给每个 agent 加一个callback参数指向自定义 loggerdef agent_callback(agent_name: str, message: str, *args): if deciding in message.lower(): logger.info(f[{agent_name}] decision context: {args[0]}) analyst Agent( roleMarket Analyst, goalAnalyze trends, backstory..., callbackagent_callback # 这里注入 )这样就能捕获到关键决策点的原始输入补全 CrewAI 日志的盲区。3.4 状态持久化与长周期任务如何让 agent “记得昨天的事”真正的生产系统不可能只跑一次对话。用户可能中断后回来系统需要 resume或者一个 report generation task 要跑 20 分钟中间不能丢状态。AutoGen 的状态方案它本身不提供持久化但ConversableAgent的chat_messages属性是可序列化的。我常用方案是把整个groupchat.messages用pickle存 Rediskey 为session_id。resume 时pickle.load()后传给initiate_chat。但要注意pickle会序列化函数对象如果 agent 里用了 lambda 或闭包会失败。安全做法是所有 tools 必须是模块级函数且 agent 初始化时用functools.partial绑定参数而不是闭包。另外GroupChatManager的reset方法会清空 history但不会清空 agent 的chat_messages这点容易混淆。CrewAI 的状态方案它原生支持Crew.kickoff(..., inputs{session_id: abc123})并允许你在 task 的description里引用{{inputs.session_id}}。更进一步它提供Crew.set_cache()方法可接入 Redis 或 SQLite。但实测发现cache 只缓存 task 的 output不缓存中间状态。比如一个generate_reporttask 分三步1fetch data2analyze data3write report。如果第二步失败cache 里只有第一步的 output第二步的中间结果如 processed_dataframe丢了。我的 workaround 是在每个关键 step 后手动调用self.agent.cache.set(f{task_id}_step2, intermediate_result)把中间态存进去。这增加了代码量但换来的是可控的恢复点。3.5 生产部署考量Docker、监控、扩缩容当系统要上生产框架的“运维友好度”立刻成为焦点。AutoGen 的部署它本质是 Python 应用Dockerfile 极简FROM python:3.11-slim COPY requirements.txt . RUN pip install -r requirements.txt COPY . /app CMD [python, app.py]监控方面我用 Prometheus FastAPI middleware在/healthendpoint 暴露active_chats_count、avg_response_time、tool_error_rate三个指标。扩缩容简单水平扩展实例用 Redis 共享 session state。但要注意GroupChatManager不是线程安全的多个请求并发调用同一个 instance 会乱。解决方案是每个请求 new 一个 GroupChatManager把 shared state如 Redis client注入进去而不是复用全局 instance。CrewAI 的部署它依赖更多组件Dockerfile 需额外步骤FROM python:3.11-slim # 安装系统依赖CrewAI 的某些 tool 需要 RUN apt-get update apt-get install -y libglib2.0-0 libsm6 libxext6 libxrender-dev COPY requirements.txt . RUN pip install -r requirements.txt COPY . /app CMD [python, app.py]监控上CrewAI 提供Crew.on_task_start/on_task_end回调可轻松对接 Datadog。但扩缩容有坑Crew实例不是无状态的它内部维护task_queue和agent_states。我试过用 Redis cache但发现agent_states里的llm对象如ChatOpenAI无法序列化。最终方案是把 Crew 拆成 stateless factory stateful executor。CrewFactory.get_crew(session_id)返回一个新 crew其agent的llm配置从环境变量读取所有状态存在 Redisexecutor 只负责按 queue 执行 task。这增加了架构复杂度但换来的是真正的水平扩展能力。4. 实战场景对比六个真实用例的选型决策树4.1 场景一动态知识库问答系统支持上传 PDF/Excel需求特点用户上传文件 → 系统解析 → 基于内容回答问题 → 支持追问如“刚才提到的第三个项目预算多少”AutoGen 方案agent AFileParserAgent用pypdf/openpyxl解析输出结构化 textagent BQAAgent接收 A 的 output user question用 RAG 检索后回答关键技巧在QAAgent的system_message里硬编码“你必须严格基于以下 context 回答不得编造。context 由 FileParserAgent 提供包含 [文件名] 的全部文本。”优势追问时只需把历史 message 全部传入LLM 自动关联。劣势PDF 表格解析质量差常丢失行列关系需额外写table_enhancertool。CrewAI 方案task1ParseDocumentTask→ outputparsed_texttask2AnswerQuestionTask→ inputcontextparsed_textexpected_outputJSON {answer: string, source_pages: [int]}关键技巧用output_pydanticAnswerSchema强制结构化避免 LLM 自由发挥。优势task 间 context 传递稳定source_pages字段可直接用于前端高亮。劣势追问需重新 kickoff crew无法复用 task1 的 parsed_text 缓存除非手动存 Redis。选型结论若追问频率高3 次/会话选 AutoGen若需强结构化输出如审计日志选 CrewAI。4.2 场景二自动化周报生成从 Jira/Slack/GitHub 拉取数据需求特点每周一早 8 点自动拉取上周数据 → 生成 markdown 报告 → 发送至 Slack 频道AutoGen 方案用 cron 触发initiate_chatagent A 调 Jira APIagent B 调 GitHub APIagent C 汇总。问题Jira API 响应慢10sLLM 等待超时直接 abort。解决在llm_config里设request_timeout: 30并用asyncio.to_thread包装 API call。CrewAI 方案task1FetchJiraDatatimeout20task2FetchGitHubDatatimeout20task3GenerateReportdepends on [task1, task2]优势depends on保证顺序timeout参数直接生效无需改 LLM config。劣势FetchJiraData失败时整个 crew abort无法 fallback 到“只用 GitHub 数据生成简化版报告”。选型结论流程固定、依赖明确、需定时执行 → CrewAI需复杂 fallback 逻辑如“Jira 不可用时查本地缓存”→ AutoGen。4.3 场景三客户支持对话路由识别意图 → 分派给专家需求特点用户发消息 → 判断是“退货”“物流”“技术问题” → 路由给对应 agent → 保持上下文连贯AutoGen 方案RouterAgent接收消息输出{intent: return, confidence: 0.92}GroupChatManager根据 intent 路由给ReturnsAgent关键RouterAgent的system_message必须包含所有 intent 的明确定义否则 LLM 会发明新 intent。优势路由决策透明可 audit 每次判断依据。CrewAI 方案RoutingTask→ output{next_agent: returns_specialist}Crew根据 output 动态选择 agent问题next_agent字段必须严格匹配 agent name大小写敏感拼错即 crash。解决在RoutingTask的output_pydantic里定义 enumclass NextAgent(str, Enum): RETURNS returns_specialist选型结论需要可解释性、审计合规 → AutoGen追求开发速度、容忍小概率 crash → CrewAI。4.4 场景四AI 编程助手理解需求 → 写代码 → 单元测试 → 修复 bug需求特点多轮交互状态强依赖test failure 信息必须传给 fix agentAutoGen 方案CoderAgent写 code →TesterAgent运行 test →FixerAgent读取 test output 修复关键TesterAgent的 tool 必须返回{code: ..., test_output: ..., error_lines: [12,15]}FixerAgent的system_message要强调“只修改 error_lines 指定的行”。优势test output 原样传递无信息损失。CrewAI 方案task1WriteCodetask2RunTestsinputcodetask1.outputtask3FixCodeinputtest_outputtask2.output问题RunTests的 output 是字符串FixCode的expected_output要求 JSON需额外写 parser tool。解决用output_pydanticTestResult让RunTests直接返回 Pydantic model。选型结论代码质量要求极高、需精确控制修改范围 → AutoGen接受一定抽象损耗、重在快速迭代 → CrewAI。4.5 场景五多源新闻聚合RSS/Telegram/API → 去重 → 摘要 → 分类需求特点数据源异构、实时性要求高、需 deduplicationAutoGen 方案FetcherAgent并行调多个 source →DeduperAgent用 sentence-transformers 计算相似度 →SummarizerAgent优势deduplication 逻辑可自定义如“标题相似度 0.85 且发布时间 1h 视为重复”直接写在 agent 代码里。CrewAI 方案task1FetchRSStask2FetchTelegramtask3Deduplicateinputsources[task1.output, task2.output]劣势Deduplicatetask 的 input 是 list of strings无法直接访问每个 source 的 metadata如 publish_time需提前在 fetch task 里把 metadata 嵌入 output string。选型结论需精细控制算法逻辑、数据源 metadata 丰富 → AutoGen数据源简单、重在 pipeline 编排 → CrewAI。4.6 场景六合规审查助手检查合同条款是否符合 GDPR需求特点输出必须 100% 可追溯、每个判断需引用具体条款AutoGen 方案GDPRAgent的system_message硬编码 GDPR Article 17, 20, 22 条款原文每次回答必须包含source: GDPR Article 17(1)(a)优势audit trail 清晰监管检查时可直接导出 message history。CrewAI 方案ReviewTask→output_pydanticGDPRComplianceReport字段含violations: List[Violation]Violation含article_ref: str优势结构化输出可直接入库生成 PDF 报告。劣势article_ref字段若填错如 Art. 17 而非 Article 17validation fail但 LLM 不知道错在哪。选型结论强监管、需人工复核 → AutoGen需自动化报告生成、对接内部系统 → CrewAI。5. 常见问题与排查技巧实录那些文档里不会写的坑5.1 AutoGen 高频问题速查表问题现象根本原因排查技巧我的 workaroundGroupChatManager无限循环agent A 说完 A 又说speaker_selection_method设为round_robin且没有max_round限制在initiate_chat时加max_round20并监听chat_history长度突增用custom_speaker_selection函数加入“若连续两轮相同 agent则强制切换”逻辑LLM 总是忽略system_message里的约束system_message过长500 字LLM 注意力衰减用print(len(system_message))检查把非核心约束移到message.content把核心约束如“必须输出 JSON”放在system_message开头 50 字内其余放descriptionfunction_call返回NoneLLM 不执行工具llm_config[functions]里函数名与function_call.name不一致大小写/下划线print([f[name] for f in llm_config[functions]])对比用tool(nameget_weather)显式指定 name不依赖函数名Redis cache 失效session 无法 resumepickle序列化时遇到不可序列化对象如lambdatry: pickle.dumps(obj) except Exception as e: print(type(e))所有 agent 初始化用functools.partial(MyTool, api_keyos.getenv(KEY))5.2 CrewAI 高频问题速查表问题现象根本原因排查技巧我的 workaroundCrew.kickoff()报错AttributeError: NoneType object has no attribute invokeAgent.llm未正确初始化如ChatOpenAI(modelgpt-4)但 API key 错误print(agent.llm)看是否为None检查OPENAI_API_KEY环境变量在Agent.__init__末尾加assert self.llm is not None, LLM not initializedTask的expected_output校验失败但输出看起来正确LLM 输出含不可见字符如\u200b零宽空格或换行符print(repr(task_output))查看原始 bytes在output_pydantic的 validator 里用field_validator(output)(lambda v: v.strip().replace(\u200b, ))Crew执行缓慢verbose log 显示大量Waiting for task...processHierarchicalProcess下manager agent 的 LLM 调用慢如 gpt-3.5-turbo 响应 5sprint(time.time())打点 manager agent 的llm.invoke前后把 manager agent 的llm换成Ollama(modelllama3)本地模型提速 3 倍Tool调用失败但 log 显示successTrueTool.func返回NoneCrewAI 默认视为 successprint(tool.func(*args))直接调用看返回值所有 tool 函数末尾加return success或结构化 dict绝不返回None5.3 跨框架通用避坑指南坑一LLM 的“自信幻觉”陷阱无论 AutoGen 还是 CrewAILLM 都可能在不确定时假装 confident。比如get_weather(New York)返回{temperature: 25, condition: sunny}但实际 New York 正在下雪。我的对策是所有工具调用后强制加一道VerificationAgent。它不调 API只用 LLM 检查返回值合理性“如果温度 25°C 且天气晴朗纽约当前时间应为夏季白天是否符合” 如果 LLM 判定不合理触发重试或报警。这增加了一次 LLM 调用但把错误拦截在源头。坑二Prompt 的“语义漂移”问题同一个system_message在 GPT-4 和 Claude-3 上行为可能完全不同。我在一个法律合同分析项目里发现GPT-4 严格遵守“只输出 article number”Claude-3 却总加解释。解决方案为每个 LLM 模型定制 prompt 版本并在 agent 初始化时动态加载。用model_name作为 key从 YAML 文件读取对应 prompt template。坑三Token 限制的隐形杀手AutoGen 的max_tokens控制总长度CrewAI 的Task.max_iter控制重试次数但没人告诉你LLM 的 context window 是硬上限超了会静默截断。我线上出过事故一个 12000 token 的长文档分析GPT-4-32k 模型在第 11900 token 处被截断LLM 以为文档结束输出“未发现风险条款”。解决方法在所有 agent 的system_message末尾加一句“你收到的文档可能被截断请在输出中声明是否读取完整。若不完整要求用户提供剩余部分。”这句话成本不到 10 token却避免了重大漏检。坑四调试时的“时间感知错乱”multi-agent 系统里agent A 的“现在”和 agent B 的“现在”可能不同步。比如 A 在 10:00:00 调用 APIB 在 10:00:05 收到 response但 B 的system_message里写“当前时间是 10:00:00”。我的做法所有 agent 的system_message禁止写绝对时间改用相对描述“你刚收到上一个 agent 的最新输出”、“请基于本次会话的全部历史决策”。最后分享一个小技巧无论用哪个框架上线前必做