|
|
1 месяц назад | |
|---|---|---|
| .. | ||
| ref | 1 месяц назад | |
| README.md | 1 месяц назад | |
| cloud_browser_guide.md | 1 месяц назад | |
| context-comparison.md | 1 месяц назад | |
| context-management.md | 1 месяц назад | |
| decisions.md | 1 месяц назад | |
| dependencies.md | 1 месяц назад | |
| multimodal.md | 1 месяц назад | |
| project-structure.md | 1 месяц назад | |
| skills.md | 1 месяц назад | |
| sub-agents.md | 1 месяц назад | |
| testing.md | 1 месяц назад | |
| tools-adapters.md | 1 месяц назад | |
| tools.md | 1 месяц назад | |
| trace-api.md | 1 месяц назад | |
可执行规格书:本文档是系统的核心设计。代码修改必须同步更新此文档。 如文档与代码冲突,以代码为准,并立即修复文档。
维护原则:
module/file.py:function_name单次调用是 Agent 的特例:
| 特性 | 单次调用 | Agent 模式 | Sub-Agent 模式 |
|---|---|---|---|
| 循环次数 | 1 | N (可配置) | N (可配置,受限) |
| 工具调用 | 可选 | 常用 | 受限工具集 |
| 状态管理 | 无 | 有 (Trace) | 有 (独立 Trace + 父子关系) |
| 记忆检索 | 无 | 有 (Experience/Skill) | 有 (继承主 Agent) |
| 执行图 | 1 条 Message | N 条 Messages 的 DAG | 嵌套 DAG(多个 Trace) |
| 触发方式 | 直接调用 | 直接调用 | 通过 Task 工具 |
| 权限范围 | 完整 | 完整 | 受限(可配置) |
┌─────────────────────────────────────────────────────────────┐
│ Layer 3: Skills(技能库) │
│ - Markdown 文件,存储详细的能力描述 │
│ - 通过 skill 工具按需加载 │
└─────────────────────────────────────────────────────────────┘
▲
│ 归纳
┌─────────────────────────────────────────────────────────────┐
│ Layer 2: Experience(经验库) │
│ - 数据库存储,条件 + 规则 + 证据 │
│ - 向量检索,注入到 system prompt │
└─────────────────────────────────────────────────────────────┘
▲
│ 提取
┌─────────────────────────────────────────────────────────────┐
│ Layer 1: Task State(任务状态) │
│ - 当前任务的工作记忆 │
│ - Trace + Messages 记录执行过程 │
│ - GoalTree 管理执行计划 │
└─────────────────────────────────────────────────────────────┘
注入方式:
skill 工具动态加载到对话历史async def run(task: str, max_steps: int = 50) -> AsyncIterator[Union[Trace, Message]]:
# 1. 创建 Trace
trace = Trace.create(mode="agent", task=task, status="in_progress")
await trace_store.create_trace(trace)
yield trace # 返回 Trace(表示开始)
# 2. 加载 Skills(内置 + 自定义)
skills = load_skills_from_dir(skills_dir)
skills_text = format_skills(skills)
# 3. 检索 Experiences,构建 system prompt
experiences = await search_experiences(task)
system_prompt = build_system_prompt(experiences, skills_text)
# 4. 初始化消息和 GoalTree
messages = [{"role": "user", "content": task}]
goal_tree = GoalTree(mission=task)
# 5. ReAct 循环
for step in range(max_steps):
# 注入当前计划到 system prompt
plan_text = goal_tree.to_prompt()
# 调用 LLM
response = await llm.chat(
messages=messages,
system=system_prompt + plan_text,
tools=tool_registry.to_schema()
)
# 记录 assistant Message
assistant_msg = Message.create(
trace_id=trace.trace_id,
role="assistant",
goal_id=goal_tree.current_id,
content=response.content, # text + tool_calls
)
await trace_store.add_message(assistant_msg)
yield assistant_msg
# 没有工具调用,完成
if not response.tool_calls:
break
# 执行工具
for tool_call in response.tool_calls:
result = await execute_tool(tool_call)
# 记录 tool Message
tool_msg = Message.create(
trace_id=trace.trace_id,
role="tool",
goal_id=goal_tree.current_id,
tool_call_id=tool_call.id,
content=result,
)
await trace_store.add_message(tool_msg)
yield tool_msg
# 添加到消息历史
messages.append({"role": "assistant", "tool_calls": [tool_call]})
messages.append({"role": "tool", "tool_call_id": tool_call.id, "content": result})
# 6. 完成
trace.status = "completed"
await trace_store.update_trace(trace.trace_id, status="completed")
yield trace
关键机制:
AsyncIterator[Union[Trace, Message]] - 实时返回执行状态goal_id 关联所属 Goal主 Agent 通过 task 工具启动 Sub-Agent。
层级关系:
Main Trace (primary agent)
└─▶ Sub Trace (parent_trace_id 指向主 Trace)
└─▶ Steps...
关键字段:
Trace.parent_trace_id - 指向父 TraceTrace.agent_definition - Sub-Agent 类型(如 "explore")实现位置:agent/tools/builtin/task.py(待实现)
@dataclass
class Trace:
trace_id: str
mode: Literal["call", "agent"]
task: Optional[str] = None
agent_type: Optional[str] = None
status: Literal["running", "completed", "failed"] = "running"
# Sub-Agent 支持
parent_trace_id: Optional[str] = None # 父 Trace ID
agent_definition: Optional[str] = None # Agent 类型名称
spawned_by_tool: Optional[str] = None # 启动此 Sub-Agent 的 Message ID
# 统计
total_messages: int = 0
total_tokens: int = 0
total_cost: float = 0.0
# 上下文
uid: Optional[str] = None
context: Dict[str, Any] = field(default_factory=dict)
current_goal_id: Optional[str] = None # 当前焦点 goal
实现:agent/execution/models.py:Trace
对应 LLM API 的消息,加上元数据。不再有 parent_id 树结构。
@dataclass
class Message:
message_id: str
trace_id: str
role: Literal["assistant", "tool"] # 和 LLM API 一致
sequence: int # 全局顺序
goal_id: str # 关联的 Goal 内部 ID
tool_call_id: Optional[str] = None # tool 消息关联对应的 tool_call
content: Any = None # 消息内容(和 LLM API 格式一致)
description: str = "" # 系统自动提取的摘要
# 元数据
tokens: Optional[int] = None
cost: Optional[float] = None
实现:agent/execution/models.py:Message
Message 类型:
role="assistant":模型的一次返回(可能同时包含文本和多个 tool_calls)role="tool":一个工具的执行结果(通过 tool_call_id 关联)详细的模块文档请参阅:
使用示例:examples/subagent_example.py
工具接入规范:
agent/tools/builtin/vendor/ + 适配器 → agent/tools/advanced/bash_command 调用(如 browser-use)内置工具(builtin/):
read_file, edit_file, write_file - 文件操作bash_command - 命令执行glob_files, grep_content - 文件搜索skill, list_skills - 技能库管理高级工具(advanced/):
webfetch - 网页抓取(调用 opencode)lsp_diagnostics - LSP 诊断(调用 opencode)Skills(agent/skills/):
browser_use - 浏览器自动化(包含环境配置工具)详细设计:参考 docs/tools-adapters.md
核心特性:
from reson_agent import tool, ToolResult, ToolContext
@tool(
url_patterns=["*.google.com"],
requires_confirmation=True
)
async def my_tool(arg: str, ctx: ToolContext) -> ToolResult:
return ToolResult(
title="Success",
output="Result content",
long_term_memory="Short summary"
)
实现:
agent/llm/prompts/wrapper.py:SimplePrompt - Prompt 包装器agent/llm/gemini.py:_convert_messages_to_gemini - 格式转换使用示例:examples/feature_extract/run.py
职责:加载和处理 .prompt 文件,支持多模态消息构建
文件格式:
---
model: gemini-2.5-flash
temperature: 0.3
---
$system$
系统提示...
$user$
用户提示:%variable%
核心功能:
$section$ 分节语法%variable% 参数替换实现:
agent/llm/prompts/loader.py:load_prompt() - 文件解析agent/llm/prompts/loader.py:get_message() - 参数替换agent/llm/prompts/wrapper.py:SimplePrompt - Prompt 包装器使用:
prompt = SimplePrompt("task.prompt")
messages = prompt.build_messages(text="...", images="img.png")
分类:
| 类型 | 加载位置 | 加载时机 |
|---|---|---|
| Core Skill | System Prompt | Agent 启动时自动 |
| 普通 Skill | 对话消息 | 模型调用 skill 工具时 |
目录结构:
./agent/skills/
├── core.md # Core Skill(自动加载到 System Prompt)
└── browser_use/ # 普通 Skill(按需加载到对话消息)
├── browser-use.md
├── setup.py
└── __init__.py
Core Skill(agent/skills/core.md):
普通 Skill:通过 skill 工具动态加载
# Agent 运行时调用
await tools.execute("skill", {"skill_name": "browser-use"})
# 内容注入到对话历史
实现:
agent/memory/skill_loader.py:SkillLoader - Markdown 解析器agent/memory/skill_loader.py:load_skills_from_dir() - Skills 自动加载(内置 + 自定义)agent/tools/builtin/skill.py:skill() - skill 工具实现agent/tools/builtin/skill.py:list_skills() - 列出可用 skills详细文档:参考 docs/skills.md
存储:PostgreSQL + pgvector
CREATE TABLE experiences (
exp_id TEXT PRIMARY KEY,
scope TEXT, -- "agent:executor" 或 "user:123"
condition TEXT, -- "当遇到数据库连接超时"
rule TEXT, -- "增加重试次数到5次"
evidence JSONB, -- 证据(step_ids)
source TEXT, -- "execution", "feedback", "manual"
confidence FLOAT,
usage_count INT,
success_rate FLOAT,
embedding vector(1536), -- 向量检索
created_at TIMESTAMP,
updated_at TIMESTAMP
);
检索和注入:
# 1. 检索相关 Experiences
experiences = await db.query(
"""
SELECT condition, rule, success_rate
FROM experiences
WHERE scope = $1
ORDER BY embedding <-> $2
LIMIT 10
""",
f"agent:{agent_type}",
embed(task)
)
# 2. 注入到 system prompt
system_prompt = base_prompt + "\n\n# Learned Experiences\n" + "\n".join([
f"- When {e.condition}, then {e.rule} (success rate: {e.success_rate:.1%})"
for e in experiences
])
实现:agent/memory/stores.py:ExperienceStore(待实现 PostgreSQL 版本)
class TraceStore(Protocol):
async def save(self, trace: Trace) -> None: ...
async def get(self, trace_id: str) -> Trace: ...
async def add_message(self, message: Message) -> None: ...
async def get_messages(self, trace_id: str) -> List[Message]: ...
async def get_messages_by_goal(self, trace_id: str, goal_id: str) -> List[Message]: ...
class ExperienceStore(Protocol):
async def search(self, scope: str, query: str, limit: int) -> List[Dict]: ...
async def add(self, exp: Dict) -> None: ...
async def update_stats(self, exp_id: str, success: bool) -> None: ...
class SkillLoader(Protocol):
async def scan(self) -> List[str]: # 返回 skill names
"""扫描并返回所有可用的 skill 名称"""
async def load(self, name: str) -> str: # 返回内容
"""加载指定 skill 的 Markdown 内容"""
实现:
agent/execution/protocols.pyagent/memory/protocols.py实现策略:
FileSystemTraceStore - 文件持久化(支持跨进程)agent/
├── __init__.py # 公开 API
│
├── core/ # 核心引擎
│ ├── runner.py # AgentRunner
│ └── config.py # AgentConfig, CallResult
│
├── execution/ # 执行追踪
│ ├── models.py # Trace, Message
│ ├── protocols.py # TraceStore
│ ├── fs_store.py # FileSystemTraceStore
│ ├── api.py # RESTful API(DAG 视图)
│ └── websocket.py # WebSocket
│
├── memory/ # 记忆系统
│ ├── models.py # Experience, Skill
│ ├── protocols.py # MemoryStore, StateStore
│ ├── stores.py # 存储实现
│ └── skill_loader.py # Skill 加载器(自动加载内置 skills)
│
├── tools/ # 工具系统
│ ├── registry.py # ToolRegistry
│ ├── models.py # ToolResult, ToolContext
│ ├── schema.py # SchemaGenerator
│ ├── url_matcher.py # URL 模式匹配
│ ├── sensitive.py # 敏感数据处理
│ ├── builtin/ # 核心工具
│ ├── advanced/ # 高级工具
│ └── adapters/ # 外部集成
│
├── llm/ # LLM 相关
│ ├── gemini.py
│ ├── openrouter.py
│ └── prompts/
│ ├── loader.py
│ └── wrapper.py
│
├── skills/ # 内置 Skills(自动加载)
│ └── core.md # 核心 skill,每次运行自动加载
│
└── subagents/ # Sub-agent
详见 设计决策文档
核心决策:
Skills 通过工具加载(vs 预先注入)
Skills 用文件系统(vs 数据库)
Experiences 用数据库(vs 文件)
Context 管理:GoalTree + Message + DAG 可视化
docs/context-management.md开发调试时可通过 API 查看 DAG 可视化:
# 启动 API Server
python api_server.py
# 查看 DAG
curl http://localhost:8000/api/traces/{trace_id}/dag
实现:agent/execution/api.py
详见 测试指南
测试分层:
运行测试:
# 单元测试
pytest tests/ -v -m "not e2e"
# 覆盖率
pytest --cov=agent tests/ -m "not e2e"
# E2E 测试(可选)
GEMINI_API_KEY=xxx pytest tests/e2e/ -v -m e2e
| 概念 | 定义 | 存储 | 实现 |
|---|---|---|---|
| Trace | 一次任务执行 | 文件系统(JSON) | execution/models.py |
| Message | 执行消息(对应 LLM 消息) | 文件系统(JSON) | execution/models.py |
| GoalTree | 层级执行计划 | goal.json | goal/models.py |
| Goal | 计划中的目标节点 | 嵌套在 GoalTree 中 | goal/models.py |
| Sub-Agent | 专门化的子代理 | 独立 Trace | tools/builtin/task.py |
| AgentDefinition | Agent 类型定义 | 配置文件/代码 | subagents/ |
| Skill | 能力描述(Markdown) | 文件系统 | memory/skill_loader.py |
| Experience | 经验规则(条件+规则) | 数据库 + 向量 | memory/stores.py |
| Tool | 可调用的函数 | 内存(注册表) | tools/registry.py |
| Agent Loop | ReAct 循环 | - | core/runner.py |
| Doom Loop | 无限循环检测 | - | core/runner.py |