1. CoPaw 多智能体框架到底解决了什么问题
CoPaw 是一个面向生产环境的多智能体 AI 助手框架,基于 Python 构建,核心目标是把大语言模型的能力封装成可编排、可扩展、可持久化的智能体服务。它适合谁?如果你正在做个人知识管理、自动化工作流、多平台助手接入,或者想系统理解 Agent Runtime 和 Skill System 的运行机制,CoPaw 的架构设计值得逐层拆解。它和单 Agent 框架最大的区别在于:Gateway 与 Agent 分离、原生多智能体协作、动态技能加载、分层记忆管理,这四点决定了它能不能从"玩具"变成"工具"。
我试过把 CoPaw 跑在一台 8GB 内存的开发机上,从 Gateway 启动到第一个 Agent 响应,整个链路涉及消息路由、上下文构建、技能加载、模型调用、流式输出、记忆持久化六个阶段。这篇文章按 12 个章节拆解,重点放在 Agent Runtime、Skill System、记忆管理、多智能体协作、端到端对话流程,同时给出 TaoToken 统一 Key 接入 AI 工具的 settings.json / config.toml 骨架,以及 CC Switch、Cline 的配置示例,最后附上对话链路验证动作,帮你复现完整流程。
CoPaw 的定位可以用一句话概括:让 AI 助手从"聊天工具"变成"生产力工具"。它具备长期记忆、技能扩展、多轮协作能力,而不是每次对话都从零开始。下面这张对比表能帮你快速判断它是否适合你的场景。
| 特性 | CoPaw | 单 Agent 框架 | 云端助手 |
|---|---|---|---|
| 架构设计 | 网关+智能体分离 | 单体结构 | 封闭 |
| 多智能体 | 原生支持 | 有限 | 不支持 |
| 技能系统 | 动态加载 | 插件式 | 固定 |
| 记忆管理 | 分层记忆 | 向量数据库 | 平台托管 |
| 模型支持 | 多提供商 | 单一为主 | 平台绑定 |
| 部署方式 | 本地/远程 | 本地 | 云端 |
适用场景包括:个人知识管理(长期对话记忆、文件整理、笔记归档)、自动化工作流(定时任务、数据抓取、报表生成)、多平台助手(同时接入多个消息渠道)、企业级部署(私有化、多用户管理、权限控制)。
2. TaoToken 统一 Key 前置配置
在拆解 CoPaw 内部机制之前,先把模型接入层打通。CoPaw 支持多模型提供商,但如果你同时用多个 AI 工具(CoPaw、Cline、CC Switch 等),每个工具单独配 Key 会很麻烦。TaoToken 提供统一 Key 接入,官网地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 端点是 https://taotoken.net/api 。
你需要先拿到 API Key,入口在控制台的 API Keys 页面:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 。拿到 Key 之后,不同工具的配置方式略有差异,下面给出骨架。
CoPaw 的模型配置通常放在config.yaml或providers.yaml中,核心字段是 base_url、api_key、model。如果你用 OpenAI 兼容格式接入,配置如下:
# .copaw/providers.yaml providers: taotoken: type: openai_compatible base_url: "https://taotoken.net/api" api_key: "sk-你的TaoToken密钥" models: - name: "claude-sonnet-4-20250514" alias: "claude" - name: "gpt-4o" alias: "gpt4" default_model: "claude" timeout: 60 max_retries: 3如果你用的是 Cline(VS Code 插件),配置放在 settings.json 中:
{ "cline.apiProvider": "openai", "cline.openAiBaseUrl": "https://taotoken.net/api", "cline.openAiApiKey": "sk-你的TaoToken密钥", "cline.openAiModelId": "claude-sonnet-4-20250514" }CC Switch 的配置类似,它支持多套配置切换,适合同时管理多个模型端点:
{ "providers": [ { "name": "taotoken", "baseUrl": "https://taotoken.net/api", "apiKey": "sk-你的TaoToken密钥", "models": ["claude-sonnet-4-20250514", "gpt-4o"] } ], "activeProvider": "taotoken" }注意:API Key 不要硬编码在会提交到 Git 的文件里,建议用环境变量或本地配置文件,并在 .gitignore 中排除。
配置完成后,可以用一个最小请求验证 Key 是否生效:
curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer sk-你的TaoToken密钥" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-20250514", "messages": [{"role": "user", "content": "ping"}], "max_tokens": 16 }'如果返回正常的 JSON 响应,说明 Key 和端点都没问题。这一步是后面所有配置的基础,建议先跑通再继续。
3. Agent Runtime 核心机制拆解
Agent Runtime 是 CoPaw 真正"思考"的部分,它采用经典的 ReAct(Reasoning + Acting)循环模式。理解这个循环,就理解了 CoPaw 处理请求的主线。
# Agent Loop 伪代码示意 while task_not_completed: # 1. 感知:获取当前上下文 context = build_context(memory, user_message, system_prompt) # 2. 思考:调用 LLM 决定下一步 response = llm.generate(context, tools_available) # 3. 行动:执行工具调用或生成回复 if response.has_tool_calls: results = execute_tools(response.tool_calls) memory.add_observation(results) else: return response.content # 4. 检查:是否完成任务 if response.is_final_answer: break工具调用使用 OpenAI 兼容的 Function Calling 格式。当 LLM 决定调用工具时,返回的结构如下:
{ "tool_calls": [ { "id": "call_abc123", "type": "function", "function": { "name": "execute_shell_command", "arguments": "{\"command\": \"ls -la\", \"timeout\": 60}" } } ] }工具执行后,结果被格式化为 tool 角色的消息返回给 LLM:
{ "role": "tool", "tool_call_id": "call_abc123", "content": "total 128\ndrwxr-xr-x 5 user group 160 Mar 27 10:00 ." }每个 Agent 拥有独立的工作目录,结构如下:
~/.copaw/workspace/ ├── agents/ │ ├── agent_001/ # Agent 专属空间 │ │ ├── memory/ # 每日记忆文件 │ │ ├── skills/ # 自定义技能 │ │ └── uploads/ # 上传文件缓存 │ └── agent_002/ ├── shared/ # 共享资源 │ ├── models/ # 本地模型缓存 │ └── skills/ # 全局技能库 └── logs/ # 运行日志 └── llm_calls.jsonl # LLM 调用记录Agent Runtime 的关键设计在于:上下文构建是动态的,每次循环都会重新组装系统提示词、记忆、历史消息和可用工具列表。这意味着技能加载和记忆检索都发生在运行时,而不是启动时一次性确定。这种设计让 CoPaw 可以在对话过程中动态调整能力,但也对上下文管理提出了更高要求。
4. Skill System 技能系统与动态加载
技能是 CoPaw 的功能扩展单元,采用模块化设计。每个技能是一个独立目录,包含 SKILL.md 文档和可选的 Python 代码。
active_skills/ ├── skill_name/ │ ├── SKILL.md # 技能文档(必需) │ ├── __init__.py # 技能入口(可选) │ ├── tools.py # 工具函数(可选) │ └── resources/ # 资源文件(可选) │ ├── templates/ │ └── data/每个技能必须包含 SKILL.md,格式如下:
--- name: skill_name version: 1.0.0 description: 技能的简短描述 triggers: - 触发词1 - 触发词2 builtin_skill_version: "1.0" copaw: emoji: "🛠" --- ## 使用说明 技能的详细使用说明... ## 工具列表 - `tool_name`: 工具描述技能在 Agent 启动时动态加载,加载流程如下:
# 技能加载伪代码示意 class SkillLoader: def load_skill(self, skill_path): # 1. 读取 SKILL.md metadata = parse_skill_md(skill_path / "SKILL.md") # 2. 注册工具 if (skill_path / "tools.py").exists(): tools = import_tools(skill_path / "tools.py") self.tool_registry.register(tools) # 3. 加载提示词 if metadata.system_prompt: self.prompt_manager.add(skill_path / metadata.system_prompt) return SkillInstance(metadata)内置技能覆盖了常见场景:file_reader 读取和总结文本文件、browser_visible 可视化浏览器操作、xlsx 处理 Excel 文件、pdf 操作 PDF、pptx 生成 PowerPoint、cron 定时任务管理、multi_agent_collaboration 多智能体协作、pua 高难问题解决模式、guidance 安装配置指导。
技能系统的关键点在于:SKILL.md 是必需的,它定义了技能的元数据和触发条件;tools.py 是可选的,如果技能需要执行代码就提供;技能可以热插拔,按需加载,不需要重启整个 Agent。这种设计让 CoPaw 的能力可以持续扩展,而不影响核心运行时。
5. 记忆与上下文管理
CoPaw 采用分层记忆系统,平衡 recall 和成本。三层记忆分别是工作记忆、短期记忆和长期记忆。
┌─────────────────────────────────────────────────────────┐ │ 三层记忆金字塔 │ ├─────────────────────────────────────────────────────────┤ │ Level 3: 长期记忆 (Long-term) │ │ ├── MEMORY.md # 精心整理的核心知识 │ │ └── 存储: 关键决策、技术方案、个人偏好 │ │ └── 容量: 无限制 | 更新: 手动 │ ├─────────────────────────────────────────────────────────┤ │ Level 2: 短期记忆 (Short-term) │ │ ├── memory/2026-03-27.md # 每日会话记录 │ │ └── 存储: 原始对话、执行记录、思考过程 │ │ └── 容量: ~30天 | 更新: 自动 │ ├─────────────────────────────────────────────────────────┤ │ Level 1: 工作记忆 (Working) │ │ ├── 当前会话上下文 │ │ └── 存储: 当前对话历史、系统提示词 │ │ └── 容量: 受限于模型上下文窗口 │ └─────────────────────────────────────────────────────────┘长期记忆文件 MEMORY.md 的结构示例:
# MEMORY.md ## 技术决策 - 2026-03-26: 采用 RetryChatModel 包装器进行 LLM 日志记录 - 2026-03-26: 技能系统采用 SKILL.md + 可选代码的混合模式 ## 关键配置 - LLM 日志路径: ~/.copaw/llm_calls.jsonl - 网关地址: 127.0.0.1:18789 ## 个人偏好 - 时区: Asia/Shanghai - 语言: 中文优先每日笔记(短期记忆)的结构示例:
# memory/2026-03-27.md ## Session: 1774525792430 ### 14:30 - 技能系统优化 - 创建了新的文档技能 - 遇到浏览器启动问题,已解决 ### 16:45 - 记忆管理 - 更新了 MEMORY.md - 压缩了昨日会话上下文当上下文窗口接近上限时,CoPaw 自动触发压缩(Compaction),把旧消息替换为结构化摘要:
session_meta: session_id: "1774525792430" agent_id: "RRepcB" model: "kimi-k2.5" date: "2026-03-26" deliverables: - category: "技能" item: "llm_log_viewer" status: "完成" insights: architecture: - "CoPaw 使用 RetryChatModel → OpenAIChatModelCompat → OpenAIChatModel 链" next_steps: - "继续优化技能系统"分层记忆的核心价值在于:工作记忆保证当前对话的连贯性,短期记忆保留最近几周的细节,长期记忆沉淀核心知识。压缩机制则确保上下文不会无限增长,同时保留关键信息。
6. 多智能体协作与消息处理
CoPaw 支持多个 Agent 实例协作,消息通过总线传递。路由逻辑如下:
用户消息 ──────▶┌─────────────┐ │ Gateway │ └──────┬──────┘ │ ┌──────────────┼──────────────┐ ▼ ▼ ▼ ┌──────────────┐┌──────────────┐┌──────────────┐ │ Agent:助手 ││ Agent:专家 ││ Agent:执行 │ │ (通用对话) ││ (代码审查) ││ (任务执行) │ └──────────────┘└──────────────┘└──────────────┘ │ │ │ └──────────────┼──────────────┘ ▼ ┌─────────────┐ │ 结果汇总 │ └─────────────┘Agent 间通过消息总线通信,一个 Agent 可以请求另一个 Agent 协助:
# Agent A 请求协作 response = agent.chat( agent_id="expert_agent", message="请审查这段代码...", context=shared_context ) # 专家 Agent 返回结果 { "agent_id": "expert_agent", "response": "发现3个问题:1. ... 2. ...", "confidence": 0.95 }典型协作场景包括:代码开发(架构师 → 开发者 → 审查者,顺序流水线)、数据分析(数据工程师 → 分析师 → 可视化专家,并行+汇总)、内容创作(研究员 → 写作 → 编辑,迭代反馈)。
消息处理与流式输出的生命周期如下:
1. 用户发送消息 │ ▼ 2. Gateway 接收并验证 │ ▼ 3. 路由到对应 Agent │ ▼ 4. Agent 构建上下文 ┌─────────────────┐ │ 系统提示词 │ │ 历史消息 │ │ 当前消息 │ │ 可用工具 │ └─────────────────┘ │ ▼ 5. 调用 LLM (流式) ┌─────────────────┐ │ chunk 1: "Hello"│ │ chunk 2: "world"│ │ chunk 3: "!" │ └─────────────────┘ │ ▼ 6. 返回给用户流式输出的实现方式:
async def stream_response(messages, tools): async for chunk in llm.astream(messages, tools=tools): # 解析 chunk delta = chunk.choices[0].delta if delta.content: # 文本内容 yield {"type": "content", "data": delta.content} if delta.tool_calls: # 工具调用 yield {"type": "tool_call", "data": delta.tool_calls}消息格式遵循 OpenAI 兼容规范,包含 system、user、assistant、tool 四种角色。工具调用时,assistant 消息的 content 为 null,tool_calls 字段包含调用信息;工具执行结果以 tool 角色返回,通过 tool_call_id 关联。
7. 模型提供商与故障转移
CoPaw 的模型层采用链式结构,支持重试、故障转移和多模型切换。
┌─────────────────────────────────────────────────────────┐ │ RetryChatModel │ │ - 重试策略 (指数退避) │ │ - 故障转移 (Failover) │ │ - 日志记录 (可选) │ └──────────────────────┬──────────────────────────────────┘ │ ┌──────────────────────▼──────────────────────────────────┐ │ OpenAIChatModelCompat │ │ - API 格式兼容 │ │ - 参数标准化 │ └──────────────────────┬──────────────────────────────────┘ │ ┌──────────────────────▼──────────────────────────────────┐ │ OpenAIChatModel │ │ - HTTP 请求构造 │ │ - 流式响应处理 │ │ - Token 用量统计 │ └──────────────────────┬──────────────────────────────────┘ │ ┌──────────────┴──────────────┐ ▼ ▼ ┌───────────────┐ ┌───────────────┐ │ TaoToken API │ │ 本地模型 │ │ (统一端点) │ │ (Ollama) │ └───────────────┘ └───────────────┘故障转移配置示例:
model_config: primary: "taotoken:claude-sonnet-4-20250514" fallbacks: - "taotoken:gpt-4o" - "ollama:qwen2.5" retry_policy: max_retries: 3 backoff_factor: 2.0 timeout: 60支持的模型提供商包括:TaoToken(统一端点,多模型)、Moonshot(Kimi,中文优化)、OpenAI(通用能力强)、Anthropic(安全性高)、Ollama(本地部署,隐私优先)、Azure OpenAI(企业合规)。
故障转移的核心逻辑是:主模型调用失败时,按 fallbacks 列表依次尝试;重试采用指数退避,避免雪崩;所有调用记录到 llm_calls.jsonl,便于排查。
8. 会话管理与状态持久化
会话是 CoPaw 管理对话状态的核心单元,结构如下:
@dataclass class Session: session_id: str # 唯一标识 agent_id: str # 所属 Agent user_id: str # 用户标识 channel: str # 来源渠道 messages: List[Message] # 消息历史 metadata: Dict # 会话元数据 created_at: datetime # 创建时间 updated_at: datetime # 最后活跃 expires_at: datetime # 过期时间为防止内存无限增长,CoPaw 实施会话修剪:
# 修剪策略配置 pruning_config = { "max_messages": 100, # 单会话最大消息数 "max_age_hours": 24, # 会话最大存活时间 "summary_threshold": 50, # 触发摘要的消息数 "keep_recent": 10 # 始终保留的最近消息数 } # 修剪流程 async def prune_session(session): if len(session.messages) > pruning_config["max_messages"]: # 1. 生成历史摘要 summary = await generate_summary( session.messages[:-pruning_config["keep_recent"]] ) # 2. 替换旧消息为摘要 session.messages = [ Message(role="system", content=f"历史摘要: {summary}"), *session.messages[-pruning_config["keep_recent"]:] ]状态持久化的目录结构:
sessions/ ├── active/ # 活跃会话(内存) ├── archived/ # 归档会话(磁盘) │ ├── 2026-03/ │ │ ├── session_001.json │ │ └── session_002.json │ └── 2026-04/ └── index.db # 会话索引会话管理的设计要点:活跃会话保存在内存中,保证响应速度;归档会话持久化到磁盘,支持历史查询;修剪策略防止内存泄漏;摘要机制保留关键信息。
9. 安全与认证机制
CoPaw 默认采用配对码机制防止未授权访问,流程如下:
1. 陌生人发送消息 │ ▼ 2. Gateway 拦截 │ ▼ 3. 生成配对码: ABC123 │ ▼ 4. 通知管理员 │ ▼ 5. 管理员执行: copaw pairing approve ABC123 │ ▼ 6. 陌生人获得访问权限OAuth 集成配置示例:
# config/oauth.yaml google: client_id: "xxx.apps.googleusercontent.com" client_secret: "xxx" redirect_uri: "http://localhost:18789/oauth/callback" scopes: - "openid" - "email" - "profile" github: client_id: "xxx" client_secret: "xxx"远程访问安全方面,CoPaw 默认只监听 127.0.0.1:18789,如果需要远程访问,建议通过内网穿透或私有网络方案,并配合防火墙规则限制来源 IP。认证层支持 API Key、OAuth、配对码三种方式,可以根据部署场景组合使用。
10. 工程实践与最佳实践
项目结构规范建议:
copaw-project/ ├── .copaw/ # CoPaw 配置目录 │ ├── config.yaml # 主配置 │ ├── providers.yaml # 模型配置 │ └── workspace/ # 工作空间 │ ├── active_skills/ # 激活的技能 │ │ ├── my_custom_skill/ │ │ │ ├── SKILL.md │ │ │ └── tools.py │ │ └── another_skill/ │ ├── memory/ # 记忆文件 │ │ ├── MEMORY.md │ │ └── 2026-03-27.md │ └── docs/ # 项目文档 └── README.md主配置示例:
# config.yaml agent: name: "猫头鹰" identity: "CoPaw 内部逻辑引导" timezone: "Asia/Shanghai" language: "zh" model: default: "taotoken:claude-sonnet-4-20250514" temperature: 0.7 max_tokens: 4000 memory: daily_notes: true compaction_threshold: 50 skills: auto_load: true builtin: - file_reader - browser_visible - xlsx - pdf调试与监控命令:
# 查看最近日志 copaw logs --tail 100 # 分析 token 用量 copaw logs --stats --since "1 day ago" # 导出日志 copaw logs export --format jsonl --output llm_logs.jsonl # 查看 Agent 状态 copaw agent status # 查看活跃会话 copaw sessions list --active # 查看技能加载情况 copaw skills list --verbose性能优化建议:上下文长度定期触发 compaction 降低 token 成本;工具调用减少不必要的工具定义降低决策延迟;模型选择简单任务用轻量模型降低成本;缓存策略缓存常用查询结果减少重复调用;并发处理使用 async/await 提高吞吐量。
故障排查清单:
## Agent 无响应 - [ ] 检查 Gateway 是否运行: `copaw gateway status` - [ ] 检查模型配置: `copaw model test` - [ ] 查看日志: `copaw logs --level error` ## 技能加载失败 - [ ] 检查 SKILL.md 格式 - [ ] 验证 Python 依赖 - [ ] 查看技能日志: `copaw skills logs <skill_name>` ## 记忆丢失 - [ ] 检查 workspace 目录权限 - [ ] 验证 MEMORY.md 格式 - [ ] 检查磁盘空间11. 端到端对话流程实战验证
这一节以真实场景为例,完整展示 CoPaw 处理一轮对话请求的全流程。场景是用户请求"帮我配置 qmd 技能,并同步记忆文件",时间范围从请求入口到记忆更新。
请求入口处理(Gateway 层):
1. HTTP POST /v1/agents/RRepcB/chat Body: {"message": "本地安装qmd技能,其它agent都已经装了", "session_id": "1774525792430"} 2. 认证鉴权 - 验证 API Key - 检查用户权限 - 限流检查(Rate Limit: 100/min) 3. 消息路由 - 解析 target_agent = "RRepcB" - 查找 Agent 实例(存在,直接使用) - 将消息放入 Agent 的消息队列 4. 日志记录 - 记录请求元数据(时间、用户、消息长度) - 生成 trace_id 用于全链路追踪Agent 接收消息并启动 ReAct Loop:
# Agent.message_handler 接收消息 class Agent: def handle_message(self, message: Message): # 1. 解析消息 user_content = message.content session_id = message.session_id # 2. 加载会话上下文 session = self.session_manager.get(session_id) # 3. 触发 ReAct Loop response = self.react_loop.run( user_message=user_content, session=session, tools=self.skills.get_available_tools() ) return responseReAct Loop 启动,构建上下文:
def react_loop(user_message, session, tools): # Step 1: 构建系统提示词 system_prompt = build_system_prompt() # 包含:Agent身份、核心准则、工具列表、记忆管理规则 # Step 2: 加载工作记忆 working_memory = session.get_history(limit=20) # Step 3: 检索相关长期记忆 relevant_memories = memory_search(query=user_message, top_k=5) # 查询: "qmd技能安装" → 返回 MEMORY.md 中的 qmd 配置记录 # Step 4: 构建完整上下文 context = { "system": system_prompt, "memories": relevant_memories, "history": working_memory, "user": user_message }技能路由决策,Agent 分析用户意图:
用户意图分析: - "本地安装qmd技能" → 需要安装/配置技能 - "其它agent都已经装了" → 参考其他Agent的配置 技能匹配: - qmd_memory_sync (记忆同步) - 相关 - file_reader (文件读取) - 可能需要查看其他Agent配置 - execute_shell_command (执行命令) - 需要执行安装 - qmd (本地搜索) - 配置完成后使用 决策: 先安装qmd,然后配置记忆同步第一轮工具调用,查找其他 Agent 配置:
{ "name": "glob_search", "arguments": { "pattern": "**/qmd/**", "path": "C:\\zss_workspace" } }执行结果为空,LLM 推理:"其他 Agent 也没有安装,需要从技能库安装"。
第二轮工具调用,下载并安装 qmd:
{ "name": "execute_shell_command", "arguments": { "command": "mkdir active_skills\\qmd" } }{ "name": "execute_shell_command", "arguments": { "command": "powershell -Command \"Invoke-WebRequest -Uri 'https://clawhub.ai/steipete/qmd' -OutFile 'active_skills/qmd/SKILL.md'\"" } }执行结果:成功下载 SKILL.md(26,633 bytes),但发现是 HTML 页面,需要下载 zip 包。
{ "name": "execute_shell_command", "arguments": { "command": "powershell -Command \"Invoke-WebRequest -Uri 'https://wry-manatee-359.convex.site/api/v1/download?slug=qmd' -OutFile 'active_skills/qmd/qmd.zip'\"" } }解压并安装:
{ "name": "execute_shell_command", "arguments": { "command": "powershell -Command \"Expand-Archive -Path 'active_skills/qmd/qmd.zip' -DestinationPath 'active_skills/qmd/' -Force\"" } }执行结果:成功安装 qmd 技能,包含 SKILL.md(817 bytes)和 _meta.json(122 bytes)。
第三轮工具调用,配置 Ollama:
{ "name": "execute_shell_command", "arguments": { "command": "curl http://localhost:11434/api/version" } }结果:{"version":"0.18.2"},Ollama 运行中。
拉取 embedding 模型:
{ "name": "execute_shell_command", "arguments": { "command": "ollama pull nomic-embed-text" } }{ "name": "execute_shell_command", "arguments": { "command": "ollama pull shaw/dmeta-embedding-zh" } }执行结果:两个模型下载完成,nomic-embed-text 274MB,shaw/dmeta-embedding-zh 408MB。
第四轮工具调用,修复 better-sqlite3:
{ "name": "execute_shell_command", "arguments": { "command": "cd \"%APPDATA%\\npm\\node_modules\\@tobilu\\qmd\" && npm rebuild better-sqlite3" } }执行结果:rebuilt dependencies successfully。
第五轮工具调用,创建记忆集合并索引:
{ "name": "execute_shell_command", "arguments": { "command": "qmd-wrapper.bat collection add memory --name memory --mask \"*.md\"" } }{ "name": "execute_shell_command", "arguments": { "command": "qmd-wrapper.bat collection add . --name copaw --mask \"**/*.md\"" } }执行结果:memory 集合 3 个文件,copaw 集合 251 个文件。
LLM 汇总执行结果并生成响应:
execution_summary: qmd_skill_installed: true location: "active_skills/qmd/" ollama_status: "running (v0.18.2)" models_installed: ["nomic-embed-text", "shaw/dmeta-embedding-zh"] native_deps: "rebuilt" collections: memory: {"files": 3, "path": "memory/*.md"} copaw: {"files": 251, "path": "**/*.md"}生成的响应内容包含安装完成报告和使用说明,通过 WebSocket 流式发送给用户:
for chunk in response_stream: websocket.send({ "type": "content", "data": chunk, "session_id": "1774525792430" }) websocket.send({ "type": "done", "session_id": "1774525792430" })会话状态更新与记忆持久化:
# 更新工作记忆 session.add_message({ "role": "user", "content": "本地安装qmd技能,其它agent都已经装了", "timestamp": "2026-03-27T09:30:00Z" }) session.add_message({ "role": "assistant", "content": response_content, "timestamp": "2026-03-27T09:36:00Z", "tools_used": ["glob_search", "execute_shell_command", "write_file"] }) # 持久化到磁盘 session.save()记忆文件更新:
# 自动更新每日笔记 edit_file( "memory/2026-03-27.md", old_text="", new_text=""" ## qmd + Ollama 配置完成 ### 配置清单 - [x] Ollama 服务运行 (v0.18.2) - [x] Embedding模型: nomic-embed-text (274MB) - [x] Embedding模型: shaw/dmeta-embedding-zh (408MB) - [x] qmd CLI 安装完成 - [x] better-sqlite3 原生模块重建 - [x] 集合创建: copaw (251个文件), memory (3个文件) """ ) # 更新长期记忆 edit_file( "MEMORY.md", old_text="| llm_log_viewer | `active_skills/llm_log_viewer/` | 查看 LLM 对话日志 | 📜 |", new_text="""| llm_log_viewer | `active_skills/llm_log_viewer/` | 查看 LLM 对话日志 | 📜 | | qmd | `active_skills/qmd/` | 本地搜索/索引 CLI | |""" )完整时序图:
用户 Gateway Agent Skills LLM Ollama | | | | | | |─"安装qmd技能"─▶| | | | | |─route(msg)─────▶| | | | | |─load_session()─│ | | | |◀─session───────│ | | | | | | | | | |─memory_search()▶| | | | |◀─results───────│ | | | | | | | | | |─────── LLM调用 ────────▶| | | |◀────── response ────────| | | | | | | | | |─glob_search()──▶| | | | |◀─results───────│ | | | | | | | | | |─curl(Ollama)───▶| | | | |◀─running───────│ | | | | | | | | | |─execute_shell()▶| | | | | (mkdir) | | | | | |◀─done──────────│ | | | | | | | | | |─download(qmd)──▶| | | | |◀─SKILL.md──────│ | | | | | | | | | |─npm(rebuild)───▶| | | | |◀─success───────│ | | | | | | | | | |─ollama(pull)───▶| | | | |◀─models────────│ | | | | | | | | | |─qmd(collection)▶| | | | |◀─indexed───────│ | | | | | | | | | |─────── LLM调用(汇总) ───▶| | | |◀────── final_response ──| | | | | | | | |◀─stream_response─│ | | |◀─chunk1─│ | | | | |◀─chunk2─│ | | | | |◀─done───│ | | | | | | | | | | | | |─save_session()─▶| | | | |─update_memory()▶| | | | | | | | [总耗时: ~6分钟] [Token消耗: ~15,000 input, ~2,000 output] [工具调用: 12次]延迟分布与优化建议:
| 阶段 | 耗时 | 占比 | 优化建议 |
|---|---|---|---|
| 消息路由 | <100ms | <1% | - |
| 记忆检索 | ~500ms | 8% | 使用 qmd 缓存 |
| LLM推理(决策) | ~2s | 33% | 批量请求 |
| 工具执行(下载) | ~3min | 50% | 预下载镜像 |
| 响应生成 | ~1s | 17% | - |
Token 消耗分析:
System Prompt: ~2,000 tokens Memory Context: ~3,000 tokens History(20轮): ~5,000 tokens User Message: 20 tokens Tool Results: ~5,000 tokens ────────────────────────────── Total Input: ~15,000 tokens Output: ~2,000 tokens瓶颈识别与优化:主要瓶颈是模型下载(nomic-embed-text 274MB,shaw/dmeta-embedding-zh 408MB)和 npm rebuild(编译原生模块)。优化策略是预下载常用模型到镜像,使用预编译的 better-sqlite3 二进制包,可用并行下载。
数据持久化流程:
对话完成 │ ├──▶ 工作记忆 ──▶ 保存到 session.json │ ├──▶ 提取关键事件 ──▶ 追加到 memory/2026-03-27.md │ └──▶ 提取核心知识 ──▶ 更新 MEMORY.md12. 对话链路验证与排障
配置完成后,你需要验证整条链路是否打通。最直接的方式是发一条测试消息,观察 Gateway 日志、Agent 日志和 LLM 调用记录。
# 1. 确认 Gateway 运行 copaw gateway status # 2. 发送测试请求 curl -X POST http://127.0.0.1:18789/v1/agents/default/chat \ -H "Authorization: Bearer 你的本地Key" \ -H "Content-Type: application/json" \ -d '{"message": "你好,请回复你的身份", "session_id": "test_001"}' # 3. 查看 LLM 调用记录 tail -n 5 ~/.copaw/logs/llm_calls.jsonl # 4. 查看会话状态 copaw sessions list --active如果返回正常响应,说明 Gateway、Agent、模型三层都通了。如果卡住,按下面的顺序排查。
常见错误一:模型返回 401。说明 API Key 无效或过期。检查 providers.yaml 中的 api_key 字段,确认没有多余空格,确认 Key 对应的账户有余额。用第 2 节的 curl 命令单独测试 Key。
常见错误二:技能加载失败。检查 SKILL.md 的 frontmatter 格式,name 和 version 字段是否完整,triggers 是否为列表。如果技能包含 tools.py,确认 Python 依赖已安装。
常见错误三:记忆文件不更新。检查 workspace 目录权限,确认 MEMORY.md 和 memory/ 目录可写。如果 compaction_threshold 设置过高,可能还没触发压缩。
常见错误四:流式输出中断。检查网络稳定性,确认 timeout 设置足够长。如果用的是本地模型,确认 Ollama 服务没有 OOM。
常见错误五:多智能体路由错误。检查 agent_id 是否存在于配置中,确认 Gateway 的路由规则没有冲突。
验证成功后,你可以继续扩展:接入更多技能、配置多 Agent 协作、调整记忆压缩阈值、切换模型提供商。TaoToken 的统一 Key 让你在切换模型时不需要改多处配置,只需要在 providers.yaml 中调整 default_model 即可。模型对话入口在 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite ,接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,长期编码和 Agent 场景可以看 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。
整条链路跑通之后,你会发现 CoPaw 的价值不在于单次对话有多聪明,而在于它能记住、能扩展、能协作。Agent Runtime 负责思考,Skill System 负责能力,Memory 负责沉淀,Gateway 负责连接。把这四层理解清楚,再复杂的场景也能拆解成可配置的模块。