<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Slack on AI博士 万戈</title>
        <link>https://www.yesmiracle.net/tags/slack/</link>
        <description>AI博士万戈的技术博客，聚焦 Agentic AI、AI Infra 与 Agent Security，分享 AI 基础设施与工程落地实践。</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <managingEditor>admin@yesmiracle.net (万戈)</managingEditor>
        <webMaster>admin@yesmiracle.net (万戈)</webMaster>
        <lastBuildDate>Tue, 28 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://www.yesmiracle.net/tags/slack/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>CopilotKit 开源了 OpenTag！AG-UI 协议驱动的跨平台聊天 Agent，一个深入源码的架构拆解</title>
        <link>https://www.yesmiracle.net/post/20260728-opentag-copilotkit-slack-agent/</link>
        <pubDate>Tue, 28 Jul 2026 00:00:00 +0000</pubDate>
        <author>admin@yesmiracle.net (万戈)</author>
        <guid>https://www.yesmiracle.net/post/20260728-opentag-copilotkit-slack-agent/</guid>
        <description>&lt;img src="https://www.yesmiracle.net/post/20260728-opentag-copilotkit-slack-agent/cover.svg" alt="Featured image of post CopilotKit 开源了 OpenTag！AG-UI 协议驱动的跨平台聊天 Agent，一个深入源码的架构拆解" /&gt;&lt;p&gt;你团队里用 Claude in Slack 吗？每月 $25/人、对话不能持久化、MCP 工具不支持、想改行为还要写 Support Ticket？CopilotKit 刚开源的 &lt;strong&gt;OpenTag&lt;/strong&gt;，就是冲这个痛点的——它让你在自己的基础设施上跑一个和 Claude in Slack 一模一样的 AI Agent，还能接自己的模型、挂自己的 MCP 工具、渲染图表和卡片。&lt;/p&gt;
&lt;p&gt;更让我兴奋的是它的架构设计。OpenTag 不是又一个「把 LLM 接入 Slack」的玩具，它背后有一套清晰的&lt;strong&gt;四层协议栈&lt;/strong&gt;和一个&lt;strong&gt;可替换的双运行时&lt;/strong&gt;设计，和之前拆解过的 &lt;a class=&#34;link&#34; href=&#34;https://www.yesmiracle.net/post/20260719-nanobot-architecture/&#34; &gt;Nanobot&lt;/a&gt; 和 &lt;a class=&#34;link&#34; href=&#34;https://www.yesmiracle.net/post/20260719-pi-agent-architecture/&#34; &gt;Pi Agent&lt;/a&gt; 走的是完全不同的技术路线。这篇文章从源码出发，拆解 OpenTag 的每一层。&lt;/p&gt;
&lt;h2 id=&#34;700-star-的-slack-agent-开源替代&#34;&gt;700+ Star 的 Slack Agent 开源替代&lt;/h2&gt;
&lt;p&gt;先给个全景感：OpenTag 是 CopilotKit 基于其 &lt;a class=&#34;link&#34; href=&#34;https://github.com/CopilotKit/CopilotKit/tree/main/packages/channels&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;@copilotkit/channels&lt;/code&gt;&lt;/a&gt; SDK 构建的参考实现，MIT 协议开源，GitHub 上不到两周就攒了 700+ Star。&lt;/p&gt;
&lt;p&gt;它的定位非常明确——&lt;strong&gt;一个可以自托管的 Claude in Slack 替代品&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 Slack 频道里 @mention 机器人，它就能读对话、回答问题、调用 MCP 工具&lt;/li&gt;
&lt;li&gt;生成的响应不是纯文本，而是&lt;strong&gt;原生 UI 组件&lt;/strong&gt;（Slack Block Kit、Discord Components V2、Telegram HTML）&lt;/li&gt;
&lt;li&gt;所有写操作（创建 Linear Issue、写 Notion 文档）都经过&lt;strong&gt;人工确认门&lt;/strong&gt;（Human-in-the-Loop）&lt;/li&gt;
&lt;li&gt;支持四种聊天平台：Slack、Discord、Telegram、WhatsApp——&lt;strong&gt;同一套代码，一个 &lt;code&gt;createBot&lt;/code&gt; 启动全部&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;听起来和 &lt;a class=&#34;link&#34; href=&#34;https://www.yesmiracle.net/post/20260719-nanobot-architecture/&#34; &gt;Nanobot&lt;/a&gt; 有点像？确实，都是「把 Agent 放进聊天工具」的路子。但 OpenTag 在架构上走了完全不同的方向——它用了一套叫 AG-UI 的协议把 Bot 层和 Agent 层解耦，而不是像 Nanobot 那样用 asyncio.Queue 内部耦合。&lt;/p&gt;
&lt;h2 id=&#34;四层架构从聊天界面到-agent-大脑&#34;&gt;四层架构：从聊天界面到 Agent 大脑&lt;/h2&gt;
&lt;p&gt;OpenTag 的架构可以拆成四层，每层职责单一、通过协议通信：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;用户聊天界面 (Slack/Discord/Telegram/WhatsApp)
       │
       ▼  @mention  /command
