数据截至 (上游 commit 6692a1b5195b)
CowAgent 全景:一个 Agent Harness 怎么转
30 秒导读: CowAgent 是一个开源的"超级 AI 助手",前身是知名项目 chatgpt-on-wechat。 它把十余个聊天渠道(Web 控制台、微信、飞书、Telegram、Slack…)的消息统一汇进一座 bridge, 按用户会话隔离出各自独立的 Agent 实例,让单个 Agent 用 tool-call 循环反复推理, 底层大模型(Claude / GPT / Gemini / DeepSeek…)可在 Web 控制台一键切换。它是一份 Agent Harness(智能体运行骨架) 的参考实现——本页只讲"大盘怎么转",细节留给各章。
1. 这是什么(零基础也能懂)
一句话定义: CowAgent 是一个你可以 24 小时挂在电脑或服务器上、通过任意聊天软件跟它对话的 AI 助手——它会自己拆解任务、调用工具操作你的电脑和外部服务、积累长期记忆,并在使用中"自我进化"。
它解决谁的什么问题。 假设你想要一个"随叫随到、还能真动手干活"的私人 AI: 不只是聊天, 而是能读写文件、跑命令、开浏览器、查资料、定时提醒,还记得你上周说过的事。自己从零搭这套东西 很费劲——要接入聊天渠道、要管多个用户的会话、要接大模型、要给模型配"手脚"(工具)。CowAgent 把这些打包成一个开箱即用的骨架(harness),你只管插上模型的 API key 就能跑。
它的前身与定位。 项目原名 chatgpt-on-wechat(把 ChatGPT 接到微信上),现已升级并更名为
CowAgent,定位从"聊天机器人"变成"超级 Agent 助手 + Agent Harness 参考实现"
(README.md:277-279 「Project Renaming Notice」)。
它能做什么(功能一览):
| 能力 | 一句话 |
|---|---|
| 规划 Planning | 拆解复杂任务,循环调用工具直到达成目标 |
| 记忆 Memory | 三层记忆(上下文→每日→核心)+ 夜间 Deep Dream 蒸馏 |
| 知识 Knowledge | 自动把有价值的信息整理成 Markdown 知识库 + 知识图谱 |
| 技能与工具 Skills/Tools | 内置文件/终端/浏览器/搜索等十余种工具 + MCP 生态 + 可对话创建技能 |
| 自进化 Evolution | 空闲时自动回看对话,改进技能、跟进未完成任务 |
| 多渠道 Channels | Web、微信、飞书、钉钉、企微、QQ、公众号、Telegram、Slack… |
| 多模型 Models | Claude/GPT/Gemini/DeepSeek/Qwen/GLM… Web 控制台一键切换 |
用起来什么样。 一行命令装好,打开浏览器就能用:
# 一句话安装(Linux / macOS),脚本自动装依赖、写配置、启动服务
bash <(curl -fsSL https://cdn.link-ai.tech/code/cow/run.sh)
# 启动后打开 Web 控制台:聊天、配模型、连渠道、装技能都在这里
# http://localhost:9899
# 之后用 cow CLI 管理服务
cow start | stop | restart # 起停重启
cow status | logs # 状态与日志
cow skill install <name> # 装一个技能
Web 控制台端口 9899 写死在默认配置里(config.py:252 "web_port": 9899);安装/CLI 命令引自
README.md:66-97。
一句话直觉。 把 CowAgent 想成一台总机 + 一个会用工具的助理:各个聊天软件是打进来的电话线, 总机(bridge)按"谁在打"接到对应的分机(每个用户一个独立 Agent 实例),分机背后是同一位会 查资料、会敲命令、记得住事的助理,而助理用哪颗"大脑"(哪个大模型)可以随时换。
2. 顶层全景(它大概怎么转)
2.1 一张图看懂主链路
怎么读这张图: 从上到下是一条消息的生命周期——进来、被路由到某个 Agent、循环推理、 调模型、原路返回。左边是"输入",右边(底部)是"输出",中间的 Agent 是心脏。
十余个渠道 Channels channel/channel_factory.py
┌───────────────────────────────┐ create_channel(channel_type)
│ Web(9899,默认) 微信 飞书 钉钉 │
│ 企微 QQ 公众号 Telegram Slack… │ ──消息──┐
└───────────────────────────────┘ │
▼
┌─────────────────────────────────┐
│ bridge(总机) │ bridge/agent_bridge.py
│ AgentBridge.agent_reply │
│ / ChatService.run │ agent/chat/service.py
│ │
│ ① 按 session_id 取/建 Agent 实例 │ get_agent(session_id)
│ → 多用户会话隔离 │
│ ② 先落库用户消息(即时可见) │ _pre_persist_user_message
│ ③ 注册取消令牌(可中途 /cancel) │ get_cancel_registry().register
└───────────────┬─────────────────┘
▼
┌───────────────────────────────────────┐
│ 单个 Agent(一位助理) │ agent/protocol/agent.py
│ run_stream → tool-call 循环 │ agent/protocol/agent_stream.py
│ ┌──────────────────────────────────┐ │
│ │ 想 → 调工具 → 看结果 → 再想 … │ │ 最多 max_steps 轮
│ └──────────────────────────────────┘ │
│ 周围五大子系统供它取用(见 §2.3) │
└───────────────┬───────────────────────┘
▼
┌───────────────────────────────────────┐
│ Models(可切换的大脑) │ bridge/agent_bridge.py
│ AgentLLMModel.call_stream │ AgentLLMModel
│ 按模型名前缀路由到具体 bot │ _resolve_bot_type
│ Claude/GPT/Gemini/DeepSeek/GLM… │
└───────────────┬───────────────────────┘
│ 生成的文本/工具调用
▼
④ 落库新消息 → 原路 Reply 回发到来源渠道
_persist_messages / Reply(ReplyType.TEXT, response)
2.2 部件一句话职责
| 部件 | 干什么 | 在哪个文件(关键符号) |
|---|---|---|
| Channels | 把各 聊天平台的消息标准化后送进来,并负责把回复发回去 | channel/channel_factory.py create_channel |
| ChannelManager | 多渠道并发启动,每个渠道跑在自己的守护线程里 | app.py ChannelManager.start |
| AgentBridge | 总机:按 session_id 隔离并缓存 Agent 实例、持久化、挂取消令牌 | bridge/agent_bridge.py AgentBridge |
| AgentLLMModel | 模型适配层:把 Agent 的请求转成 COW 现有 bot,按模型名一键切后端 | bridge/agent_bridge.py AgentLLMModel |
| ChatService | Web 流式路径:把 Agent 事件翻译成 CHAT 协议的 chunk 推给前端 | agent/chat/service.py ChatService.run |
| Agent | 心脏:持有消息历史、工具、五大子系统,跑 tool-call 循环 | agent/protocol/agent.py Agent.run_stream |
| AgentStreamExecutor | 循环的真正执行者:一轮轮调模型、执行工具、管上下文 | agent/protocol/agent_stream.py AgentStreamExecutor |
2.3 主线走一遍(高层,不进代码)
一条消息从进到出,大致经过 6 步:
- 进渠道。 某个渠道(如 Web 控制台)收到用户消息,
create_channel造出的渠道实例把它标准化。 - 进总机、认会话。 bridge 从 context 里取出
session_id(通常是用户标识),用它去get_agent(session_id)取对应的 Agent——没有就现建一个。这 一步是多用户隔离的关键: 不同用户各有独立的 Agent 实例与消息历史(bridge/agent_bridge.py:363-393)。 - 先存用户消息 + 挂取消令牌。 在真正跑之前,就把用户那句话落库,这样即使用户刷新页面
也能看到自己的气泡;同时注册一个取消令牌,支持中途
/cancel(_pre_persist_user_message、get_cancel_registry)。 - Agent 循环推理。 单个 Agent 用 tool-call 循环反复"想→调工具→看结果→再想",最多
max_steps轮(§01 详解)。 - 调模型生成。 循环每一轮都通过
AgentLLMModel调底层大模型;用哪个模型由配置里的模型名 前缀决定,可在 Web 控制台一键换(bridge/agent_bridge.py:75-124)。 - 落库 + 原路返回。 本轮新产生的消息(助理回复、工具调用/结果)被持久化,最终回复顺着
来源渠道发回给用户(
_persist_messages、Reply)。
注意有两条进 Agent 的路:IM/通用渠道走
AgentBridge.agent_reply(bridge/agent_bridge.py:437), Web 流式聊天走ChatService.run(agent/chat/service.py:30)。两者殊途同归——都先get_agent(session_id)拿到隔离实例,再驱动同一个AgentStreamExecutor;区别只是 Web 那条 额外把内部事件翻译成前端要的流式 chunk(见 §2.4)。
2.4 Web 流式:事件如何变成前端 chunk
Web 控制台要实时看到"打 字机效果 + 工具在跑"的反馈。ChatService 里的 _StreamState 充当翻译器:
Agent 在循环里不断抛出事件(message_update 增量文本、tool_execution_start/end 工具、
turn_end 一轮结束…),回调把它们逐个翻成 CHAT 协议的 chunk 推给浏览器
(agent/chat/service.py:65-166,on_event + _StreamState)。这层"事件→chunk"的翻译是 Web
体验流畅的关键,细节属于实现层,本页不展开。
3. 五大子系统:各管一摊(路由到该读的章)
Agent 这颗心脏并不孤立,周围有五个子系统按需供它取用。下面这张表既是"职责速览",也是 阅读地图——想深入哪一块,就跳对应章。
| 子系统 | 一句话职责 | 主要所在 | 深入读哪章 |
|---|---|---|---|
| 提示词 Prompt | 每一轮都从零重建系统提示词(拼身份/工具/技能/记忆段) | agent/prompt/builder.py build_agent_system_prompt | 02-system-prompt.md |
| 记忆 Memory | 三层记忆 + 关键词/向量混合检索 + 夜间 Deep Dream 蒸馏 | agent/memory/manager.py MemoryManager | 04-memory-knowledge.md |
| 知识 Knowledge | 把有价值信息自动整理成 Markdown 知识库 + 索引 | agent/knowledge/service.py KnowledgeService | 04-memory-knowledge.md |
| 技能与工具 Skills/Tools | 工具是原子能力,技能是 SKILL.md 定义的组合工作流;含 MCP 集成 | agent/tools/tool_manager.py ToolManager · agent/skills/manager.py SkillManager | 05-skills-tools-mcp.md |
| 自进化 Evolution | 空闲时回看对话,改进技能、跟进未完成任务、整理记忆 | agent/evolution/trigger.py start_evolution_trigger | 06-self-evolution.md |
而这颗心脏本身——那个"想→调工具→再想"的循环怎么转、上下文长了怎么不崩——是全库最核心的两章:
- 核心循环:tool-call 多轮推理如何驱动整个 Agent → 01-agent-loop.md
- 上下文与健壮性:长对话如何裁剪、坏消息如何自愈、如何避免 tool_use/tool_result 配对错乱 → 03-context-robustness.md
建议阅读顺序: 先本页(全景)→ 01(循环,理解心脏)→ 02(提示词,每轮的输入从哪来)→ 03(健壮性,长跑不崩)→ 04(记忆知识)→ 05(技能工具)→ 06(自进化)。由浅入深,一级级往下走。
4. 巧妙之处(本页层面能看到的几处)
这些是"路由/骨架"层面就能读出的设计精华;各子系统内部的巧妙留给对应章。
-
按 session_id 隔离多实例,天然支持多用户/多渠道并发。 一个
AgentBridge维护session_id -> Agent的字典,get_agent懒加载:同一进程里,不同用户各有独立历史与状态, 互不串味(bridge/agent_bridge.py:280-393,self.agents = {}+get_agent)。 -
先落库用户消息,再跑 Agent。 把"存用户那句话"提前到运行之前,新会话和用户气泡立刻可见—— 哪怕用户马上刷新或切走,也不丢在途会话(bridge/agent_bridge.py:518-525,
_pre_persist_user_message)。落库时若关闭了 thinking 展示,还会先剥掉 assistant 的 thinking 块再存,避免思维链在历史里重现(_strip_thinking_blocks,bridge/agent_bridge.py:1067)。 -
可中途取消的令牌机制。 每次回复注册一个取消
Event,Web 用 per-turnrequest_id、 IM 渠道退化用session_id作 key;执行器在安全检查点轮询它,于是/cancel能真正打断 一次在跑的推理(bridge/agent_bridge.py:461-467,get_cancel_registry)。 -
模型"一键切换"靠模型名前缀路由。
AgentLLMModel._resolve_bot_type用一张前缀表 (claude→Claude、gemini→Gemini、deepseek→DeepSeek…)把配置里的模型名映射到具体 bot, 换模型只是改配置字符串,不动 Agent 代码(bridge/agent_bridge.py:75-124)。 -
给任意 bot 动态"补上"工具调用能力。
add_openai_compatible_support在运行时把一个 OpenAI 兼容 bot 的类替换成混入了工具调用 mixin 的增强类,让原本不支持 tool-call 的 bot 也能用, 而无需改它的源码(bridge/agent_bridge.py:21-61)。 -
启动即热身,首条消息不卡。 进程启动就在后台预加载 MCP 子进程、预热 AgentBridge/调度器, 把 npx 下载、调度线程启动等成本挪到用户开口之前(app.py:294-315、382-391,
_warmup_mcp_tools/_warmup_scheduler)。
5. 边界与说明(本页范围)
- 本页只讲全景与路由,不深入任一子系统的实现;每个子系统的原理、坑与源码走读在各自章节。
- 成本与安全(README.md:272):Agent 模式比普通聊天更耗 token;且 Agent 能访问你的本地操作系统,
官方明确只建议部署在可信环境。部署到公网服务器时需把
web_host设为0.0.0.0并设web_password,还要放行9899端口(README.md:83-85)。 - 本文所有引用锁定在
sourceCommit = eeb4b7981e19b8df5516e27b8a974600ee729885。
6. 全库代码地图(导航索引)
一张跨全库的跳转表:想改/想读某主题,直接按符号名 grep 进源码。
| 主题 | 文件 | 符号 |
|---|---|---|
| 进程入口 / 多渠道并发启动 | app.py | run · ChannelManager.start · _warmup_scheduler |
| 渠道工厂(十余渠道) | channel/channel_factory.py | create_channel |
| 总机 / 会话隔离 | bridge/agent_bridge.py | AgentBridge · get_agent · agent_reply |
| 用户消息持久化 | bridge/agent_bridge.py | _pre_persist_user_message · _persist_messages |
| 取消令牌 | bridge/agent_bridge.py · agent/protocol/cancel.py | get_cancel_registry |
| 模型适配 / 一键切换 | bridge/agent_bridge.py | AgentLLMModel · _resolve_bot_type · add_openai_compatible_support |
| Web 流式:事件→CHAT chunk | agent/chat/service.py | ChatService.run · _StreamState |
| Agent 实例装配(接线五子系统) | bridge/agent_initializer.py | AgentInitializer.initialize_agent |
| 核心循环(→ 01) | agent/protocol/agent.py · agent/protocol/agent_stream.py | Agent.run_stream · AgentStreamExecutor.run_stream |
| 系统提示词(→ 02) | agent/prompt/builder.py | build_agent_system_prompt · PromptBuilder.build |
| 上下文/健壮性(→ 03) | agent/protocol/agent_stream.py | _trim_messages · _call_llm_stream |
| 记忆(→ 04) | agent/memory/manager.py | MemoryManager.search · MemoryManager.add_memory |
| 知识(→ 04) | agent/knowledge/service.py | KnowledgeService · rebuild_index_md |
| 技能(→ 05) | agent/skills/manager.py · agent/skills/loader.py | SkillManager · load_skills_from_dir |
| 工具 / MCP(→ 05) | agent/tools/tool_manager.py | ToolManager.load_tools · sync_mcp_into_agent · refresh_mcp_if_changed |
| 自进化(→ 06) | agent/evolution/trigger.py | start_evolution_trigger · note_user_turn · mark_run_active |