
Cloudflare Think Channels 完全指南多端接入、按渠道策略与带外通知实战【免费下载链接】agentsBuild and deploy AI Agents on Cloudflare项目地址: https://gitcode.com/GitHub_Trending/agents1/agents导读cloudflare/thinkThink是 Cloudflare Agents 生态中一个基于 Durable Object SQLite 构建的聊天 Agent 基类而Channels渠道是它提供的一套把对话表面统一抽象的概念无论是浏览器 WebSocket、Telegram/Slack 等 Messenger Webhook、语音还是自定义传输协议都可以抽象为一个 channel从而为不同表面分别配置系统提示词、工具集裁剪、模型步数上限并支持不触发模型推理的带外通知out-of-band notice。读完本文你将掌握通过configureChannels()声明多端 Agent、用runTurn({ channel })按渠道分发轮次、用deliverNotice()异步推送状态消息以及如何利用channel可观测事件与renderAttachment()完成回复附件的渠道化投递。本文以 docs/think/channels.md 为骨架结合cloudflare/think包的源码packages/think/src/channels/index.ts、packages/think/src/think.ts与单元测试packages/think/src/tests/channels.test.ts、packages/think/src/tests/deliver-notice.test.ts逐层展开保证每个结论都有文档与代码双重依据。实验性声明Channels 相关 API 处于 Experimental 阶段在 Think 脱离实验期之前API 表面可能继续演进。一、什么是 Channel把 Messengers 泛化为一套统一词汇一个 channel 就是 Think Agent 说话所经过的表面浏览器 WebSocket、Messenger WebhookTelegram、Slack 等、语音或你自己的自定义传输。Channels 把 Messengers 泛化为一套统一词汇这样你就可以对每个渠道施加按渠道策略per-channel policy——不同的系统提示词、收窄的工具集、步数上限无论轮次从哪个表面到达都能跨表面投递带外通知。隐式 web 渠道与渠道注册表每个 Think Agent 始终存在一个隐式的web渠道即浏览器客户端使用的 WebSocket 聊天。你通过configureChannels()声明额外的渠道也可以覆盖web渠道的策略而getMessengers()返回的 Messengers 会被自动吸收为kind: messenger的渠道因此现有的 Messenger 应用无需任何改动即可继续工作。源码层面resolveChannels()负责把三类来源合并成一个统一渠道注册表隐式web渠道IMPLICIT_WEB_CHANNEL默认能力为canStream: true、canEditMessages: trueingress 为{ transport: websocket }configureChannels()返回的每条声明getMessengers()的每条 Messenger 条目自动包装为kind: messenger渠道。对应实现见 packages/think/src/channels/index.ts#L94-L175。注册表解析完成后kind: messenger的渠道会被抽取出来继续喂给未变的ThinkMessengerRuntime——这正是configureChannels()包装而非替换getMessengers()的底层含义。渠道 id 的保留与冲突规则源码对web这个 id 做了硬性保留在configureChannels()中声明web时kind必须是web否则抛出Channel web is reserved for the built-in WebSocket chat surface错误——因为换成其他 kind 会静默破坏原生聊天入口/投递路径在getMessengers()中声明名为web的 Messenger 同样会抛出错误同一个 id 同时出现在configureChannels()与getMessengers()中会抛出channel ids must be unique。这些行为都被 packages/think/src/tests/channels.test.ts 的单元测试逐一锁定例如always includes an implicit web channel验证空配置下web渠道始终存在throws when configureChannels() replaces web with a non-web kind验证保留规则的强约束throws on a duplicate id across configureChannels() and getMessengers()验证 id 唯一性。二、声明渠道configureChannels()完整配置在子类中覆写configureChannels()返回一个channel id →ChannelDefinition的映射。id 就是在某次轮次上选择渠道所用的标识符。默认实现返回{}即只有隐式web渠道见 packages/think/src/think.ts#L4468-L4470。最小示例import { Think, messengerChannel } from cloudflare/think; import { telegram } from chat-adapter/telegram; export class Assistant extends ThinkEnv { configureChannels() { return { // 覆盖内置 web 渠道的策略 web: { kind: web, ingress: { transport: websocket }, instructions: You are chatting in a web app. Use markdown freely. }, // 一个限制更严的语音渠道 voice: { kind: voice, ingress: { transport: voice }, instructions: Keep replies short and speakable. No markdown., maxTurns: 3 }, // 一个 Messenger 渠道Chat SDK webhook telegram: messengerChannel( telegram({ /* adapter config */ }) ) }; } }注意对web做策略覆盖只写instructions时源码会先把IMPLICIT_WEB_CHANNEL与你的声明做浅合并{ ...IMPLICIT_WEB_CHANNEL, ...definition }因此内置的websocketingress 与默认 capabilities 不会被静默丢弃——测试allows overriding the web channels policy with a kind: web entry验证了这一点。ChannelDefinition字段详解下表来自原文档字段类型与语义同时对齐源码接口 ChannelDefinition字段类型说明kindweb \| messenger \| voice \| custom表面类别ingress{ transport: websocket \| voice }或 webhook Messenger 规格轮次如何到达。messengerChannel()会替你构造 webhook 形式instructionsstring \| (ctx: ChannelContext) string \| Promisestring前置到该系统渠道轮次的系统提示词tools(all: ToolSet) ToolSet收窄该渠道的装配工具集只能过滤不能新增工具maxTurnsnumber该渠道单轮次的模型步数上限capabilitiesChannelCapabilities表面能力流式、消息编辑。web有默认值conversationMessenger 会话模式或解析器Messenger 线程路由见 Messengersdeliverychannel 投递策略Messenger 投递策略messengerChannel()与类型安全用messengerChannel()把 Chat SDK 适配器定义包装成kind: messenger渠道。源码实现非常直接packages/think/src/channels/index.ts#L71-L81export function messengerChannel( definition: MessengerDefinition ): ChannelDefinition { return { kind: messenger, capabilities: definition.capabilities, conversation: definition.conversation, delivery: definition.delivery, ingress: { transport: webhook, ...definition } }; }它会自动继承适配器的 capabilities / conversation / delivery并把整个 MessengerDefinition 展开进ingresstransport 固定为webhook。反向抽取逻辑messengerFromChannel()则在resolveChannels()中把这类渠道还原为ThinkMessengers输入喂给 Messenger 运行时。想要对内联渠道映射做编译期检查时给返回值标注ThinkChannels类型或用satisfies ThinkChannels。ThinkChannels Recordstring, ChannelDefinition见 packages/think/src/channels/index.ts#L66。渠道种类速查KindIngress说明web{ transport: websocket }始终存在。只有在要设置策略时才需要在configureChannels()中声明不能移除messengerwebhookmessengerChannel(...)喂入 Messenger 运行时等价于一条getMessengers()条目voice{ transport: voice }应用策略与轮次上下文带外投递尚未接线custom应用自定义用于自有传输。目前与voice有相同的投递限制从源码看ChannelIngress是一个判别联合webhook形态携带完整MessengerDefinition而websocket/voice不需要凭空发明 webhook 字段packages/think/src/channels/index.ts#L30-L33。三、按渠道策略指令、工具与步数上限的覆盖语义渠道策略在beforeTurn之前作为**可覆写默认值overridable default**应用因此beforeTurn的覆写仍然优先。实际装配顺序可以从 packages/think/src/think.ts#L6327-L6349 看到instructions前置到该系统提示词。若声明为函数则以ChannelContext为参数调用求值。最终系统提示词拼接为channelInstructions \n\n baseSystemtools过滤已装配的工具集。源码中渠道工具过滤发生在工具合并完成后、beforeTurn之前且过滤只能删不能加——config.toolsbeforeTurn返回这一缝只能新增工具maxTurns限制模型步数优先级为beforeTurn返回的maxSteps 渠道maxTurns 实例maxSteps默认值。源码中对应config.maxSteps ?? channelDefinition?.maxTurns ?? this.maxStepspackages/think/src/think.ts#L6443-L6447。此外ChannelContextpackages/think/src/channels/index.ts#L39-L45携带channelId、kind、capabilities与可选的messenger/thread信息。instructions函数型声明因此可以在运行时基于渠道上下文动态生成提示词例如区分群聊与私聊。四、在轮次上选择渠道runTurn({ channel })与activeChannel向runTurn()或chat()传入channel即可在指定渠道上运行轮次。渠道 id 会被盖章stamp到用户消息上因此续跑continuation或恢复recovery的轮次会重新解析同一个渠道并重新应用其策略。await this.runTurn({ input: Read this out loud, channel: voice });源码侧的关键机制_stampChannel()把channel写进用户消息的持久化 metadataRESERVED_MESSAGE_METADATA_KEYS包含channel续跑与恢复路径分别通过_channelFromLatestUserMessage()/_channelFromMessages()从持久化历史中重新解析渠道确保中断后的重试依然应用原渠道策略packages/think/src/think.ts#L11708-L11720未注册的渠道 id 不会抛出异常恢复的轮次可能引用一个已被移除的渠道但会打印console.warn提示避免打错 id 而静默失去策略packages/think/src/think.ts#L4541-L4555。轮次进行中可用this.activeChannel获取当前渠道上下文——一个包含channelId、kind及相关时Messenger 细节的ChannelContext可安全地从工具或钩子中读取。其 getter 直接返回私有字段_activeChannelContextpackages/think/src/think.ts#L4519-L4521。上下文通过_withChannelContext()做保存/恢复保证嵌套轮次安全。未指定channel的轮次则在无渠道上下文下运行不应用任何渠道策略。五、带外通知deliverNotice()全解析deliverNotice()向某个渠道发送消息而不启动模型轮次。适用场景状态更新你的导入已完成、把某个 action 的回复附件reply attachment上屏等。它不运行推理、不进入轮次队列因此在工具execute内部调用也绝对安全。基础用法await this.deliverNotice(Your export is ready to download.); await this.deliverNotice(Background research finished., { informModel: true // 同时记录到 transcript让下一轮知道 });选项类型type DeliverNoticeOptions { channel?: string; // 默认取活动轮次的渠道否则 web informModel?: boolean; // 同时写入模型可见的 transcript默认 false kind?: final | interim | notice | command; // 线上标签默认 notice thread?: string; // 多线程 Messenger 在轮次外投递时必填 };按目标渠道的行为差异web——通知总是追加到 transcript这是它唯一的渲染路径informModel此时只控制措辞。源码实现web分支调用addMessages([this._noticeMessage(...)])informModel: true时文本带[Delivered to the user out of band]前缀见 packages/think/src/think.ts#L4684-L4687messenger——通知发布到提供商。轮次外需传thread指定会话informModel: true时同时写入 transcript。源码通过_activeDeliverySurface或ThinkMessengerRuntime.resolveDeliverySurface(channelId, thread)解析投递表面后调用surface.post()voice/custom——轮次外投递直接抛错因为这些表面还没有投递目标。错误信息会区分渠道未注册、缺少 thread与该 kind 尚无带外投递表面三类原因packages/think/src/think.ts#L4695-L4709。路由优先级为显式options.channel→ 活动轮次的渠道 →web。无论成功失败都会发出notice:delivered/notice:failed可观测事件。测试 packages/think/src/tests/deliver-notice.test.ts 覆盖了关键行为informModel为 false 时web 通知以纯文本追加消息角色为assistantinformModel: true时文本带上[Delivered to the user out of band]前缀kind会被记录到消息 metadata 的deliveryKind字段默认值为notice通知不产生模型轮次连续两次deliverNotice后 transcript 只有两条 assistant 消息无法解析目标渠道时快速失败cannot resolve a delivery surface。renderAttachment()把回复附件变成通知覆写renderAttachment(attachment)可将 action 的回复附件渲染为通知文本。Think 在每轮结束时调用它并把渲染结果作为一条尾部的interim通知投递返回undefined则跳过该附件类型。默认实现packages/think/src/think.ts#L16423-L16447处理了三种类型card把 payload 序列化为 json 代码块email_draft渲染为Email draft加上To:与Subject:行voice_note返回undefined由 voice transport 带外处理不渲染文本其余未知类型返回undefined跳过。投递过程是 best-effort 的renderAttachment抛错只console.warn并继续处理下一个附件deliverNotice失败同样只警告不会让整轮失败_renderChannelAttachmentspackages/think/src/think.ts#L16453-L16480。同时该轮会发出channel:delivered事件记录渠道级投递。六、与 Messengers 的关系包装而非替换configureChannels()包装getMessengers()而不是替换它每条getMessengers()条目都会成为一个kind: messenger渠道Messengers 指南中的一切——Telegram 配置、webhook 路由、会话目标、投递与恢复——继续全部适用configureChannels()中的渠道 id 与getMessengers()id 冲突属于错误源码在resolveChannels()中显式抛错纯 Messenger 应用继续用getMessengers()同时需要web/voice/custom策略或带外通知时再使用configureChannels()。初始化时序上_initializeChannels()只在根 AgentparentPath为空上运行先调用configureChannels()与getMessengers()合并出渠道注册表与 Messenger 定义存在 Messenger 时才实例化ThinkMessengerRuntimepackages/think/src/think.ts#L4758-L4780。注意子 Agent 没有渠道注册表此时请求渠道不会应用策略源码对_channels undefined的情况静默处理。七、可观测性channel事件渠道活动通过agents/observability的channel可观测渠道上报import { subscribe } from agents/observability; const unsubscribe subscribe(channel, (event) { // event.type 为以下之一 // channel:resolved — 某轮次解析到了一个已注册渠道 // channel:delivered — 某轮次的最终回复已投递 // notice:delivered — deliverNotice() 成功 // notice:failed — deliverNotice() 抛错 });源码中四类事件的 payload 结构packages/think/src/think.ts#L1846-L1859channel:resolved{ channel, kind, requestId? }channel:delivered{ channel, kind: DeliveryKind, turnEnded }notice:delivered{ channel, kind: DeliveryKind, informModel }notice:failed{ channel, error }。利用这些事件可以搭建渠道维度的监控面板追踪每个渠道的轮次解析率、最终回复是否送达、带外通知的成功/失败率。八、API 参考速查成员说明configureChannels()返回渠道映射。默认{}仅隐式web渠道deliverNotice(text, options?)向渠道发送不带模型轮次的带外消息activeChannel进行中轮次的ChannelContext无则undefinedrenderAttachment(attachment)把回复附件映射为渠道通知文本返回undefined跳过messengerChannel(definition)把 Chat SDK 适配器包装为kind: messenger渠道相关类型与函数都从cloudflare/think导出ThinkChannels、ChannelDefinition、ChannelContext、ChannelKind、ChannelCapabilities、DeliverNoticeOptions、messengerChannel等。九、设计实践建议综合文档与源码几个值得落地的设计模式按渠道差异化提示web渠道允许 Markdown 与长回复voice渠道要求短句、无 Markdown 并设maxTurns: 3Messenger 渠道用适配器自己的指令——一套 Agent 多端复用策略互不干扰。工具集按渠道收窄例如voice渠道用tools()过滤掉文件编辑类工具只保留查询类因为过滤发生在工具合并之后、beforeTurn之前任何渠道都无法新增自身未授权的工具。工具内安全地投递状态在耗时工具的execute中直接deliverNotice()绕开轮次队列与推理天然免疫死锁对 Messenger 渠道记得在轮次外传thread。附件上屏让 action 记录 reply attachment见 Actions再通过renderAttachment()的覆写把卡片、邮件草稿等渲染成渠道通知。监控渠道健康订阅channel可观测事件重点关注notice:failed与channel:delivered及早发现某端投递故障。相关阅读Think Messengers——Chat SDK Webhook 的深度配置与投递Think Actions——记录供renderAttachment()使用的回复附件Think 生命周期钩子——beforeTurn等钩子与渠道策略的优先级关系Think 入口文档——runTurn()三种模式与完整配置覆盖表其中configureChannels()默认{}渠道注册表解析实现packages/think/src/channels/index.ts运行时集成与投递实现packages/think/src/think.ts单元测试packages/think/src/tests/channels.test.ts、packages/think/src/tests/deliver-notice.test.ts。【免费下载链接】agentsBuild and deploy AI Agents on Cloudflare项目地址: https://gitcode.com/GitHub_Trending/agents1/agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考