mcpField
A
Address Validator

Address Validator

远程服务
kder-ai.com地图与出行01 周前更新

关于 Address Validator

Address Validator 是面向需要规范化和地理编码配送地址的服务的按次付费 HTTP API。它返回可配送性与置信度评分、缓存键,并在供应商不可用时提供降级结果。

主要功能

  1. 01规范化可识别的配送地址
  2. 02返回纬度和经度
  3. 03提供可配送性与置信度评分
  4. 04缓存重复地址的结果
  5. 05供应商故障时返回降级响应

适用场景

  1. 01配送前规范化原始地址
  2. 02检查地址坐标和配送可能性
  3. 03供应商不可用时处理地址验证

MCP 相关

该 API 提供 `/manifest`,用于向 x402 或 MCP 目录描述服务及其模式。README 未说明 MCP 工具或 MCP 服务接口。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://kder-ai.com/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

工具

1
参数类型必填说明
addressany是

详细介绍

地址验证 API

按请求付费的 HTTP API(x402 协议,默认价格为 0.02 USDC),接收原始送货地址,并返回标准化后的地址、 其坐标、可投递评分和缓存键。

1. 概述

  • 唯一的付费入口:POST /validate — 未提供有效付款证明时, 返回 402 Payment Required。
  • 输出:标准化后的地址(line1、line2、city、state、zip、 country);如果供应商识别出该地址,则会进行修正(D84: 拼写、城市、补充邮政编码);latitude/longitude(Nominatim 地理编码)、deliverability、 confidence、degraded 和 cache_key。
  • 发现:GET /manifest 描述服务及其架构,供 x402 / MCP 目录使用。
  • 弹性:如果无法连接供应商,API 仍会返回 200,并设置 degraded: true — 绝不会返回可能让人误以为地址确定无效的错误。

规范中的成功标准,以及自动验证方式:

#标准验证方式
1无证明的调用会收到 402(公布价格和协议)tests/test_payment.py(8 个测试)、tests/test_routes_extra.py::test_metrics_count_unpaid_requests、scripts/e2e_check.py
2提供有效证明的调用会收到 200 和结果tests/test_cache.py(实际付费调用)、tests/test_validation.py::test_valid_address_with_mocked_provider、scripts/e2e_check.py
3对重复地址使用缓存,避免再次调用供应商tests/test_cache.py::test_second_identical_request_hits_cache 和 ::test_distinct_requests_call_provider_twice、scripts/e2e_check.py
4供应商故障会快速返回明确的降级响应tests/test_validation.py::test_degraded_flag_set_when_provider_unreachable、tests/test_circuit_breaker.py、tests/test_latency_budget.py

本服务不会做什么:没有应用层速率限制(D21)— 限制由 Nginx 在边缘层执行(nginx-hardening.conf:每 IP 每秒 10 个请求,突发上限为 20,超出时返回 429)。旧版支付方式(共享密钥 HMAC 证明,D15)不能再仅凭签名通过验证:自 W1 加固(12/10/2026)以来,链上确认(D27)默认已启用,并要求在 Base 上向收款钱包转入已确认的 USDC。合成 HMAC 证明只有在明确声明的配方(TEST_MODE=true)中才会获得 200,相应写入行会标记为 test_mode,因此不计入实际收入(D40)。所有内容均有文档记录(README.md §7 和 §9、SECURITY.md §3 和 §6、AUDIT_TRAFIC_VPS.md §5),而非刻意隐瞒。

2. 快速开始

前置条件:Python 3.12(仓库虚拟环境运行于 3.12.10,与 Dockerfile 中的 python:3.12-slim 镜像一致)。PostgreSQL 和 Redis 均为可选项: 即使没有它们,API 也会启动并正常降级(/health 会说明这一点)。

# 1. Environnement virtuel
py -3.12 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt -r requirements-dev.txt

# 2. Configuration (jamais de secret dans le dépôt)
Copy-Item .env.example .env        # renseigner SMARTY_AUTH_ID / API_SECRET_KEY / clés CDP

# 3. Lancer l'API
.\.venv\Scripts\python.exe -m uvicorn app.main:app --reload --port 8000
# Vérifications
.\.venv\Scripts\python.exe -m pytest -q                  # suite complète
.\.venv\Scripts\python.exe scripts\run_tests.py          # oracle de tests (rapport JUnit)
.\.venv\Scripts\python.exe scripts\doc_check.py README.md 10   # sections de ce fichier
.\.venv\Scripts\python.exe scripts\e2e_check.py http://127.0.0.1:8000   # recette bout-en-bout

容器化启动:docker compose up -d(参见 docker-compose.yml 和 Dockerfile)。

生产环境部署(Debian 12 VPS、Nginx + HTTPS、x402 支付): DEPLOIEMENT_VPS.md — 实际部署报告、与计划之间已知的差异,以及运维注意事项。

3. 配置

所有值均来自环境变量或 .env(pydantic-settings、 app/config.py)。未知变量会被忽略(决策 D8)。

