[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fwivfk0mJhEKjQzyjyMJBP2vj3I-UzNMjlxFTJh-w8d0":3,"$f9jELLyR6rTMndRF1eRgAKT981Mf2Pt_mUxx7si6bfTM":47},[4],{"id":5,"type":6,"title":7,"slug":8,"summary":9,"body":10,"coverUrl":11,"productScreenshots":12,"productLinks":13,"authorName":14,"authorUrl":15,"authorSubject":16,"category":17,"tags":22,"sourceLabel":39,"sourceName":39,"sourceUrl":39,"status":40,"seoTitle":39,"seoDescription":39,"canonicalUrl":39,"isFeatured":41,"sno":42,"sortOrder":43,"publishedAt":44,"updatedAt":45,"createdAt":46},"0e852b5f-2e67-4b3b-b05e-3c32af8dcd6f","article","Agent网关为什么成了企业标配？","ai-agent-gateway-mcp-governance","当成千上万个内部工具都开放给 Agent，谁能调什么、怎么审计就成了大问题。","当公司里只有一个 AI Agent、接三五个工具时，一切都好说。但当 Uber、Amazon 这样的公司把成千上万个内部接口都开放给 Agent 使用时，问题就来了：谁有权调用哪个工具？调用记录怎么审计？出事了怎么追责？\n\n2026 年，行业给出的答案高度一致——在 Agent 和工具之间，架一层「网关」。\n\n## MCP 解决了连接，没解决治理\n\n先回顾概念。MCP（模型上下文协议）像 USB-C，让 AI 能统一地连上各种工具。它极大降低了「接工具」的成本，但它 deliberately 不管一件事：**治理**。工具定义会直接喂给模型，工具服务谁都能部署，中间没有一个「执行前的检查点」。\n\nhttps:\u002F\u002Ffoundit.cn\u002Farticle\u002Fmcp-ai-usb-c-moment\n\n在小规模下这没问题。可一旦你有几十上百个 MCP 服务、多个团队、还有合规要求，问题就集中爆发：凭证散落各处（每个服务一套 auth）、工具太多塞爆模型的上下文窗口、没有统一的权限和审计。这时候，「网关 + 注册表」就成了必然。\n\n## 网关做什么：Agent 世界的「控制平面」\n\n把网关理解成所有 Agent 流量的统一入口和守门人。它通常和一个「注册表」（Registry，记录有哪些工具可用）配合，构成控制平面：\n\n- **鉴权与最小权限**：在网关层判断「这个 Agent 能不能在此刻、用这些参数、调这个工具」，而不是在每个应用边界各写一遍。\n- **审计**：所有调用留痕，可追溯、可回放。\n- **脱敏**：请求发往外部模型前，先在网关抹掉 PII（个人信息）和内部标识。\n- **按需暴露工具**：只把当前 Agent 真正需要的工具喂给它，缓解上下文膨胀。\n\nUber 的做法很典型：他们建了 MCP 网关和注册表作为控制平面，把成千上万个内部接口自动暴露成 MCP 工具，所有 Agent 流量都走一个 Go 写的代理，先做 PII 脱敏再放行，每周有数万次 Agent 执行经过它。\n\n## 关键设计原则：写操作要「确定性」\n\n一个反复被强调的原则是：**推理层和动作层要分开**。大模型负责「想」（reasoning），但真正有副作用的「做」（mutation、写操作）必须放在确定性的基础设施里，由网关做鉴权和控制，而不是任由模型的概率性输出直接触发。\n\n```mermaid\nflowchart TD\n    A[Agent 推理层\u003Cbr\u002F>决定要调什么] --> B[网关 Gateway]\n    B --> C{鉴权 + 策略检查}\n    C -->|通过| D[脱敏 PII]\n    C -->|拒绝| X[阻断并记录]\n    D --> E[注册表: 定位工具]\n    E --> F[MCP Server 执行]\n    F --> G[审计日志]\n    style X fill:#c0392b,color:#fff\n```\n\n## 一个最小示意的策略配置\n\n网关的核心是「策略」。用伪配置表达「只有客服 Agent 能查订单，且必须带租户 ID」大致是这样：\n\n```yaml\npolicies:\n  - agent: \"support-agent\"\n    allow_tools: [\"order.read\"]\n    require_params: [\"tenant_id\"]     # 缺少则拒绝\n    redact: [\"customer.phone\", \"customer.email\"]  # 出网关前脱敏\n  - agent: \"*\"\n    deny_tools: [\"payment.refund\"]    # 退款一律禁止 Agent 自主执行\n```\n\n思路是「默认拒绝、显式放行」，把危险的写操作（如退款）从 Agent 自主能力里彻底拿掉。\n\n## 取舍与边界\n\n- **网关是额外一跳**，会带来一点延迟和运维成本，但换来的是可控和可审计，对企业几乎是必需的。\n- **幂等性很重要**：Agent 会重试，写操作要用幂等键，避免「重试导致重复退款」这类事故。\n- **别把治理逻辑塞进提示词**：靠 prompt 让模型「自觉守规矩」不可靠，规则要落在确定性的网关里。\n- 小团队、个人项目未必需要完整网关，但「有副作用的动作要有检查点」这个原则任何规模都适用。\n\n## Tips\n- 工具超过一把、或有多团队\u002F合规要求时，就该考虑引入网关 + 注册表。\n- 把鉴权、审计、脱敏统一收敛到网关层，别在每个应用里各写一套。\n- 严格区分「读」和「写」：读可以放开些，写必须过网关、带幂等键、可审计。\n- 用「默认拒绝、显式放行」的策略模型，危险操作直接从 Agent 能力里移除。\n- 记住这条准则：让模型负责思考，让确定性基础设施负责执行。","https:\u002F\u002Foxqtewbrpuiouqqjrvdv.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fpublic-media\u002F2026-07-19\u002F83ff5d2f-70e3-4012-a71d-bac22e1541f2.jpg",[],[],"Foundit AI","https:\u002F\u002Ffoundit.cn","f39339b1-aaa6-4e86-b0c2-a6e6a21113b5",{"id":18,"name":19,"slug":20,"description":21},"6179d3b6-dc34-4483-9ded-3cd9f1b37a47","科普","abbreviation","介绍各领域新兴概念",[23,27,31,35],{"id":24,"name":25,"slug":26},"0848beb4-db26-4fb8-b391-f852a11be192","AI编程","ai-coding",{"id":28,"name":29,"slug":30},"d2513b48-43d7-49ba-adac-6d09366f751f","内容由AI生成","gen-by-ai",{"id":32,"name":33,"slug":34},"7c76bfc2-f80f-4ee0-a95d-27bd8708b434","技术","slug",{"id":36,"name":37,"slug":38},"4c2bbea6-eab7-40a8-8447-1de478ff7749","分析","analyse",null,"published",false,73,0,"2026-07-20T00:00:00.000Z","2026-07-19T17:54:58.419Z","2026-07-19T17:10:44.985Z",[48,66,90],{"id":49,"type":6,"title":50,"slug":51,"summary":52,"body":53,"coverUrl":54,"productScreenshots":55,"productLinks":56,"authorName":14,"authorUrl":15,"authorSubject":16,"category":57,"tags":58,"sourceLabel":39,"sourceName":39,"sourceUrl":39,"status":40,"seoTitle":39,"seoDescription":39,"canonicalUrl":39,"isFeatured":41,"sno":62,"sortOrder":43,"publishedAt":63,"updatedAt":64,"createdAt":65},"a3c11b62-9668-40cf-822d-25787f994c75","A2A：当 Agent 开始互相「递名片」","a2a-agent-to-agent-protocol","MCP 让 AI 统一接上工具，却没解决 Agent 之间怎么分工。A2A（Agent-to-Agent 协议）用「Agent Card 名片」让智能体互相发现、委派任务、协作交付。","你有没有想过：当公司里不止一个 AI Agent，而是几十个，它们该怎么分工？谁负责查天气、谁负责排日程、谁负责写代码？如果让它们各自为战，那不过是把「一个人的孤岛」换成「一群人的孤岛」。\n\n一个叫 A2A 的协议正在解决这个问题——它让 Agent 之间能像人一样「互相介绍、认领任务、协作交付」。\n\n## MCP 解决了「接工具」，没解决「连同伴」\n\n我们先前聊过 MCP（模型上下文协议）：它像 USB-C，让 AI 能统一地连上各种工具——读代码、查数据库、调 API。但 MCP  deliberately 不回答另一个问题：Agent 和 Agent 之间怎么发现彼此、怎么分工？\n\nhttps:\u002F\u002Ffoundit.cn\u002Farticle\u002Fmcp-ai-usb-c-moment\n\n举个例子。你问一个「个人助理 Agent」：「帮我看看明天北京的天气，如果下雨就改到室内，并把会议邀约发给团队。」这个助理自己未必会看天气、也不该直接改所有人的日历。更合理的做法是：它去找到「天气 Agent」和「日历 Agent」，把子任务委派给它们，再把结果拼起来回答你。A2A（Agent-to-Agent Protocol，智能体到智能体协议）就是干这件事的标准。\n\n## A2A 是什么\n\nA2A 由 Google 在 2025 年 4 月提出，几个月后捐给 Linux 基金会，和 MCP 一样进入了中立治理。它的核心思想非常像现实中的名片交换：\n\n- 每个 Agent 都发布一张机器可读的 **Agent Card（名片）**，声明自己叫什么、能做什么、接受什么格式的输入、返回什么、需要怎样的鉴权。\n- 一个「编排 Agent」读到这些名片，就知道「这个任务该交给谁」。\n- 然后它通过 JSON + HTTP 协议把任务委派过去，支持长任务、流式结果和多轮对话。\n\n业界给的类比很精准：**MCP 连接 Agent 与工具，A2A 连接 Agent 与同伴。** 工具是被「调用」然后返回；同伴是被「委派」然后协商。\n\n2026 年 4 月，A2A 发布了 **1.0 版本**，成为稳定的生产标准，并带来了「带签名的 Agent Card」用于可验证身份。一年之内已有 150+ 组织在生成环境运行它，IBM 自家的 Agent Communication Protocol 也在 2025 年 8 月合并进了 A2A，没有让这一层 fragmentation（碎片化）。\n\n## 它是怎么运作的：发现 → 委派 → 交付\n\n整个协作流程可以拆成三步，用一张图就能看明白：\n\n```mermaid\nflowchart LR\n    U[用户需求] --> O[编排 Agent]\n    O -->|读取 Agent Card| C[天气 Agent]\n    O -->|读取 Agent Card| I[日历 Agent]\n    O -->|委派子任务| C\n    O -->|委派子任务| I\n    C --> R1[天气结果]\n    I --> R2[日程结果]\n    R1 --> O\n    R2 --> O\n    O --> A[汇总后回答用户]\n```\n\n落到代码层面，Agent Card 就是一份 JSON。比如一个天气 Agent 的名片可能长这样：\n\n```json\n{\n  \"name\": \"天气 Agent\",\n  \"description\": \"提供全球城市天气查询\",\n  \"url\": \"https:\u002F\u002Fweather-agent.example\u002Fa2a\",\n  \"capabilities\": { \"streaming\": true },\n  \"skills\": [\n    {\n      \"id\": \"get_weather\",\n      \"name\": \"查询天气\",\n      \"examples\": [\"北京今天天气如何？\"]\n    }\n  ],\n  \"authentication\": { \"schemes\": [\"Bearer\"] }\n}\n```\n\n编排 Agent 拉取这张名片后，就知道「查天气」这个技能由谁提供、去哪个地址调用、要带什么鉴权。它把用户问题拆成子任务，分别委派，再把各 Agent 的回包汇总成最终答案。长任务还能流式返回进度，不必干等。\n\n## 它能做什么，做不了什么\n\nA2A 解决的是「信封」问题——怎么发现同伴、怎么把任务送过去、怎么收回结果。但它有意**不定义「信封里写什么」**：两个 Agent 之间到底该用怎样的语义去沟通、任务怎么拆解，是高于协议层的事。\n\n- **强项**：跨厂商、跨框架。无论 Agent 是用 LangGraph、CrewAI、LlamaIndex 还是微软、谷歌的框架写的，只要都讲 A2A，就能互相委派。主流 agent 框架已原生支持。\n- **边界**：协议标准化的是「通信格式」，不是「协作智能」。任务拆得好不好、委派得对不对，仍然取决于编排 Agent 本身的设计。\n- **补充视角**：也有人提出基于 W3C 去中心化身份（DID）的替代方案，觉得 A2A 的模型「太像传统 Web」。但在企业多 Agent 系统里，A2A 已经是事实上的默认答案。\n\n## Tips\n\n- 记住分层：想接工具看 **MCP**，想让 Agent 互相协作看 **A2A**——两者互补，不是替代。\n- 设计多 Agent 系统时，先画清「谁发布名片、谁做编排、任务怎么拆」三件事，再选框架。\n- 评估一个 Agent 平台是否「能协作」，看它是否支持 A2A 1.0 与签名 Agent Card（身份可验证很重要）。\n- 别指望协议替你做任务规划：A2A 管「送信」，拆任务的逻辑要你自己写或交给编排模型。\n- 落地节奏上，先把 MCP 接好让单个 Agent 能干活，再用 A2A 把多个能干的 Agent 织成网络——这是 2026 年最主流的演进路径。","https:\u002F\u002Foxqtewbrpuiouqqjrvdv.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fpublic-media\u002F2026-07-19\u002F7819028f-dd6f-4988-9964-56134773dc53.jpg",[],[],{"id":18,"name":19,"slug":20,"description":21},[59,60,61],{"id":24,"name":25,"slug":26},{"id":36,"name":37,"slug":38},{"id":32,"name":33,"slug":34},75,"2026-07-17T00:00:00.000Z","2026-07-20T01:14:37.908Z","2026-07-19T16:17:09.511Z",{"id":67,"type":6,"title":68,"slug":69,"summary":70,"body":71,"coverUrl":72,"productScreenshots":73,"productLinks":74,"authorName":14,"authorUrl":15,"authorSubject":16,"category":75,"tags":76,"sourceLabel":84,"sourceName":39,"sourceUrl":39,"status":40,"seoTitle":39,"seoDescription":39,"canonicalUrl":39,"isFeatured":85,"sno":86,"sortOrder":43,"publishedAt":87,"updatedAt":88,"createdAt":89},"1d21b863-e352-417e-81f6-3a8abcb73dd6","Bridge API 是什么？","bridge-api","本地运行的 AI Provider Runtime —— 一个 API，连接所有 AI 网页","## 1. 概述与定位\n\n**Bridge API** 是一个运行在用户本机的 **AI Provider Runtime**。它对外提供统一的 **OpenAI Compatible API**（`\u002Fv1\u002Fchat\u002Fcompletions`、`\u002Fv1\u002Fmodels`），并在内部通过 Chrome 扩展把请求转发给已经登录的 **DeepSeek 网页**。账号、Cookie 与项目文件全程不离开本机，Bridge 不保存账号、不代理账号、不托管 Cookie。\n\n| 它“不是”什么 | 它“是”什么 |\n| --- | --- |\n| 不是 DeepSeek 官方 API（无需 API Key） | AI Provider Runtime，DeepSeek 只是第一个 Provider |\n| 不是单纯浏览器插件（插件只控制网页） | 本地文件系统 \u002F Git 能力的受保护网关 |\n| 不是一个被绑定的模型（Provider 无关） | 让任意 OpenAI 客户端直接调用浏览器里的 AI |\n\n> **核心设计原则**：Provider 无关、本地优先、开放接口、模块化扩展、最小权限。所有项目读取、Git 分析、上下文构建均在本地完成。\n\n## 2. 系统架构\n\nBridge API 由三层组成：左侧任意 OpenAI 客户端、中间本地 Runtime、右侧浏览器与本地项目。Runtime 是唯一的“大脑”，所有业务逻辑都收敛在这里；浏览器扩展只是 DOM 控制终端，Native Host 是最小权限的文件系统代理。\n\n```mermaid\nflowchart TD\n  C[OpenAI 兼容客户端\u003Cbr\u002F>Cursor \u002F VS Code \u002F CLI\u003Cbr\u002F>Cherry Studio \u002F Open WebUI\u003Cbr\u002F>LangChain]\n  subgraph R[Bridge API Runtime]\n    direction TB\n    GW[API Gateway · Node http]\n    PM[Provider Manager · Agent Engine]\n    BB[Browser Bridge · Context Engine]\n    TE[Tool Engine · Project Engine]\n    GE[Git Engine · Security Engine]\n    Q[Single Task Queue · 配置]\n  end\n  E[Chrome 扩展 MV3\u003Cbr\u002F>background.js + content.js]\n  D[DeepSeek 网页\u003Cbr\u002F>chat.deepseek.com]\n  N[Native Host\u003Cbr\u002F>文件\u002FGit 白名单]\n  P[本地授权项目\u003Cbr\u002F>路径\u002F敏感保护]\n  C -->|HTTP \u002F SSE| R\n  R -->|指令 \u002F 事件| E\n  E -->|DOM 控制| D\n  R -. 规划 .-> N\n  N -->|文件 \u002F Git| P\n  R -. 受保护访问 .-> P\n```\n\n**关键解耦点**：扩展不持有文件系统权限，文件访问要么由 Runtime 直接执行（当前 MVP），要么经由 Native Host 的白名单协议；浏览器侧只负责把 Prompt 写进网页、把回答读出来，业务规则（鉴权、队列、路径安全、工具解析）全部在 Runtime 完成。\n\n## 3. 技术栈与工程结构\n\n项目是一个 npm **workspaces** 单仓（monorepo），包含 `apps\u002F*`、`packages\u002F*`、`providers\u002F*` 三组包。运行时直接以 `node --experimental-strip-types` 执行 TypeScript（Node 22+），无需构建步骤；类型检查用 `tsc --noEmit`。\n\n```\nbridge-api\u002F\n├── apps\u002F\n│   ├── runtime\u002F        # 核心 Runtime 入口（src\u002Findex.ts, server.ts, config.ts）\n│   │   └── public\u002F     # 本地图形控制台（index.html \u002F app.js \u002F styles.css）\n│   ├── cli\u002F            # bridge CLI（纯 HTTP 客户端）\n│   ├── extension\u002F      # Chrome MV3 扩展（background.js, content.js, popup.*）\n│   └── native-host\u002F    # 最小权限 Native Messaging Host（协议骨架）\n├── packages\u002F\n│   ├── protocol\u002F       # 类型契约：ChatMessage, ChatDelta, Provider, BrowserCommand\u002FEvent\n│   ├── provider-manager\u002F  # Provider 注册、切换、健康检查\n│   ├── browser-bridge\u002F    # Runtime ↔ 扩展的命令\u002F事件桥\n│   ├── agent-engine\u002F      # 多轮代码代理 + 工具协议解析\n│   ├── context-engine\u002F    # ripgrep 检索 + 上下文构建\n│   ├── project-engine\u002F    # 多项目管理、路径保护、读写替身脱敏\n│   ├── tool-engine\u002F       # 工具执行、待批准变更\n│   ├── git-engine\u002F        # git status \u002F diff 封装\n│   ├── security-engine\u002F   # 敏感路径判定、密钥脱敏\n│   ├── queue\u002F             # 单任务串行队列\n│   └── shared\u002F            # createId \u002F toErrorMessage \u002F expandHome\n├── providers\u002F\n│   └── deepseek\u002F       # DeepSeekWebProvider（实现 Provider 契约）\n├── tests\u002F              # core.test.ts（node --test）\n├── PRD.md  README.md  progress.md  package.json  tsconfig.json\n```\n\n各 `packages\u002F*` 之间是显式的依赖关系（通过相对 `..\u002F..\u002Fpackages\u002Fxxx\u002Fsrc\u002Findex.ts` 导入），运行时由 `apps\u002Fruntime\u002Fsrc\u002Findex.ts` 统一实例化并注入：\n\n```ts\nconst browser   = new BrowserBridge();\nconst projects  = new ProjectEngine(config.workspace, config.projects);\nconst git       = new GitEngine();\nconst providers = new ProviderManager([new DeepSeekWebProvider(browser)], config.provider);\nconst context   = new ContextEngine(projects, git);\nconst tools     = new ToolEngine(projects, context, git);\nconst agent     = new AgentEngine(providers, projects, tools);\nconst server    = createRuntimeServer({ config, browser, providers, projects, context, git, queue, tools, agent });\n```\n\n## 4. 一次对话请求的完整生命周期\n\n所有请求进入 `createRuntimeServer` 的单一 Node `http` 处理器。下面以 `POST \u002Fv1\u002Fchat\u002Fcompletions` 为主线，展示从鉴权到 SSE 输出的全过程。\n\n```mermaid\nflowchart TD\n  A[POST \u002Fv1\u002Fchat\u002Fcompletions] --> B[鉴权: Bearer \u002F x-bridge-token]\n  B -->|否| B1[401 未授权]\n  B -->|是| C[校验 model == active.model]\n  C --> D{是代码请求?}\n  D -->|否| E[普通对话: providers.active.stream]\n  E --> E1[SSE 直出]\n  D -->|是| F[进入 SingleTaskQueue 排队]\n  F --> G[AgentEngine.stream 多轮循环]\n  G --> H{生成待批准变更?}\n  H -->|是| H1[等待人工审批]\n  H -->|否| H2[SSE 流式回答 \u002F 工具结果]\n```\n\n> **SSE 通道约定**：模型正文走 `data:` 帧；Bridge 内部状态（队列位置、心跳）走 **注释帧** `: bridge-status ...`，避免被 OpenAI 客户端误并入回答。OpenAI 客户端会把每个 `data:` 帧当作模型输出，因此内部状态必须放在注释帧里，只有图形控制台会读取并展示。\n\n## 5. 多轮本地代码代理\n\n当请求被判定为“代码请求”（`bridge.mode=code` 或末条消息命中 `code|repo|项目|文件|修改|…` 等关键词）时，`AgentEngine` 接管，进入一个最多 16 轮的工具循环。核心目标是让网页版 DeepSeek 既能“读”本地项目，又不会未经授权地改文件。\n\n```mermaid\nflowchart TD\n  A[第 N 轮开始] --> B[仅发送最新轮次给 DeepSeek 网页]\n  B --> C[收集回答 含120s单轮超时]\n  C --> D[解析 BRIDGE_TOOL 信封 多格式]\n  D --> E{检测到工具调用 且通过协议校验?}\n  E -->|否| E1[返回最终回答]\n  E -->|是| F{客户端提供工具?}\n  F -->|是| F1[转为 OpenAI tool_calls 交客户端执行]\n  F -->|否| G[本地 ToolEngine 执行]\n  G --> H{是写操作?}\n  H -->|是| H1[生成待批准变更 \u002F 直写]\n  H -->|否| H2[结果作为 tool 消息回灌]\n  H2 -->|循环 不超过16轮| B\n```\n\n实现要点：\n\n- **状态页面复用**：DeepSeek 网页本身是有状态的会话，所以每一轮只把“最新工具结果 \u002F 修复指令”发给网页，绝不回放完整对话历史（否则它会重复回答早期问题）。见 `providers\u002Fdeepseek\u002Fsrc\u002Findex.ts` 的 `promptForWebConversation`。\n- **协议自愈**：若 DeepSeek 返回的工具指令不符合规范，Agent 会把它作为 `assistant` 消息连同修复提示再发一次，最多修复 2 次；仍失败则拒绝执行、不做任何文件修改。\n- **去重**：模型可能在同一回答里以“规范信封 + 渲染兼容形式”重复同一动作，`uniqueToolCalls` 只执行一次，但会保留刻意不同的多次 Edit。\n- **写保护**：Write\u002FEdit 在默认配置下只生成“待批准变更”；仅当项目开启 `autoApplyWrites` 才直接落盘。\n\n## 6. BRIDGE TOOL PROTOCOL V1\n\n网页版模型无法直接调用函数，只能生成文本。Bridge 约定模型在需要工具时输出一个“信封”，Runtime 解析后本地执行。为兼容不同模型的输出风格，解析器支持多种形态（见 `agent-engine` 的 `parseToolCalls`）：\n\n**支持的信封格式**\n\n- `\u003Cbridge_tool>…\u003C\u002Fbridge_tool>`\n- `[[BRIDGE_TOOL]] … [[\u002FBRIDGE_TOOL]]`\n- `**Calling:** … ```` ```json ``` ````\n- `Tool: … Arguments: {…}`\n- `Action: … Action Input: {…}`\n- `【调用 xxx】{…}` 本地化形式\n- `\u003CGlob>…\u003C\u002FGlob>` 等 XML 标签\n- `\u003Ctool_call name=\"…\">`\n\n**规范信封（推荐）**\n\n````\n[[BRIDGE_TOOL]]\n{\"name\":\"Write\",\"arguments\":{\n  \"path\":\"index.html\",\n  \"content\":\"\u003C!doctype html>...\"\n}}\n[[\u002FBRIDGE_TOOL]]\n````\n\n可用工具：`Glob` `Read` `Grep` `Git_Status` `Git_Diff` `Write` `Edit`。名称大小写敏感；Write 需非空 path+content；Edit 需 path+old_string+new_string。\n\n### 工具分发表（ToolEngine.execute）\n\n| 工具名（含别名） | 底层动作 | 越界 \u002F 敏感保护 |\n| --- | --- | --- |\n| `Glob \u002F list_files \u002F list_directory` | ripgrep `--files`（失败回退 Node 递归） | 过滤 node_modules\u002F.git\u002F敏感文件，限 300 条 |\n| `Read \u002F read_file \u002F cat` | `ProjectEngine.read` | 敏感文件返回 [REDACTED]，输出限 80KB |\n| `Grep \u002F search \u002F search_files` | `ContextEngine.search`(ripgrep) | 同 Glob |\n| `Git_Status \u002F Git_Diff \u002F diff` | `GitEngine`(git) | 必须在项目根 |\n| `Write \u002F write_file \u002F propose_write` | `ToolEngine.proposeWrite` | 生成待批准变更（或直写），限 1MB |\n| `Edit \u002F replace \u002F replace_text` | `ProjectEngine.replaceText` | 精确单处匹配，否则报错 |\n\n## 7. Provider 抽象与 DeepSeek Web Provider\n\n所有 AI 网页都通过统一的 `Provider` 契约接入（定义于 `packages\u002Fprotocol`）：\n\n```ts\ninterface Provider {\n  readonly id: string;\n  readonly model: string;\n  health(): Promise\u003CProviderStatus>;\n  stream(request: ChatCompletionRequest, signal: AbortSignal): AsyncIterable\u003CChatDelta>;\n}\n```\n\n`ProviderManager` 持有已注册 Provider 的映射，提供 `active` 访问器、`switch(id)` 与 `status()`。当前仅注册 `DeepSeekWebProvider`，但切换到 ChatGPT\u002FClaude\u002FGemini 等无需改动其它模块——这正是“Provider 无关”的体现。\n\n**DeepSeekWebProvider 的工作方式**\n\n- **发 prompt**：调用 `browser.enqueuePrompt(provider, prompt)`，把消息压入命令队列，并返回异步事件流。\n- **读回答**：从扩展 POST 回来的 `BrowserEvent`（`delta` \u002F `complete` \u002F `error`）逐帧 yield 为 `ChatDelta`。\n- **超时保护**：首字超时（默认 75s）与单轮超时（默认 120s）通过 `AbortController` 中断；若页面有输出但读完无正文，提示刷新页面。\n- **健康**：`health()` 仅看扩展是否连上，不检查账号有效性。\n\n## 8. 浏览器扩展与 Runtime 通信协议\n\nRuntime 与 Chrome 扩展之间是一个 **长轮询 + 事件回传** 的 HTTP 协议（不依赖 WebSocket，部署更简单）：\n\n```mermaid\nsequenceDiagram\n  participant R as Runtime（服务端）\n  participant B as 扩展 background\n  participant C as DeepSeek 网页\n  B->>R: 1. GET \u002Fbridge\u002Fbrowser\u002Fcommands\u002Fnext（长轮询）\n  R-->>B: 2. 返回 send_prompt 命令\n  B->>C: 3. chrome.tabs.sendMessage（bridge-command）\n  B->>C: 4. 写入 composer + 点击发送\n  C-->>B: 5. 抓取回答文本（delta）\n  B->>R: 6. POST \u002Fbridge\u002Fbrowser\u002Fevents（accepted\u002Fdelta\u002Fcomplete）\n  R-->>R: 7. BrowserBridge 触发事件 → yield 给 Provider\n```\n\n扩展侧实现细节：`background.js` 以约 400ms 间隔轮询 `\u002Fbridge\u002Fbrowser\u002Fcommands\u002Fnext`，拿到命令后定位 `chat.deepseek.com` 标签页，转发给 `content.js`；`content.js` 负责在 DOM 中找到输入框（`textarea#chat-input` 或 contenteditable）、注入文本、点击发送按钮，并轮询页面直到回答稳定，再把 `delta`\u002F`complete` 事件回传。选择器集中在 `content.js`，便于在 DeepSeek 改版时单点修复。\n\n## 9. 安全模型\n\nBridge 的信任边界是 **“本地、显式授权、最小权限”**。所有文件 \u002F Git 访问都经过以下层层关卡：\n\n```mermaid\nflowchart LR\n  A[Token 鉴权] --> B[路径越界检测]\n  B --> C[敏感文件拦截]\n  C --> D[内容脱敏 \u002F 大小限制]\n  D --> E[人工审批]\n```\n\n- **路径越界保护**：`ProjectEngine.resolve` 用 `path.resolve` 后强制要求绝对路径以项目根开头，`..\u002Foutside` 直接抛错。\n- **敏感文件拦截**：`isSensitivePath` 命中 `.env*`、`*.pem\u002F*.key\u002F*.p12` 时，读取返回 `[REDACTED]`，写入直接拒绝。\n- **密钥脱敏**：`redact` 把 `api_key \u002F token \u002F secret \u002F password \u002F authorization \u002F cookie \u002F private_key \u002F jwt = …` 的值替换为 `[REDACTED]`，模型看到的是脱敏文本。\n- **写需审批**：默认 Write\u002FEdit 只生成待批准变更，需在控制台点击“批准并写入”才修改磁盘；开启 `autoApplyWrites` 的项目才会直写。\n- **尺寸上限**：单文件写入 \u002F 编辑拒绝超过 1MB 的内容。\n- **配置权限**：`~\u002F.bridge-api\u002Fconfig.json` 以 `0o600` 仅当前用户可读写；环境变量 `BRIDGE_*` 在下次启动时优先于已保存配置。\n\n## 10. 模块清单\n\n| 包 | 职责 | 关键类型 \u002F 方法 |\n| --- | --- | --- |\n| `packages\u002Fprotocol` | 跨模块类型契约 | `ChatMessage` `ChatDelta` `Provider` `BrowserCommand` `BrowserEvent` |\n| `packages\u002Fprovider-manager` | Provider 注册\u002F切换\u002F健康 | `ProviderManager.active\u002Fswitch\u002Fstatus` |\n| `packages\u002Fbrowser-bridge` | 命令队列 + 事件桥 | `BrowserBridge.enqueuePrompt\u002FwaitForCommand\u002Faccept` |\n| `packages\u002Fagent-engine` | 多轮代码代理 + 协议解析 | `AgentEngine.stream` `parseToolCalls` `validToolCall` |\n| `packages\u002Fcontext-engine` | ripgrep 检索 + 上下文构建 | `ContextEngine.search\u002Fbuild` |\n| `packages\u002Fproject-engine` | 多项目、路径保护、读写 | `ProjectEngine.add\u002Fread\u002Fwrite\u002FreplaceText\u002Ftree\u002Fresolve` |\n| `packages\u002Ftool-engine` | 工具执行、待批准变更 | `ToolEngine.execute\u002FapplyChange\u002FdiscardChange` |\n| `packages\u002Fgit-engine` | git 封装 | `GitEngine.status\u002Fdiff` |\n| `packages\u002Fsecurity-engine` | 敏感判定与脱敏 | `isSensitivePath` `redact` |\n| `packages\u002Fqueue` | 单任务串行队列 | `SingleTaskQueue.run\u002Fstatus` |\n| `packages\u002Fshared` | 通用工具 | `createId` `toErrorMessage` `expandHome` |\n| `providers\u002Fdeepseek` | DeepSeek Web Provider | `DeepSeekWebProvider.health\u002Fstream` |\n| `apps\u002Fruntime` | Runtime 入口 + HTTP 服务 + 控制台 | `createRuntimeServer` `loadConfig\u002FsaveConfig` |\n| `apps\u002Fcli` | 纯 HTTP 客户端 | `bridge doctor\\|providers\\|ask\\|search\\|diff` |\n| `apps\u002Fextension` | Chrome MV3 扩展 | `background.js` `content.js` `popup.*` |\n| `apps\u002Fnative-host` | 最小权限文件\u002FGit 代理（骨架） | 白名单 action：project.add \u002F file.read \u002F file.tree \u002F git.* |\n\n## 11. API 速查\n\n| 方法 | 路径 | 用途 |\n| --- | --- | --- |\n| `GET` | `\u002Fv1\u002Fmodels` | 列出当前模型（如 `deepseek-web`） |\n| `POST` | `\u002Fv1\u002Fchat\u002Fcompletions` | 对话补全（支持 OpenAI SSE；`bridge.mode\u002FprojectKey` 扩展字段） |\n| `GET\u002FPOST\u002FDELETE` | `\u002Fbridge\u002Fprojects` | 管理本地项目 |\n| `POST` | `\u002Fbridge\u002Fsearch` · `\u002Fbridge\u002Fcontext` | 检索 \u002F 构建上下文 |\n| `POST` | `\u002Fbridge\u002Fgit\u002Fstatus` · `\u002Fbridge\u002Fgit\u002Fdiff` | Git 信息 |\n| `POST` | `\u002Fbridge\u002Ffile\u002Fread` · `\u002Fbridge\u002Ffile\u002Ftree` | 安全读取项目文件 |\n| `GET\u002FPOST\u002FDELETE` | `\u002Fbridge\u002Fchanges` · `…\u002F:id\u002Fapply` | 查看 \u002F 批准 \u002F 丢弃待写入变更 |\n| `GET\u002FPOST` | `\u002Fbridge\u002Fproviders` · `\u002Fbridge\u002Fprovider\u002F*` | Provider 状态与切换 |\n| `GET\u002FPOST` | `\u002Fbridge\u002Fconfig` | 读取 \u002F 保存本地 Runtime 配置 |\n| `GET` | `\u002Fbridge\u002Fhealth` | Runtime 健康状态 |\n| `GET` | `\u002Fbridge\u002Fbrowser\u002Fcommands\u002Fnext` | 扩展长轮询拉取指令 |\n| `POST` | `\u002Fbridge\u002Fbrowser\u002Fevents` | 扩展回传浏览器事件 |\n\n> 鉴权：请求头 `Authorization: Bearer \u003Ctoken>` 或 `x-bridge-token: \u003Ctoken>`。代码任务可通过 `X-Bridge-Project-Key` 请求头或请求体 `bridge.projectKey` 指定跨机可移植的工作区。\n\n## 12. 运行与验证\n\n```sh\n# 安装依赖\nnpm install\n\n# 生成并导出 Bridge Token，启动 Runtime（默认 127.0.0.1:3210）\nexport BRIDGE_TOKEN=\"$(openssl rand -hex 32)\"\nnpm run dev\n\n# 打开控制台 http:\u002F\u002F127.0.0.1:3210\u002F ，输入同一 Token 即可使用图形界面\n\n# 验证\nnpm test        # node --test 单元测试（provider 切换、路径\u002F密钥防护、队列、协议）\nnpm run typecheck\n\n# CLI 示例\nbridge doctor                       # 健康检查\nbridge providers                    # 列出 Provider\nbridge ask \"解释这个项目\"            # 发起对话\nbridge search \u003Cproject> login       # 检索\nbridge diff \u003Cproject>               # Git diff\n```\n\nChrome 扩展联调：`chrome:\u002F\u002Fextensions` → 开发者模式 → 加载 `apps\u002Fextension`；粘贴 `http:\u002F\u002F127.0.0.1:3210` 与 Token，测试连接后登录 DeepSeek 网页，状态变为“DeepSeek 已连接”。","https:\u002F\u002Foxqtewbrpuiouqqjrvdv.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fpublic-media\u002F2026-07-28\u002F34426959-c183-4447-aa39-d75304c50248.jpg",[],[],{"id":18,"name":19,"slug":20,"description":21},[77,78,79,83],{"id":24,"name":25,"slug":26},{"id":36,"name":37,"slug":38},{"id":80,"name":81,"slug":82},"3e0592e0-696e-4f08-9bc4-1ff63ac83443","插件","plugin",{"id":32,"name":33,"slug":34},"资料来源",true,2,"2026-07-28T00:00:00.000Z","2026-07-28T09:00:20.568Z","2026-07-28T08:49:59.731Z",{"id":91,"type":6,"title":92,"slug":93,"summary":94,"body":95,"coverUrl":96,"productScreenshots":97,"productLinks":98,"authorName":14,"authorUrl":15,"authorSubject":16,"category":99,"tags":104,"sourceLabel":39,"sourceName":39,"sourceUrl":39,"status":40,"seoTitle":39,"seoDescription":39,"canonicalUrl":39,"isFeatured":41,"sno":112,"sortOrder":43,"publishedAt":113,"updatedAt":114,"createdAt":115},"969a6246-646c-424b-9693-af4b2a1ea01d","Agent 记忆机制：短期、长期与情景记忆怎么配合才不「转头就忘」","agent-memory-short-long-episodic","只靠上下文窗口的 AI 总会忘。本文讲清 Agent 的三类记忆（短期\u002F长期语义\u002F情景）与一套「检索注入 + 写回」的读写机制，给出向量记忆最小示例，以及记太多变噪声、遗忘权等边界。","一个只会「看完当前对话就忘」的 AI，很难称职：你昨天告诉它的偏好，今天它又不记得了；长项目上下文一多，它就抓不住重点。\n\nAgent 的「记忆」机制，就是补上这块短板——让它在会话之间、在长篇任务里，能存得住、取得出该记的东西。\n\n## 背景：模型的记忆只有「当下」\n\n大模型本身的上下文窗口是一次会话的临时记忆：超出窗口的旧内容会被丢弃，关掉对话更是全清零。要让 Agent 有「长期记忆」，必须把信息存到模型之外的存储里，用时再按需取回，塞进当前上下文。\n\n## 三类记忆与一套读写\n\n- **短期记忆**：就是当前上下文窗口，放正在进行的事。\n- **长期记忆（语义）**：沉淀下来的稳定知识、用户偏好、项目背景，通常存进向量数据库，用时语义检索取回。\n- **情景记忆（episodic）**：过去发生过的「事件流水」，如「上周三用户让我改过配色」，便于回溯。\n\n```mermaid\nflowchart TD\n    A[用户输入] --> B[短期: 当前上下文]\n    B --> C{需要过往知识?}\n    C -->|是| D[向量检索长期记忆]\n    C -->|否| E[直接回应]\n    D --> F[取回相关片段 注入上下文]\n    F --> G[模型回应]\n    G --> H[新事实写回长期记忆]\n```\n\n## 一个最小可运行的例子\n\n把「值得长期记住」的内容向量化入库，对话时先检索再回答：\n\n```python\nmemory_db.add(embed(\"用户偏好：回复用简体中文，不要 emoji\"), meta={\"type\": \"preference\"})   # 写入：用户告知了稳定偏好\n\nhits = memory_db.search(embed(current_msg), top_k=3)   # 读取：每次对话前，取回相关记忆注入\ncontext = \"\\n\".join(h[\"text\"] for h in hits)\nreply = model(f\"已知背景：\\n{context}\\n\\n用户：{current_msg}\")\n```\n\n关键在「写什么、怎么取」：写得太碎会噪声爆炸，写得太多又撑爆上下文，要靠检索精准度平衡。\n\n## 取舍与边界\n\n- **记太多 = 噪声**：什么都往长期记忆塞，检索回来一堆无关内容，反而干扰模型。要有「该不该记」的判断。\n- **检索精度决定上限**：记忆再全，取不回对的片段也白搭；embedding 质量和分块策略很关键。\n- **隐私与遗忘权**：存了用户偏好就要能删，合规上要支持「忘记我」。\n- **短期别无限拉长**：上下文越长越贵越易迷失，长任务应定期摘要压缩，而非无脑堆叠。\n\n## Tips\n\n- 先区分：临时的事放上下文，稳定的事（偏好\u002F背景）才进长期记忆。\n- 长期记忆用向量库存，对话前检索注入，别全量塞。\n- 写入要有取舍，别把流水账全记；定期清理低价值记忆。\n- 给用户「遗忘」能力，存了偏好就得能删。\n- 长任务用摘要压缩替代无脑堆叠，省 token 也提信噪比。","https:\u002F\u002Foxqtewbrpuiouqqjrvdv.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fpublic-media\u002F2026-07-20\u002F0d047e5d-2518-4d5b-bef9-94fc23fd4fa7.jpg",[],[],{"id":100,"name":101,"slug":102,"description":103},"d6750616-07d9-4350-8485-1834c77be3d2","指南","guide","指导建议，仅供参考",[105,106,107,108],{"id":24,"name":25,"slug":26},{"id":36,"name":37,"slug":38},{"id":32,"name":33,"slug":34},{"id":109,"name":110,"slug":111},"a202d639-99a6-488a-a712-4d4c6ffd7e15","开发","dev",70,"2026-07-09T00:00:00.000Z","2026-07-20T03:44:07.492Z","2026-07-20T01:13:03.202Z"]