# Reson Agent 可扩展的 Agent 框架。支持多步工具调用、计划管理、子 Agent 协作、回溯重跑和上下文压缩。 ## Quick Start ```bash pip install -r requirements.txt # 配置 LLM API Key cp .env.example .env # 编辑填入 API Key ``` ### 最小示例 ```python import asyncio from agent import AgentRunner, RunConfig from agent.trace import FileSystemTraceStore from agent.llm import create_openrouter_llm_call runner = AgentRunner( trace_store=FileSystemTraceStore(base_path=".trace"), llm_call=create_openrouter_llm_call(model="anthropic/claude-sonnet-4.5"), ) async def main(): async for item in runner.run( messages=[{"role": "user", "content": "列出当前目录的文件"}], config=RunConfig(model="anthropic/claude-sonnet-4.5"), ): print(item) asyncio.run(main()) ``` ## 自定义工具 用 `@tool` 装饰器注册。`RunConfig(tools=None)`(默认)时所有已注册工具自动对 LLM 可用,无需额外配置。 ```python from agent import tool, ToolResult @tool(description="查询产品库存") async def check_inventory(product_id: str, warehouse: str = "default") -> ToolResult: """查询指定仓库的产品库存 Args: product_id: 产品唯一标识符 warehouse: 仓库编码,默认为主仓库 """ stock = await query_db(product_id, warehouse) return ToolResult(output=f"库存: {stock}") # 确保此模块在 runner.run() 之前被 import ``` **注意**: `@tool` 通过副作用注册到全局 registry,必须确保定义工具的模块在调用 `runner.run()` 前被 import。 ### 参数 Schema 生成 框架从函数签名和 docstring 自动生成 OpenAI Tool Schema,无需手写 JSON: - **参数类型**:从类型注解推断(`str`/`int`/`float`/`bool`/`list`/`dict`,支持 `Optional`、`Literal`、`List[T]`) - **参数描述**:从 Google 风格 docstring 的 `Args:` 段提取 - **必填/可选**:有默认值的参数为可选,否则为必填 - **工具描述**:优先使用 `@tool(description=...)` 参数,其次取 docstring 首行 - `uid` 和 `context` 参数由框架自动注入,不会出现在 Schema 中 上面的 `check_inventory` 会生成: ```json { "type": "function", "function": { "name": "check_inventory", "description": "查询产品库存", "parameters": { "type": "object", "properties": { "product_id": {"type": "string", "description": "产品唯一标识符"}, "warehouse": {"type": "string", "description": "仓库编码,默认为主仓库", "default": "default"} }, "required": ["product_id"] } } } ``` ### 限制工具范围 ```python # 只启用指定工具(在内置工具基础上追加) config = RunConfig(tools=["check_inventory", "another_tool"]) ``` ## 自定义 Skills Skills 是 Markdown 文件,提供领域知识,注入到 system prompt。 ``` my_project/ └── skills/ └── my_domain.md ``` ```markdown --- name: my-domain-skill description: 领域专属知识 --- ## Guidelines - 规则 1 - 规则 2 ``` ```python runner = AgentRunner( llm_call=..., trace_store=..., skills_dir="./skills", # 指向你的 skills 目录 ) ``` 内置 skills(`agent/memory/skills/`)始终自动加载,`skills_dir` 的内容额外追加。 ## 经验系统(Experience System) 经验系统通过**提取、注入、反馈、更新**四个环节,让 Agent 从历史执行中学习并持续改进。 ### 核心流程 **1. 提取(Extract)** - **触发时机**:Level 2 压缩时自动触发 - **提取方式**:在压缩历史消息前,先调用 LLM 对当前执行过程进行反思(reflect) - **输出格式**:ACE 规范经验条目 ``` 当 [条件/Context] 时,应该 [动作/Action](原因:[逻辑/Reason]) ``` - **存储位置**:追加到 `experiences.md` 文件(默认 `./.cache/experiences.md`) **2. 注入(Inject)** - **触发时机**:切换 Goal 时自动触发 - **检索策略**:两阶段检索 - Stage 1: 语义路由(LLM 挑选 2*k 个相关经验) - Stage 2: 质量精排(根据 metrics 筛选最终 k 个) - **注入方式**:将检索到的经验注入到主 Agent 的上下文中 **3. 反馈(Feedback)** - **触发时机**:压缩时分析历史消息中经验的使用效果 - **评价维度**: - `helpful`: 经验有效,帮助完成任务 - `harmful`: 经验误导,导致错误 - `mixed`: 部分有效,需要改进 - **反馈来源**:LLM 分析执行过程中经验的实际效果 **4. 更新(Update)** - **Metrics 更新**:根据反馈调整 `helpful` 和 `harmful` 计数 - **内容进化**: - `helpful` + 有改进建议 → 触发经验重写(evolve) - `harmful` 累积 → 降低检索权重或标记为有害 - **质量过滤**:检索时自动过滤 `quality_score < -2` 的有害经验 ### 经验文件格式 ```markdown --- id: ex_02271430_a3f2 trace_id: 6822d4e0-8aeb-449f-962e-c431c409a5a0 tags: {intent: [解构, 图片分析], state: [多图]} metrics: {helpful: 3, harmful: 0} created_at: 2026-02-27 14:30:15 updated_at: 2026-02-27 15:20:42 --- 当需要分析多张图片时,应该先并行读取所有图片再统一分析(原因:避免重复调用 LLM,节省 token 和时间)。 ``` ### 经验库瘦身 `experience.py` 中提供 `slim_experiences()` 函数,可调用顶级 LLM 合并语义相似的经验,减少冗余。 **功能**: - 识别并合并语义高度相似的经验 - 保留 helpful 最高的 ID - 合并 metrics(helpful/harmful 取各条之和) - 保持 ACE 规范格式 **状态**:已实现但暂未自动调用,可在 `analyze_story/run.py` 的交互菜单中手动触发(选项 7)。 ### 配置 ```python runner = AgentRunner( llm_call=..., trace_store=..., experiences_path="./.cache/experiences.md", # 自定义经验文件路径 ) ``` ## AgentRunner 参数 ```python AgentRunner( llm_call, # 必需:LLM 调用函数 trace_store=None, # Trace 持久化(推荐 FileSystemTraceStore) tool_registry=None, # 工具注册表(默认:全局 registry) skills_dir=None, # 自定义 skills 目录 experiences_path="./.cache/experiences.md", # 经验文件路径 memory_store=None, # 记忆存储 utility_llm_call=None, # 轻量 LLM(生成任务标题等) ) ``` ## RunConfig 参数 ```python RunConfig( model="gpt-4o", # 模型标识 temperature=0.3, max_iterations=200, # Agent loop 最大轮数 tools=None, # None=全部已注册工具,List[str]=内置+指定工具 system_prompt=None, # None=从 skills 自动构建 agent_type="default", # 预设类型:default / explore / analyst trace_id=None, # 续跑/回溯时传入已有 trace ID after_sequence=None, # 从哪条消息后续跑(message sequence) ) ``` ## LLM Providers 框架内置两个 provider: ```python from agent.llm import create_openrouter_llm_call, create_gemini_llm_call # OpenRouter(支持多种模型) llm = create_openrouter_llm_call(model="anthropic/claude-sonnet-4.5") # Google Gemini llm = create_gemini_llm_call(model="gemini-2.5-flash") ``` 自定义 provider 只需实现签名: ```python async def my_llm_call(messages, model, tools, temperature, **kwargs) -> dict: # 调用你的 LLM return { "content": "...", "tool_calls": [...] or None, "prompt_tokens": 100, "completion_tokens": 50, "cost": 0.001, "finish_reason": "stop", } ``` ## API Server ```bash python api_server.py ``` | 方法 | 路径 | 说明 | |------|------|------| | GET | `/api/traces` | 列出 Traces | | GET | `/api/traces/{id}` | Trace 详情 | | GET | `/api/traces/{id}/messages` | 消息列表 | | POST | `/api/traces` | 新建并执行 | | POST | `/api/traces/{id}/run` | 续跑/回溯 | | POST | `/api/traces/{id}/stop` | 停止 | | WS | `/api/traces/{id}/watch` | 实时事件 | 需在 `api_server.py` 中配置 Runner 才能启用 POST 端点。 ## 项目结构 ``` agent/ ├── core/ # AgentRunner + 预设 ├── tools/ # 工具系统(registry + 内置工具) ├── trace/ # 执行追踪 + 计划(GoalTree)+ API ├── memory/ # Skills + Experiences └── llm/ # LLM Provider 适配 ``` 详细架构文档:[docs/README.md](./docs/README.md)