
1. 项目概述与整体设计思路1.1 Agent-Reach 是什么要解决什么问题先说说我做这个项目的背景。去年开始团队内部陆续接入了几个大模型应用比如客服助手、工单分类器、知识库问答跑起来效果都不错。但一碰到需要动真格的业务就卡住了让 Agent 查一下订单物流信息查完要能顺便改一下备注让 Agent 判断一个工单是不是超时判断完要能自动催办。这些操作单靠大模型聊天能力根本做不了必须让它伸进业务系统里真正调接口、拿数据、回写状态。Agent-Reach 这个名字拆开来看就非常直白Agent 是智能体Reach 是触达。它要解决的核心问题就是让大模型驱动的 Agent 从只能说话变成能动手干活。说白了这是一个面向 AI Agent 的工具触达层Agent 在对话或推理过程中产生一个调用意图Reach 负责把这个意图翻译成真实系统能理解的 API 请求、数据库操作或者命令指令再把结果取回来交给模型继续推理。这个项目适合谁参考如果你正在做智能客服、办公助手、自动化运维机器人或者你只是想在 Dify、Coze、FastGPT 这类编排平台里接几个自定义工具却不知道怎么设计这一层那么 Agent-Reach 的思路都可以直接抄作业。它不是一个具体的大模型也不是一套业务流程系统而是夹在中间的那一层胶水。1.2 为什么需要单独做一个触达层最开始我也走过弯路以为让 Agent 干活很简单直接在 prompt 里把 API 文档扔给它就行。真实环境里这样玩会踩到三个大坑一是工具数量膨胀后无从管理。业务系统多接口更多订单系统有几十个接口CRM 有上百个全塞进 prompt 上下文既浪费 token 又容易让模型眼花缭乱不知道该选哪个工具。二是安全边界模糊。如果让大模型直接面向全量接口万一它调用了不该调的删除接口后果不堪设想。三是返回格式不统一。有的接口返回 JSON有的返回 XML有的直接给我一个 HTML 错误页模型根本没法稳定解析。Agent-Reach 的思路是把模型能用什么、能用哪些工具这件事收敛到一个触达层里定义一套统一的工具描述 Schema让模型只面对结构化的工具说明而不是杂乱无章的 API 文档加一层权限控制每个 Agent 实例绑定的工具范围是预先配置好的模型只能在白名单里选择做一层协议转换把模型输出的函数调用指令转换为各类系统真实需要的请求格式屏蔽底层差异。这就好比给 Agent 配了一个手但这个手不是它自己的而是接了一个机械臂——机械臂的每个关节、每个动作范围都被人为限定住了能干精细活也不会乱来。1.3 整体架构拆解编排、触达、系统三方各司其职Agent-Reach 在落地时分成三个层级彼此职责边界尽量拆干净编排层负责 Agent 的对话流程、上下文管理、意图识别。这一层可以由 Dify、Coze、LangGraph 等承担也可以是自研的状态机。它只需要做一件事识别出现在该调用哪个工具了然后把调用请求抛给下达层。触达层Agent-Reach 核心负责接收编排层抛过来的工具调用意图做参数校验、路由分发、协议适配、权限校验、结果归一化。它不关心业务逻辑只保证请求能送达、结果能回来。系统层也就是实际被操作的业务系统比如订单中心、工单系统、支付网关、数据库。这一层不感知 Agent 的存在它们只觉得是有人调了一个正常 API。这三层之间通过标准 HTTP 接口通讯触达层本身无状态可以水平扩展。我实测过50 个并发请求同时在触达层做路由转发平均延迟增加不到 3 毫秒主要是连接池复用的功劳。下面这张表把各层职责做了一个快速对照层级核心职责典型技术选型关键设计点编排层对话管理、工具意图决策Dify / Coze / LangGraph上下文窗口管理、工具选择策略触达层请求受理、权限校验、协议转换、结果归一FastAPI Redis PostgreSQL工具注册中心、超时控制、限流降级系统层提供真实业务能力内部微服务 / 数据库 / 第三方 SaaS接口契约稳定、可观测性埋点选择这个分层还有一个重要的现实考量团队协作边界清晰。业务系统的人不需要懂 prompt只需要照着 Swagger 把接口注册进来算法的人不需要关心订单表结构只需要写好工具名和参数说明。整个链路不抢别人的活反而把大家串起来了。2. 核心模块解析与实操要点2.1 工具注册中心让 Agent 看得见 工具Agent-Reach 最底层的模块是工具注册中心。所有可以被 Agent 调用的能力都要先在这里登记。登记的内容不是简单的接口地址而是一份完整的描述元数据我管它叫Tool Schema。这个 Schema 长这样{ name: query_order_status, description: 根据订单号查询订单当前状态返回状态码、物流单号和更新时间。当用户询问我的订单到哪了或发货没有时使用。, parameters: { type: object, properties: { order_id: { type: string, description: 订单号通常是数字字母组合如 ORD202501001 } }, required: [order_id] }, endpoint: { method: GET, url: https://order-center.example.internal/api/v1/orders/{order_id}, headers: { X-Internal-Auth: ${ORDER_CTR_TOKEN}, X-Source: agent-reach } }, permission: [agent:crm_assistant], timeout_ms: 3000 }这里有几个细节都是踩坑之后才补上的name 必须全局唯一且语义清晰。模型在选择工具时靠的就是名字和描述之间的语义匹配名字起得含糊比如api_get_1模型大概率会不知所措。description 要写清楚什么时候用。不要只写查询订单状态要写当用户询问订单到哪了、发货没有、物流信息时使用。模型对用途描述越具体选错工具的概率就越低。参数描述要给取值范围和示例。比如order_id描述里给一个示例值模型在抽取参数时会更容易对齐格式。endpoint 支持模板变量路径参数用占位符。这在实现路由时很重要不要把所有东西都塞 query string很多老系统的接口路径参数就是长在 URL 里的。permission 数组是用来做 Agent 维度的白名单。注册中心可以知道某个 Agent 有权调用哪些工具到达层在真正执行前还要再做一次校验。注册中心我建议用 PostgreSQL 存储而不是配置文件。因为工具有几十个甚至上百个之后配置文件根本管不过来而且你有天然的检索需求哪些工具挂在订单中心哪个 Agent 绑定了哪些工具。用数据库存储天然支持这些查询配合一个简单的管理后台业务方可以自助注册工具不需要经过开发。2.2 请求处理与协议适配统一入口分发请求进到触达层内部核心是一个请求处理器。编排层会发过来一个标准请求大概是这样的{ agent_id: crm_assistant, request_id: req_20250117_001, tool_name: query_order_status, arguments: { order_id: ORD202501001 }, trace_id: trace_abc_123 }触达层拿到请求后的执行链路是身份识别 → 权限校验 → 工具匹配 → 参数校验 → 协议适配 → 发起调用 → 结果归一化 → 返回。其中协议适配是最容易出问题的一环。为什么因为下游系统的风格差异太大了。有的系统要用 GET有的要用 POST有的接受 JSON有的只接受 form-data有的接口鉴权需要每次重新签名有的只需要一个静态 token。如果不做适配层这些脏活就会散落在编排层的 prompt 逻辑里极难维护。我在 Agent-Reach 里做了一个Adapter 模式每种下游系统风格对应一个适配器。比如http-json-adapter适用于标准 REST JSON 接口做 URL 拼接、Header 注入、响应体 JSON 解析。sign-request-adapter适用于需要动态签名的接口支持在调用前根据密钥生成签名常见的 MD5、HMAC-SHA256 都内置了。sql-read-adapter适用于只读查询场景通过配置好的命名 SQL 模板执行查询并返回结果避免让模型随意生成 SQL。Naming 是个关键点。sign-request-adapter的签名逻辑必须在到达层完成绝不能把密钥放到编排层更不能暴露给模型。密钥只存在于配置文件或环境变量中适配器在每次调用前从密钥管理服务拉取用完即扔。2.3 超时、限流与降级策略稳定比功能重要Agent 调业务系统跟人调业务系统有一个巨大差别Agent 有对话等待机制用户等不了太久。一个工具如果 3 秒没返回编排层大模型那边还傻等着用户早就不耐烦了。所以 Agent-Reach 把超时控制提到了非常高的优先级。我给不同工具设置了不同的超时时间查询类工具3 秒。写操作类工具5 秒。跨系统编排任务10 秒且要求下游支持异步回调。这里有个非常重要的取舍不要让 Agent 等待同步返回超过 8 秒。如果业务逻辑确实需要长时间处理可以采用先返回任务受理 ID再由回调接口把结果推回来的异步模式。这个在实现上稍微复杂一点但体验完全不一样。限流降级也是必须做的。我把限流设计成两层Agent 维度限流每个 Agent 每秒最多调用 10 次工具防止循环调用风暴打爆下游。工具维度限流单个工具接口的 QPS 上限对齐下游系统的实际承载能力。这个数据从哪来拿订单中心举例它单机 QPS 上限约 800那我给这个工具的触达层限流就设 600留出余量。降级策略采用的是有损但可用的思路当触达层自身过载或者下游系统连续超时直接返回给编排层一个统一错误码并附上一句模型能理解的话术比如工具暂时不可用请稍后重试。这样大模型就能用自然语言转告用户而不是把技术错误裸奔出去。2.4 可观测性没有日志链线上问题根本没法查Agent-Reach 的可观测性是我重点投入的部分。因为一次 Agent 调用链路是用户提问 → 大模型推理 → 工具选择 → 到达层路由 → 系统接口 → 结果返回 → 大模型生成回复。任何一环出问题排查链路都会很痛苦。我的方案是三个字Trace 贯穿。编排层每次发起工具调用时都带上一个trace_id到达层把这个 ID 透传到下游系统下游也在日志里打印它。这样拿到一个用户反馈我刚才问订单状态失败了我可以直接根据trace_id查整条链路看是模型选择错了工具还是到达层请求被限流还是下游系统超时了。日志方面每条到达层记录包含请求 ID 和 trace ID工具名称、参数摘要注意脱敏不能打敏感字段耗时和状态码错误堆栈只在错误时记录。这些日志统一走标准输出采集到 Loki配合 Grafana 做面板。我们还设置了告警比如工具成功率低于 95%P95 延迟超过 2 秒都会触发通知。做了一段时间后我发现Agent 的稳定性问题有九成出在触达层模型本身反而是最稳的。3. 实操过程从零搭建一个 Agent-Reach 实例3.1 环境准备与基础依赖先交代环境。我是在一台 4 核 8G 的 Linux 服务器上跑的系统是 Ubuntu 22.04。需要装的东西如下# 更新系统并安装基础工具 sudo apt update sudo apt install -y git curl wget python3-venv # 安装 Docker 和 Docker Compose 插件 curl -fsSL https://get.docker.com | sh sudo apt install -y docker-compose-plugin # 安装 Node.js 18用于本地调试脚本 curl -fsSL https://deb.nodesource.com/setup_18.x | sudo bash sudo apt install -y nodejs数据库我直接用 Docker 起了两个PostgreSQL 和 Redis。PostgreSQL 用来存工具注册数据Redis 用来做限流计数和热点缓存。docker run -d --name pg \ -e POSTGRES_USERreach \ -e POSTGRES_PASSWORDreach_secret \ -e POSTGRES_DBagent_reach \ -p 5432:5432 \ postgres:16 docker run -d --name redis \ -p 6379:6379 \ redis:7触达层的主体我用 Python 的 FastAPI 写原因有二一是 FastAPI 天然支持异步适合大量 IO 密集的转发场景二是 Pydantic 做参数校验太方便了直接可以给模型输出做结构化校验。项目依赖十分精简fastapi0.115.5 uvicorn[standard]0.30.1 httpx0.27.2 pydantic2.8.0 redis5.0.0 psycopg2-binary2.9.9 python-json-logger2.0.73.2 初始化数据库表结构工具注册中心最核心的是tools表和agent_tool_bindings表。tools表存工具元数据agent_tool_bindings表做多对多绑定关系。CREATE TABLE tools ( id SERIAL PRIMARY KEY, name VARCHAR(128) NOT NULL UNIQUE, description TEXT NOT NULL, schema JSONB NOT NULL, endpoint JSONB NOT NULL, permission JSONB NOT NULL DEFAULT [], timeout_ms INT NOT NULL DEFAULT 3000, status VARCHAR(20) NOT NULL DEFAULT active, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE agent_tool_bindings ( agent_id VARCHAR(128) NOT NULL, tool_id INT NOT NULL REFERENCES tools(id), created_at TIMESTAMPTZ DEFAULT now(), PRIMARY KEY (agent_id, tool_id) ); CREATE INDEX idx_tools_status ON tools(status); CREATE INDEX idx_bindings_agent ON agent_tool_bindings(agent_id);实际使用中发现一个细节description字段要留足够大的容量因为模型对工具描述的字数很敏感写几百个字符都是常态。另外schema和endpoint直接存 JSONB不用拆成多张表查询和写入都更省事。初始化之后我写了一个简单的脚本把一个测试工具query_order_status注册进去curl -X POST http://localhost:8000/api/tools \ -H Content-Type: application/json \ -d { name: query_order_status, description: 根据订单号查询订单当前状态, schema: { type: object, properties: { order_id: {type: string, description: 订单号} }, required: [order_id] }, endpoint: { method: GET, url: https://mock-api.example.com/orders/{order_id}, headers: {Authorization: Bearer token} }, permission: [test_agent], timeout_ms: 3000 }3.3 核心代码请求处理主流程触达层的核心代码就是一个路由函数加几个服务类。这里我只贴重点逻辑。首先是接收请求的主入口from fastapi import FastAPI, HTTPException, Request from pydantic import BaseModel from typing import Any, Dict app FastAPI(titleAgent-Reach) class ToolCallRequest(BaseModel): agent_id: str request_id: str tool_name: str arguments: Dict[str, Any] trace_id: str app.post(/api/execute) async def execute_tool_call(req: ToolCallRequest): # 第一步权限校验 allowed await tool_service.check_permission(req.agent_id, req.tool_name) if not allowed: raise HTTPException(status_code403, detailagent not allowed to call this tool) # 第二步加载工具定义 tool await tool_service.load_tool(req.tool_name) if not tool or tool[status] ! active: raise HTTPException(status_code404, detailtool not found or inactive) # 第三步参数校验基于 json schema errors validate_arguments(tool[schema], req.arguments) if errors: raise HTTPException(status_code400, detailerrors) # 第四步限流检查 allow_request, retry_after await rate_limiter.check(req.agent_id, req.tool_name) if not allow_request: return {status: rate_limited, retry_after: retry_after} # 第五步调用适配器执行 result await adapter_executor.execute( tooltool, argumentsreq.arguments, timeout_mstool[timeout_ms], trace_idreq.trace_id ) # 第六步结果归一化并返回 return {status: success, tool_name: req.tool_name, result: result}注意到我每一步都有明确的返回结构特别是限流和权限这类异常尽量不抛 HTTP 异常而是返回结构化 JSON 给编排层。这样大模型可以理解当前状态给出合理回复而不是收到一片错误堆栈。然后是适配器执行器的核心逻辑class AdapterExecutor: def __init__(self): self.adapters { http-json: HttpJsonAdapter(), sign-request: SignRequestAdapter(), sql-read: SqlReadAdapter(), } async def execute(self, tool, arguments, timeout_ms, trace_id): adapter_type tool[endpoint].get(adapter_type, http-json) adapter self.adapters.get(adapter_type) if not adapter: raise ValueError(funsupported adapter: {adapter_type}) return await adapter.invoke(tool, arguments, timeout_ms, trace_id)HttpJsonAdapter.invoke的核心逻辑是用 httpx.AsyncClient 发请求替换 URL 路径中的模板变量注入 headers超时后抛一个自定义异常。class HttpJsonAdapter: async def invoke(self, tool, arguments, timeout_ms, trace_id): endpoint tool[endpoint] url endpoint[url] # 替换路径占位符如 {order_id} for key, value in arguments.items(): url url.replace(f{{{key}}}, str(value)) headers endpoint.get(headers, {}).copy() headers[X-Trace-Id] trace_id async with httpx.AsyncClient(timeouttimeout_ms / 1000) as client: resp await client.request( methodendpoint.get(method, GET), urlurl, headersheaders, paramsarguments if endpoint.get(method) GET else None, jsonarguments if endpoint.get(method) ! GET else None, ) resp.raise_for_status() return resp.json()这段代码里特别值得注意的一个细节是GET 请求的参数走params非 GET 走json这个判断一定要明确写出来。我在最初版本里图省事全部塞 params结果下游 POST 接口全都不认参数排查了半天。3.4 跑通一个真实的 Agent 对话任务工具注册好后我把它接入 Dify 的自定义工具里。Dify 里配置一个 OpenAPI Schema接口 schema 端点暴露自触达层管理后台然后在 Agent 应用中选择该工具。实际操作里我设置了一个 Prompt 场景客服助手用户询问订单到哪了你负责查询订单状态。当用户在对话框里输入我的订单 ORD202501001 发货了吗完整链路是Dify 识别到需要调用工具从已绑定工具中选择query_order_status模型从用户输入中抽取order_id参数生成工具调用请求Dify 发起 POST 请求到触达层的/api/execute触达层校验权限、限流、适配然后转发给 mock 订单中心订单中心返回{status: shipped, tracking_no: SF1234567890}触达层把这个 JSON 原样返回给 Dify大模型基于这个结果生成用户可读的回复您的订单已发货物流单号是 SF1234567890。这一步跑通后基本验证了整个架构的可行性。后面再接入其他系统、其他工具就是一个往注册中心里堆工具的过程了。3.5 接入真实业务系统前需要补的功课mock 跑通不等于直接接真实系统。在接真实业务系统前有几个必须补的功课写操作必须做审批兜底给工具定义里加一层高风险操作确认。我设计了一个need_confirm字段如果为 true则到达层在执行前返回一个待确认状态由用户在对话里输入确认后才真正执行。敏感字段脱敏策略订单金额、手机号、身份证这类字段在下游返回后、回传给大模型之前要做掩码处理。我建议不要在注册工具时手动指定哪些字段脱敏而是让下游系统自己做好返回口径到达层统一强制脱敏。实现上可以做一个常用正则规则库比如手机号中四位用*代替。幂等策略写操作接口要支持幂等键。到达层使用request_id作为下游的Idempotency-Key这样即使编排层重试下游也不会重复执行。这些功课看着琐碎但全部是线上事故换来的经验。不补这些Agent 跑着跑着就会出现把订单备注清空了给用户重复发了优惠券这类事故。4. 常见问题与排查技巧实录4.1 模型理解了意图但就是不调用工具这是我在接入初期遇到最多的现象用户问我的订单到哪了大模型的回复是好的您的订单已经发货物流单号是……——但这里面的信息其实是模型编的它根本没有去调用查询工具。排查思路先看 Dify 那边工具是否真的绑定到了当前 Agent。经常有人配了工具但没在 Agent 配置里勾选。再看工具描述写得好不好。很多工具描述写得太单一比如只写查询订单接口没有告诉模型当用户询问物流、发货状态、运输进度时都应该调用。把使用场景描述扩充后调用率明显提升。还有一种可能是模型故意不调用因为它的训练偏好让它倾向于直接回答。解决的办法是在 System Prompt 里加一条硬性规则涉及查询用户私有数据时必须调用工具否则不要给出确定性结论。修完后我实测了一轮100 条真实用户问题工具调用率从 76% 提升到 94%。那剩下的 6% 大多是因为用户话术中本身没给出足够参数。4.2 工具调用成功了但大模型看不懂结果下游返回的 JSON 有时结构复杂比如嵌套了多层对象或者直接把列表塞在 result 里。大模型收到后可能解析不完整回复内容缺胳膊少腿。我的解决方案是在触达层做结果裁剪和摘要。大体思路是如果结果是列表且超过 10 条只返回前 5 条并附上共 25 条此为前 5 条的说明。如果嵌套层级超过 3 层自动把深层对象拍平。如果某个字段值是超长的文本比如备注字段可能有 2000 字就截断到 100 字以内。这样大模型拿到的就是一份干净、好消化的结果而不是一团原始 JSON。试过之后最终回答的准确率提升非常明显尤其是复杂查询场景。实操建议是这些过滤规则不是写死在下游而是在触达层做通用配置。因为下游系统返回什么你管不了但触达层可以统一把结果加工成适合模型理解的样子。4.3 并发环境下回调冲突某个场景里Agent 调用一个耗时 10 秒的异步任务接口立刻返回了一个task_id后面的结果靠回调。最初我在 Redis 里用task_id作为 key 存结果回调来了就写进去Agent 轮询查询结果。第一次上线就出事故两个不同 Agent 同时调了同一个任务回调写的时候互相覆盖导致 A 拿到 B 的结果。排查到最后发现task_id 不是全局唯一的它在不同业务场景下会重复。修复方案简单粗暴回调结果的 key 不直接用task_id而是用触达层自己生成的request_id task_id复合键并且在写回调时校验这个 key 是否对应当前的request_id。这样即使下游系统的 task_id 重复也不会错乱。4.4 排查速查表整理一张速查表直接抄作业用现象排查思路常见根因Agent 不调用任何工具检查工具绑定、工具描述、System Prompt 约束工具未绑定到当前 Agent / 描述场景不全工具调用报 403检查 agent_id 与工具 permission 绑定关系新增 Agent 后忘记绑定工具工具调用超时检查下游系统负载、网络延迟下游接口慢、触达层连接池不够结果返回但不准确检查返回给模型前的裁剪逻辑、脱敏规则嵌套 JSON 太深、字段值太长限流频繁触发检查限流参数与下游承载能力限流阈值设得太低 / 循环调用错误回调数据错乱检查 key 是否全局唯一下游 task_id 跨场景重复4.5 再补充三个容易踩的隐蔽坑坑一参数名大小写不一致。模型抽取参数时可能产生OrderId、order_id、orderid这样的大小写变体。解决的办法是工具 Schema 里加alias字段把常见别名都列出来触达层做一次参数名归一化映射。坑二URL 编码问题。参数值里带#、、这类字符时直接拼进 URL 会导致下游解析错误。正确的做法是使用urlencode对路径参数做编码。这个问题在查物流单号时特别常见因为有些单号里带。坑三模型对布尔值理解偏弱。如果工具参数里有is_urgent: true模型传yes或1也是可能发生的。所以触达层的参数校验工具要允许做宽松类型转换把字符串形式的true、1、yes统一转为布尔值。否则就会卡在参数校验环节。5. 扩展可能性与个人实操心得5.1 从工具触达走向流程编排Agent-Reach 目前解决的是单个工具调用也就是说一次请求到达触达层它只调用一个下游接口。但在真实业务中很多场景要求多步骤编排先查订单状态再判断是否需要催发货然后调用物流系统发起催件最后给用户发一条短信通知。完整的编排能力需要引入一个状态机和任务 DAG这会让触达层变重。我的建议是尽量把这个编排逻辑放回编排层比如 Dify 里的工作流而不是让触达层做编排。触达层保持单次调用、无状态、可水平扩展的纯粹性整个链路的可维护性会高很多。如果一定要在触达层做编排建议只支持顺序依赖模式不要引入并行分支和条件分支。我在一个内部实验项目中试过支持 DAG 编排结果状态膨胀很快排查问题难度直线上升最后砍掉了。5.2 从HTTP 接口走向数据级触达另一个扩展方向是让触达层直接面对数据源比如提供预定义的 SQL 模板能力。这样做的好处是省掉了下游系统开发接口的成本超高频查询场景里性能也更好。但它有条件限制只适合只读查询并且查询结果必须限定行数上限。我在sql-read-adapter里做了两层保护一是 SQL 模板里强制拼上LIMIT 50二是参数只允许作为模板的绑定变量不允许拼进 SQL 语句。在前端配置时特别叮嘱了业务方可以自定义查询逻辑但不得修改模板的固定部分。用了一段时间后这个能力被用得越来越频繁但还是那句话——只开放只读一切写操作必须走标准接口这个底线不能破。5.3 回顾Agent-Reach 到底改变了什么回到最初的问题。在没有 Agent-Reach 之前我们的智能客服只能说用户问帮我改一下订单备注客服助手回复很抱歉我暂时无法操作订单。有了 Agent-Reach 之后同样的问题是好的我来帮您修改订单备注请问需要改成什么内容——这一步跨越看起来只是技术层面打通了几个接口但用户感知上的差别是巨大的。我个人最大的体会是做 Agent 落地最难的从来不是大模型调优而是给模型配上一双稳定且安全的手。大模型本身可以犯错但有了触达层之后每一个动作都变得可注册、可审计、可限流、可回滚。Agent-Reach 这套模式后续我打算继续往下打磨的方向是接入更多非 HTTP 协议的系统比如老旧的 WebService 接口、MQ 消息发送、文件系统操作乃至操作已经存在的 GUI 应用程序。核心思路始终不变模型不直接碰任何东西所有触碰都经过触达层这双受控且带着度量衡的手。在做完 Agent-Reach 并稳定运行一段时间后我更加确信这个方向是对的。如果你也在做 Agent 相关项目建议从触达层开始做设计而不是从多聪明的模型开始。模型再聪明手脚伸展不出去一切仍是纸上谈兵。