字段变量默认值作用
api_host / api_portAPI_HOST / API_PORT127.0.0.1 / 8000uvicorn 监听地址(127.0.0.1:服务由 Nginx 对外发布,而非直接发布)
api_secret_keyAPI_SECRET_KEYchange_me付款证明的 HMAC 密钥——务必更换
database_urlDATABASE_URLpostgresql://user:password@localhost:5432/address_validatorPostgreSQL(付款日志)
redis_urlREDIS_URLredis://localhost:6379/0结果缓存
smarty_auth_id / smarty_auth_tokenSMARTY_AUTH_ID / SMARTY_AUTH_TOKEN空验证服务提供商的凭据
cdp_api_key_id / cdp_api_key_secretCDP_API_KEY_ID / CDP_API_KEY_SECRET空Coinbase CDP SDK(可选)
cdp_wallet_addressCDP_WALLET_ADDRESS空在 402 中公布的钱包
x402_priceX402_PRICE0.02每次验证的价格,单位为 USDC
x402_onchain_verifyX402_ONCHAIN_VERIFYtrueUSDC 转账的链上确认(D27,自 W1 起默认启用)——仅当 TEST_MODE=true 时才允许设为 false;在验收测试之外,届时将拒绝所有共享密钥证明——参见 §7
base_rpc_urlBASE_RPC_URLhttps://mainnet.base.orgD27 启用时使用的 Base JSON-RPC 节点(链 ID 8453)
x402_usdc_contractX402_USDC_CONTRACT0x833589…4bda02913Base 上的原生 USDC 合约
x402_min_confirmationsX402_MIN_CONFIRMATIONS1接受付款前要求的最小确认数
x402_network / x402_chain_idX402_NETWORK / X402_CHAIN_IDbase / 8453accepts[] 中公布的网络和链
x402_domain_name / x402_domain_versionX402_DOMAIN_NAME / X402_DOMAIN_VERSIONUSD Coin / 2代币的 EIP-712 域——由 scripts/test_x402_payment.py --check-domain 在链上验证
x402_facilitator_urlX402_FACILITATOR_URLhttps://api.cdp.coinbase.com/platform/v2/x402付款协调器(依次调用 /verify 和 /settle)
x402_facilitator_verifyX402_FACILITATOR_VERIFYtrue结算前调用 /verify
x402_require_settlementX402_REQUIRE_SETTLEMENTtrue仅在收到款项后才提供服务(false = 绝不可用于生产环境)
public_base_url / mcp_public_urlPUBLIC_BASE_URL / MCP_PUBLIC_URLhttps://kder-ai.com / .../mcp发布在 accepts[].resource、MCP 卡片和目录中的 URL
discovery_log_*DISCOVERY_LOG_ENABLED, DISCOVERY_LOG_PATH, DISCOVERY_LOG_RAW_IP, DISCOVERY_LOG_SALT, DISCOVERY_LOG_RETENTION_DAYS日志已启用,路径为空(journald),IP 已假名化,保留 30 天402 拒绝日志及其保留期限(PRIVACY.md 3)
dashboard_user / dashboard_passwordDASHBOARD_USER / DASHBOARD_PASSWORDkder / 空/dashboard——为空时端点关闭(503);每个 IP 连续输错 LOGIN_MAX_FAILURES 次密码后,将被锁定 LOGIN_LOCK_MINUTES 分钟(D67)
geoip_db_path / audience_retention_daysGEOIP_DB_PATH / AUDIENCE_RETENTION_DAYS/var/lib/address-validator/dbip-country.mmdb / 400受众跟踪(D67):由 scripts/maj_geoip.sh 安装的 DB-IP Lite 国家数据库(缺失时国家未知);page_visits 和 api_calls 行的保留期限
pilotage_comptesPILOTAGE_COMPTES空仪表板账户(D74),格式为“姓名=email”,以逗号分隔;绝不写入代码(公开仓库)
cost_server_eur / cost_smarty_eur / cost_smarty_per_call_usd / cost_mail_eurCOST_SERVER_EUR / COST_SMARTY_EUR / COST_SMARTY_PER_CALL_USD / COST_MAIL_EUR0仪表板读取的成本(D68):全部为 0 时,不计算当月结果
test_mode / test_mode_cutoff_utcTEST_MODE / TEST_MODE_CUTOFF_UTCfalse / 2026-10-11T12:00:00+00:00标记为 test_mode 的交易属于验收测试:不计入 real_*,但计入 test_* 和 total_*(D40)
environment / log_levelENVIRONMENT / LOG_LEVELdevelopment / INFO环境和日志详细程度

4. 端点与数据契约

