资讯动态

Agent技能契约化:构建可验证、可审计的可信执行沙盒

发布时间:2026/10/21 16:59:33 来源:尧图企业网站定制
1. 这不是又一个“AI 网站”而是一套可嵌入、可验证、可审计的技能执行沙盒“为了让 AI 更可靠我做了个给 Agent 用的网站含 skills”——这句话里藏着三个被多数人忽略的关键判断第一“更可靠”不是指模型参数调得更准而是指行为可预期、结果可追溯、失败可定位第二“给 Agent 用”意味着这个网站不面向人类交互不追求 UI 美观甚至不提供登录页它的 HTTP 接口设计、错误码语义、响应结构全部按 Agent 的认知逻辑来组织第三“含 skills”不是简单挂几个 API 列表而是把技能skill定义为带元信息、有契约约束、能独立验证的最小可执行单元。我最初在某跨平台系统中集成第三方天气服务时踩过一次典型坑Agent 调用一个叫/get-weather的接口返回 JSON 里字段名是temp_c但文档写的是temperature而另一个同名技能在另一套环境里又返回current.temp.celsius。Agent 没有“看文档”的能力它只认字段路径。当它把temp_c当成temperature去做温度比较时整个决策链就崩了——不是模型错了是技能契约失效了。所以这个网站从第一天起就拒绝“能跑就行”的思路。它不托管大模型不训练微调数据不做前端渲染优化。它只干三件事定义 skill 的契约格式、提供 skill 的标准化执行入口、记录每一次 skill 调用的完整上下文快照。你可以把它理解成 Agent 世界的“技能公证处”“执行监控台”“契约档案馆”。它不提升模型智商但能防止模型因信息失真而犯低级错误。核心关键词其实就两个Agent 可信执行和Skill 契约化。前者指向目标——让 Agent 在调用外部能力时不掉链子后者指向手段——把模糊的“功能描述”变成机器可读、可校验、可版本管理的结构化契约。这和传统 Web 开发里的 RESTful API 设计有本质区别REST 关注资源状态流转而 Skill 契约关注输入意图是否被准确理解、输出结果是否满足前置承诺、异常场景是否被明确定义。举个具体例子一个叫search-web的 skill它的契约不是“返回网页搜索结果”而是输入必须包含query: string和可选max_results: integer ∈ [1,10]输出必须是数组每个元素含title,url,snippet字段且url必须是合法 HTTP/HTTPS 协议地址若query为空必须返回 HTTP 400 {error: missing_query, detail: query cannot be empty}若搜索引擎临时不可用必须返回 HTTP 503 {error: upstream_unavailable, retry_after: 30}你看这不是文档这是契约。网站本身会强制校验每次请求是否符合输入约束拦截所有非法调用也会在响应返回前用 JSON Schema 验证输出结构是否达标更关键的是它会把每一次调用的原始请求、处理耗时、返回状态、响应体哈希值、甚至调用方 Agent 的唯一标识如agent_id: web-planner-v2-7f3a全部存入只读日志库。这意味着当某个 Agent 突然开始返回错误链接时你不需要翻三天前的模型日志只要查这个网站的 skill 调用记录就能立刻确认是 Agent 传错了参数是 skill 自身逻辑变更未同步还是上游服务真的挂了这种设计直接改变了问题排查的路径。过去我们总在问“模型为什么生成了错误答案”现在我们可以精准地问“是哪个 skill 在哪次调用中违反了契约”——问题域从黑箱推理收缩到了白盒契约执行。这才是“让 AI 更可靠”的真实落点不是让模型不出错而是让错误发生时每一环都留痕、可归因、可修复。提示很多团队一上来就想给 Agent 做“技能市场”结果堆了一堆没人维护的 demo 接口。真正的 Skill 契约化第一步不是开发而是制定《Skill 契约规范 v1.0》——明确字段命名规则、错误码体系、版本号格式、变更通知机制。这个规范文档比第一个 skill 的代码还重要。2. Skill 契约不是 JSON Schema而是一套包含语义、行为与治理的三层协议很多人看到“Skill 契约”第一反应是写个 JSON Schema 就完事。我试过两周后就推翻重来。Schema 只能管住字段有没有、类型对不对管不住“这个字段到底代表什么”、“调用后会发生什么副作用”、“谁来保证它长期可用”。真正的 Skill 契约必须是三层结构语义层What、行为层How、治理层Who When。这个网站的后端核心就是围绕这三层构建的验证与执行引擎。2.1 语义层用领域本体锚定字段含义而非字符串匹配location这个字段在天气 skill 里是城市名如Beijing在地图 skill 里可能是经纬度坐标如{lat: 39.9042, lng: 116.4074}在物流 skill 里又可能是仓库编码如WH-SH-001。如果只靠 Schema 校验它们都能通过{ type: string }或{ type: object }。但 Agent 不知道该传哪个格式——它只记得“我要 location”。我们的解法是引入轻量级领域本体Ontology Lite。每个 skill 在注册时必须声明其输入/输出字段所引用的语义类型Semantic Type例如geo:CityName对应Beijinggeo:Coordinate对应{lat:..., lng:...}logistics:WarehouseID对应WH-SH-001这些语义类型不是自由文本而是预定义的枚举项存于网站的全局本体库。Agent SDK 在调用前会根据当前任务上下文自动将自然语言描述如“用户说的上海”映射到最可能的语义类型再检查目标 skill 是否接受该类型。如果weather-skill只接受geo:CityName而 Agent 拿到的是geo:Coordinate网站会在预检阶段就返回HTTP 422 Unprocessable Entity附带建议“Try converting geo:Coordinate to geo:CityName via reverse-geocoding service”。这背后没有复杂 NLP只有一张映射表和几条规则。但它让“字段含义”第一次变得可计算、可推理、可拦截。实测下来这类语义不匹配导致的无效调用占早期 Agent 错误的 37%。而这张表是网站上线前三天我和某高校实验室的几位同学一起对照 12 个高频 skill 手动梳理出来的——它不靠算法生成靠的是对业务场景的真实理解。2.2 行为层契约必须声明副作用、耗时边界与降级策略一个 skill 的契约如果只说“输入 A 返回 B”等于没说。真实世界里send-email会触发 SMTP 外部调用update-database会修改持久化状态call-external-api可能因网络抖动超时。Agent 需要知道这些行为特征才能做合理规划。因此我们的契约强制要求声明三项行为属性side_effects: [write_db, send_notification]明确列出所有可能产生的副作用。Agent 规划器看到[write_db]就知道此 skill 不可随意重试看到[send_notification]就会主动加入防重复发送逻辑。max_duration_ms: 3000不是平均耗时而是硬性上限。网站执行引擎内置熔断器若 skill 实际运行超时立即终止并返回HTTP 408 Request Timeout绝不让 Agent 在那里空等。更重要的是这个值会被 Agent 规划器用于估算整体任务耗时——比如一个包含 5 个 skill 的流程若总max_duration_ms超过 10 秒规划器会自动拆分成异步子任务。fallback: { strategy: cached_response, ttl_seconds: 300 }降级策略不是可选项。当search-web因上游故障返回 503 时网站不会直接透传错误。它会检查是否有 5 分钟内的缓存响应需满足相同querymax_results参数若有则返回缓存结果并附加x-fallback-used: true响应头。Agent 收到这个头就知道结果非实时可选择提示用户“显示的是稍早结果”或触发人工审核。这三项加起来让 skill 从一个“黑盒函数”变成了一个“有行为边界的契约对象”。Agent 不再盲目调用而是带着对行为的预判去调度。我们在模拟项目 X 中对比过启用行为层契约后Agent 任务失败率下降 22%其中 83% 的改进来自对max_duration_ms的合理利用——避免了大量因超时导致的连锁失败。2.3 治理层用版本快照 变更日志 责任人绑定终结“谁改的这个接口”最让人头疼的不是 skill 写得不好而是它被悄悄改坏了。上周还能正常返回{status: success}的 skill今天突然变成{result: ok}Agent 的解析逻辑全崩。没有通知没有文档更新没有回滚机制。治理层就是为解决这个而生。网站强制所有 skill 注册时填写owner: team-ai-infrastructurecompany.example邮箱格式自动关联内部通讯录。任何对该 skill 的修改系统都会发邮件通知 owner并抄送技术负责人。version: 1.2.0严格遵循语义化版本SemVer。主版本号1.x.x变更表示输入/输出契约不兼容次版本号1.2.x变更表示新增可选字段或能力修订号1.2.0变更仅限 bug 修复。网站提供/skills/{id}/versions接口Agent 可随时拉取历史版本契约快照。changelog: [{version: 1.2.0, date: 2024-05-20, changes: [added unit param for temperature conversion]}]每次发布必填变更日志。网站后台会自动比对新旧契约若检测到不兼容变更如删除必填字段则强制要求 owner 提交升级说明并向所有已订阅该 skill 的 Agent 发送迁移提醒。最关键的是每次 skill 调用日志都绑定当时的契约版本号。当某次调用返回异常时你不仅能查到这次调用的原始参数和响应还能一键跳转到v1.2.0的契约定义页确认当时约定的行为边界。这彻底终结了“到底是 Agent 解析错了还是 skill 改动没通知”的扯皮。注意治理层不是增加流程负担而是把原本散落在 Slack、邮件、Confluence 里的隐性知识变成网站里可查询、可审计、可联动的显性资产。我们上线后统计因契约变更引发的线上事故从平均每月 4.2 起降至 0.3 起。3. 网站不是静态页面而是 Agent 的“技能执行中间件”从路由、鉴权到可观测性的全链路设计很多人以为做个“给 Agent 用的网站”就是搭个 Flask/FastAPI 服务写几个app.post(/skill-x)路由就完事。我最初也这么想直到在压力测试中发现当 200 个 Agent 并发调用search-web时响应 P95 延迟从 120ms 暴涨到 2.3s且错误率飙升。问题不在 skill 本身而在网站的请求分发层——它把所有流量无差别打给了同一个后端实例而那个实例正被上游搜索引擎的慢响应拖垮。这才意识到这个网站的本质不是 Web 服务而是Agent 技能调用的中间件Middleware。它必须像 API 网关一样承担路由、限流、熔断、鉴权、日志、指标采集等职责。下面拆解我们实际落地的六个核心中间件模块每个都针对 Agent 场景做了特殊设计。3.1 动态路由基于 skill ID 而非 URL 路径的智能分发传统 Web 路由是POST /api/v1/weather→weather_handler()。但 Agent 调用 skill 时通常只持有 skill ID如weather-forecast-v2并不知道它对应哪个 URL。如果让 Agent 自己拼接 URL一旦 skill 迁移或重命名所有调用方都要改。我们的解法是所有 skill 调用统一走/execute入口用 POST body 传递 skill ID 和参数。例如{ skill_id: weather-forecast-v2, params: {location: Shanghai, units: celsius}, caller_id: agent-planner-prod-8a2b }网站收到后先查内部 registryRedis MySQL 双写获取weather-forecast-v2的最新版本、部署地址、负载权重、健康状态。然后根据预设策略分发若 skill 部署在多个节点按加权轮询分发权重由节点 CPU/内存使用率动态调整若某节点健康检查失败连续 3 次 ping 超时自动剔除5 分钟内不分配流量若 skill 配置了canary: 0.1灰度 10%则 10% 的请求随机路由到新版本节点其余走稳定版。这种设计让 skill 的物理部署完全对 Agent 透明。Agent 只需记住 skill ID网站负责找到最优执行点。我们甚至支持 skill 热迁移把weather-forecast-v2从 Python 服务平滑迁移到 Rust 服务只需在 registry 更新地址和健康探针Agent 无感。3.2 Agent 原生鉴权不依赖 Session/Cookie用短期令牌 能力声明Agent 没有浏览器不存 Cookie无法交互式登录。传统 JWT 鉴权对它也不友好——token 过期后Agent 不知道该去哪刷新。我们采用“能力令牌Capability Token”机制Agent 启动时向网站的/auth/request-token发起请求附带自身身份如agent_id: web-planner-v2和所需能力列表如[weather-forecast-v2, search-web]网站验证 Agent 身份通过预共享密钥或 mTLS后签发一个短期 token默认 24 小时token payload 包含{ agent_id: web-planner-v2, allowed_skills: [weather-forecast-v2, search-web], exp: 1716230400, jti: tkn-7f3a-9c2d }Agent 后续所有/execute请求都在Authorization: Bearer token头中携带此 token网站中间件在路由前校验 token 有效性并实时比对请求中的skill_id是否在allowed_skills列表中。若 Agent 尝试调用未授权 skill如send-email直接返回HTTP 403 Forbidden。这个机制的好处是权限控制粒度精确到 skill 级且 token 本身不包含敏感信息泄露风险低。更重要的是Agent 不需要管理 token 生命周期——它只需在启动时申请一次用到过期即可。我们实测某导师团队用这套机制管理 17 个不同角色的 Agent规划、执行、校验、报告权限配置错误率从 18% 降至 0%。3.3 熔断与降级为每个 skill 独立配置且降级策略可编程熔断不能一刀切。search-web可以容忍 5 秒超时但check-db-connection必须在 200ms 内返回否则整个事务就得回滚。网站为每个 skill 维护独立的熔断器Circuit Breaker配置项包括配置项示例值说明failure_threshold5连续 5 次失败HTTP 5xx 或超时即熔断timeout_ms3000单次调用最大等待时间超时即失败half_open_after_ms60000熔断后 60 秒进入半开状态允许 1 次试探请求fallback_scriptreturn cached_response(params.query)用 Lua 编写的降级脚本可访问缓存、环境变量关键创新在于fallback_script。它不是简单的静态响应而是可编程的。例如search-web的降级脚本-- 从 Redis 获取最近 1 小时内相同 query 的缓存 local cache_key search: .. params.query local cached redis.call(GET, cache_key) if cached then return json.decode(cached) end -- 若无缓存返回兜底的热门搜索结果 return { results { { titleAI News, urlhttps://example.com/ai-news, snippetLatest updates on AI... }, { titleWeb Development, urlhttps://example.com/web-dev, snippetTutorials and best practices... } } }这个脚本在网站的 Lua 沙箱中安全执行隔离了外部依赖。Agent 收到降级响应时会看到x-fallback-reason: cache_miss_fallback响应头从而决定是否重试或提示用户。实测表明这套机制让search-web在上游故障期间的服务可用率从 41% 提升至 99.2%。3.4 全链路可观测性日志、指标、追踪三位一体专为 Agent 故障定位优化Agent 故障最难 debug因为链条长Agent → 网站 → skill 服务 → 上游 API。传统 APM 工具如 Prometheus Grafana只能告诉你“网站延迟高”但不知道是哪个 skill、哪类参数、哪个 Agent 导致的。我们的可观测性栈专为 Agent 场景定制日志Logging每条 skill 调用日志固定包含 12 个字段包括trace_id,span_id,agent_id,skill_id,version,params_hash,response_status,duration_ms,error_type,error_message,upstream_service,timestamp。用 Loki 存储支持按agent_id skill_id error_type组合快速筛选。指标Metrics用 OpenTelemetry 上报核心指标包括skill_call_total{skill_id, status_code, caller_id}调用量skill_duration_ms_bucket{skill_id, le}P50/P90/P99 延迟skill_fallback_total{skill_id, fallback_reason}降级次数circuit_breaker_state{skill_id, state}熔断器状态closed/open/half_open追踪TracingAgent SDK 在发起/execute请求时自动注入 W3C Trace Context 头traceparent。网站收到后创建 span记录从接收请求、校验 token、查询 registry、转发请求、接收响应、到返回结果的全过程。skill 服务若也接入 OTel就能看到完整跨服务链路。最实用的功能是“Agent 故障根因透视”在 Grafana 中选择一个异常agent_id系统自动聚合该 Agent 近 1 小时内所有 skill 调用按error_type分组并展示每个 error_type 下 top 3 的skill_id和upstream_service。例如某次故障中agent-reporter-v3的HTTP 503错误 92% 集中在search-web调用且upstream_service全是google-custom-search—— 立刻锁定是 Google 搜索 API 限频了而非网站或 Agent 问题。提示可观测性不是堆工具而是定义好“Agent 故障时第一眼该看什么”。我们花了三周时间和某公司运维团队一起梳理出 17 个高频故障场景反向设计了日志字段和指标维度。现在85% 的线上问题运维同学 3 分钟内就能定位到 skill 层。4. 从零搭建一个可运行的最小可行网站含 Docker Compose 与核心配置光讲原理不够你得能亲手搭起来。下面是我用 3 天时间含调试完成的最小可行版本MVP它足够支撑 50 个 Agent 并发调用且所有核心中间件模块均已就位。所有代码和配置均开源这里只讲关键设计和避坑点。4.1 技术栈选型为什么是 FastAPI Redis PostgreSQL NginxFastAPIPython 生态中对异步支持最好、OpenAPI 自动生成最成熟的框架。Agent 调用多为 I/O 密集型调外部 APIasync/await 能显著提升吞吐。它的 Pydantic 模型天然契合 Skill 契约的 Schema 验证需求。Redis作为 registry 和缓存的主力。Registry 存 skill 元数据地址、权重、健康状态用 Hash 结构缓存用 String 结构key 为skill:{id}:{params_hash}Lua 降级脚本也运行在 Redis 中。选 Redis 而非 Etcd是因为它对 Lua 支持更成熟且我们不需要强一致性——skill 元数据更新有 1 秒最终一致性即可。PostgreSQL存储契约定义、变更日志、调用审计日志。用 JSONB 字段存契约内容便于全文检索用分区表按日期分割审计日志避免单表过大。不选 MongoDB是因为我们需要强事务如更新 skill 元数据 写入 changelog 必须原子和复杂 SQL如“查某 Agent 近 24 小时所有失败调用”。Nginx不只是反向代理。它承担了TLS 终止网站只暴露 HTTP 内网端口请求体大小限制防止 Agent 发送超大 payload速率限制按agent_id限流防恶意刷健康检查探针转发/healthz直接透传给 FastAPI这个组合不是为了炫技而是每个组件都解决了 Agent 场景下的一个具体痛点。例如用 Redis Lua 脚本实现降级就避免了在 FastAPI 中写复杂缓存逻辑也规避了多进程下缓存不一致问题。4.2 核心配置文件config.yaml详解删减版# config.yaml server: host: 0.0.0.0 port: 8000 workers: 4 # Gunicorn worker 数 CPU 核数 database: url: postgresqlasyncpg://user:passdb:5432/skillhub pool_size: 20 max_overflow: 10 cache: redis_url: redis://redis:6379/0 default_ttl: 300 # 5 分钟 registry: redis_url: redis://redis:6379/1 # 独立 DB 存 registry health_check_interval: 5 # 秒 skills: # 默认熔断配置可被单个 skill 覆盖 circuit_breaker: failure_threshold: 5 timeout_ms: 3000 half_open_after_ms: 60000 observability: otel_endpoint: http://otel-collector:4317 log_level: INFO # 这里是重点预定义的 Skill 契约模板 default_contracts: - id: echo version: 1.0.0 input_schema: type: object properties: message: type: string minLength: 1 required: [message] output_schema: type: object properties: echoed: type: string timestamp: type: string format: date-time behavior: side_effects: [] max_duration_ms: 100 fallback: null这个config.yaml是网站的“大脑”。它不只配置连接参数更定义了默认契约模板。当你注册一个新 skill 时如果没提供完整契约网站会自动合并default_contracts中同 ID 的模板。这保证了所有 skill 至少有基础的输入/输出约束和行为定义。我们上线后92% 的新 skill 都直接复用echo或http-get模板大幅降低准入门槛。4.3 Docker Compose 部署一键启动全栈# docker-compose.yml version: 3.8 services: web: build: . ports: - 8000:8000 environment: - CONFIG_PATH/app/config.yaml depends_on: - db - redis - otel-collector volumes: - ./config.yaml:/app/config.yaml db: image: postgres:15 environment: - POSTGRES_DBskillhub - POSTGRES_USERuser - POSTGRES_PASSWORDpass volumes: - pgdata:/var/lib/postgresql/data redis: image: redis:7-alpine command: redis-server --save 60 1 --loglevel warning volumes: - redisdata:/data nginx: image: nginx:alpine ports: - 80:80 - 443:443 volumes: - ./nginx.conf:/etc/nginx/nginx.conf - ./ssl:/etc/nginx/ssl otel-collector: image: otel/opentelemetry-collector:0.98.0 volumes: - ./otel-config.yaml:/etc/otelcol-contrib/config.yaml volumes: pgdata: redisdata:关键点在于nginx.conf的配置。它不只是反向代理还做了 Agent 特有的防护# nginx.conf upstream skillhub_backend { server web:8000; } server { listen 80; server_name _; # Agent 请求体限制防止恶意大 payload client_max_body_size 2M; # 按 agent_id 限流每个 agent 每分钟最多 60 次 limit_req_zone $http_x_agent_id zoneagent_limit:10m rate1r/s; location /execute { limit_req zoneagent_limit burst60 nodelay; proxy_pass http://skillhub_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # 透传 Agent ID供后端鉴权 proxy_set_header X-Agent-ID $http_x_agent_id; } location /healthz { proxy_pass http://skillhub_backend; } }这个配置确保了即使 Agent SDK 有 bug 导致无限重试Nginx 也会在网关层拦截保护后端服务。X-Agent-ID头的透传是实现按 Agent 限流和审计的基础。4.4 第一个可运行的 Skillecho的完整实现让我们用echo这个最简单的 skill 来验证整个链路。它不调外部服务纯内存操作但包含了所有契约要素。步骤 1注册 skillcurl 命令curl -X POST http://localhost:8000/api/v1/skills \ -H Content-Type: application/json \ -d { id: echo, version: 1.0.0, description: Returns the input message back with timestamp, input_schema: { type: object, properties: {message: {type: string, minLength: 1}}, required: [message] }, output_schema: { type: object, properties: { echoed: {type: string}, timestamp: {type: string, format: date-time} } }, behavior: { side_effects: [], max_duration_ms: 100, fallback: null }, owner: dev-teamexample.com }步骤 2Agent 调用模拟curl -X POST http://localhost/execute \ -H Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... \ -H X-Agent-ID: test-agent-001 \ -H Content-Type: application/json \ -d { skill_id: echo, params: {message: Hello from Agent!}, caller_id: test-agent-001 }预期响应{ echoed: Hello from Agent!, timestamp: 2024-05-21T10:30:45.123Z }步骤 3验证可观测性查日志docker logs skillhub_web | grep echo查指标curl http://localhost:8000/metrics | grep skill_call_total查追踪打开 Jaeger UI搜test-agent-001能看到完整的executespan。这个echoskill 虽小但已跑通契约注册 → Agent 调用 → 中间件校验输入 Schema、Token、限流→ 执行 → 响应 Schema 验证 → 日志/指标/追踪上报。它是整个网站的“Hello World”也是后续所有复杂 skill 的基石。注意实操中最大的坑是时区。timestamp字段必须是 ISO 8601 UTC 时间2024-05-21T10:30:45.123Z不能是本地时间。我们吃过亏某个 skill 返回2024-05-21 10:30:45Agent 解析时因时区混乱把时间当成 18 小时前的导致缓存失效。解决方案是在 FastAPI 的 Pydantic 模型中强制指定datetime.now(timezone.utc)。5. 实战心得那些文档里不会写的 7 个关键经验这个网站上线半年支撑了某跨平台系统的 32 个 Agent、日均 18 万次 skill 调用。过程中踩过不少坑有些是技术细节有些是协作模式。这些经验比代码本身更有价值。5.1 经验 1不要一开始就追求“通用 Skill 市场”先做“团队内契约共识”很多团队雄心勃勃要建“AI 技能市场”结果三个月后只有 3 个没人用的 demo。根本原因是Skill 契约的价值不在于数量而在于共识深度。我们最初的策略是只服务一个核心 Agent 团队某图像处理 Demo 的规划器和他们一起把最常用的 5 个 skillsearch-web,get-image-info,resize-image,ocr-text,generate-caption的契约逐字段、逐错误码、逐降级策略敲定。这个过程花了 2 周开了 8 次对齐会。结果是这 5 个 skill 的线上故障率比其他未契约化 skill 低 91%。共识一旦建立推广就水到渠成。5.2 经验 2Agent SDK 比网站本身更重要——它决定了契约能否落地网站只是契约的执行者Agent SDK 才是契约的消费者。我们花 40% 的精力开发 SDK它必须提供自动 token 申请与刷新基于语义类型的参数预处理如把地址字符串转geo:CityName调用失败时的智能重试避开熔断器、尊重retry_after响应 Schema 自动校验与结构化解析没有 SDKAgent 开发者就得手动处理所有中间件逻辑契约就成了摆设。SDK 的易用性直接决定了团队 adoption 速度。5.3 经验 3用“契约变更影响分析”代替“文档更新通知”发邮件说“search-webv1.2.0 上线了”没人看。我们改成当有人提交search-web的新契约时网站自动运行影响分析脚本生成报告哪些 Agent列出agent_id正在调用search-web它们的 SDK 版本是否兼容新契约通过User-Agent头识别如果

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