
1. 为什么会有Agent-Reach智能体困在对话气泡里的真实瓶颈1.1 先给结论推理再强够不到东西就等于零我在做多智能体自动化项目的时候有一个特别强烈的体感大模型负责的那部分——理解意图、拆解任务、生成步骤——其实已经做得很好了真正拖后腿的是执行端。Agent能说我可以帮你查天气、订会议室、发邮件但真要落地的时候它得能真正调用那个API、真正读写那个数据库、真正拿到那份文件。这一步行业里有各种叫法Tool Use、Function Calling、MCP工具接入都离不开一个本质问题Agent的手能伸多远。我给自己这套连接层方案起了一个更形象的名字——Agent-Reach。Reach解决的问题非常朴素让智能体真正够得着外部世界。你给它接一个内部系统、一个外部服务、一个同事Agent它的手就多长了一截。但问题是大多数Agent框架在这块的抽象都太浅了。你可以在代码里注册十个工具函数可一旦到了实际业务里工具会变多、权限要分级、外部系统不稳定、上下文还得省着用这时候你就会发现能注册工具和能可靠地使用工具完全是两回事。这篇东西不是讲论文也不是给你吹概念。我准备把我从零开始设计Agent-Reach这个连接层的完整过程、踩过的坑、每次选择背后的理由原原本本摆出来。如果你也在做Agent类项目或者准备给自己的Agent接真实系统这篇应该能帮你少走几个月的弯路。内容会偏工程但我尽量把每个术语都讲成人话。1.2 三个让人崩溃的场景逼我动手自研先说第一个场景。我给客户做了一套客服Agent接了一个内部工单系统的API。上线第一周成功率不到60%。原因查到最后很尴尬——不是接口挂了而是工单系统的认证token会定期轮换Agent用的还是旧token。按常规做法这属于基础设施问题但Agent不会自己感知token失效它只会照常发请求然后拿到401然后告诉你工单创建失败。用户看到的是Agent无能根源是Reach层没做认证生命周期管理。第二个场景是工具爆炸。业务方一开始只要三个工具三个月后变成了两百多个。这时候最痛苦的已经不是调用了而是选择。模型对着两百个工具描述光看tool schema就要烧掉一大截上下文选错的概率也直线上升。我们当时用的老框架一把梭地把所有工具塞给模型结果就是prompt臃肿、调用错乱、调试起来想骂人。第三个场景是Agent之间的协作。两个Agent要交接一个任务A把结果塞给BB再干下一步。听着简单但A这边的工具、认证、上下文格式跟B是完全独立的两套。你没法指望A把用户的诉求直接丢给B就完事——B不认你A的中间格式B也没有A的权限。这跟人类团队一个道理你让销售直接交接给研发中间得有规范的口径和流程。没有这层东西多Agent就是一盘散沙。这三个场景让我意识到Agent落地的瓶颈不在模型的推理能力而在够得到这件事本身。于是我开始动手写Agent-Reach。1.3 设计目标把够得到拆成可度量的工程问题动手之前我先给自己定了几个目标写在了笔记本第一页。第一个是能力可注册、可发现。任何工具、API、数据源、子Agent都按统一格式注册进去Agent用的时候按需发现而不是把所有东西一次性塞进prompt。第二个是调用可管控。认证、权限、频控、预算必须在Reach这一层统一收口不让每个Agent各搞一套。第三个是失败可恢复。调用失败要有重试、降级、明确报错不能让Agent在401、超时、限流这些事上装傻。第四个是链路可观测。每一次Reach调用从意图到结果都要有日志、有指标、能回溯。这四条定完Agent-Reach的骨架就清楚了。说白了它就是一个横在Agent和外部世界之间的连接层——往下统一接各种资源往上给Agent一套干净的调用接口。接下来的几个章节我会按架构、调用链、多Agent协作、踩坑、度量这个顺序把整个项目讲透。2. Agent-Reach的架构拆解四个模块管住手伸出去的每一米2.1 Capability Registry能力注册表所有够得到的唯一入口Agent-Reach的设计核心是Capability Registry能力注册表。我把它想成是一个能力版的搜索引擎——Agent不直接知道某个工具函数的地址它只向Registry发问谁能帮我创建工单Registry返回一批候选能力。一个能力的注册描述我用的是这样的结构Python示例dataclass class Capability: name: str # 全局唯一名称如 jira.create_issue type: str # api / function / agent / db / file intent_tags: list[str] # 意图标签供语义匹配[创建工单, issue, bug] input_schema: dict # 入参的 JSON Schema output_schema: dict # 出参的 JSON Schema用于结果校验 auth_required: bool # 是否需要认证 auth_provider: str | None # 认证提供方标识 timeout: float # 建议超时单位秒 rate_limit: int # 每分钟最大调用次数 cost_per_call: float # 估算单次成本用于预算管控 health_check: str | None # 可选的健康检查方式 version: str # 能力版本这串字段是我踩了不少坑才定下来的。比如intent_tags一开始我没设计后来发现靠模型读name和schema去猜工具用途猜错率很高。加上标签之后匹配准确率明显提升。cost_per_call和rate_limit也是后来加的——不加不行模型在循环里疯狂调用一个计费API的场景我见过不止一次。注册的方式很简单装饰器或者配置文件都行。我在项目里两种都支持开发期用装饰器最快registry.register( namejira.create_issue, typeapi, intent_tags[创建工单, issue, 提交bug], timeout10, rate_limit60, ) def create_issue(project: str, summary: str, description: str) - dict: # 真实调用 Jira REST API ...注册表必须在Agent容器之外单独跑或者至少做成一个独立服务。为什么我一开始把Registry直接内嵌在Agent进程里结果两个Agent各有一份注册表A注册的能力B看不到多Agent协作直接哑火。后来我把它抽成独立服务所有Agent共享一份全局注册表这个问题才根治。2.2 Reach Resolver从模糊意图到候选能力集的映射逻辑Resolve是Reach层里最有智能味道的一环但我个人的工程判断是这里应该用轻量的语义匹配而不是硬上一个微调模型。实践下来三层过滤的方案性价比最高。第一层是关键词/标签匹配。利用intent_tags做文本命中复杂度低、速度快。第二层是向量召回。把用户请求和每个能力的name加intent_tags加简短描述分别做embedding用余弦相似度筛Top-K。第三层是模型精排。在小规模候选里比如Top-5让大模型结合上下文做最终选择。代码示意async def resolve(request: str, top_k: int 5) - list[Capability]: # 第一层标签命中 tag_hits registry.search_by_tags(request) # 第二层向量召回 vec_hits await vector_store.search( embed(request), top_ktop_k * 2 ) merged dedupe(tag_hits vec_hits) # 第三层模型精排只针对 Top-5 以内 ranked await llm_rerank(request, merged[:5]) return ranked这里我必须强调一个经验给模型的候选一定要限量。我曾经为了省事把Top-50全部丢给精排模型去挑结果模型选择了符合直觉但错误的工具原因是候选太多时模型注意力会发散。控制在5个以内精确率可以从78%升到91%。提示Resolve阶段给模型的候选数量一定要控制在5个以内。我实测Top-5对应的工具选择精确率约91%Top-50直接掉到78%。宁可在前置过滤阶段多花点时间做标签和向量匹配也别把大量候选丢给模型做开放选择。2.3 Protocol Bridge不重新发明协议只做四种接入方式Agent-Reach不打算重新发明一套API协议那没有任何意义。它要做的是把四种常见接入方式统一成一种内部调用表示接入方式适用场景内部适配方式REST/HTTP API大多数SaaS、内部系统requests/httpx封装统一处理JSON序列化Python函数/本地命令本地工具、脚本、CLI装饰器注册进程内直接调用数据库/文件读取结构化数据、知识库安全查询封装只暴露白名单操作子Agent调用多Agent协作走内部握手协议构造ReachRequest转发这个表基本覆盖了我目前遇到的所有接入场景。Protocol Bridge的核心逻辑不复杂——把外部五花八门的调用格式转成内部统一的ReachRequest和ReachResponse两个标准结构下游是做认证、重试、观测还是做权限都只认这两个结构。dataclass class ReachRequest: capability: str params: dict agent_id: str trace_id: str deadline: float # 绝对截止时间防止无限等待 budget: float | None # 本次调用预算上限 dataclass class ReachResponse: status: str # ok / error / timeout / denied / degraded data: dict | None error: ReachError | None latency_ms: int cost: floatdeadline这个字段是我血的教训换来的。早期没有绝对截止时间只设了超时重试结果一个Agent在死循环里反复调用一个慢接口把整个消息队列堵了十分钟。后来每个Request必须带deadline解析层发现超时就立刻放弃绝不重试超死循环。2.4 Reach Policy Engine认证、权限、频控、预算的四个控制阀Policy Engine是Agent-Reach里最不起眼但最救命的模块。它管四件事认证你是谁、权限你许不许用、频控你用得够不够克制、预算你烧了多少钱。认证这里我强烈建议走统一Credential Vault而不是让能力函数自己带着token。每个Agent启动时拿到一个短期票据Policy Engine用票据去Vault换真正的访问凭证。凭证不外泄到Agent内存之外Agent其实不知道自己的token是什么它只负责发请求真正签名是在Bridge这层做的。这样token轮换、吊销都集中在VaultAgent层面完全无感。权限做到服务级-能力级-参数级三层。一个Agent可能有读权限但没有写权限可能有创建工单的权限但project参数被限定在指定项目里。参数级过滤我用JSON Schema校验加预设模板比如POLICY { agent_id: customer-service, allowed: [ { capability: jira.create_issue, param_rules: {project: {enum: [CS-001, CS-002]}}, max_per_minute: 10, max_cost_per_call: 0.5, } ] }频控和预算本质上是把钱和量量化成硬约束。实践上我会让每个Agent在启动时声明自己的预算包比如这个会话最多烧两块钱的API费用Policy Engine在每个Request到来时做累加判断超了就回deniedAgent可以转而求助用户或走人工兜底。3. 一次调用的完整链路从Agent说我要XX到结果回填的每一毫秒3.1 意图解析阶段把模糊表述变成明确的ReachRequest在Agent-Reach里Agent不是直接调用工具而是先产出一个结构化的调用意图。比如用户说帮我查一下上个月的工单情况Agent内部走一遍Reach层首先把这句话解析成候选能力请求——resolve(查工单情况)返回候选其中就包括jira.search_issues和datawarehouse.query_tickets两个前者查的是工单系统的实时数据后者查的是数仓的离线聚合数据。这一步看起来简单但这个解析动作由谁来做直接决定整个Reach层的可靠性。我尝试过两种方案让Agent自由发挥生成JSON以及用约束生成的函数调用接口。结论是必须用结构化约束也就是Function Calling或JSON Mode这类机制否则模型会给你编出capability字段里不存在的名字甚至把params嵌套格式写错。我的做法是Agent推理循环中设置一个固定的动作格式所有外部操作必须输出成ReachAction再由Reach层接管{ type: reach_call, capability: jira.search_issues, params: {jql: created -30d, fields: [summary, status]} }模型只负责决定干什么Reach层负责怎么干成。这个分离非常重要——模型不接触token、不接触连接池、不接触重试逻辑它只输出意图剩下的脏活全交给Reach层。3.2 参数补全与Schema校验宁可让模型少写不可让它瞎编意图拿到之后Reach层先做参数补全。Agent给出来的params经常不完整比如用户只说了查工单但API要求必须带fields参数。这时候有两种补全方式一是默认值补全二是在描述里标记必填让模型在生成阶段就把参数带全。我两边都做。Schema里标注的required字段如果在Request里缺失且没有默认值时Reach层不会直接报错而是返回参数缺失给Agent让Agent结合对话历史来补。有些参数则可以安全默认比如timeout用10秒。默认值补全要克制只有对业务结果毫无影响的参数才能默认——我见过有人默认了projectmain结果一个测试工单开到了生产项目里。校验用jsonschema库就行重点是校验时机必须在调用任何外部系统之前。校验失败的信息要结构化包含哪个字段、缺了什么、期望什么类型这样Agent才能根据错误信息自行修正而不是把原始的schema异常直接怼给用户。3.3 执行与重试如何设计该重试和不能重试的边界执行阶段Reach层通过Protocol Bridge发出真实调用。这里最需要设计的是重试策略我的规则是三色分类绿色错误可重试网络抖动、503、超时、限流。可以重试但必须指数退避且总重试次数不超过3次。黄色错误条件重试认证过期需要刷新票据、幂等冲突。先执行恢复动作如刷新token恢复成功再重试一次。红色错误绝不重试参数校验失败、404、权限拒绝、业务规则冲突。重试一万次也是同样的失败直接返回给Agent。这个分类我写进了Bridge层任何能力接入时必须声明自己抛出的错误属于哪一类。写清楚之后重试的成功率提升明显而且假死问题大幅减少——因为红色错误不再被无限重试。async def execute(req: ReachRequest) - ReachResponse: try: result await bridge.invoke(req.capability, req.params) return ReachResponse(statusok, dataresult, latency_ms..., cost...) except RetryableError: for attempt in range(3): await asyncio.sleep(2 ** attempt) try: result await bridge.invoke(req.capability, req.params) return ReachResponse(statusok, dataresult, ...) except NonRetryableError: break return ReachResponse(statuserror, errorReachError(retry_exhausted)) except NonRetryableError as e: return ReachResponse(statuserror, error...)注意所谓可重试只限于绿色错误。任何参数校验失败、权限拒绝、业务冲突的错误都不要放进重试逻辑里否则就是死循环的温床。我线上出过最长的一次假死就是参数错误被当成可重试错误循环了二十多分钟。超时设计也在这里。我采用每层递减策略Reach层给Agent的总deadline是15秒内部Bridge的超时设10秒实际HTTP请求超时设8秒留给DNS、序列化、排队一定余量。这样最外层永远比最内层早一点触发不会出现多层同时爆超时的脏状态。3.4 结果回填与上下文管理工具输出是上下文里最值得省的一块调用成功之后还有个容易被忽视的问题结果怎么回到Agent的上下文里。工具返回的数据常常很大——一次数据库查询可能返回几百行记录直接全量塞给模型上下文立刻爆掉还可能夹带敏感字段。我的做法是三个动作裁剪、摘要、标记。裁剪是只保留output_schema里声明过的字段凡是Schema没提到的字段一律丢弃这同时解决敏感数据泄漏的一大部分问题。摘要是对大数据做统计性压缩比如查询返回200行日志就压缩成共200条其中error状态5条最近一条时间xx。标记是给每条工具结果打一个溯源标识方便Agent在需要时回头取原始数据而不用一开始就全量带进来。def compress(result: dict, schema: dict) - str: safe filter_by_schema(result, schema) if estimate_tokens(safe) 800: return summarize(safe) [full_data_hash...可通过retrieve能力取原始数据] return json.dumps(safe, ensure_asciiFalse)实测下来结果回填从全量塞改成裁剪摘要后同一个任务的上下文token消耗降低了约60%而任务完成质量没有下降反而因为模型注意力集中在摘要上答案更准了。4. 多Agent协作让Agent之间也能够得到彼此4.1 Agent Directory为什么每个Agent都需要一个通讯录单Agent的Reach解决手伸到系统多Agent的Reach解决手伸到另一个同事。Agent之间的调用不能靠硬编码对方的地址或API——那样你又回到了有状态耦合的老路。Agent-Reach里每个Agent在启动时会向Agent Directory注册自己声明自己能提供什么服务、接收什么输入、输出什么格式。注册结构类似于Capability但要加几个协作字段dataclass class AgentProfile: agent_id: str capabilities: list[str] # 提供的可达能力 input_format: str # 接收数据的格式 output_format: str # 输出数据的格式 reliability: float # 历史成功率 avg_latency_ms: float # 平均响应延迟 stateful: bool # 是否是有状态AgentDirectory的主要作用是解耦。Agent A不需要知道Agent B的地址、认证、实现细节它只需要知道谁可以做合同审核Directory返回候选Reach Resolver复用同一套逻辑来选择。A到B之间永远只走一条路A - Reach层 - Directory定位B - 握手协议 - B执行 - 结果回传A。这里有个很反直觉的经验不要因为B可靠就永远只找B。可靠性和负载是变化的A选协作对象时应该带上筛选兜底的逻辑——首选一个高可靠的但这个选择失效时能立刻切换。我用的是对Directory返回的候选做活跃度排序会话级亲和策略简单说就是给协作对象加一个短期热连接缓存但每次调用前都做一次轻量健康检查。4.2 协作握手协议不信任对方应该懂只信任白纸黑字Agent之间协作最容易翻车的地方是你以为对方懂了你的意思。Agent A说帮我处理这批用户反馈它脑子里的处理是打标归类Agent B理解的处理可能是发邮件回复。问题根源在于自然语言描述在Agent之间的传递歧义比人之间更大因为模型编造语义是常态。所以Agent-Reach在Agent协作上加了一层握手协议发起方必须显式声明任务类型、输入输出格式约束、验收标准、超时时间。接收方不是听懂了就开干而是先回一个HandshakeAck把它的理解复述一遍比如我收到的任务是将这批反馈按情绪打标为positive/negative输出JSON数组每条含text和label。理解无误请确认。发起方确认后B才真正执行。这个握手看着笨但实测效果非常好。第一歧义在动手前就被消灭了第二如果A记错了格式B会在握手时catch到而不是执行完发现格式不匹配第三握手过程天然形成了一条可审计的协作契约日后排查问题有据可查。4.3 任务移交的可靠语义At-Least-Once还是At-Most-Once多Agent协作里有个绕不开的语义问题A把任务交给B如果B执行了一半崩溃了A是重发一遍可能导致B重复执行还是不重发可能导致任务丢失我给出的工程答案是按任务性质分。对于幂等任务比如生成一份摘要按标签订单用At-Least-OnceA可以放心重发B重复执行不会造成额外破坏。对于非幂等任务比如发起一笔退款发送一封邮件必须At-Most-Once通过任务ID去重B记录已经执行过的task_id重复请求直接返回已完成结果见缓存。async def dispatch(task: CooperativeTask): if await handshake(task) ! ack: return ReachResponse(statuserror, errorReachError(handshake_rejected)) if not task.idempotent: cached await dedup_store.get(task.task_id) if cached: return ReachResponse(statusok, datacached) result await agent_b.execute(task) if not task.idempotent: await dedup_store.set(task.task_id, result, ttl3600) return ReachResponse(statusok, dataresult)这套语义实装后两个最头疼的场景都稳了一是B重复执行导致用户收到两封一样邮件二是B挂掉后任务凭空消失没人管。幂等标记其实很便宜——每个任务定义里加一个布尔字段而已但它能把可靠两个字落到实处。5. 落地Agent-Reach时我踩过的一组坑每一条都是真金白银换来的5.1 工具输出爆掉上下文的教训第一次全量回填模型直接失忆我第一次把Agent-Reach接到一个数据分析Agent上时傻乎乎地允许了一个SQL查询能力把完整的2000行查询结果全量返回给模型。结果那个Agent在接下来的对话里开始选择性失忆——它记不清用户最初的问题答非所问甚至把表里的杂项数据当成结论。查token消耗一次查询就烧了大概9000个token。后来我加了压缩器3.4节那个compress函数但这个坑值得单独拿出来说因为很多人会忽略工具结果也是上下文的一部分而且是最高危的一部分。LLM对长上下文的注意力是递减的你塞一堆它用不上的原始数据就会稀释它对真正关键信息的注意力。我的原则是工具结果默认不超800 token要超就摘要加提供按需取原始数据的通道。5.2 token轮换导致的幽灵401认证生命周期必须由Reach层统一管理前面提到的客服Agent翻车案例我这里展开讲讲排查链路。现象很简单Agent报告创建工单失败接口返回401。看日志Request走到了BridgeBridge调了工单系统API返回401Agent就放弃了。表面原因似乎是没权限但业务方说服务账号权限明明在。真正的根因藏在两层之下。第一层token有效期是2小时Agent每处理一轮会话可能超过2小时旧token已经过期。第二层Agent进程里缓存着最初的token一直到进程重启都不会换。也就是说整个Agent生命周期里超过2小时后的所有调用必然是401而Agent毫无感知。修复方案就是我前面写的Credential Vault加短期票据。Vault负责维护最新的token并在过期前主动刷新Agent手里的票据只够向Reach层申请访问且票据本身有效期很短。实测修复后401类失败从每周几十次降到0。5.3 死循环调用与消息队列堵塞deadline救了大忙还有一次比401更恐怖的故障。某个Agent在处理一个分析任务时因为工具返回的数据格式和模型预期不符模型在循环里反复调用同一个格式化工具而那个工具每次都报参数错误。参数错误在我当时的设计里属于可重试于是每轮循环都重试3次每次重试之间还有退避加起来就是无限循环把消息队列堵满了。这个事故逼我把上文那个错误三色分类和deadline机制彻底实装。现在我敢说任何没有deadline的Agent调用设计都是定时炸弹。不要相信模型不会犯错模型在工具调用上的犯错率比想象高得多工程层必须兜底。5.4 并发场景下的能力踩踏RateLimit在单Agent不够要全局最后一个坑跟并发有关。我一开始把rate_limit配置在Agent本地做计数想着这个Agent每分钟最多调60次就够了。但实际部署时有6个Agent实例每个本地计数60次外部API实际承受的是每分钟360次直接把供应商的限流给干穿了。正确做法是RateLimit要放在Reach层的集中式组件里像Redis的滑动窗口计数那样全局统一。同一能力不管来自哪个Agent实例都共用同一个计数。我把这个写进了Policy Engine之后供应商再也没有因为限流把我家服务封过。5.5 工具选择看似合理但错误的典型case最后补一个模型行为层面的坑。Resolve阶段Top-5精排后模型偶尔会选一个名字看似匹配但语义不符的工具。比如用户问上个月总共花了多少钱候选里有billing.query_total和ledger.aggregate_entries模型总选后者因为它的描述里出现了aggregate聚合这个词而用户问题里有总共。可实际上ledger的聚合口径跟计费完全不一样结果数字错得离谱。这个问题的解法不是换模型而是在能力描述里加上排除语义——比如在ledger.aggregate_entries的描述里明确写此项为会计分类账目汇总不适用于计费账单查询。看似废话但实测能把这种语义撞车率从8%降到2%以内。写能力描述的时候一定要花心思写它不是什么而不是只写它是什么。6. 用数据说话Agent-Reach的效果度量和后续可扩展方向6.1 三个度量指标Reach成功率、Reach延迟、Reach覆盖度工具做出来不能靠感觉评判。我在生产环境定义了三个核心指标指标定义目标值Reach成功率一次Reach调用从发起到返回ok的占比含重试成功≥ 98%Reach延迟从Agent发出调用意图到拿到结果的毫秒数P50/P95分别看P50 800msP95 2sReach覆盖度Agent请求的意图中能被注册表命中的比例≥ 95%这三个指标分别反映的是Reach层的鲁棒性、调用链路的性能、注册表的完备度。覆盖度低说明你还没把该接的系统接进来成功率低说明重试、恢复逻辑有bug延迟高说明Bridge或Policy引擎有瓶颈。我自己的实测数据可以分享一下接入Agent-Reach三个月后一个客服工单场景的成功率从62%升到97.5%P95延迟稳定在1.3秒左右覆盖度91%——剩下的9%主要是新业务方还没把能力注册进来。对比改造前最大的变化其实是错误变得可解释以前Agent失败是一团迷雾现在每一次失败都有ReachError、有trace_id、有错误分类10分钟内能定位到根因。6.2 调优经验三条注册表收敛、降级链、健康检查第一注册表的条目不是越多越好。200个能力和2000个能力Resolve的召回准确率是不同的。我建议定期做死能力清理——超过30天没有一次成功调用的能力直接标记为deprecated不再参与召回。这跟搜索引擎删死链是一个道理。第二给每个关键能力设计降级链。主能力挂了降级到备选能力。比如jira.create_issue挂了降级写邮件通知人工billing.query_total挂了从本地缓存取最近一次快照。降级链数据要写进Capability定义里并且降级行为要能被Agent感知——Agent知道自己在降级模式下就不会给用户拍胸脯保证实时数据。第三健康检查不能省。我给注册表里每个外部依赖配了一个轻量health check每30秒探一次。发现不健康的能力Registry会把它的availability标为falseResolve阶段直接跳过它。这样Agent永远不会把请求发给一个已知故障的系统——它省掉的不仅是失败重试更是模型的装懂风险。6.3 后续还能怎么扩展从连接层走向Agent基础设施Agent-Reach目前的形态是一个独立的连接层但它完全可以往Agent基础设施方向长。我在考虑两个扩展一是把Reach的能力接入到更细粒度的事件触发模型里让Agent从被用户叫醒变成被状态变化叫醒——比如工单状态从open变为resolved时自动唤起另一个Agent做回访。二是把Reach层的观测数据和训练流程打通把每一次意图-工具-结果-用户反馈沉淀成数据集反哺给Resolve的排序模型让它越用越准。这两个方向都还在验证中目前我能确认的是连接层是Agent系统里最值得投入的部分。模型会换代prompt会重写但Agent怎么可靠地够到世界这个问题会一直存在下去。先把这层基建做好后面换什么样的模型、接什么样的场景都会省力得多。最后补一个我在写Agent-Reach时始终放在心里的原则——连接层的本质不是把API包一层皮而是给Agent一个够得到、够得稳、够得起的承诺。够得到是能力够得稳是可靠性够得起是成本和权限的边界。能把这三个字做扎实Agent项目才算是真正落了地。