方法路径作用来源
GET/服务身份信息和链接app/main.py:57-65
GET/manifestx402 描述(价格、货币、架构)app/routes/manifest.py
GET/healthPostgreSQL 和 Redis 的实际状态,检查时间上限为 2 秒app/routes/health.py
GET/metrics计数器、断路器状态、缓存状态app/routes/metrics.py
GET/metrics/revenue24 小时 / 7 天 / 30 天汇总收入——real_* 不含测试环境,total_* 为整个账本(D40)——以及账本可用性app/routes/revenue.py
GET/dashboard运营仪表板——私有(Basic Auth;若未设置 DASHBOARD_PASSWORD,则返回 503;每个 IP 输入 5 次错误密码后封锁 15 分钟,D67);从 D67 起,每次访问公共页面和每次 API 调用都会留下一条追踪记录(国家、来源、耗时、状态;不记录 IP 或 Cookie);从 D69 起,采用 v2 设计(侧边栏、醒目的结果卡片、点状世界地图、含来源、robots 和页面的 Site 与 SEO、访问 → 付费转化路径);从 D68 起,提供资金页面(实际收款、待收订阅款、成本、结果、预测、按国家和渠道划分的收入)、API 页面(状态、响应时间、缓存、渠道、国家)和客户页面(即将结束的试用、配额、从未调用),以及警报、`?p=jour7j
GET/dashboard/argent、/dashboard/api、/dashboard/clients、/dashboard/site、/dashboard/registre运营控制页面,每个分区对应一个页面(D71);访问权限与 /dashboard 相同;通过 ?p= 保留时间段筛选app/routes/dashboard.py、app/pilotage_page.py
GET POST/dashboard/mot-de-passe、/dashboard/nouveau-mot-de-passe仪表板账户(D74):向 PILOTAGE_COMPTES 中的邮箱发送链接(有效期 30 分钟、仅限使用一次,数据库中只存储指纹),以设置密码(bcrypt 指纹);对未知邮箱也返回相同响应;每个账户每小时最多发送 3 个链接;之后通过邮箱登录app/pilotage_comptes.py、app/routes/dashboard.py
GET POST/dashboard/connexion、/dashboard/deconnexion仪表板登录页面(D69),取代 Basic Auth 挑战窗口:签名 Cookie __Host-av_pilotage(HMAC,有效期 12 小时,HttpOnly、Secure、SameSite=Strict);相同的 5 次尝试限制,之后暂停 15 分钟;拒绝来自其他网站的表单;无会话的浏览器会被重定向到此页面,脚本仍使用 Basic Auth 挑战app/routes/dashboard.py、app/pilotage_page.py
GET/prospection潜在客户开发 CRM(列表、筛选、标记、导出)——私有,与 /dashboard 使用相同的访问保护(若未设置密码或 PROSPECTION_DB 不存在,则返回 503)app/routes/prospection.py、prospection/README.md
GET/pricing公开的商业方案页面(D43)——公开、可被索引、缓存 5 分钟;不使用外部资源,与 /dashboard 共用样式表(app/web.py)app/routes/pricing.py
GET POST/signup自助注册(D44)——公开;密码使用 bcrypt 加密,API 密钥 sk_live_ 仅显示一次;每个 IP 每小时最多注册 5 次app/routes/signup.py、app/accounts.py
GET POST/validate-form公开免费试用(D46)——公开、可被索引;每个 IP 每 24 小时最多试用 3 次(D94)(超出时返回 429 和准确的 Retry-After);不写入数据、不加载任何内容,并明确标示降级结果;也接受单行地址(address 字段,D86)app/routes/validate_form.py、app/ratelimit.py
POST/stripe/webhookStripe 支付(D91):经过签名验证的 checkout.session.completed(Stripe-Signature,HMAC-SHA256,有效期 5 分钟)会将 client_reference_id 对应的账户切换至付费方案(2 900 → Starter,7 900 → Pro);customer.subscription.deleted 会将账户恢复为已过期试用状态;若未设置 STRIPE_WEBHOOK_SECRET,则返回 503app/routes/stripe_webhook.py、app/accounts.py
GET/robots.txt、/sitemap.xml、/favicon.ico搜索引擎优化(D65)——面向搜索引擎和 AI 搜索引擎开放的公共网站,包含公共页面 × 6 种语言的站点地图及其 hreflang,以及图标;公共页面带有 `` 区块(规范链接、Open Graph、JSON-LD);www. 会通过 301 重定向至 PUBLIC_BASE_URLapp/seo.py
GET/819a36fb2a9140f4f142b6e80ae19cc3.txtIndexNow 密钥(D81),按设计公开;scripts/indexnow.py --envoyer 会向 Bing、Yandex、Seznam 和 Naver 提交站点地图中的页面app/seo.py
GET/guide公开集成指南(D48)——公开、可被索引、可缓存 5 分钟,不含机密信息:JSON 契约、返回码、缓存、配额、直接调用 / CSV / Shopify / WooCommerce 示例app/routes/guide.py
GET/agents、/compare内容页面(D66)——公开、可被索引,支持 6 种语言:面向 AI Agent 的地址验证(MCP、x402、无需账户),以及 Google、Smarty、PostGrid 和 Geoapify 已公布价格的比较(数据采集于 2026 年 10 月 14 日,注明来源,并说明“何时选择哪一家”);我们的数据来自代码和配置app/routes/contenu.py
GET POST/compte、/compte/cle客户专区:月度仪表板(D64:本月数据、根据账户状态推断的下一步、逐日曲线、建议)、API 密钥、方案和账单——私有(通过 /compte/connexion 登录,或由脚本发送 Basic Auth;无会话时返回 303 并跳转至登录页;重新生成密钥时需要再次输入密码;数据库无响应时返回 503)app/routes/signup.py、app/accounts.py
GET POST/compte/connexion、/compte/deconnexion客户专区登录(D62)——私有页面(no-store、noindex);Cookie __Host-av_session(随机令牌,数据库中只存储指纹,最长有效期 12 小时);每个 IP 和账户输入 5 次错误密码后封锁 15 分钟;拒绝来自其他网站的表单app/routes/connexion.py
GET POST/compte/mot-de-passe-oublie、/compte/nouveau-mot-de-passe忘记密码(D63)——通过邮件发送使用 PUBLIC_BASE_URL 生成的链接,数据库中只存储指纹,有效期 30 分钟且仅限使用一次;无论账户是否存在,均返回相同响应;每个账户每小时最多发送 3 封邮件,每个 IP 每小时最多请求 5 次;设置新密码后会关闭所有会话;通过 SMTP_HOST 发送(空值 = 不发送邮件)app/routes/mot_de_passe.py
POST/validate付费——完整验证;两种付费方式:订阅(X-API-Key,D45)或按次付款(x402 / HMAC 证明)app/routes/validate.py
GET/docs交互式文档(FastAPI)自动生成
GET/llms.txt、/AGENTS.md、/.well-known/security.txt面向 Agent 的发现文件,由 Nginx 静态提供(参见 DISCOVERY.md)nginx-discovery.conf
POST/mcpMCP 服务(JSON-RPC 2.0):免费发现,tools/call 付费(x402 v2 传输:付款信息位于 params._meta["x402/payment"],方案和收据位于工具结果中;接受 v1 X-PAYMENT 请求头)app/routes/mcp.py
GET/.well-known/mcp-serverMCP 发现卡片(由应用提供)app/routes/mcp.py
GET/.well-known/x402x402 发现清单(IETF 草案 draft-hawkins-x402-dns-discovery-03),由应用提供;/openapi.json 只公开 API(D95)app/routes/manifest.py
每个以 402 拒绝的请求都会以元数据形式记录日志
(时间戳、endpoint、User-Agent、伪名化的 IP):绝不会记录已验证的地址。
设置与保留期限:PRIVACY.md §3、DISCOVERY.md §4。
4.1 实际收入与登记收入(D40)

/metrics/revenue 会公布同一登记簿的三种统计口径,绝不混用:

字段内容
real_validations_paid, real_revenue_usdc客户端支付的金额——可公开的数字
total_validations_paid, total_revenue_usdc登记簿中的全部金额,包括验收测试(审计)
test_validations_paid, test_revenue_usdc从实际收入中排除的验收测试金额:real_* + test_* = total_*

别名 validations_paid 和 revenue_usdc(D31)指向实际收入。 交易仅通过以下两种方式之一标记为 test_mode: 服务记录交易时设置了 TEST_MODE=true(正在进行验收测试),或 使用 scripts/migrate_test_mode.py 标记已写入的行——阈值为 TEST_MODE_CUTOFF_UTC(默认值 2026-10-11T12:00:00+00:00,即当天的两笔验收测试交易)。不会根据金额或地址推断:未标记的行仍计入实际收入。/dashboard 会优先显示实际收入,并在单独的卡片中显示验收测试收入。

对于已写入的登记簿,无需重新部署即可补做标记: venv/bin/python scripts/migrate_test_mode.py(模拟运行,逐行处理),然后添加 --apply。重复运行不会再写入任何内容(幂等);可通过以下命令检查结果: curl -s http://127.0.0.1:8000/metrics/revenue。

请求(app/schemas.py:11-16):{"address": {"street", "city", "state", "zip", "country"}}——country 默认值为 US,其他字段均为必填项(缺少字段会返回 422)。

响应(app/schemas.py:19-37):{"result": {"validated", "standardized", "latitude", "longitude", "deliverability", "confidence", "degraded", "cache_key"}, "price_paid", "transaction_id"}。

验证流水线(app/validation/__init__.py:26-41): parse → standardize → verify(供应商)→ geocode → score。从 D84 起,已识别的地址会根据供应商修正后的形式(corrige)再次经过 parse → standardize,然后再进行地理编码。

输出含义
degraded: true无法查询供应商(故障、超时、断路器打开):此时 deliverability 的值为 invalid,但这不能证明地址不存在
deliverability / confidence根据 DPV 代码得出:Y → residential 0,99;S → residential 0,95;D → commercial 0,99;X → unknown 0,50;N → invalid 0,00;若已获取坐标,则 +0,05(app/validation/scorer.py:17-36)
cache_key规范化后的原始地址的 SHA-256:用于标识缓存条目并支持删除(参见 PRIVACY.md §5)
4.2 同一次验证的两种付费方式(D45)

POST /validate 服务于两类客户端:提供 API 密钥的订阅商店,以及按次付费的自主 Agent(§5)。密钥优先:如果两者都提供,则以订阅方式为准,调用不会通过 USDC 扣款。

模式输入请求头扣款内容price_paid
订阅X-API-Key: sk_live_…账户计数器(customer_validations)0.0
x402 / HMACX-PAYMENT 或 X-Payment-Proof支付登记簿(D29)0.02(USDC)

响应包含 X-Payment-Mode(api_key、x402 或 hmac):没有这个请求头,客户端就无法区分调用是由订阅覆盖,还是已扣款。密钥模式下,另外两个请求头也会说明账户状态——X-Plan 和 X-Quota-Remaining(无限量方案时不提供;不提供即表示“无限量”)。

情况状态码原因
密钥有效,且本月仍有配额200已提供服务,账户已扣减,USDC 登记簿保持不变
密钥未知(或为空)401需要修正的是客户端配置
免费试用已结束(方案为 trial)403账户存在,但不再允许访问服务
本月配额已用完402使用量已达上限,并非身份验证失败
账户数据库无法访问503未能验证的密钥不等于被拒绝的密钥——绝不会返回 402

配额按月计算,与 /pricing 上公布的一致:统计周期为 UTC 日历月(accounts.month_start());/compte 仍会显示终身计数,但它不会阻止任何操作。拒绝响应的内容可供识别({"mode": "api_key", "reason": "cle_inconnue" | "compte_expire" | "quota_atteint"}),只包含密钥的前缀(sk_live_ab12),并指出可采取的下一步(upgrade → /pricing)。

$cle = "sk_live_..."   # affichée une seule fois à l'inscription, régénérable sur /compte
$corps = '{"address":{"street":"1 Rue de Paris","city":"Saint-Denis","state":"RE","zip":"97400","country":"RE"}}'
$r = Invoke-WebRequest -Uri http://127.0.0.1:8000/validate -Method POST `
     -Headers @{ "X-API-Key" = $cle } -ContentType "application/json" -Body $corps
