让 AI 智能体「对外营业」这件事,卡点通常不在模型,而在那堆没人愿意写的编排胶水:接哪个渠道、密钥怎么放、工具调用前要不要拦一道、审计日志怎么出。Agent-net 在 9 月开源的 Webagent 换了个思路——不给框架,给一份契约:填一份声明式 JSON 配置,为九个槽位各挑一个 provider,然后 webagent serve。这篇教程把它在本地跑通,并重点讲清楚它把安全放在代码层的那一刀。
先搞懂:一份契约服务三种人
Webagent 用 Go 写成,一个智能体被抽象成「一个 Brain(模型 + 指令)跑在一组槽位之上」。槽位定义在 core/,每个槽位是一个服务提供者接口(SPI),在 spi/ 里有 provider 注册表和指定的默认项。这个设计同时服务三类使用者,且都不需要改核心代码:
| 使用者 | 做法 | 是否需要写代码 |
|---|---|---|
| 配置型业务 | 从菜单里挑 provider,填 JSON spec | 不需要 |
| 扩展型团队 | 注册一个自定义 provider | 需要,但只写 provider |
| 合作方 | 提供官方适配器 | 需要,且要过该槽位的一致性测试 |
Step 1:准备 Go 环境
# 1) 安装 Go 工具链(版本要求以仓库 README 为准)
go version
# 2) 拉取 Webagent 并构建 CLI
# 仓库地址与模块路径以官方发布为准
go install github.com/agent-net/webagent/cmd/webagent@latest
# 3) 确认命令可用
webagent --help
# 4) 仓库自带两个示例 spec:zomato.json 与 bakery.json
项目当前标记为 v0,浏览器动作、带 OAuth 的 MCP、OTel 导出、以及 AgentNet 身份与计费层都尚未实现。用它做内部试点或原型没问题,直接上生产前建议先读完仓库里的「deferred hardening」清单。
Step 2:先跑通 echo brain——不需要任何凭证
默认的 echo brain 不需要任何密钥,所以可以先把链路跑通再谈模型:
# 校验配置(会报告解析结果与工具数量)
webagent validate bakery.json
# 起服务
webagent serve bakery.json
# 另一个终端里发一条消息到 HTTP 通道
curl -s -X POST http://localhost:8080/ -H 'Content-Type: application/json' -d '{"message":"今天有什么可买的"}'
Step 3:为九个槽位各选一个 provider
九个槽位各有内置 provider 与默认值。最小可用配置只需要明确改动其中一两个:
| 槽位 | 内置 provider | 默认 |
|---|---|---|
| Retrieval(检索) | live / keyword / hybrid | live |
| Memory(记忆) | session | session |
| Guardrail(护栏) | basic / off | basic |
| Channel(通道) | a2a / web / slack / whatsapp | a2a |
| Secrets(密钥) | env / file / static | env |
| Presenter(呈现) | text / terminal(QR) / web | text |
| Model(模型) | echo / openrouter / gateway | echo |
| Action(动作) | none / demo / mcp | none |
| Observability(可观测) | none / log / memory | none |
Model(换成真实模型)和 Action(接 MCP),其余保持默认。每多改一个槽位就多一组变量,排错成本翻倍。Step 4:接上真实模型与密钥
# 把 OpenRouter 密钥存到操作系统配置目录(权限 0600)
webagent keys set openrouter
# spec 里只写 provider 名字,不写密钥本体
# 任何以 Secret 结尾的配置键都会被当作“引用”,
# 在构建期通过所选 Vault 解析
# 优先级:已导出的环境变量 > 键值库
export OPENROUTER_API_KEY=sk-or-...
两条铁律:①密钥永不写进 spec 文件,这样 spec 可以安全进版本库;②解析失败的引用会让构建直接失败,而不是起来一个没有凭证的通道——这是好事,别把它改成「先起服务再说」。
Step 5:把已有 MCP Server 变成 Action provider
如果你已经有 MCP Server,不需要写新的编排代码——加一个 spec 块即可。连接走 Streamable HTTP(JSON 与 SSE),支持 Bearer 或 API Key 认证,构建期完成握手,并把每个工具交给 Guard 之后再交给智能体:
{
"action": {
"provider": "mcp",
"url": "https://your-mcp.example.com/mcp",
"auth": { "type": "bearer", "tokenSecret": "MCP_TOKEN" }
}
}
webagent validate 会打印握手后的真实工具数量。如果数量为 0,说明握手或鉴权没成,而不是模型不会用工具。Step 6:安全为什么放在代码层,而不是提示词里
整个项目最关键的架构决定叫 action.Guard:智能体持有的每一个工具——无论来自 action provider 还是宿主注入——都会被包装一层,选定的护栏在动作执行之前运行。模型无法绕过它,因为这不是「提示词里写了不要做」,而是调用路径上少了一条直通线。
项目的 DESIGN.md 把这件事挂在一条研究结论上:决定智能体成败的是架构而不是模型能力,同样的模型在不同架构下任务成功率差距明显。
辩证看:「Guarded」这个词承担了很多期待。provider 注册表的安全性,取决于默认 provider 是谁在维护;而 SPI 层的 provider 由谁审计、两个基于 Webagent 构建的智能体谈崩了责任归谁,目前都没有答案。把它当成一个把安全前置的工程选择,而不是一份安全保证。
Step 7:挂上 Slack 与 WhatsApp 通道
# Slack:事件回调指向
/slack/events
# WhatsApp:Meta 回调指向
/whatsapp/webhook
# 适配器行为(已内建):
# - 校验每个入站 webhook 的签名
# - 先立即应答,再通过平台 API 回复
# - 忽略自己发出的消息,避免自环
# - 对重复投递做去重
Present 槽位的 terminal(QR) 或 web 呈现方式在终端里验证对话,再去申请渠道凭证。渠道侧的审批往往是整条链路上最慢的一环。常见问题速查
| 现象 | 常见原因 | 处理 |
|---|---|---|
| validate 报工具数为 0 | MCP 握手或鉴权未通过 | 先用 curl 直连 MCP 端点确认凭证 |
| 服务起不来,提示引用解析失败 | 以 Secret 结尾的键没解析到值 | 按预期行为处理:补密钥,不要放宽校验 |
| 通道起来了但收不到消息 | 回调路径或签名配置不对 | 核对 /slack/events 与 /whatsapp/webhook |
| 模型不回话 | Model 槽位仍是默认 echo | 改为 openrouter 或 gateway 并设好密钥 |
| 想做浏览器点击类动作 | v0 尚未实现浏览器动作提供方 | 暂用 MCP 动作包一层,或等官方补齐 |
结语
Webagent 真正值得关注的不是代码量,而是它选择先发布一份能跑的契约:九个槽位、每槽一个 provider、一份 JSON 取代胶水代码。对整个 Agent 生态来说,这比再等一份「智能体之间怎么互相发现与付费」的规范文档更实用——但也要清醒:一份能跑的契约不等于一套成熟的商业基础设施,身份、计费与审计仍然空着。
务实的用法是把它当作「对外营业层」的原型工具:先把 spec 跑通、把 Guard 的位置确认下来、把 MCP 工具挂上去,等身份与计费补齐再谈规模化。这样即使 v0 有缺口,你积攒的配置与流程也不会白费。