
1. 为什么会有 Agent-Reach从单 Agent 卡壳说起今年年初我在做一版面向企业内部的自动化助手原型。当时手上的方案很常见一个主 Agent 对接大模型写好 system prompt配几个工具函数让它帮忙查库存、填工单、回邮件。单看每个场景效果都还过得去但一旦把场景串起来就出问题了——查库存的结果要给填工单的流程用填完工单要触发审批通知审批结果又要回流给主 Agent 继续下一步。刚开始我用最粗暴的办法把所有能力统统塞进一个 Agent 的 tool list 里prompt 写得越来越长模型在工具选择上开始频繁出错今天抽风去调库存接口明天把邮件发给了错误的收件人。更难受的是排查困难几十个工具被同一个 Agent 调用日志里只能看到模型每一步吐出的 JSON根本分不清是哪一环出了岔子。这个阶段我意识到一个很本质的问题真正拖后腿的不是大模型本身而是 Agent 的“触达”方式。单个 Agent 的能力边界一旦扩张到十几个工具、跨三四个系统它既要做意图理解、又要做参数抽取、还要在失败时自行决策回退路径几乎必然出问题。业界的解法也很明确——把大任务拆开用多个专用 Agent 各管一段彼此通过消息协作。但拆开之后马上冒出新麻烦谁来发现哪个 Agent 能处理当前请求请求应该发给谁、按什么协议发对方忙不过来或者挂了怎么办这些问题单独看都不难凑到一起却没有任何现成框架能直接满足我的需求。我试过当时主流的几套多 Agent 框架用下来的感受都不太对味。有的框架把 Agent 间通信绑定在特定基础设施上换一套部署环境就要改代码有的强迫所有 Agent 共用同一个向量库做“记忆同步”数据耦合重得吓人还有的只适合演示——编排图画得漂漂亮亮真实场景里一个超时就把整条链路上所有 Agent 全部卡死。我需要的其实是一个轻量的“触达层”它不负责 Agent 的智力部分只负责把请求准确、可靠、可追踪地送到正确的 Agent 手里再把结果原样带回来。这就是 Agent-Reach 的起点——一套以“触达”为核心的多 Agent 调度与协作骨架不绑定具体模型不强加记忆机制只解决“谁该处理、怎么送过去、出了事怎么收场”这三件事。如果你也在做多 Agent 系统并且已经厌倦了给编排框架打补丁或者你想理解多 Agent 协作的底层通信逻辑而不是停留在画流程图这篇文章应该能给你一些实在的参考。后面所有内容都基于我实际搭过的 Agent-Reach 第一版包含设计思路、踩坑记录和可复现的最小代码路径。2. Agent-Reach 要解决的四个核心问题2.1 Agent 的“发现”问题能力描述必须是显式的传统单体系统里服务之间的调用靠的是固定接口接口长什么样提前都写死了。多 Agent 场景完全不是这样一个请求进来时系统要能判断出“这件事应该由哪个 Agent 处理”而这个判断必须建立在“系统知道每个 Agent 能干什么”的前提之上。很多人在这一步就栽了跟头——他们用自然语言描述 Agent 的能力比如“这个 Agent 负责处理退货请求”。听起来没问题但真到匹配时大模型去读这段描述再决定路由每次都会有一点不确定的偏差有时候把换货请求分给退货 Agent有时候把退款咨询分给售后 Agent。Agent-Reach 的做法是把能力定义成一个结构化的描述文件我把它叫 Capability Descriptor。它不只是一段文字而是包含意图域、输入参数 schema、输出结果 schema、以及关键触发词的一组元数据。路由匹配时优先做确定性的 schema 校验和关键词加权只有低置信度时才让大模型介入决策。这样既保留了灵活性又把错误率压到了可接受的范围。2.2 请求的“可达”问题触达不是简单转发把请求从一个 Agent 送到另一个 Agent听起来就是一次 HTTP 调用的事实际里全是坑。第一对方 Agent 可能正处于长任务执行中没有空闲槽位接收新请求第二对方 Agent 依赖的外部系统可能临时抖动这时候直接转发请求只会浪费一次算力和时间第三Agent 之间传递的不只是文本可能还有结构化数据、文件引用、甚至需要回调的令牌。所以 Agent-Reach 里设计了一层 Request Envelope它把触达请求包装成标准结构里面包含请求 ID、来源 Agent ID、目标 Agent ID、能力匹配度、载荷、超时预算、重试策略和回调地址。转发动作本身是异步的接收方拿到 Envelope 后会先根据自身负载决定是立即处理、进入队列还是返回忙信号。这个设计让“触达”从简单的消息投递变成了带反馈的协商过程双方都有退路。2.3 链路的“回溯”问题每个请求必须可追踪多 Agent 协作最让人头疼的调试场景是什么是整条链路跑下来结果错了但谁都不知道是哪一步错的。单体 Agent 的日志还能靠 prompt 回放来查多 Agent 场景下请求会在好几个进程之间跳转如果没有全局唯一的追踪标识排查一次问题可能要把所有 Agent 的日志导出来手工比对时间戳。Agent-Reach 在入口处为每个业务请求生成全局唯一 Trace ID所有内部触达都携带这个 ID。日志系统里每条记录都会带上 Agent 名称、耗时、匹配分数、载荷摘要和错误码。我做了一个基于结构化日志的简单追踪界面输入 Trace ID 就能还原出完整的触达链路——从入口 Agent 到最终执行 Agent每一步谁处理的、花了多久、返回了什么。光是这一个能力就把排障时间从小时级降到了分钟级后面排错那章我会展开说一次真实的排查过程。2.4 失败后的“收场”问题降级策略必须前置设计多 Agent 系统里失败是常态不是意外。外部接口会超时模型会输出格式错误的 JSONAgent 会崩溃重启。大多数自研系统在失败处理上是事后补救的——出错了就往上层抛异常结果整个链路都跟着遭殃。Agent-Reach 从设计上就把“失败预案”写进了路由规则里。每个路由请求都带有一组可选的兜底方案可以重试当前 Agent 两次可以降级到能力重叠的备用 Agent可以调用确定性代码路径绕过 AI 决策也可以直接返回可读错误给用户。这些兜底方案不是运行时临时想的而是注册路由时预先配置好的策略表。实际运行效果很明显面向用户的成功率从 82% 提升到 97%提升的部分几乎都来自降级路径而不是重试。3. Reach Bus 的关键设计能力描述、路由与交接协议3.1 能力描述文件 Capability Descriptor 的字段设计先说最基础的能力描述。我在 Agent-Reach 里用一个 JSON 文件描述每个 Agent 的能力边界字段设计是整个系统路由准确性的基石。{ agent_id: order-refund-agent, display_name: 订单退款处理Agent, version: 1.3.0, intents: [ { name: refund_request, description: 用户要求对已支付订单发起退款, confidence_weight: 0.9 }, { name: refund_status_inquiry, description: 用户查询退款进度, confidence_weight: 0.7 } ], keywords: [退款, 退钱, refund, money back], input_schema: { type: object, properties: { order_id: { type: string, required: true }, reason: { type: string, required: false }, expect_refund_method: { type: string, required: false } } }, output_schema: { type: object, properties: { refund_status: { type: string, enum: [applied, rejected, need_review] }, refund_id: { type: string }, message: { type: string } } }, timeout_ms: 15000, max_concurrency: 5, fallback_agents: [human-service-agent], tags: [order, payment, refund] }字段不多但每个都有讲究。intents 是意图离散化列表每项带 confidence_weight用于路由阶段做加权打分keywords 是轻量级预筛条件可以在不调用大模型的情况下先排除明显不匹配的 Agentinput_schema 和 output_schema 用于触达时的参数重构和返回结果的校验。最关键的是 fallback_agents——预先声明这个 Agent 处理不了时应该把请求交给谁。后面做降级靠的就是这个字段。3.2 路由匹配先用确定性规则再用模型兜底路由是整个 Reach Bus 最核心的模块。我的实现分了三层按优先级从高到低执行第一层是精确匹配。请求里如果已经携带了目标 Agent ID比如上游 Agent 显式指定“这个交给退款 Agent”直接命中不做任何模型推理。这一层不消耗大模型算力延迟最低用于系统内部明确的交接。第二层是元数据匹配。拿请求的文本和结构化的意图做关键词加权匹配。比如请求里出现“退款”加订单号而订单退款 Agent 的 keywords 里正好有“退款”就是一次命中。这里的关键是要求至少命中一个关键词且意图域的 confidence_weight 超过 0.6 分才算合格否则宁可往下走也不强行匹配为的是避免错误的确定性。第三层才是模型路由。前两层都没匹配上时把请求的描述、候选 Agent 的 intents 列表、以及候选数量上限拼接成一段精简的决策 prompt让大模型做一次分类任务。注意这层不是让模型自由发挥而是让它从给定候选中选一个或者输出 none同时返回置信度。置信度低于阈值时系统直接转人工兜底不硬选。路由模块还会记录每一层匹配的日志包括候选 Agent 列表、分数明细、最终选择。这些日志是后来优化路由策略的数据来源我靠它们把模型的兜底调用量从最初的 53% 降到了 22%——意思是超过一半的请求在第二层就被确定了不用每次都付出模型推理的算力成本。3.3 交接协议Request Envelope 与回调机制Agent 之间不会直接互调内部方法所有的触达都通过 Envelope 走总线。我定义了下面的传输结构作为内部统一协议{ schema_version: 1.0, envelope_id: env_01J2XAB9KT7QEXAMPLE, trace_id: trace_01J2XAB9KT7QEXAMPLE, source_agent: conversation-front-agent, target_agent: order-refund-agent, routing_hint: exact_match, payload: { order_id: SO-20241107-023, reason: 商品破损, expect_refund_method: original }, callback: { type: async, endpoint: http://conversation-agent.internal/callback, expected_schema: refund_result }, timeout_ms: 15000, retry_policy: { max_attempts: 2, backoff_ms: 500, on_failure: fallback }, metadata: { priority: normal, tenant_id: tenant_a } }Envelope 设计里有三个容易被忽略但很重要的点。第一个是 callback接收方处理完结果之后不是直接返回 HTTP response而是异步 POST 到 callback endpoint。这样发送方可以立刻释放继续处理其他请求不会出现一条链路同步阻塞整条链路的情况。第二个是 retry_policy它精确规定了重试几次、间隔多久、最终失败动作是 fallback 还是直接丢弃。第三个是 metadata.priority高优先级任务会被接收方 Agent 优先处理我用来确保 VIP 用户的请求不被普通请求堵住。3.4 为什么不在 Agent 之间直接点对点调用你可能想问搞这么多结构化包装直接在代码里让 Agent A 把结果传给 Agent B 不就行了小规模可以规模稍大就会失控。点对点调用最致命的问题是耦合每个 Agent 都得知道其他 Agent 的地址、方法签名、鉴权方式新增一个 Agent 就要改一堆调用方代码。更糟的是没有统一的超时、重试和追踪机制每个调用方都写一套逻辑最终一定不一致。Reach Bus 本质上是一个轻量消息中枢它把“调用具体 Agent”这件事抽象成了“基于能力描述和路由规则发一个请求”。发方不需要知道收方 Agent 部署在哪、怎么鉴权、内部用什么模型只需要提交一个结构化请求剩下的事全部由总线处理。这个抽象让新增 Agent 的成本变得极低——注册一份 Capability Descriptor连上总线其他 Agent 就能自动发现它的存在。我后来加了三个新 Agent整个接入工作只花了一个下午靠的就是这套松耦合机制。4. 最小可用的 Agent-Reach从零搭建的实操路径4.1 整体组件布局先给你一张我在第一版落地的组件清单总共四个核心模块Reach RegistryAgent 注册中心存储 Capability Descriptor提供注册、更新、下线的 API。Reach Router路由引擎负责意图匹配、分数计算、模型兜底决策和降级策略执行。Reach Bus传输层负责 Envelope 的接收、投递、回调、超时管理和重试。Reach Monitor基于结构化日志的追踪与统计模块提供 Trace ID 查询和延迟分布统计。前三个模块跑在 Python 3.11 FastAPI 的进程里Monitor 不单独部署直接读取统一日志流做聚合。所有 Agent 只要实现一个简单的 SDK 客户端就能接入——发送请求、接收 Envelope、回调结果SDK 封装了大部分重复逻辑。4.2 接入一个 Agent 的全过程为了让你对整体成本有直观感知我拿“订单退款 Agent”当例子完整走一遍接入流程。第一步编写 Capability Descriptor 并注册到 Registry。这一步就是把我上面展示的 JSON 保存为文件然后调用注册接口curl -X POST http://localhost:8300/registry/agents \ -H Content-Type: application/json \ -d order-refund-descriptor.json注册成功后 Registry 会返回 agent_id后续更新只需要提交新的 descriptor 文件版本号需要递增Router 会自动拉取最新版本匹配。第二步实现 Agent 的业务入口函数。SDK 提供了一个装饰器可以让你把一个普通 Python 函数注册成 Agent 的处理器from agent_reach_sdk import register_handler, Envelope register_handler(agent_idorder-refund-agent) def handle_refund_request(envelope: Envelope): order_id envelope.payload[order_id] reason envelope.payload.get(reason, unknown) result { refund_status: applied, refund_id: generate_refund_id(order_id), message: f退款申请已受理原因为{reason} } return resultSDK 在后台会完成 Envelope 解析、结果校验、回调触发这些事。你只需要关心业务逻辑本身不需要自己处理传输层的细节。第三步配置回调地址和降级策略。在注册 Descriptor 时已经声明了 fallback_agents 和 timeout_msSDK 初始化时还需要传入 Agent 自身能接收回调的 endpoint。这里要特别注意 callback endpoint 必须是接收方 Agent 可达的地址部署在不同网络环境时最容易在这里断链。三步走完这个 Agent 就具备了被其他 Agent 通过总线触达的能力。我在实际接入时还写了一个自检命令脚本会自动发一条测试请求走完整条链路并打印延迟接入完跑一遍能省不少联调时间。4.3 路由和总线的最小实现逻辑Router 的核心代码不长我把骨架贴出来给你参考匹配逻辑的关键分支def route_envelope(envelope, registry): descriptors registry.list_active_agents() # 第一层exact match请求中直接指定了目标 Agent if envelope.target_agent: descriptor registry.get_descriptor(envelope.target_agent) if descriptor: return route_to(descriptor, envelope) # 第二层关键词 意图分数加权匹配 candidates [] for desc in descriptors: score keyword_match(envelope.payload, desc[keywords]) if score 0: intent_score max( [i[confidence_weight] for i in desc[intents] if i[name] in extract_intent_hints(envelope.payload)], default0.0 ) total score * 0.6 intent_score * 0.4 if total 0.55: candidates.append((total, desc)) if candidates: candidates.sort(keylambda x: x[0], reverseTrue) best_score, best_desc candidates[0] if best_score 0.7: return route_to(best_desc, envelope) # 第三层模型兜底 decision model_route(descriptors, envelope) if decision and decision.confidence 0.75: return route_to(decision.descriptor, envelope) # 全部失败转人工兜底 return route_to(registry.get_descriptor(human-service-agent), envelope)三层结构里每一层的阈值都来自我压测时的统计结果0.55 是召回率曲线的拐点0.7 是精确率稳定超过 93% 的阈值0.75 是模型兜底决策最可靠的置信度。这些数字不是拍脑袋定的是本项目环境下跑出来的经验值你拿到自己的场景里要做同样的事——拿一批历史请求回放画出精确率和召回率曲线再选拐点。4.4 让 Agent 接收请求内置消费循环Agent 端不需要自己开线程池SDK 启动时会根据 Descriptor 里的 max_concurrency 自动创建消费队列。每收到一个 Envelope先检查当前并发数超过阈值就直接返回 429 忙信号由总线根据重试策略决定后续动作。这个“告诉对方我忙”的机制非常关键它给系统提供了天然的背压能力避免打满资源后所有请求一起超时。def start_consumer(agent_id, handler): queue Queue(maxsizedescriptor[max_concurrency]) def worker(): while True: envelope queue.get() try: result handler(envelope) callback(envelope, result) except Exception as e: callback(envelope, {error: str(e)}) finally: queue.task_done() for _ in range(descriptor[max_concurrency]): threading.Thread(targetworker, daemonTrue).start()5. 工单自动化链路的真实复盘一次触达失败的完整排查5.1 业务场景三个 Agent 协作处理一张工单Agent-Reach 上线后我拿内部 IT 工单场景做了第一场真实战役。流程是这样的前端对话 Agent 接收员工提报的问题描述识别出问题类型后把硬件报修类请求触达给硬件支持 Agent把账号权限类请求触达给账号管理 Agent处理完成后结果回传给对话 Agent再由对话 Agent 组织语言回复员工。某天下午两点左右大量员工反馈同一个现象工单提交之后一直显示处理中五分钟内没有任何结果返回。我立刻拉出监控面板发现账号管理 Agent 的待处理队列长度从 0 瞬间涨到了 47而硬件支持 Agent 一切正常。更奇怪的是账号管理 Agent 进程本身没有崩CPU 和内存都正常但请求进去之后就像石沉大海。5.2 逐步排查从队列长度反推入口压力我先查了总线上各 Agent 的接收成功率账号管理 Agent 的数据显示触达请求全部成功投递但完成率只有 5%。这说明问题不在传输层也不在路由层——请求已经到了 Agent 内部但没有被处理完。接着看 Agent 内部的日志发现处理器抛了一个奇怪的异常——某个外部权限系统返回的 JSON 里多了一个之前没见过字段导致解析器直接抛错。这个异常抛出的位置在 handler 的日志输出之后、业务逻辑完成之前。关键来了我第一版代码里异常处理犯了个错误我让 SDK 捕获到异常后只是打印日志没有给总线返回失败回调也没有触发 Envelope 里的 fallback 策略。于是请求就在队列里一直被占用直到超时而队列满员后新的请求被背压挡在外面形成雪崩。5.3 根因异常路径没有回应总线这就引出 Agent-Reach 设计里非常重要的一句话——任何情况下都必须在超时预算内向总线给出回应要么返回结果要么返回错误绝不能默默吞掉异常。当时的修复分了两步。第一步在 handler 外层加了一个统一异常捕获所有未处理异常都会被 SDK 转换成结构化的错误回调标记为 error_fallback_triggered并自动按 Descriptor 里的 fallback_agents 把请求降级给后备 Agent。第二步是数据层面的防御外部系统返回的 JSON 解析改成宽容模式未知字段先缓存再告警不让单次异常数据打挂整个队列。register_handler(agent_idaccount-admin-agent) def handle_account_request(envelope: Envelope): try: external_data fetch_account_system(envelope.payload[employee_id]) # 宽容解析未知字段不阻断主流程 safe_data tolerate_unknown_fields(external_data) return process_account_request(safe_data) except Exception as e: # 关键把异常变成结构化错误响应回传总线 return EnvelopeError( error_codeEXTERNAL_SYSTEM_PARSE_ERROR, messagestr(e), retryableTrue, fallback_after2 )5.4 排查过程中的两个次要发现主问题修完之后我顺手在追踪日志里发现两个以前没注意的现象也值得一说。第一个是 Trace ID 在跨进程传递时偶尔会丢。原因是某个 Agent 内部自己发起了一个子任务调用子任务代码是我写的但当时忘了把 Trace ID 透传出去导致监控面板里出现断裂的链路。修复方式很朴素——SDK 在启动时从环境变量读 Trace ID子任务默认继承父任务的上下文不需要人工传参。第二个是重复回调导致结果覆盖。有些 Agent 处理完成后回调发送方但发送方在这段时间内已经超时进入了降级路径结果回来后发送方无法判断这份结果对应的是哪个降级轮次。我在 Envelope 里加了一个 round_trip 计数器每轮请求自增一次回调里带上轮次编号发送方只接受最新轮次的结果过期结果直接丢弃并写告警日志。这个问题没有监控数据几乎发现不了因为它不会造成功能报错只会让结果偶尔被旧数据覆盖。6. 规模化使用 Agent-Reach 必须知道的约束与经验6.1 慎用同步链路把设计全部调整为异步消息最初我相信同步调用简单直接一个 Agent 处理完直接返回给下一个接口接接口。结果在实际负载下有两大痛点一是链路总延迟等于所有 Agent 延迟相加最慢的一个 Agent 卡住三秒整条链路用户体验就崩了二是资源占用极端不平滑请求集中在同一时间进入时所有 Agent 的线程被同时投诉系统整体吞吐量很受影响。改成异步消息之后总线只负责投递和收取回调每个 Agent 各管各的队列慢的 Agent 不拖累快的 Agent队列也变成了天然的缓冲平滑了波峰。如果你要参考这个项目第一个建议就是从一开始就别写同步链路全部按异步设计。就算早期场景简单同步链路能跑后期扩张时改造代价也会大得让你不想动。6.2 契约变化是最大的隐性成本容器间要紧耦合Agent 之间通过 Capability Descriptor 声明能力但声明归声明真正调用时参数和返回结果还得对得上。我遇到的典型坑是前端对话 Agent 在处理完对话后返回的结果后端接收 Agent 按老 schema 解析结果多了一个字段就报错。业务逻辑没问题纯契约不一致导致的问题。现在的经验是Descriptor 里给 schema 加了 version 字段每次变更必须递增版本Router 在触达时会做一次 schema 兼容性检查不兼容直接拦住并告警。另外我还推行了一件事——接口联调时必须用真实数据跑通全链路多 Agent 契约出问题的高发区往往是大家各自为战、用模拟数据自测导致的。6.3 降级策略别做成“无限重试”成本与时间都要设上限最开始的降级策略配置得很粗糙失败就重试最多重试五次间隔还越来越短。实际跑起来发现两个问题一是重试会放大外部系统的压力对方明明已经挂了重试五次只会把它们压得更死二是重试太久会显著拉低整体延迟用户那边早就没耐心了。我现在用的策略是“快速失败 单次降级”。最多重试两次间隔固定在 500 毫秒总重试时间不超过 1.5 秒超过之后直接降级到 fallback Agent 或者返回错误。安全的做法是永远不要指望某个远程系统会在你的重试期间恢复设计时假设它随时会坏把兜底方案做扎实。6.4 可观测性从第一天就要做日志结构必须严格统一多 Agent 系统的调试体验很大程度取决于日志统一到什么程度。第一版我有好几个 Agent 日志格式都不一致有的用 JSON 输出有的用文本拼接排查时每看一种格式都要重新熟悉一遍。后来我统一了所有 Agent 的日志格式要求每条日志至少包含 trace_id、agent_id、event_type、elapsed_ms、payload_summary 这五个字段。全部走结构化日志流所有监控面板都可以基于同一套字段做聚合。这个改动本身不复杂但收益非常显著后面再遇到问题基本是在面板上一查定位不用再翻原始日志大海捞针。6.5 别忘了安全和边界Agent 不能乱调别人的敏感工具最后说一个不常有人提但很重要的点。Agent 之间可以触达不代表可以随便触达所有能力。我在做权限隔离时给每个 Agent 分配了 token总线在投递时会校验发方的调用权限。比如前端对话 Agent 可以触达账号管理 Agent 的密码重置工具但硬件支持 Agent 没有这个权限。这个可以在 Descriptor 里加一个 allowed_callers 字段Regex 匹配一下就行。安全设计不一定复杂但一定要有不然一个 Agent 被攻破整条链路上所有 Agent 的能力都会暴露给对方。7. Agent-Reach 下一步从“触达”走向“协商”第一版 Agent-Reach 解决的是“找到对的 Agent把请求送过去把结果带回来”这件事。做到这一步多 Agent 协作已经能跑出基本盘了。但跑了这大半年我心里有几个方向明确想试这里也分享出来算是给这个项目留个续集。第一个方向是把“让一个 Agent 处理问题”升级成“让多个 Agent 共同商量问题”。现在的协作模式是链式的请求沿链路传导单向流转。但很多任务天然是分支汇聚式的比如一个审批流程财务 Agent 和合规 Agent 并行处理同一份申请两个结果都要回来后才能决定最终状态。我打算把总线从点到点通信扩展成话题群组一组 Agent 订阅同一个 topic各自处理后在协调者那里汇合。第二个方向是让 Agent 具备自助注册能力。现在的 Descriptor 还是要人工编写注册我想让 Agent 在启动时自动探测自己的能力边界生成 Descriptor 后提交注册。这个想法落地难点在于能力探测不能是形式化的——一个描述为“能处理报表”的 Agent真让它处理报表时可能根本不会。可靠性校验怎么设计是一个绕不开的问题。第三个方向是把总线的触达记录反哺给路由匹配。现在匹配靠关键词加模型兜底但每次触达的真实结果数据其实都在完全可以把历史成功率和失败率作为特征加入路由打分。也就是说一个 Agent 处理某类请求屡屡超时它的匹配分就应该自动降低让请求流向更可靠的候选。这等于给系统加了一个简单的自适应机制让它能基于运行数据自我优化。这些方向我不会一步到位全做完会挑一两个先验证跑出稳定性后再扩展。Agent-Reach 从一开始的目标就不是做一个功能全面的平台而是把“触达”这个最底层的问题解决干净。只有 Agent 之间能低成本、可靠地互相找到并协作上层那些复杂的编排、规划、反思才有意义。