$r.Headers["X-Payment-Mode"], $r.Headers["X-Plan"], $r.Headers["X-Quota-Remaining"]
$r.Content | ConvertFrom-Json | Select-Object price_paid, transaction_id
# -> api_key  trial  99 ; price_paid = 0.0, transaction_id = $null

不带 X-API-Key 请求头的同一次调用仍通过 x402 计费:密钥模式没有影响自主 Agent。/metrics 发布的计数器:api_key_requests、api_key_validations、api_key_denied、api_key_unavailable。

4.3 公开免费试用(D46)

GET /validate-form 提供公开页面——可被索引、可缓存 5 分钟,且独立运行:不含脚本或外部资源,并使用共享样式表(app/web.py)。这是访客看到的第一个页面;CSP(form-action 'self')让浏览器能够验证代码所作的承诺。

项目行为
上限VALIDATE_FORM_RATE_LIMIT_PER_DAY(默认 10)次试用;按 IP 和每 24 小时计算;窗口为固定窗口,从首次试用开始,拒绝请求不会延长窗口
拒绝429 + 准确的 Retry-After(窗口剩余秒数),并重申上限及提供指向 /signup 的链接
写入无:不会写入 customers、customer_validations 或 payment_transactions。只有 validate_form_requests / validate_form_validations / validate_form_denied 计数器会递增
处理流程与 /validate 相同(perform_validation):判定结果和缓存均相同
缓存和索引空表单响应为 public, max-age=300,且可被索引;所有 POST 响应(结果、错误、拒绝)均为 no-store + noindex,因为其中包含一个地址
降级结果按实际情况显示:“服务提供方未响应,此响应无法说明该地址的情况”——绝不将其显示为无效地址
输入对输入进行转义并重新显示,以便修改;国家代码不足两个字母时会被拒绝(400),且不会调用任何服务提供方

/metrics 中可查看上限计数器:只有记录上限拒绝,才能区分“无人尝试”和“所有人都被拦截”。

4.4 公开集成指南(D48)

GET /guide 回答刚收到密钥的客户端会提出的问题:身份验证(X-API-Key 或 x402)、准确的 JSON 契约、八种返回代码及相应操作、缓存和限额规则,以及四个实用案例(PowerShell 直接调用、Python 导入 CSV、Shopify、WooCommerce)。

项目行为
发布的信息公共基础 URL、价格、免费试用限额、X-Payment-Mode / X-Plan / X-Quota-Remaining 请求头和套餐:从代码和配置中读取,绝不手动复制(如果模板尚未替换,门禁会拒绝)
机密信息无:该页面可被索引,因此本身就是公开的。示例密钥是模板(sk_live_VOTRE_CLE)
独立性无脚本、无外部资源,共用样式表,Cache-Control: public, max-age=300,form-action 'none'
导航只有一处定义(app/web.py: site_head()):可从所有公开页面访问 /guide,而且 /pricing 不再复制自己的 <nav>
明示的限制不提供 Shopify 应用或 WooCommerce 插件(由客户的服务发起调用);degraded 结果表示“需要重新核验”,绝不表示地址无效
4.5 商店欢迎邮件(D49)

