模型和对话循环都是现成的,Anthropic 给脑子,Agents SDK 给循环。我们真正花时间的地方是四件事:给它什么工具,喂它什么上下文,什么时候叫它起来干活,哪些事必须先问人。
按工作量从大到小排。横条只是我读目录结构后的粗略感觉,不是统计出来的行数。
agent 能做多少事,取决于你给它多少工具。现在有两类只读工具:查 HL(行情、K 线、账户、挂单、成交、组合表现)和查网页(Exa / Tavily)。还有一类 propose 工具,只能「提议」写画像或建 Routine。
researchTools.ts · ResearchService.ts ·
WebResearchService.ts ·
proposeTools.ts
让 bot 不用人叫也会干活。定时 Routine 靠 DO alarm;条件 Routine 先用普通代码判断条件,命中了才叫模型。
RoutineService ·
ConditionCheckService ·
conditionEvaluator · nextFireAt ·
routineAlarms.ts
接四家 provider,保存 key 时先真调一次验活,把各家五花八门的报错归成几类,按 Run 记 token 用量和费用。
providerClient · probeModel ·
classifyProviderError ·
runUsageMiddleware ·
estimateModelCost
代码不多,但最影响效果。system prompt 里放职能说明、画像和工具使用规则;大块数据先压缩成摘要再给模型。
systemPrompt.ts · threadSummary ·
candleSummary
模型想改持久数据时,只能弹一张确认卡。答这张卡的只能是用户带会话的 HTTP 请求,模型自己答不了,WebSocket 帧也答不了。
proposals.ts ·
AgentRuntime.answerProposal
把 Think 接到我们的端口上,装配所有者 DO,写 SQLite 迁移和 repository。
thinkRuntime.ts · BotOwner.ts ·
infrastructure/sqlite/
HTTP 路由、推送、休眠和硬删、全局暂停、监控指标、每小时一次的 HL 红线巡检。很琐碎,但上线前一样都不能少。
routes/* · PushService ·
OwnerLifecycleService · platform/*
写工具最容易低估的是描述。模型看不到你的代码,只能读描述来决定什么时候用、怎么用。
strictObject,模型多编一个字段就直接拒掉。不严格的话,模型会自己发明参数
从上往下读:客户端怎么连进来,Worker 里有什么,往外又连了谁。
业务代码住在 contexts/bot(领域、应用、存储),apps/bot
只是壳:把 DO、路由、bindings 拼起来。这跟仓库里其它 context
的分法一致。
每条都是一个取舍。看懂「为什么」,比记住「是什么」有用。
一个用户的全部 bot、线程、Routine 都在同一个 DO 的 SQLite 里。DO 是单线程的,不用加锁,用户之间天然隔离,WebSocket 也直接挂在上面。代价是一个用户的负载没法拆到多台机器上,不过一个人的 bot 量远远到不了那个级别。
业务代码只认
submit / wait / abort / thread / answerProposal
这五个方法,不认识 Think。Agents SDK 还在 experimental,版本锁死在
0.30.0。哪天它不好用了,只换
thinkRuntime.ts 这一个文件,注释里也写了 pi 是备选。
没有「新建对话」。bot 的所有产出都落进同一条线程,用户回头看只有一个地方。Run 是记账单位:花了多少 token、为什么失败、是谁触发的,都挂在 Run 上。
用户发消息走 Think
自带的聊天协议,流式输出、断线重连都是现成的。Routine
和确认卡续跑这类「服务端主动」的活,走端口的
submit。两种来源在线程里分开显示,Routine
不能冒充用户发言。
Worker 一发版,名下所有 DO 都会重启,所有 WebSocket 都会断。拆开以后,bot 发版不会连累主 API。两边只能 bot 单向调 server,用户数据库从不绑定到 bot 这边。
HL 一律只读 mainnet。模型再怎么出错,也写不坏账本。将来 M2 要下单,走的是 ADR-0188 那套服务端托管 agent key 的拓扑,动钱之前还要过手机确认这一关。
每个 Run 最多调 12 次工具(RUN_TOOL_CALL_BUDGET),条件
Routine 先用代码判断,最后有配额兜底,用户自带 key
所以账单在他自己那儿。模型很容易陷进「再查一次」的循环,这条硬上限是最后一道闸。
全局暂停开关存在 KV 里,读不到时就当作「已暂停」。宁可 bot 少跑一次,也不要在该停的时候还在跑。
HL、检索、四家模型全部换成替身。模型替身靠一种小脚本驱动,比如
[tool:NAME*N@{json}] 表示「调 N
次这个工具」,这样编排逻辑能确定地测。但要注意,这测不出模型本身答得好不好,那需要另做评估。
用一个具体场景把上面的东西串起来。绿色步骤不花模型钱,蓝色步骤花。
submit 一个 Run,来源标成
routine,并带上命中的数据。开始花钱
第 3 步是整套设计里最省钱的一招。要是每次巡检都让模型来判断「危不危险」,一个用户一天就要叫好几十次模型。
先看它们之间是什么关系,再看每个词的意思。
user_id 当键,不用钱包地址。只读观察的账户建不了会话,所以没有 bot。