ANALYSIS
CoPaw Agent 架构详解
概述
CoPaw 的 Agent 架构是一个完全模块化的系统,所有核心组件均为解耦模块。这种设计使得 CoPaw 具有高度的可扩展性和可定制性。
Agent 核心架构
架构概览
PRTCL // PLAINTEXT
┌─────────────────────────────────────────┐│ 用户交互层 ││ ( 多渠道接入:钉钉、飞书、QQ 等 ) │└──────────────┬──────────────────────────┘ │┌──────────────▼──────────────────────────┐│ 消息队列层 ││ ( 消息缓冲、优先级调度、可靠投递 ) │└──────────────┬──────────────────────────┘ │┌──────────────▼──────────────────────────┐│ Agent 核心 ││ ┌─────────────────────────────────┐ ││ │ Prompt 系统 │ ││ └─────────────────────────────────┘ ││ ┌─────────────────────────────────┐ ││ │ Hooks 系统 │ ││ └─────────────────────────────────┘ ││ ┌─────────────────────────────────┐ ││ │ Tools 系统 │ ││ └─────────────────────────────────┘ ││ ┌─────────────────────────────────┐ ││ │ Memory 系统 │ ││ └─────────────────────────────────┘ │└──────────────┬──────────────────────────┘ │┌──────────────▼──────────────────────────┐│ 模型层 ││ ( 云端 API、本地模型、推理服务 ) │└─────────────────────────────────────────┘核心组件
| 组件 | 说明 | 特性 |
|---|---|---|
| Prompt 系统 | 提示词管理和组装 | 模块化、可组合 |
| Hooks 系统 | 钩子系统,拦截和扩展 | 事件驱动、灵活 |
| Tools 系统 | 工具管理和调用 | 可扩展、可替换 |
| Memory 系统 | 记忆管理和检索 | 语义化、持久化 |
Prompt 系统
Prompt 系统架构
组件:
PRTCL // PLAINTEXT
Prompt 系统├── Prompt Loader ( 加载器 )├── Prompt Builder ( 构建器 )├── Prompt Renderer ( 渲染器 )└── Prompt Cache ( 缓存 )Prompt 加载
加载顺序:
PRTCL // PYTHON
# Prompt 加载顺序FILE_ORDER = [ ("AGENTS.md", True), # 必需,Agent 角色定义 ("SOUL.md", True), # 必需,核心个性 ("PROFILE.md", False), # 可选,用户档案 ("SKILLS.md", False), # 可选,技能定义]示例文件:
AGENTS.md:
PRTCL // MARKDOWN
# Agent 角色定义
你是 CoPaw,一个智能 AI 助手。
## 角色- 个人助理- 信息助手- 创意助手
## 目标- 帮助用户解决问题- 提供准确信息- 生成创意内容
## 原则- 友好- 专业- 准确- 有帮助SOUL.md:
PRTCL // MARKDOWN
# 核心 Soul
你是一个温暖、友善的 AI 助手。
## 性格- 温暖:对用户充满关怀- 友善:总是乐于助人- 专业:提供高质量服务- 幽默:适度使用幽默
## 价值观- 用户至上- 隐私保护- 持续学习PROFILE.md:
PRTCL // MARKDOWN
# 用户档案
## 基本信息姓名:用户语言:中文时区:Asia/Shanghai
## 偏好- 回答风格:简洁明了- 详细程度:适中- 语气:友好
## 习惯- 工作时间:9:00-18:00- 休息时间:12:00-13:00Prompt 构建
构建过程:
PRTCL // PYTHON
class PromptBuilder: """Prompt 构建器"""
def __init__(self, workspace: str): self.workspace = workspace self.prompts = {}
def load_prompts(self) -> Dict[str, str]: """加载所有 Prompt 文件""" for filename, required in FILE_ORDER: path = os.path.join(self.workspace, filename) if os.path.exists(path): with open(path, 'r', encoding='utf-8') as f: self.prompts[filename] = f.read() elif required: raise FileNotFoundError(f"必需的 Prompt 文件缺失: {filename}") return self.prompts
def build_system_prompt(self) -> str: """构建系统提示词""" parts = [] for filename in FILE_ORDER: if filename[0] in self.prompts: parts.append(self.prompts[filename[0]]) return "\n\n".join(parts)Prompt 渲染
变量替换:
PRTCL // PYTHON
class PromptRenderer: """Prompt 渲染器"""
def render(self, template: str, variables: Dict[str, Any]) -> str: """渲染 Prompt""" from jinja2 import Template
# 使用 Jinja2 模板 template_obj = Template(template) return template_obj.render(**variables)示例:
PRTCL // PYTHON
template = """你好 {{ user_name }}!
今天是 {{ date }},有什么可以帮你的吗?"""
variables = { 'user_name': ' 张三 ', 'date': '2026-03-12'}
result = renderer.render(template, variables)# 输出:你好 张三!# 今天是 2026-03-12,有什么可以帮你的吗?Hooks 系统
Hooks 系统架构
组件:
PRTCL // PLAINTEXT
Hooks 系统├── Hook Registry ( 注册表 )├── Hook Executor ( 执行器 )├── Hook Middleware ( 中间件 )└── Hook Context ( 上下文 )Hook 类型
Pre-LLM Hooks(LLM 调用前):
pre_reasoning:推理前处理pre_compaction:压缩前处理pre_validation:验证前处理
Post-LLM Hooks(LLM 调用后):
post_compaction:压缩后处理post_validation:验证后处理post_processing:后处理
Hook 示例
自定义 Hook:
PRTCL // PYTHON
from copaw.hooks import Hook, HookContext
class CustomHook(Hook): """自定义 Hook"""
def __init__(self, config: Dict[str, Any]): super().__init__(config) self.enabled = config.get('enabled', True)
async def before_llm_call(self, context: HookContext) -> None: """LLM 调用前""" if not self.enabled: return
# 自定义逻辑 context.data['custom_value'] = 'custom' self.log("Pre-LLM hook executed")
async def after_llm_call(self, context: HookContext) -> None: """LLM 调用后""" if not self.enabled: return
# 自定义逻辑 result = context.data.get('result') self.log(f"Post-LLM hook executed: {result}")
def log(self, message: str) -> None: """记录日志""" print(f"[CustomHook] {message}")注册 Hook:
PRTCL // PYTHON
from copaw.hooks import HookRegistry
# 注册 Hookregistry = HookRegistry()registry.register('custom', CustomHook)
# 使用 Hookhook = registry.get('custom')await hook.before_llm_call(context)Hook 链
Hook 链执行:
PRTCL // PYTHON
class HookChain: """Hook 链"""
def __init__(self, hooks: List[Hook]): self.hooks = hooks
async def execute_before(self, context: HookContext) -> None: """执行所有 Pre-Hooks""" for hook in self.hooks: await hook.before_llm_call(context)
async def execute_after(self, context: HookContext) -> None: """执行所有 Post-Hooks""" for hook in reversed(self.hooks): await hook.after_llm_call(context)Tools 系统
Tools 系统架构
组件:
PRTCL // PLAINTEXT
Tools 系统├── Tool Registry ( 注册表 )├── Tool Manager ( 管理器 )├── Tool Executor ( 执行器 )└── Tool Cache ( 缓存 )内置工具
文件操作工具:
PRTCL // PYTHON
class ReadFileTool(Tool): """读取文件工具"""
name = "read_file" description = "读取文件内容"
async def execute(self, file_path: str) -> str: """执行工具""" with open(file_path, 'r', encoding='utf-8') as f: return f.read()网络搜索工具:
PRTCL // PYTHON
class WebSearchTool(Tool): """网络搜索工具"""
name = "web_search" description = "搜索网络信息"
async def execute(self, query: str) -> List[Dict[str, Any]]: """执行工具""" # 调用搜索 API results = await self.search_api.search(query) return results计算器工具:
PRTCL // PYTHON
class CalculatorTool(Tool): """计算器工具"""
name = "calculator" description = "数学计算"
async def execute(self, expression: str) -> float: """执行工具""" # 安全计算 result = eval(expression, {'__builtins__': {}}, {}) return result自定义工具
创建自定义工具:
PRTCL // PYTHON
from copaw.tools import Tool
class CustomTool(Tool): """自定义工具"""
name = "custom_tool" description = "自定义工具描述"
def __init__(self, config: Dict[str, Any]): super().__init__(config) self.param1 = config.get('param1', 'default')
async def execute(self, input_data: Dict[str, Any]) -> Dict[str, Any]: """执行工具""" try: result = self.process(input_data) return { 'success': True, 'result': result } except Exception as e: return { 'success': False, 'error': str(e) }
def process(self, input_data: Dict[str, Any]) -> Any: """处理输入数据""" # 处理逻辑 return processed_result注册工具:
PRTCL // PYTHON
from copaw.tools import ToolRegistry
# 注册工具registry = ToolRegistry()registry.register('custom', CustomTool)
# 使用工具tool = registry.get('custom')result = await tool.execute({'param': 'value'})工具链
工具链执行:
PRTCL // PYTHON
class ToolChain: """工具链"""
def __init__(self, tools: List[Tool]): self.tools = tools
async def execute(self, input_data: Dict[str, Any]) -> Dict[str, Any]: """执行工具链""" current_data = input_data
for tool in self.tools: result = await tool.execute(current_data) if result.get('success'): current_data = result.get('result') else: return { 'success': False, 'error': result.get('error'), 'failed_at': tool.name }
return { 'success': True, 'result': current_data }Memory 系统
Memory 系统架构
组件:
PRTCL // PLAINTEXT
Memory 系统├── Memory Manager ( 管理器 )├── Memory Storage ( 存储 )├── Memory Retriever ( 检索器 )└── Memory Index ( 索引 )记忆存储
文件存储:
PRTCL // PYTHON
class FileMemoryStorage: """文件存储"""
def __init__(self, path: str): self.path = path os.makedirs(path, exist_ok=True)
async def save(self, key: str, value: Any) -> None: """保存记忆""" file_path = os.path.join(self.path, f"{key}.json") with open(file_path, 'w', encoding='utf-8') as f: json.dump(value, f, ensure_ascii=False)
async def load(self, key: str) -> Optional[Any]: """加载记忆""" file_path = os.path.join(self.path, f"{key}.json") if os.path.exists(file_path): with open(file_path, 'r', encoding='utf-8') as f: return json.load(f) return None数据库存储:
PRTCL // PYTHON
class DatabaseMemoryStorage: """数据库存储"""
def __init__(self, connection_string: str): self.connection_string = connection_string self.pool = await self.create_pool()
async def save(self, key: str, value: Any) -> None: """保存记忆""" async with self.pool.acquire() as conn: await conn.execute( "INSERT INTO memories (key, value) VALUES ($1, $2)", key, json.dumps(value) )
async def load(self, key: str) -> Optional[Any]: """加载记忆""" async with self.pool.acquire() as conn: record = await conn.fetchrow( "SELECT value FROM memories WHERE key = $1", key ) return json.loads(record['value']) if record else None记忆检索
语义检索:
PRTCL // PYTHON
class SemanticMemoryRetriever: """语义检索"""
def __init__(self, index: Any): self.index = index
async def search(self, query: str, top_k: int = 5) -> List[Dict[str, Any]]: """语义搜索""" # 向量化查询 query_vector = self.embed(query)
# 搜索最相似的 results = self.index.search(query_vector, top_k)
return results
def embed(self, text: str) -> List[float]: """文本向量化""" # 调用嵌入模型 return self.embedding_model.embed(text)记忆整合
记忆整合:
PRTCL // PYTHON
class MemoryConsolidator: """记忆整合"""
async def consolidate(self, memories: List[Dict[str, Any]]) -> List[Dict[str, Any]]: """整合记忆""" # 按相似度分组 groups = self.group_by_similarity(memories)
# 合并相似记忆 consolidated = [] for group in groups: if len(group) > 1: merged = self.merge_group(group) consolidated.append(merged) else: consolidated.append(group[0])
return consolidated
def group_by_similarity(self, memories: List[Dict[str, Any]]) -> List[List[Dict[str, Any]]]: """按相似度分组""" # 实现分组逻辑 pass
def merge_group(self, group: List[Dict[str, Any]]) -> Dict[str, Any]: """合并记忆组""" # 实现合并逻辑 passAgent 循环
ReAct 循环
循环流程:
PRTCL // PLAINTEXT
开始 │ ├─→ 接收用户消息 │ ├─→ Pre-Hooks │ ├─→ 构建 Prompt │ ├─→ 调用 LLM │ ├─→ Post-Hooks │ ├─→ 判断是否需要工具 │ ├─ 是 → 执行工具 → 更新上下文 → 继续 │ └─ 否 → 继续下一步 │ ├─→ 压缩上下文(如果需要) │ ├─→ 判断是否完成 │ ├─ 否 → 返回构建 Prompt 步骤 │ └─ 是 → 继续下一步 │ └─→ 返回结果上下文压缩
压缩策略:
PRTCL // PYTHON
class ContextCompactor: """上下文压缩器"""
def __init__(self, config: Dict[str, Any]): self.threshold = config.get('threshold', 0.8) self.keep_recent = config.get('keep_recent', 5)
async def compact(self, messages: List[Dict[str, Any]], max_length: int) -> List[Dict[str, Any]]: """压缩上下文""" current_length = self.calculate_length(messages)
if current_length <= max_length: return messages
# 压缩策略 compressed = []
# 保留最近的 N 条消息 recent = messages[-self.keep_recent:] compressed.extend(recent)
# 压缩中间部分 middle = messages[self.keep_recent:-self.keep_recent] if middle: summary = await self.summarize(middle) compressed.insert(0, { 'role': 'system', 'content': f"[摘要] {summary}" })
return compressed
def calculate_length(self, messages: List[Dict[str, Any]]) -> int: """计算上下文长度""" length = 0 for msg in messages: length += len(msg.get('content', '')) return length
async def summarize(self, messages: List[Dict[str, Any]]) -> str: """总结消息""" # 调用 LLM 总结 pass最佳实践
模块化设计
原则:
- 单一职责:每个组件只做一件事
- 低耦合:组件之间依赖最小化
- 高内聚:相关功能集中在一起
- 可测试:每个组件都可独立测试
性能优化
优化策略:
- 异步处理:使用异步 I/O
- 缓存机制:缓存频繁访问的数据
- 批处理:批量处理相似请求
- 资源池:使用连接池和线程池
错误处理
错误处理策略:
- 优雅降级:失败时提供备用方案
- 错误恢复:自动恢复机制
- 日志记录:详细记录错误信息
- 用户反馈:及时向用户反馈错误
资源链接
- CoPaw 架构文档: https://copaw.bot/docs/architecture
- AgentScope 文档: https://github.com/modelscope/agentscope
- 架构设计模式: https://copaw.bot/docs/patterns
最后更新: 2026-03-12 作者: EchoHaoRan
R P
Rhine Lab Pioneer Division
Auth_Verified: 2026.04.08
Auth_Verified: 2026.04.08