这不是一个页面,而是一条消息:发送给刚创建账户的商店。内容存放在 EMAIL_BIENVENUE.md 中,有两种形式——供 n8n 加载的模板(包含 {{…}} 变量,并在表格中说明)以及一份可直接发送给首位客户(Tiitoune Art)的示例。

项目行为
数字试用天数、赠送配额和月费从代码(accounts.JOURS_ESSAI、VALIDATIONS_ESSAI)及 /pricing 中读取;如果邮件未包含这些信息,门禁会拒绝
声明的方式订阅(X-API-Key):不包含 X-PAYMENT、X-Payment-Proof 或 tx_hash——门禁禁止在此消息中使用这些内容(按次付费是 Agent 使用的方式,相关说明见 /guide)
机密信息绝不包含任何密钥:文本引导用户前往 /signup 和 /compte。门禁会拒绝完整的 sk_live_ 密钥或仓库中的默认值
明示的限制不会自动扣款;degraded 表示地址“无法判断”;保留指纹(而非地址);通过 cache_key 删除
发送示例中不再包含任何合并变量(已验证),且模板中的每个变量都有说明(已验证)
4.6 客户跟踪(D50)

跟踪表的价值取决于它是否与实际提供的服务一致。 账户表中已有的信息足以回答决定收入的唯一问题:有哪些账户,哪些账户正在悄然流失,以及应该对他们说什么? 规则位于 app/suivi.py(状态、阈值、紧急程度顺序),执行逻辑位于 scripts/suivi_clients.py。

# rapport lisible, sur la base de la configuration (DATABASE_URL)
.\.venv\Scripts\python.exe scripts\suivi_clients.py

# export pour un tableur, seuils resserrés
.\.venv\Scripts\python.exe scripts\suivi_clients.py --format csv --sortie suivi.csv --essai-bientot-jours 5

# expliquer après coup un classement : rejouer le rapport à une date donnée
.\.venv\Scripts\python.exe scripts\suivi_clients.py --maintenant 2026-10-01T09:00:00+00:00
项目行为
已发布状态与付费路由一致:accounts.plan_status / consumption / refusal_reason,以及从 REFUS_HTTP 读取的 HTTP 状态码——不复制任何阈值,因此不可能出现偏差
顺序按紧急程度排列:当前被拒绝的账户,然后是即将结束的试用或即将达到配额的账户,最后是尚未完成集成的账户;优先级相同时,截止日期越近越靠前
密钥仅显示密钥前缀(足以在电话中识别账户),绝不显示完整密钥或其指纹;不会读取任何已验证的地址
只读仅执行 SELECT:报告无法修改生产数据库
导出--format csv 以 UTF-8 编码写入,使用分隔符「;」(适用于法语版 Excel),换行符为 \n——脚本会在写入时提醒这一点
退出代码0 已生成报告(空数据库也算一次测量),2 无法进行测量——空报告不代表「一切正常」

验证:.\.venv\Scripts\python.exe scripts\decisions_check.py D50——该检查会安装一个真实数据库,并将已发布状态与路由实际执行的拒绝规则进行比对,包括付费客户的试用日期已过期的情况。

4.7 首页(D53)

GET / 向浏览器提供展示页,并为程序保留原有 JSON(两者都设置了 Vary: Accept)。页面设计位于 app/templates/accueil/fr.html(原始样稿:docs/maquettes/page-accueil/);页面中的数据(试用期、配额、价格、x402 价格、联系方式)由 app/routes/accueil.py 从代码和配置中注入。

curl.exe -s https://kder-ai.com/                      # JSON, comme avant
curl.exe -s -H "Accept: text/html" https://kder-ai.com/   # la vitrine

验证:.\.venv\Scripts\python.exe scripts\decisions_check.py D53。

4.8 六种语言(D57)

法语页面仍位于根路径;另外五种语言使用各自的前缀。所有公开页面均提供六种语言版本:展示页、指南(D58)、免费试用(D59)、价格(D60)、注册和客户空间(D61),每个页面都使用对应的法语地址,并在前面加上语言前缀(/en/guide、/ar/signup……)。

语言首页显示货币(以欧元结算)
法语/29 € / 79 €
英语/en/$33 / $90
中文/zh/¥223 / ¥608
印地语/hi/₹3,160 / ₹8,620
西班牙语/es/29 € / 79 €
阿拉伯语(从右向左)/ar/$33 / $90

app/i18n.py 用于生成各语言的地址(chemin(lang, page))、数字和价格(prix、mention_euros,汇率为 2026 年 9 月的汇率),并渲染模板(rendre)。欧元金额来自 accounts.OFFRES(也可在 pricing.OFFRES 中查看):修改价格而不重新生成换算表,会导致 tests/test_i18n.py 和 D57 检查失败。照片由应用通过 /images/ 提供:公开 CSP 仅允许 img-src 'self'。

curl.exe -s https://kder-ai.com/en/                              # la vitrine en anglais
curl.exe -sI https://kder-ai.com/images/commercante-colis.jpg    # image/jpeg, nosniff

验证:.\.venv\Scripts\python.exe scripts\decisions_check.py D57。

4.9 AI Agent 与访问:衡量而非拦截(D72、D73)

服务会将每个调用方分类为六类(agent_ia、 annuaire_mcp、moteur、outil、navigateur、inconnu),将 AI Agent 和 MCP 目录记录到 D30 的 JSONL 日志中——绝不记录人工访问——并发布 五项指标(agents、top_ip、top_agents、 top_pages、conversion)。不会拦截任何 Agent:读取 /pricing 的 Agent 是没有浏览器的潜在客户。编辑方发布的 25 个 AI Agent 白名单位于 docs/AGENTS-IA.md,也包含在 /metrics/agents 的响应中。

curl.exe -s https://kder-ai.com/metrics/agents                        # en direct (compteurs du processus)
.\.venv\Scripts\python.exe scripts\analyser_agents.py --since 7d      # ce qui est écrit (journal JSONL)
.\.venv\Scripts\python.exe scripts\analyser_visites.py --since 24h    # tout le trafic (journal Nginx), 7 sections