┌─────────────────────────────┐
│   Bot 层 (app/)             │   ← createBot({ adapters, tools, components })
│   平台适配器 · 工具转发      │
│   UI 组件渲染 · HITL 门     │
│   Read Thread · Slash 命令  │
└──────────┬──────────────────┘
           │ AG-UI 协议 (POST /api/copilotkit/agent/triage/run)
           ▼
┌─────────────────────────────┐
│   Agent 运行时              │   ← 可替换：runtime.ts 或 agent/
│   BuiltInAgent (TS)         │
│   或 Deep Agent (Python)    │
│   LLM + MCP 工具            │
└──────────┬──────────────────┘
           │ MCP (Streamable HTTP)
           ▼
┌─────────────────────────────┐
│   数据层                    │
│   Linear MCP · Notion MCP   │
│   Web Search (OpenAI)       │
└─────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这个分层和 &lt;a class=&#34;link&#34; href=&#34;https://www.yesmiracle.net/post/20260719-pi-agent-architecture/&#34; &gt;Pi Agent&lt;/a&gt; 的「Provider → Steering → Follow-up」三层有点像，但 OpenTag 用的是一个&lt;strong&gt;公开协议 (AG-UI)&lt;/strong&gt; 来连接 Bot 和 Agent，而不是内部函数调用。这意味着你可以把 Bot 层换成任意客户端，只要它实现了 AG-UI 协议。&lt;/p&gt;
&lt;h2 id=&#34;ag-ui-协议bot-和-agent-之间的通用语&#34;&gt;AG-UI 协议：Bot 和 Agent 之间的「通用语」&lt;/h2&gt;
&lt;p&gt;AG-UI 是 CopilotKit 定义的一套 Agent-to-UI 协议，本质上是一个 &lt;strong&gt;HTTP SSE 流&lt;/strong&gt;。Bot 层把用户消息、上下文、前端工具声明打包成 AG-UI 请求发给 Agent，Agent 返回一个事件流——LLM 的 tokens、工具调用请求、UI 组件渲染指令都在这个流里传输。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;runtime.ts&lt;/code&gt; 里，Agent 端只有几十行代码：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;runtime&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CopilotSseRuntime&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;agents&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; { &lt;span style=&#34;color:#a6e22e&#34;&gt;triage&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;agent&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;listener&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;createCopilotNodeListener&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;runtime&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;basePath&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/api/copilotkit&amp;#34;&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;createServer&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;listener&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;listen&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;8200&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Bot 端用 &lt;code&gt;AGENT_URL&lt;/code&gt; 指向这个地址，两边就通了。这意味着你有一个 Agent 运行在 GPU 集群上，Bot 运行在 Slack 旁边——只要网络可达，它们就能通信。这和 Grok Build 的 ACP 协议（参考&lt;a class=&#34;link&#34; href=&#34;https://www.yesmiracle.net/post/20260726-agent-to-agent-protocol-guide/&#34; &gt;四大协议详解&lt;/a&gt;）思路一致：把 Agent 的「大脑」和「嘴巴」拆开，通过标准协议连接。&lt;/p&gt;
&lt;h2 id=&#34;双运行时设计简单场景-vs-深度研究&#34;&gt;双运行时设计：简单场景 vs 深度研究&lt;/h2&gt;
&lt;p&gt;OpenTag 最让我感兴趣的设计决策是&lt;strong&gt;提供了两个完全不同的 Agent 后端&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;① TypeScript BuiltInAgent (&lt;code&gt;runtime.ts&lt;/code&gt;)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一个单 LLM 调用 + MCP 工具的轻量运行时，适合大多数日常对话场景。核心代码不到 100 行 TypeScript：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;agent&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BuiltInAgent&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tanstack&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;factory&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;async&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;chat&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;adapter&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;openaiText&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;model&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;messages&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;systemPrompts&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [&lt;span style=&#34;color:#a6e22e&#34;&gt;SYSTEM_PROMPT&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;tools&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [&lt;span style=&#34;color:#a6e22e&#34;&gt;webSearchTool&lt;/span&gt;({ &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;web_search&amp;#34;&lt;/span&gt; }), ...&lt;span style=&#34;color:#a6e22e&#34;&gt;clientTools&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ...(&lt;span style=&#34;color:#a6e22e&#34;&gt;mcpClients&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; { &lt;span style=&#34;color:#a6e22e&#34;&gt;mcp&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; { &lt;span style=&#34;color:#a6e22e&#34;&gt;clients&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;mcpClients&lt;/span&gt; } } &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {}),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它用 TanStack AI 的 &lt;code&gt;chat()&lt;/code&gt; 做多轮工具循环，MCP 客户端在每次 turn 开始时创建、结束时关闭——&lt;strong&gt;临时连接模式&lt;/strong&gt;，避免长时间持有 MCP 连接。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;② Python Deep Agent (&lt;code&gt;agent/&lt;/code&gt;)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一个基于 LangGraph + Deep Agents 的深度研究 Agent，用了 &lt;code&gt;write_todos&lt;/code&gt; 做任务规划、虚拟文件系统做中间持久化、可选的 Tavily 做网络搜索。它不是简单的一轮 LLM 调用，而是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用 &lt;code&gt;write_todos&lt;/code&gt; 制定研究计划&lt;/li&gt;
&lt;li&gt;逐个执行研究步骤（通过 &lt;code&gt;research()&lt;/code&gt; 工具调用内部子 Agent）&lt;/li&gt;
&lt;li&gt;把发现写入虚拟文件系统&lt;/li&gt;
&lt;li&gt;合成最终报告&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;切换&lt;/strong&gt;：改 &lt;code&gt;.env&lt;/code&gt; 里的 &lt;code&gt;AGENT_URL&lt;/code&gt; 就行——&lt;code&gt;http://localhost:8200&lt;/code&gt; 用 TS，&lt;code&gt;http://localhost:8123&lt;/code&gt; 用 Python。Bot 层完全不知道背后换了个大脑。&lt;/p&gt;
&lt;p&gt;这比 Nanobot 的「单 Agent Loop」更灵活。Nanobot 的 TurnState 只有一套 8 状态机（RESTORE→COMPACT→COMMAND→BUILD→RUN→SAVE→RESPOND→DONE），而 OpenTag 让你在不同 Agent 实现之间切换，甚至可以在生产环境用 TS 运行时做日常对话、用 Python Deep Agent 做深度研究，通过路由层分发。&lt;/p&gt;
&lt;h2 id=&#34;跨平台-ui-渲染jsx-编译成原生组件&#34;&gt;跨平台 UI 渲染：JSX 编译成原生组件&lt;/h2&gt;
&lt;p&gt;这是 OpenTag 最亮眼的技术点。&lt;code&gt;@copilotkit/channels-ui&lt;/code&gt; 定义了一套&lt;strong&gt;跨平台 JSX 组件&lt;/strong&gt;，编译时自动映射到各平台的原生 UI：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;JSX 组件&lt;/th&gt;
          &lt;th&gt;Slack&lt;/th&gt;
          &lt;th&gt;Discord&lt;/th&gt;
          &lt;th&gt;Telegram&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;&amp;lt;Table&amp;gt;&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Block Kit Section&lt;/td&gt;
          &lt;td&gt;Embed&lt;/td&gt;
          &lt;td&gt;HTML &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;&amp;lt;IssueCard&amp;gt;&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Block Kit Section&lt;/td&gt;
          &lt;td&gt;Embed&lt;/td&gt;
          &lt;td&gt;Markdown&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;&amp;lt;Button&amp;gt;&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Button Element&lt;/td&gt;
          &lt;td&gt;Button Component&lt;/td&gt;
          &lt;td&gt;HTML &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;&amp;lt;Modal&amp;gt;&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Modal View&lt;/td&gt;
          &lt;td&gt;Modal&lt;/td&gt;
          &lt;td&gt;降级为对话流&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这个设计的巧妙之处在于：Agent 只需要调用 &lt;code&gt;render_chart&lt;/code&gt;、&lt;code&gt;render_table&lt;/code&gt;、&lt;code&gt;issue_card&lt;/code&gt; 等工具，Bot 层负责把工具调用翻译成对应平台的 UI 渲染。Agent 不关心用户用的是 Slack 还是 Telegram。&lt;/p&gt;
&lt;p&gt;对比来看，Nanobot 的 15+ 平台支持也是类似的思路（&lt;code&gt;Channel&lt;/code&gt; 接口抽象），但 Nanobot 的输出是纯文本 + Markdown，没有原生 UI 组件渲染。OpenTag 的 JSX 编译方案更接近「一次编写，到处原生渲染」的理想。&lt;/p&gt;
&lt;h2 id=&#34;mcp-集成与容错设计&#34;&gt;MCP 集成与容错设计&lt;/h2&gt;
&lt;p&gt;OpenTag 的 MCP 集成有两个值得关注的设计：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 独立的 MCP 连接超时容错&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;runtime.ts&lt;/code&gt; 里，每个 MCP 服务器独立连接，失败不影响其他服务器：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;settled&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;await&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Promise&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;allSettled&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;transports&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;map&lt;/span&gt;((&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;connectMcp&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;transport&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;失败的 MCP 服务器被记录到 &lt;code&gt;unavailable[]&lt;/code&gt;，系统提示词自动追加一条「数据源状态」说明，告诉模型哪些源当前不可用。模型只在用户明确需要那个源时才告知不可用——&lt;strong&gt;不会自己主动说&lt;/strong&gt;，避免打断对话。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 热度超时 + 泄漏防护&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;connectMcp()&lt;/code&gt; 有一个 8 秒超时机制。如果超时先到达，它会确保后续返回的 MCP 客户端被立即关闭：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;connecting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;then&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#a6e22e&#34;&gt;client&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;timedOut&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;client&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;close&lt;/span&gt;().&lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt;(() &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; {}); },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  () &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; {}, &lt;span style=&#34;color:#75715e&#34;&gt;// 延迟拒绝不能 crash 进程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是个教科书级的异步容错模式——我觉得 MCPZERO 的 MCP 连接池也可以借鉴这个思路。&lt;/p&gt;
&lt;h2 id=&#34;human-in-the-loop写操作必须先确认&#34;&gt;Human-in-the-Loop：写操作必须先确认&lt;/h2&gt;
&lt;p&gt;所有写操作（创建 Linear Issue、写 Notion 文档）都经过一个 &lt;strong&gt;&lt;code&gt;confirm_write&lt;/code&gt; 阻塞门&lt;/strong&gt;。Agent 在写操作前必须调用 &lt;code&gt;confirm_write&lt;/code&gt; 工具，等待用户在聊天界面点击 &lt;strong&gt;Create&lt;/strong&gt; 或 &lt;strong&gt;Cancel&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这个门在 &lt;code&gt;app/human-in-the-loop/confirm-write.tsx&lt;/code&gt; 里实现为阻塞 UI 组件——Agent 无法继续，直到用户做出决定。不像某些 Agent 框架的「先写再确认」，OpenTag 是「确认了才能写」，避免了误操作。&lt;/p&gt;
&lt;h2 id=&#34;三方横向对比&#34;&gt;三方横向对比&lt;/h2&gt;
&lt;p&gt;OpenTag、Nanobot 和 Pi Agent 都算是「让 Agent 接入聊天工具」的方向，但技术路线差异很大：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;维度&lt;/th&gt;
          &lt;th&gt;OpenTag&lt;/th&gt;
          &lt;th&gt;Nanobot&lt;/th&gt;
          &lt;th&gt;Pi Agent&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;语言&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;TypeScript (+ Python 可选)&lt;/td&gt;
          &lt;td&gt;Python 3.11+&lt;/td&gt;
          &lt;td&gt;TypeScript&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;核心协议&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;AG-UI (HTTP SSE)&lt;/td&gt;
          &lt;td&gt;asyncio.Queue (内存)&lt;/td&gt;
          &lt;td&gt;无标准化协议&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Agent 运行时&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;CopilotKit BuiltInAgent / LangGraph Deep Agent&lt;/td&gt;
          &lt;td&gt;AgentLoop + AgentRunner&lt;/td&gt;
          &lt;td&gt;Steering + Follow-up 双队列&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;多平台&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Slack/Discord/Telegram/WhatsApp&lt;/td&gt;
          &lt;td&gt;15+ 聊天平台&lt;/td&gt;
          &lt;td&gt;30+ Provider (非聊天平台)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;UI 渲染&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;JSX → 原生组件编译&lt;/td&gt;
          &lt;td&gt;纯文本/Markdown&lt;/td&gt;
          &lt;td&gt;纯文本/Markdown&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;工具系统&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;MCP (Streamable HTTP)&lt;/td&gt;
          &lt;td&gt;Python Tool 类&lt;/td&gt;
          &lt;td&gt;Plugin 系统&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;人工确认&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;阻塞式 confirm_write&lt;/td&gt;
          &lt;td&gt;无内置 HITL&lt;/td&gt;
          &lt;td&gt;无内置 HITL&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;模型&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;OpenAI-only (当前)&lt;/td&gt;
          &lt;td&gt;多 Provider 抽象&lt;/td&gt;
          &lt;td&gt;30+ Provider 抽象&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;部署&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Railway one-click&lt;/td&gt;
          &lt;td&gt;传统部署&lt;/td&gt;
          &lt;td&gt;传统部署&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;记忆系统&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;无（对话级）&lt;/td&gt;
          &lt;td&gt;Dream 两阶段记忆合并&lt;/td&gt;
          &lt;td&gt;JSONL 树形分支会话&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;核心差异点：OpenTag 走的是&lt;strong&gt;协议驱动架构&lt;/strong&gt;（AG-UI 解耦 Bot 和 Agent），Nanobot 走的是&lt;strong&gt;事件驱动架构&lt;/strong&gt;（MessageBus 解耦模块），Pi Agent 走的是&lt;strong&gt;队列驱动架构&lt;/strong&gt;（Steering + Follow-up 流水线）。三个方案都能把 Agent 放进聊天工具，但弹性和复杂度取舍不同。&lt;/p&gt;
&lt;h2 id=&#34;安全隐患&#34;&gt;安全隐患&lt;/h2&gt;
&lt;p&gt;OpenTag 的自托管模式要求 Bot 进程持有平台 Token（Slack Bot Token、Discord Bot Token 等），这意味着如果 Bot 进程被攻破，攻击者可以用这个 Token 冒充机器人在聊天工具里做任何事。&lt;/p&gt;
&lt;p&gt;CopilotKit 对此的解决方案是 &lt;strong&gt;Intelligence Gateway 模式&lt;/strong&gt;：Bot 进程不持有任何平台 Token，Token 由 CopilotKit Intelligence 平台保管，Bot 通过 WebSocket 连接到 Intelligence 的 Realtime Gateway。但这个模式目前还是 CopilotKit 的托管服务，不是开源方案——自托管的用户只能用 self-hosted 模式，把 Token 暴露在进程环境变量里。&lt;/p&gt;
&lt;p&gt;另外，OpenTag 的 MCP 连接使用了 Bearer Token 认证（&lt;code&gt;Authorization: Bearer&lt;/code&gt;），但通信没有端到端加密。如果 MCP 服务器和 Bot 进程之间的网络被嗅探，Token 和数据都可能泄露。这对 Notion MCP 侧车尤其关键——Notion 的 Integration Token 对所有 workspace 内容有读写权限。&lt;/p&gt;
&lt;p&gt;相比之下，Nanobot 的 15+ 平台支持同样面临 Token 管理问题，但 Nanobot 的 Token 是每个 channel 实例化的，影响范围更小。Pi Agent 不直接处理聊天平台 Token，风险面更窄。&lt;/p&gt;
&lt;h2 id=&#34;写在最后&#34;&gt;写在最后&lt;/h2&gt;
&lt;p&gt;OpenTag 的出现让我看到 Agent 聊天工具这个赛道正在快速成熟。CopilotKit 用 &lt;code&gt;@copilotkit/channels&lt;/code&gt; SDK 把「把 Agent 放进聊天工具」这件事从手动工程变成了框架级能力，而 AG-UI 协议的设计让 Bot 和 Agent 可以独立演化——这是正确的方向。&lt;/p&gt;
&lt;p&gt;当然，OpenTag 还远不是 Claude in Slack 的平替。它目前只支持 OpenAI 模型，没有持久化记忆，没有多租户隔离，安全模型也还在早期。但作为一个&lt;strong&gt;架构参考实现&lt;/strong&gt;，它的设计思路——AG-UI 协议、双运行时、跨平台 JSX 渲染、MCP 容错——值得每一个做 Agent 基础设施的人认真看看。&lt;/p&gt;
&lt;p&gt;GitHub: &lt;a class=&#34;link&#34; href=&#34;https://github.com/CopilotKit/OpenTag&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://github.com/CopilotKit/OpenTag&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;延伸阅读：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.yesmiracle.net/post/20260719-nanobot-architecture/&#34; &gt;Nanobot 源码深度拆解：Python 异步消息总线构建的轻量级 AI Agent 框架&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.yesmiracle.net/post/20260719-pi-agent-architecture/&#34; &gt;Pi Agent 深度拆解：TypeScript 多包架构下的 Steering + Follow-up 双队列设计&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.yesmiracle.net/post/20260726-agent-to-agent-protocol-guide/&#34; &gt;Agents 互联！A2A/MCP/ANP/ACP 四大协议详解&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
</description>
        </item>
        
    </channel>
</rss>
