结果 跑通了
建了 agent、环境、会话,发一句中文要求「做一个今日待办网页」。agent 用 write 工具在自己的 Computer 里写了 /workspace/index.html,用 bash 确认文件在,回了一句「完成了」。第二轮让它 cat 文件,把文件原样拿了出来,和它写进去的内容逐字节一致(8891 字节)。全程没有报错。
模型是预发上的 Workers AI deepseek-v4-flash,不是 Claude。花费按 org 记账前后差:244,826 → 252,899 micro-USD。
agent 做出来的网页
原样发布,没改一个字。可以直接在手机上用:加待办、点一下勾选、点 × 删除,刷新后还在(存在浏览器本地)。我在无头浏览器里试过:加 3 条、勾 1 条、删 1 条,显示 1 / 2、50%。
用的代码(没有密钥)
和调用 Anthropic 官方 Managed Agents 一样,只把 baseURL 换成预发地址。钥匙是临时签发的预发 workspace key,从环境变量读。
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
apiKey: process.env.KUL_STAGING_KEY, // 临时 kul_ws_ 钥匙,用完已吊销
baseURL: "https://kulullin-ma-staging.821623879.workers.dev",
});
const b = client.beta;
const agent = await b.agents.create({
name: "demo-todo",
model: "deepseek-v4-flash",
system: "你是一个网页开发助手。按用户要求使用工具在 /workspace 下工作,不要联网。",
tools: [{ type: "agent_toolset_20260401" }], // bash / read / write / edit / glob / grep
});
const env = await b.environments.create({ name: "demo-env", config: { type: "cloud" } });
const session = await b.sessions.create({ agent: agent.id, environment_id: env.id });
const stream = await b.sessions.events.stream(session.id);
await b.sessions.events.send(session.id, {
events: [{ type: "user.message", content: [{ type: "text",
text: "用 write 工具在 /workspace/index.html 写一个单文件网页:一个好看的「今日待办」页面……" }] }],
});
for await (const ev of stream) {
console.log(ev.type); // agent.tool_use / agent.tool_result / agent.message …
if (ev.type === "session.status_idle") break;
}
// 第二轮:同样 send 一句「用 bash 运行 cat /workspace/index.html」,从 agent.tool_result 里拿文件全文
await b.sessions.delete(session.id); // 删会话,Computer 一起销毁
await b.agents.archive(agent.id);
await b.environments.archive(env.id);
第一轮完整要求:中文界面;纯 HTML + CSS + 少量原生 JS,一个文件,不引用外部资源;适配手机;能添加、勾选、删除,用 localStorage 保存;顶部显示日期和完成进度条;圆角卡片、轻阴影。写完用 bash 跑 wc -c 确认。
时间线(从发消息算起)
wc -c /workspace/index.htmlcat /workspace/index.html用量
| 会话 | 1 个,2 轮,6 次模型请求 |
| token | 输入 7,032 · 输出 2,985 · 缓存读 11,776 |
| 会话活跃时间 | 39.4 秒 |
| 花费 | org 记账差 8,073 micro-USD(≈ $0.008)。会话 usage 里写的是 list_cost {"amount":"1","currency":"USD"},见下面的问题 |
| 持久化事件 | 30 条,和流里收到的一致 |
发现的问题 / 限制(如实记录)
- 文件要靠 cat 拿出来。产出物自动收集(outputs 登记成文件、用 files API 下载)还没做,是 #327。现在只能让 agent 把文件打印出来,或者从 write 工具的输入里取。
- 生成时 30 秒没动静。模型写网页那 31.7 秒里流上没有任何事件;agent.tool_use、tool_result、model_request_end 是一起到的。用户看不到「正在写」的进度。
- 流里 user.message 收到两次(同一个 id),每轮都是。客户端按 id 去重就没问题,但和 CMA 是否一致要全栈研发核对。
- 事件顺序:落库顺序是 tool_use → tool_result → span.model_request_end,model_request_end 排在工具结果后面,是否符合 CMA 也请全栈研发看一眼。
- 会话 usage.list_cost 是 "1" USD,按字面是 1 美元,和 org 记账的约 $0.008 对不上。可能单位是美分或做了向上取整,要全栈研发确认。
- 预发模型是 deepseek-v4-flash,网页质量代表不了 Claude 的水平;正式环境还没上(#332)。
钥匙怎么来的
按仓库里 tools/staging/README.md 写的方法:用 identity-admin key issue --remote 调预发 Worker 的维护口 /_maintenance/identity,给预发测试 workspace 临时签发一把 kul_ws_ 钥匙;跑完用 key revoke --yes 吊销(已核对 revoked=true)。没碰正式环境,没改预发代码,没直接改数据库,钥匙没有打印或落盘。