scripts/analyser_visites.py 会生成七个部分——关键数据、时间、热门页面、 热门 IP、状态码、客户端、异常(探测、敏感路径、泄露)。其中的地址会 假名化(SHA-256 + 盐值,D30),除非明确指定 --ip-en-clair;泄露指 敏感路径以 2xx 提供服务(301 会重定向到其他位置,不会暴露内容)。两个 分析器读取同一分类表:端点和报告对 Agent 的定义不会相互矛盾。

验证:.\\.venv\\Scripts\\python.exe scripts\\run_tests.py tests\\test_agents_ia.py tests\\test_visites.py。

4.10 法国地址:国家地址数据库(D79)

对于 PAYS_BAN 中的国家/地区(法国本土及海外地区:FR、RE、 GP、MQ、GF、YT、BL、MF、PM),验证会通过国家 地址数据库(app/validation/ban.py、https://data.geopf.fr/geocodage)进行, 绝不使用 SmartyStreets,因为它无法判断法国地址是否有效:

  • BAN 分数 ≥ 0,8、返回的邮政编码与输入的邮政编码相同、 城市相同(会对重音符号、大小写、连字符和标点进行规范化);
  • 仅接受 housenumber(0,99)和 street(0,95)类型——其他类型 (municipality、locality)没有识别到道路;
  • BAN 故障时会返回 degraded: true,不会回退到 SmartyStreets;
  • 在美国一侧,只有 DPV 代码 Y/S/D 才能验证地址;X 和 N 不能验证,候选地址没有 DPV 时会返回 degraded: true。

此修正前计算的法国/海外地区结果(缓存 30 天)可通过 scripts/purger_cache_ban.py 清除(默认模拟运行, 使用 --apply 才会删除)。2026 年 10 月 17 日测量:「8 rue madelaine, Lyon, 75005」从 validated: true(缓存)变为 validated: false,而 Paris 75002、Lyon 69001 和 Saint-Denis 97400 仍通过验证。

5. 付费调用示例

  1. 构建证明(客户端和 API 共用 API_SECRET_KEY):
.\.venv\Scripts\python.exe -c "from app.payment import build_payment_proof; print(build_payment_proof('0x-demo-tx'))"
# -> 0x-demo-tx:1770000000.123:<hmac_sha256_hex>
  1. 调用 API:
curl.exe -X POST http://127.0.0.1:8000/validate `
  -H "Content-Type: application/json" `
  -H "X-Payment-Proof: 0x-demo-tx:1770000000.123:<hmac>" `
  -H "X-Transaction-Id: 0x-demo-tx" `
  -d "{\"address\":{\"street\":\"1600 Amphitheatre Parkway\",\"city\":\"Mountain View\",\"state\":\"CA\",\"zip\":\"94043\",\"country\":\"US\"}}"
  1. 没有证明,或证明已过期/格式错误/伪造时,响应为 402(app/payment.py:77-85):
{"error": "Payment Required", "price": 0.02, "currency": "USDC",
 "wallet": "", "protocol": "x402", "version": "1.0"}

上文发布的 402 正文只是节选:其中还包含 x402Version、network、accepts[](x402 v1 报价),现在还包含 accepts[0].outputSchema,即 ValidationResponse 的 Pydantic 模式(D80)。 2026 年 10 月 17 日测量:正文为 1 788 字节,响应头未超过 nginx 的 4 Ko 缓冲区,且 PAYMENT-REQUIRED 响应头中也有相同的 v2 报价。

  1. 使用有效证明时,响应为 200。以下是 10 月 10 日在此设备上于预发布 环境中测得的示例(无法连接服务提供方,因此为 degraded):
{"result": {"validated": false, "standardized": {"line1": "1600 Amphitheatre Parkway", "...": "..."},
            "deliverability": "invalid", "confidence": 0.05, "degraded": true,
            "cache_key": "8f1c…"},
 "price_paid": 0.02, "transaction_id": "0x-demo-tx"}

transaction_id 只是反映收到的 X-Transaction-Id 响应头 (app/routes/validate.py:67)。

同一调用在 10 月 11 日的生产环境中(https://kder-ai.com,实际服务提供方已启用, HMAC 证明有效):

{"result": {"validated": true, "deliverability": "residential", "confidence": 1.0,
            "degraded": false, "cache_key": "250a6087…"},
 "price_paid": 0.02, "transaction_id": null}

deliverability 根据服务提供方返回的 DPV 代码得出(Y → residential,scorer.py:17-23),confidence 则计入地理编码加分 (0,99 + 0,05,最高为 1,0)。服务提供方的 metadata.rdi(此地址对应 Commercial)仍保留在原始负载中,不会由 API 暴露。

6. 缓存、弹性与延迟预算

机制行为决策
Redis 缓存键 addr:<sha256>,TTL 为 30 天,在任何网络调用之前查询D5
降级结果的 TTL5 分钟,而非 30 天:degraded: true 表示“服务提供商未响应”,而非“地址无效”。保留一个月会让短暂故障长期固定;保留 5 分钟足以避免频繁请求故障中的服务提供商。而已验证的结论仍保留 30 天D47
缓存冷却后端发生故障后,缓存会被视为不可用 30 秒:Redis 故障只产生一次开销,而非每次请求都产生开销。/health 仍会执行实际探测D25
Redis 超时连接 1 秒,读取 1 秒;公开错误计数器D12
服务提供商熔断器closed → open → half-open → closed,应用级阈值为 3 次失败,恢复时间 60 秒;一旦打开,立即返回本地响应D23
服务提供商超时精细设置:连接 2 秒,读取 4 秒(而非统一的 10 秒)D23
地理编码器超时连接 2 秒,读取 3 秒;失败时将 latitude/longitude 留为 null,但请求不会失败D26
/health 探测在事件循环之外并行执行,超时时间为 2 秒D22
可观测性在 /metrics 中公开熔断器状态和缓存可用性D24

2026/10/10 在此工作站上测得的延迟(PostgreSQL 和 Redis 已关闭, 出站网络可用,服务提供商凭据为空,因此响应为 401):

测量项数值方法
GET /health2,13 s实际 HTTP 请求(D22 的 2,0 秒上限已达到,两个探测均失败)
POST /validate 付费,第 1 次调用11,117 sscripts/e2e_check.py
POST /validate 付费,第 2 次调用11,036 sscripts/e2e_check.py
Redis 读取,后端缺失2,03 s进程内测量(得益于 D25,只产生一次开销)
服务提供商调用(401 重试 3 次)6,77 s进程内测量
Nominatim 地理编码0,86 s进程内测量
完整流水线(validate_full)7,62 s进程内测量

这些数字如实呈现,并不光鲜:降级延迟主要由服务提供商造成,其错误 4xx 会被重试(参见 TEST_REPORT.md 中的“已知限制”)。代码中记录的基准值(D23 之前为 15,2 s,D22 之前为 6,03 s)今天并未重新测量:它们在 TEST_REPORT.md 中作为历史数据列出。

7. x402 支付:已验证、已结算,以及仍保留的遗留内容

服务使用 x402 v1(仓库 coinbase/x402 中的规范 specs/transports-v1/http.md),并在 Base 上实际以 USDC 结算支付。402 的正文是一个 PaymentRequired 文档:

{ "x402Version": 1, "error": "...", "accepts": [ { "scheme": "exact",
  "network": "base", "maxAmountRequired": "20000", "asset": "0x833589…2913",
  "payTo": "0x0fe9…d339", "resource": "https://kder-ai.com/validate",
  "mimeType": "application/json", "maxTimeoutSeconds": 300,
  "extra": { "name": "USD Coin", "version": "2" } } ] }

客户端在 X-PAYMENT 中返回签名(PaymentPayload 的 base64 编码 {signature, authorization:{from,to,value,validAfter,validBefore,nonce}}),并收到 X-PAYMENT-RESPONSE({success, transaction, network, payer} 的 base64 编码)。

也支持 x402 v2(D77)。 同一个 402 还会在 PAYMENT-REQUIRED 标头中携带 v2 报价(网络 eip155:8453、字段 amount、Coinbase 目录的 bazaar 扩展)。v2 客户端通过 PAYMENT-SIGNATURE 支付,并收到 PAYMENT-RESPONSE。没有任何支付方式时,即使正文为空,/validate 也会返回 402:这是 Coinbase 目录检查所要求的行为。

按此顺序进行两项检查(app/x402.py):

  1. 本地离线检查 — 显式重新计算 EIP-712 摘要(TransferWithAuthorization、EIP-3009)(使用 eth_abi、eth_hash、eth_keys),将恢复出的签名与 authorization.from 比较,并核对目标地址、金额、代币、网络和有效期是否与已发布的报价一致。此检查通过前,不会有任何内容离开服务端;
  2. 结算 — 向 Facilitator 发送 POST /verify,然后发送 POST /settle(默认使用 Coinbase 的 Facilitator,通过使用 CDP_API_KEY_ID / CDP_API_KEY_SECRET 签名的 CDP JWT 进行身份验证)。结算哈希会写入持久化账本(D29);任何失败(明确拒绝、服务故障、缺少哈希、nonce 已结算)都视为拒绝。

已公布的 EIP-712 域(extra.name / extra.version)与合约保持一致:scripts/test_x402_payment.py --check-domain 会进行链上验证 — 2026 年 10 月 11 日在 Base 上测得:name() = "USD Coin"、version() = "2"、decimals() = 6。

仍保留的遗留内容(D15)。 仍接受 X-Payment-Proof 标头 (tx_hash:timestamp:hmac_sha256),供运营人员使用的工具和已集成的客户端使用:对称有效期为 300 秒,以恒定时间比较 HMAC,并且必须确认 Base 上的收据(D27,默认启用;只有声明了 TEST_MODE=true 的测试才会跳过),确认方式为 JSON-RPC 读取(app/onchain.py,不依赖 web3 包或密钥存储包)。HMAC 支付绝不会被描述为 x402 结算:它不包含 X-PAYMENT-RESPONSE。

MCP。 同一个工具也通过 POST /mcp 以 MCP 形式提供(JSON-RPC 2.0、无状态、无 SSE 流)。从 D78 开始,支付采用 MCP x402 v2 传输:不含支付信息的 tools/call 会返回一个 isError: true 的工具结果,其 structuredContent 为 v2 PaymentRequired(且 content[0].text 也是同一文档,网络使用 CAIP-2,资源为 mcp://tool/validate_address);随后客户端将其 v2 PaymentPayload 放入 params._meta["x402/payment"],并在 result._meta["x402/payment-response"] 中收到结算结果。此传输不再发出 JSON-RPC 402:x402 MCP 客户端读取的是结果,而不是 HTTP 状态码。保留了 D34/D37 兼容性(v1 客户端通过 X-PAYMENT 支付,并继续使用其结算标头),而 settle_payment 是两种传输唯一的验证/收款路径。GET /.well-known/mcp-server 卡片由应用提供,因此不会描述已关闭的端点。目录发布文件:server.json、.mcp.json、smithery.yaml(见 DISCOVERY.md §1)。

实际测试。 scripts/test_x402_payment.py 有三种模式:计划(验证 /manifest、402 正文和 MCP 传输报价发布的是同一份报价)、--check-domain(将已公布的域与链上合约进行比较)以及 --pay(实际支付;需要在 Base 上持有已注资 USDC 的买家钱包,并会花费 0.02 USDC)。

8. 测试与验证

工具验证内容命令
pytest单元测试和集成测试行为.\.venv\Scripts\python.exe -m pytest -q
scripts/run_tests.py测试预言机:JUnit XML 报告 + 退出代码,不依赖 pytest 的摘要行(重定向输出时该行会消失).\.venv\Scripts\python.exe scripts\run_tests.py
scripts/doc_check.py文档中包含恰好预期数量的 ## N. 章节,且编号连续.\.venv\Scripts\python.exe scripts\doc_check.py README.md 10
scripts/e2e_check.py真实 HTTP 测试流程,包含覆盖 4 项成功标准的 22 项检查.\.venv\Scripts\python.exe scripts\e2e_check.py http://127.0.0.1:8000
GATES.md门禁清单:可执行的预言机(CHECK: / EXPECT:)和人工审查见下文“如何运行门禁清单”
.cline/skills/unlazy/scripts/gate-lint.mjs验证预言机确实能够失败(门禁清单质量)node .cline\skills\unlazy\scripts\gate-lint.mjs GATES.md

在本机于 10/10/2026 测得的结果:收集到 46 项测试 — 45 项通过, 1 项跳过(跳过的测试是一项集成测试,需要真实的 SmartyStreets 凭据和网络);scripts/e2e_check.py → 22/22 项检查通过。完整详情、方法和限制见 TEST_REPORT.md。

如何从项目根目录运行门禁清单:

node .cline\skills\unlazy\scripts\gate-lint.mjs address-validator\GATES.md
node .cline\skills\unlazy\scripts\gate-check.mjs --status  address-validator\GATES.md   # lit, n'exécute rien
node .cline\skills\unlazy\scripts\gate-check.mjs --approve address-validator\GATES.md   # approuve après lecture
node .cline\skills\unlazy\scripts\gate-check.mjs           address-validator\GATES.md   # exécute les oracles approuvés

9. 部署

deploy.sh 面向 Debian/Ubuntu VPS,依次执行:安装软件包 (python3.12、PostgreSQL、Redis、Nginx、Certbot),克隆到 /opt, 创建虚拟环境,运行 pip install -r requirements.txt,创建 PostgreSQL 数据库和 用户,启用 Redis,复制 nginx.conf,获取证书(certbot --nginx),然后安装并启动 systemd 服务。脚本启用了 set -euo pipefail(D20):遇到第一个 错误时便会停止。

注意:deploy.sh 不会创建任何 .env 文件。 如果不手动执行后续步骤, 服务将使用默认值启动——即 API_SECRET_KEY=change_me、PostgreSQL 密码 change_me,且没有 SmartyStreets 凭据(此时服务提供商会返回 401,所有 响应都会降级)。部署后请立即执行:

# sur le serveur, dans /opt/address-validator
cp .env.example .env        # puis renseigner API_SECRET_KEY, SMARTY_*, DATABASE_URL, REDIS_URL
systemctl restart address-validator
systemctl status address-validator
curl -s http://127.0.0.1:8000/health
journalctl -u address-validator -n 50

容器化部署方案:docker compose up -d(Dockerfile 基于 python:3.12-slim,docker-compose.yml 用于 API 及其依赖项)。

生产 VPS(kder-ai.com)部署:scripts/deploy-kder-ai.sh ——服务器上实际执行的脚本,已纳入此处的版本控制(在 11/10/2026 之前,它仅存放于工作站和 /opt 中,因此不受 版本控制)。该脚本包含上述 11 个步骤,并额外执行以下操作:

  • 如果 API_SECRET_KEY 仍为 change_me、长度少于 32 个字符,或 .env 使用 CRLF 换行符,则拒绝部署;
  • 将 nginx-hardening.conf 安装到 /etc/nginx/conf.d/:启用 HSTS (1 年,includeSubDomains)、X-Content-Type-Options: nosniff、 Referrer-Policy: no-referrer、每个 IP 限制为 10 req/s(突发流量 20),并将 请求正文限制为 16 ko。此配置刻意不放在虚拟主机配置中,因为 certbot --nginx 每次续期都会重写该配置;
  • 执行检查;如果安全加固配置已失效,则检查会失败或发出提示: 仅监听 127.0.0.1:8000(10.6)、安全响应头(10.7)、 60 个并发请求时返回 429(10.8);
  • 如果 Debian 软件源不提供 Python 3.12,则改为编译安装。

实际部署记录(版本、日志、已接受的差异、11/10/2026 的修复)见 DEPLOIEMENT_VPS.md。

投入生产后:限制对 /metrics 和 /docs 的访问,为 Redis 启用密码,并确认 Nginx 已正确配置 HTTPS 重定向(SECURITY.md §4 和 §6)。

10. 已知限制与后续计划

限制影响文档位置
声明为测试模式(TEST_MODE=true)时,接受共享密钥证明而不查询链仅供运营方测试:写入的行会标记为 test_mode,并从实际收入中排除;非测试模式下,未经确认的 USDC 转账证明会收到 402§7、SECURITY.md §3、D27、D40、D42
证明可在 300 s 内重放同一证明可在有效窗口内多次使用§7、SECURITY.md §6
address_validations 从未填充数据库中没有地址记录:数据保留依赖 Redis 缓存(30 j)PRIVACY.md §3
record_transaction 遇到无记录时会拒绝服务自 D41 起,写入失败会返回 500(ledger_write_failures_total):付款已接受,但不会提供验证结果,且必须核对收款情况SECURITY.md §5、D41
付费计划不会过期手动授予的计划会一直保持开放,直到手动撤销:只有月度配额会关闭访问权限(D45)。没有自动计费,因此也没有需要强制执行的订阅结束日期SECURITY.md §3、D45
代码中有两个产品级限额,反滥用仍由 edge 处理Nginx 按 IP 限制为 10 次请求/s(突发 20 次,超出时返回 429),用于防止滥用;代码还会增加面向客户端的业务限额:每个 IP 每小时最多注册 5 次(/signup,D44);使用 /validate-form 时,每个 IP 每 24 h 最多免费试用 3 次(项目 3,修订后的 D21)§9、SECURITY.md §6、D21(修订版)、D44
指标存储在内存中重启后丢失,没有 Prometheus 导出或告警SECURITY.md §5
会重试供应商的 4xx 错误测得的延迟恶化至 11,1 s;退避机制针对的是不可重试错误TEST_REPORT.md、“已知限制”
代码仍接受 CORS *、公开的 /metrics 和 /docs,以及默认密钥 change_me仍需加强;但部署会拒绝 change_me 以及任何少于 32 个字符的密钥(scripts/deploy-kder-ai.sh)§9、SECURITY.md §2 和 §6
法国本土及海外地区覆盖范围已通过 Base Adresse Nationale(D79)验证:评分、邮政编码和城市;BAN 故障时状态为 degraded,绝不会给出判定;修复前缓存的结果会清理一次(scripts/purger_cache_ban.py)§4.10、D79
402 契约已发布 outputSchema(派生的输出架构)和根级 network;请求正文约为 1,8 Ko,标头保持在 4 Ko 以下§5、§7、D80
deploy.sh 不会创建 .env如果忘记手动执行该步骤,启动时会使用默认密钥§9

建议的后续工作,按价值排序:

  1. 仅重试供应商的网络错误和 5xx:移除对 401 的退避,并将恶化后的延迟降至约 3 s 以下。
  2. 消耗付款证明(防重放),并在 API_SECRET_KEY 仍为默认值时拒绝启动。
  3. 将指标接入实际监控,并在部署时生成 .env。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。