From d481b3d88cf00362a825a0f20e66920a03f08ed0 Mon Sep 17 00:00:00 2001 From: lky-spec Date: Mon, 27 Apr 2026 10:51:09 +0800 Subject: [PATCH] Remove local-only agent artifacts --- .gitignore | 4 + AGENT_IMPLEMENTATION_SPEC.md | 167 ---- agents.md | 159 --- docs/agent-skills/diagnostic-skills.zh-CN.md | 203 ---- .../AGENT_ARCHITECTURE_STATUS.zh-CN.md | 926 ------------------ .../AGENT_CURRENT_DESIGN.zh-CN.md | 613 ------------ .../architecture/AGENT_MEMORY_AND_PLANNING.md | 454 --------- .../AGENT_MEMORY_AND_PLANNING.zh-CN.md | 453 --------- .../AGENT_SKILL_ACCEPTANCE_CHECKLIST.zh-CN.md | 272 ----- .../fixtures/agent_self_play_seed.zh-CN.json | 38 - web/node_modules | 1 - 11 files changed, 4 insertions(+), 3286 deletions(-) delete mode 100644 AGENT_IMPLEMENTATION_SPEC.md delete mode 100644 agents.md delete mode 100644 docs/agent-skills/diagnostic-skills.zh-CN.md delete mode 100644 docs/architecture/AGENT_ARCHITECTURE_STATUS.zh-CN.md delete mode 100644 docs/architecture/AGENT_CURRENT_DESIGN.zh-CN.md delete mode 100644 docs/architecture/AGENT_MEMORY_AND_PLANNING.md delete mode 100644 docs/architecture/AGENT_MEMORY_AND_PLANNING.zh-CN.md delete mode 100644 docs/qa/AGENT_SKILL_ACCEPTANCE_CHECKLIST.zh-CN.md delete mode 100644 docs/qa/fixtures/agent_self_play_seed.zh-CN.json delete mode 120000 web/node_modules diff --git a/.gitignore b/.gitignore index 89880c2a..a487ae58 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ decision_logs/ nofx_test # Node.js +web/node_modules web/node_modules/ node_modules/ web/dist/ @@ -52,6 +53,9 @@ web/.vite/ # ESLint 临时报告文件(调试时生成,不纳入版本控制) eslint-*.json +# 本地 Agent QA seed(个人调试用,不纳入版本控制) +docs/qa/fixtures/agent_self_play_seed.zh-CN.json + # VS code .vscode diff --git a/AGENT_IMPLEMENTATION_SPEC.md b/AGENT_IMPLEMENTATION_SPEC.md deleted file mode 100644 index 8f1a3490..00000000 --- a/AGENT_IMPLEMENTATION_SPEC.md +++ /dev/null @@ -1,167 +0,0 @@ -# AGENT Implementation Spec - -## Goal -重构 Agent 的主循环逻辑:将意图识别、快照管理、字段提取完全交给 LLM 驱动。建立“任务栈”管理机制,确保跨 Skill、中途换话题、回填参数等复杂场景下的状态一致性,并由 DAG 自动化完成执行逻辑。 - -## 1. Core Principles - -### 1.1 必须遵守 -- 大脑前置:每一轮用户输入必须先经过意图识别,禁止规则层先于模型层截断复合语义。 -- 快照优先:LLM 必须感知当前及历史快照(Snapshot/Reference),优先判断输入是否属于对已有任务的续接。 -- DAG 驱动执行:Skill Handler 仅负责原子操作,复杂的逻辑依赖、顺序、确认由 LLM 生成的 DAG 任务包驱动执行。 - -### 1.2 明确禁止 -- 禁止静默失败:参数越界或逻辑冲突时,必须通过 LLM 反馈给用户原因,禁止直接丢弃输入。 -- 禁止单向路由:禁止在单次意图识别中只认一个 Action,必须支持多 Action 列表化输出。 - -## 2. Intent Handling - -### 2.1 总入口 -所有用户输入都必须先经过统一意图识别: -- [x] 是 - -统一意图识别需要判断以下结果: -- [x] `continue` -说明:续接当前快照。 -- [x] `switch` -说明:开启新快照或切换到历史快照。 -- [x] `cancel` -说明:明确取消当前任务。 -- [x] `instant_reply` -说明:直接回答,无需进入快照流转。 - -### 2.2 由谁判断 -意图识别主要由以下方式负责: -- [x] 大模型 - -### 2.3 当前 Flow 中的输入 -`continue`: -- 用户提供了缺失字段。 -- 用户对配置表示确认,例如“OK”“建吧”。 -- 用户对已有配置进行微调。 - -`switch`: -- 用户输入了与当前快照领域无关的新需求。 -- 例如正在调策略时突然要查余额。 -- 例如正在配置一个模型时突然要求配置另一个模型。 - -`cancel`: -- 用户表达了明确的负面意图。 -- 例如“算了”“不要了”“重来”。 - -## 3. Slot Extraction / Field Extraction - -### 3.1 抽取方式 -字段抽取主要由以下方式负责: -- [x] 大模型 - -如果由大模型负责,抽取时必须输入以下上下文: -- [x] 当前 `skill/action` -- [x] 当前 `draft/session` -- [x] 当前缺失字段(来自 DAG 定义) -- [x] 历史对话(近 3 轮) -- [x] 快照 / 当前引用 - -### 3.2 输出格式 -期望大模型返回如下结构化 JSON: - -```json -{ - "intent": "continue | switch | cancel", - "target_snapshot_id": "uuid-xxxx", - "tasks": [ - { - "skill": "strategy", - "action": "create", - "fields": { - "leverage": 20, - "name": "my_strat" - } - } - ], - "reason": "用户提供了杠杆倍数,继续策略创建流程" -} -``` - -### 3.3 合并策略 -- 补全模式:新抽取的字段 merge 到原快照中。 -- 覆盖模式:若用户明确修改已存在的值,以最新输入为准,但必须经过 Validator 重新校验。 - -## 4. Flow / State Machine - -### 4.1 统一状态机 -所有 flow 必须统一走同一个 orchestrator: -- [x] 是 - -Flow 状态至少包含: -- [x] `collecting` -说明:字段收集中。 -- [x] `waiting_confirmation` -说明:待用户确认。 -- [x] `ready` -说明:校验通过。 -- [x] `executing` -说明:DAG 执行中。 -- [x] `suspended` -说明:被新任务压栈挂起。 - -### 4.2 Switch / Suspend / Resume -用户切换话题时,当前任务应该: -- [x] 压栈 -说明:放入 History Snapshots 栈,支持后续唤回。 - -## 5. Skill Scope - -### 5.1 适用范围 -这套方法模式适用于: -- [x] 全部 -说明:实现全架构的语义编排。 - -### 5.2 不允许单独补丁 -是否禁止只针对单个 skill / 单句子打补丁: -- [x] 是 - -补充说明: -- 必须保证所有 Skill 共享同一套 Router 和快照机制。 - -## 6. Risk Control / Validation - -### 6.1 校验层 -字段抽取后必须统一进入 validator: -- [x] 是 - -validator 需要覆盖: -- [x] `strategy` 数值限制(Clamp) -- [x] `model` 配置合法性 -- [x] `exchange` 凭证合法性 -- [x] `trader` 绑定关系合法性 - -### 6.2 错误提示 -- 提示原则:LLM 解析校验失败结果,用自然语言告知用户安全范围。 -- 示例:`杠杆最高 20 倍,已为您设为 20,是否接受?` - -## 7. Performance - -### 7.1 调用策略 -- 流式响应:意图识别确定后,第一时间返回“正在处理[某意图]...”,减少用户感知延迟。 -- LLM Cache:对高频重复意图进行缓存。 - -### 7.2 快路径 -允许不用大模型直接返回的场景: -- 简单打招呼,例如 `Hi`、`Hello` -- 完全匹配的单词退出指令,例如 `exit`、`quit` - -## 8. Testing / Acceptance - -### 8.1 必测场景 -- 意图切换:正在创建策略时,询问“比特币价格”,查完后回答“继续创建刚才的策略吗”并成功恢复快照。 -- 多动作合并:一句话同时完成“创建策略 A”和“配置交易所 B”。 -- 纠错重填:用户输入了错误的杠杆倍数,系统提示纠正后,用户补填正确数值,系统能正确合并到原快照。 - -### 8.2 验收标准 -- 无静默吞咽:任何有效信息必须体现在快照更新或回复中。 -- 快照一致性:`CurrentReferences` 必须能精准映射到用户口中的“它”或“那个策略”。 - -## 9. Notes -- 快照快照还是快照:代码底层必须实现一个 `SnapshotManager`,支持 `Save/Load/List` 动作,供 LLM 通过特定的内部 Tool 进行调用。 -- DAG 是约束而非死板流程:DAG 告诉 LLM 缺什么,但 LLM 决定如何通过对话向用户要到这些。 diff --git a/agents.md b/agents.md deleted file mode 100644 index f0096928..00000000 --- a/agents.md +++ /dev/null @@ -1,159 +0,0 @@ -# NOFXi Agent 实现状态文档 - -> 更新时间:2026-04-23 - ---- - -## 一、架构概述 - -ReAct 模式:LLM 做意图识别和路由,代码执行具体 skill action。 - -### 主要流程 - -``` -用户消息 - → tryOnePassSemanticGateway(快速单次 LLM 路由) - 命中 → 直接执行 - 未命中 → tryLLMIntentRoute(完整 LLM 路由) - → skill(单个结构化操作) - → workflow(多步骤跨 skill 操作) - → planner(复杂/模糊请求) -``` - -### Intent 类型 - -| Intent | 含义 | -|--------|------| -| `continue_active` | 继续当前激活流程 | -| `resume_snapshot` | 恢复某个挂起快照 | -| `start_new` | 开启新的顶层请求 | -| `cancel` | 取消当前流程 | -| `instant_reply` | 纯聊天,不触发任务 | - ---- - -## 二、Skill 体系 - -### 4 个 Management Skills - -#### trader_management -- **触发:** 用户提到"交易员/trader/agent" + 操作动词 -- **创建必填:** name、exchange_id、ai_model_id、strategy_id -- **字段约束:** - - `name`:最多 50 字符 - - `scan_interval_minutes`:3~60 分钟,超出自动收敛 - - `initial_balance`:最低 100,超出自动收敛 - - `is_cross_margin`:bool,默认 true(全仓) - - `show_in_competition`:bool,默认 false - - `auto_start`:bool,默认 false -- **支持操作:** create、update、update_name、update_bindings、configure_strategy、configure_exchange、configure_model、start(需确认)、stop(需确认)、delete(需确认)、query_list、query_running、query_detail - -#### exchange_management -- **触发:** 用户提到交易所名称 + 操作动词 -- **创建必填(按交易所):** - -| 交易所 | 必填字段 | -|--------|---------| -| binance / bybit / gate | api_key、secret_key | -| okx / kucoin | api_key、secret_key、passphrase | -| hyperliquid | hyperliquid_wallet_addr | -| aster | aster_user、aster_signer、aster_private_key | -| lighter | lighter_wallet_addr、lighter_api_key_private_key | - -- **其他约束:** - - `api_key`:至少 8 位字母数字 - - `secret_key`:至少 8 位字母数字或十六进制 - - `lighter_api_key_index`:0~255,超出自动收敛 - - `testnet`:bool,默认 false -- **支持操作:** create、update、update_name、update_status、delete(需确认)、query_list、query_detail - -#### model_management -- **触发:** 用户提到模型/provider 名称 + 操作动词 -- **支持 provider:** openai、deepseek、claude、gemini、qwen、kimi、grok、minimax、claw402、blockrun-base -- **字段约束:** - - `api_key`:OpenAI 必须以 `sk-` 开头 - - `custom_api_url`:必须是合法 HTTPS 地址 - - `enabled=true` 前必须填写 api_key 和 custom_model_name -- **支持操作:** create、update、update_status、update_endpoint、update_name、delete(需确认)、query_list、query_detail - -#### strategy_management -- **触发:** 用户提到"策略/strategy" + 操作动词 -- **字段约束:** - - `btceth_max_leverage`:1~20,超出自动收敛 - - `altcoin_max_leverage`:1~20,超出自动收敛 - - `min_confidence`:0~100,超出自动收敛 - - `grid_count`:最小 2 - - `lower_price` 必须小于 `upper_price` - - 策略模板**不能直接启动**,只有绑定了该策略的交易员才能启动 -- **支持操作:** create、update、update_name、update_prompt、update_config、activate、duplicate、delete(需确认)、query_list、query_detail - -### 4 个 Diagnosis Skills - -- `trader_diagnosis`:交易员启动失败、未下单、收益异常等诊断 -- `exchange_diagnosis`:invalid signature、timestamp、权限不足等诊断 -- `model_diagnosis`:模型调用失败、接口不兼容、鉴权错误等诊断 -- `strategy_diagnosis`:策略不生效、参数不一致等诊断 - ---- - -## 三、LLM 收到的 Prompt 内容 - -路由阶段 LLM 收到: -1. Skill 摘要(名称、描述、创建必填) -2. Skill 禁止规则(各 skill 不能做什么) -3. 近期对话上下文 -4. 当前任务状态 -5. 当前激活流程摘要 + JSON -6. 当前引用摘要 -7. 执行状态 JSON -8. 挂起快照 JSON - -> 注意:`buildManagementSkillContext(lang, nil)` 传 nil,active skill 的 dynamic_rules 不会注入路由 LLM。 - ---- - -## 四、Snapshot / Resume 机制 - -- `SnapshotManager.Save(task)` 压栈挂起任务 -- `task.ResumeOnSuccess = true` + `task.ResumeTriggers` 控制子任务完成后自动回流 -- `maybeResumeParentTaskAfterSuccessfulSkill` 在子任务成功后检查栈,自动恢复父任务 - ---- - -## 五、本次改动记录(2026-04-23) - -### 1. 4 个 skill JSON 补全字段约束 - -文件:`agent/skills/*.json` - -- `trader_management.json`:补全 field_constraints、validation_rules、完整 actions -- `exchange_management.json`:补全各交易所必填字段、per_exchange_required_fields -- `model_management.json`:补全 provider 枚举、API key 格式、HTTPS 校验 -- `strategy_management.json`:补全杠杆/置信度/网格约束,修复中文弯引号 JSON 错误 - -### 2. 路由层加 inline_sub_intent - -文件:`agent/llm_skill_router.go` - -- `llmSkillRouteDecision` 和 `onePassGatewayDecision` 加 `InlineSubIntent` 字段 -- 两个 gateway 的 JSON shape 加 `inline_sub_intent` -- Rules 加:configure_strategy/exchange/model 流程里用户想新建依赖资源时,判断 `continue_active` + `inline_sub_intent=create_sub_resource` -- `continue_active` 分支把 `inline_sub_intent` 写入 session fields - -### 3. 执行层消费 inline_sub_intent - -文件:`agent/skill_execution_handlers.go` - -- `configure_strategy/exchange/model` 分支检测到 `inline_sub_intent=create_sub_resource` 时: - 1. 压栈当前 session(`ResumeOnSuccess=true`) - 2. 切换到对应子任务(strategy/exchange/model create) - 3. 子任务完成后自动回流父任务 - ---- - -## 六、已知问题 - -| 问题 | 状态 | -|------|------| -| 创建交易员时直接用现有配置,未询问用户确认 | 未修复 | -| 路由 LLM 缺 active session context(buildManagementSkillContext 传 nil) | 未修复 | diff --git a/docs/agent-skills/diagnostic-skills.zh-CN.md b/docs/agent-skills/diagnostic-skills.zh-CN.md deleted file mode 100644 index 96607e51..00000000 --- a/docs/agent-skills/diagnostic-skills.zh-CN.md +++ /dev/null @@ -1,203 +0,0 @@ -# NOFXi 诊断与配置 Skills(第一批) - -这份文档用于沉淀交易智能助手的第一批高频诊断与配置 skill。 - -目标不是让模型“更会想”,而是让它面对常见问题时,优先走稳定、可复用的排查路径。 - -## 设计原则 - -- 优先按 skill 回答,不要对高频问题重复自由规划 -- 先归类问题,再给出原因、检查项和修复建议 -- 能通过工具验证当前状态时,先查再下结论 -- 敏感信息只指导填写,不完整回显 -- 对结论不确定时,要明确标注为“更可能”或“优先怀疑” - -## skill_model_api_setup - -### 适用场景 - -- 用户问某个大模型的 API key 去哪里申请 -- 用户问 base URL 怎么填 -- 用户问 model name 怎么填 -- 用户问 OpenAI / Claude / Gemini / DeepSeek / Qwen / Kimi / Grok / MiniMax 怎么接入 - -### 处理策略 - -1. 先确认用户要配置哪个 provider -2. 告诉用户需要准备的最少字段: - - provider - - API key - - custom_api_url - - custom_model_name -3. 如果系统已有默认地址和默认模型名,优先给推荐值 -4. 回答按步骤组织,不要泛泛解释概念 - -### 已知实现事实 - -- 系统内置 provider 默认运行配置,见 `agent.resolveModelRuntimeConfig(...)` -- 常见 provider 已有默认 URL 和默认 model name - -## skill_model_config_diagnosis - -### 适用场景 - -- 模型保存成功但 agent 仍然不可用 -- 提示 AI unavailable -- 提示模型没启用 -- 提示 custom_api_url 不合法 -- 配置后 trader 不生效 - -### 优先排查 - -1. 是否存在已启用模型 -2. API key 是否为空 -3. custom_api_url 是否为合法 HTTPS 地址 -4. custom_model_name 是否为空或不匹配 -5. 当前 trader 是否绑定了这个模型 -6. 更新模型后是否已触发 trader reload - -### 已知实现事实 - -- 非 HTTPS 的 `custom_api_url` 会被后端拒绝,见 `api/handler_ai_model.go` -- 已启用模型如果缺少 API Key 或 URL,会导致 agent 无法就绪,见 `agent.ensureAIClientForStoreUser(...)` -- 更新模型配置后,系统会尝试移除并重载相关 trader,使新配置立即生效 - -### 输出格式 - -- 现象 -- 更可能原因 -- 先检查什么 -- 下一步怎么修复 - -## skill_exchange_api_setup - -### 适用场景 - -- 用户要新建交易所 API -- 用户不知道交易所需要哪些权限 -- 用户问 API key / secret / passphrase 分别填什么 - -### 通用处理策略 - -1. 先确认交易所类型 -2. 告知必须权限与禁止权限 -3. 告知是否需要额外字段 -4. 强调 IP 白名单与权限配置 -5. 引导用户回到系统内完成绑定 - -### 特殊规则 - -- OKX 除 API Key 和 Secret 外,还需要 passphrase -- Bybit 永续/合约交易需要合约权限 -- 不建议开启提现权限 - -### 参考文档 - -- `docs/getting-started/okx-api.md` -- `docs/getting-started/bybit-api.md` - -## skill_exchange_api_diagnosis - -### 适用场景 - -- `invalid signature` -- `timestamp` 错误 -- `IP not allowed` -- `permission denied` -- 交易所连接不上 - -### 优先排查 - -1. 系统时间是否同步 -2. API Key / Secret 是否正确 -3. 是否遗漏额外字段,如 OKX passphrase -4. IP 白名单是否包含当前服务器 -5. 是否启用了交易或合约权限 -6. 密钥是否过期或已重建 - -### 已知实现事实 - -- 时间不同步是 `invalid signature` / `timestamp` 的高频根因,见 `docs/guides/TROUBLESHOOTING.zh-CN.md` -- OKX 的 passphrase 缺失会导致签名相关问题,见 `docs/getting-started/okx-api.md` - -### 输出格式 - -- 报错现象 -- 最常见根因 -- 优先检查顺序 -- 修复步骤 - -## skill_trader_start_diagnosis - -### 适用场景 - -- trader 启动不了 -- trader 启动了但没开始交易 -- 页面显示已启动但一直没有动作 -- 用户怀疑 strategy / model / exchange 绑定有问题 - -### 优先排查 - -1. 是否有已启用的模型配置 -2. 是否有已启用的交易所配置 -3. trader 是否绑定了 exchange_id / strategy_id / ai_model_id -4. 交易所余额和权限是否满足下单条件 -5. AI 最近的决策到底是 wait、hold 还是下单失败 - -### 回答原则 - -- 要区分“没启动”“启动了但 AI 选择不交易”“尝试下单但失败”这三类 -- 不要把“没开仓”直接等同于“系统故障” - -## skill_order_execution_diagnosis - -### 适用场景 - -- 下单失败 -- 只开空不开户 / 只开单边 -- 杠杆报错 -- position side mismatch - -### 优先排查 - -1. 账户模式是否匹配,例如 Binance 是否为 Hedge Mode -2. 是否为子账户杠杆限制 -3. 合约权限是否开启 -4. 余额、保证金、可交易 symbol 是否满足条件 - -### 已知实现事实 - -- Binance 在 One-way Mode 下,可能出现 `position side mismatch` 或单边行为 -- 某些子账户杠杆上限较低,超过限制会直接失败 -- 这些问题在 `docs/guides/TROUBLESHOOTING.md` 已有明确说明 - -## skill_strategy_diagnosis - -### 适用场景 - -- 用户说策略没生效 -- 用户说 prompt 预览和实际不一致 -- 用户说修改策略后 trader 行为没有变化 - -### 优先排查 - -1. 当前编辑的是策略模板,还是 trader 的 custom prompt -2. 策略是否真的保存成功 -3. 是否需要重新读取当前配置做对比 -4. 用户说的“没生效”是指未保存、未绑定,还是运行结果与预期不一致 - -### 回答原则 - -- 先明确“对象”再排查:strategy template / trader / prompt override -- 如果能读取当前保存值,就不要凭印象判断 - -## 后续扩展方向 - -下一批可以继续补: - -- `skill_balance_and_position_diagnosis` -- `skill_market_data_diagnosis` -- `skill_prompt_generation_diagnosis` -- `skill_strategy_test_run_diagnosis` -- `skill_exchange_specific_setup_` -- `skill_model_provider_setup_` diff --git a/docs/architecture/AGENT_ARCHITECTURE_STATUS.zh-CN.md b/docs/architecture/AGENT_ARCHITECTURE_STATUS.zh-CN.md deleted file mode 100644 index 262df8a8..00000000 --- a/docs/architecture/AGENT_ARCHITECTURE_STATUS.zh-CN.md +++ /dev/null @@ -1,926 +0,0 @@ -# NOFXi Agent 架构现状说明 - -本文档说明当前 `nofxi-dev/agent` 的整体设计、关键执行链路、内存与快照机制、skill 协作方式,以及这套实现是怎么逐步收成现在这个样子的。 - -适用范围: -- `nofxi-dev/agent` -- 与 Agent 强相关的 tool / store / workflow / frontend chat 行为 - -## 1. 当前目标 - -当前 Agent 的目标不是“单轮问答机器人”,而是一个可持续管理配置、跨多轮续接、可在多个对象之间切换上下文的任务型 Agent。 - -核心要求有 4 个: - -1. 用户一句模糊话,也要先判断是在继续当前任务、切回旧任务、开新任务,还是取消。 -2. `model / exchange / trader / strategy` 四个 management skill 都要能被统一路由、统一理解、统一执行。 -3. 用户说的是名称,系统执行的是 ID,中间必须有稳定映射。 -4. 快照、当前引用对象、最近对话、执行状态,不能只是“存着”,而要真的被 LLM 当成决策输入。 - ---- - -## 2. 顶层执行链路 - -当前主入口在: -- [planner_runtime.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/planner_runtime.go:820) - -整体顺序是: - -1. `tryLLMIntentRoute` -2. `tryStatePriorityPath` -3. `tryInstantDirectReply` -4. `tryReadFastPath` -5. `tryHardSkill` -6. `runPlannedAgent` - -也就是说,现在系统优先做“统一语义判断”,然后才看 active flow、direct reply、hard skill 和 planner。 - -### 2.1 统一语义网关 - -顶层语义网关在: -- [llm_skill_router.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/llm_skill_router.go:25) - -LLM 目前先判断一条消息属于哪种 intent: - -- `continue_active` -- `resume_snapshot` -- `start_new` -- `cancel` -- `instant_reply` - -如果是 `start_new`,再继续判断 route: - -- `skill` -- `workflow` -- `planner` - -这层的意义是:先判断“这句话在和哪个上下文说话”,再判断“具体怎么做”。 - -### 2.2 顾问式系统前缀 - -现在统一语义网关和 Planner 共享同一份顾问式系统前缀,而不再只是“路由器”或“计划器”口吻。 - -这份前缀的核心基调是: - -- 你是 NOFX 的核心智能中枢 `NOFXi` -- 你的首要目标不是盲目执行命令 -- 你需要以资深量化顾问身份,确保每一次配置都正确、安全且符合逻辑 -- 当用户遇到问题时,你要结合当前状态和平台边界主动诊断,并给出具体解决方案 - -统一前缀已经抽成共享 helper: -- [prompt_persona.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/prompt_persona.go) - -当前已注入: - -- 顶层统一语义网关 -- `one-pass` 统一语义网关 -- planner -- replanner - -这样做的目的,是让“理解用户意图”和“后续制定执行计划”都遵守同一套顾问式人格、安全边界和诊断基调。 - -### 2.3 兼容式 One-Pass JSON 网关 - -为了减少 `router -> classifier -> extractor` 的串行 LLM 调用次数,当前已经在统一语义网关前面接入了一个兼容式 `One-Pass JSON` 网关: -- [llm_skill_router.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/llm_skill_router.go) - -它会在一次调用里尝试同时输出: - -- `intent` -- `target_skill` -- `target_snapshot_id` -- `extracted_fields` -- `need_planner_help` - -典型返回形状如下: - -```json -{ - "intent": "continue_active", - "target_skill": "trader_management:create", - "target_snapshot_id": "draft_7788", - "extracted_fields": {"leverage": "100"}, - "need_planner_help": false -} -``` - -当前它采用的是“兼容式接入”,不是硬切: - -1. 先尝试 `one-pass` 网关 -2. 如果输出不可用,回退到原有统一语义网关 -3. 原有 `planner / workflow / hard skill` 分层继续保留 - -这意味着系统已经开始减少多次串行 LLM 往返,但不会因为一次新网关输出失误就直接把旧链路全部推翻。 - ---- - -## 3. 状态优先层 - -状态优先层在: -- [planner_runtime.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/planner_runtime.go:954) - -它负责优先处理这些场景: - -- 是否要恢复挂起任务 -- 是否已有 active workflow -- 是否已有 active skill session -- 是否已有 active execution state - -这层不是重新发明语义,而是消费上层已经决定好的“继续当前 / 切回旧快照 / 新开任务”。 - -如果当前有 active skill session,它会进一步进入: - -- `resolveSkillSessionTurn` -- `classifySkillSessionIntentWithLLM` -- `extractSkillSessionFieldsWithLLM` - -如果当前是 execution state,则会尝试: - -- `bridgeExecutionStateToSkillSession` - -这一层的目标,是把“planner 等待态”或者“执行等待态”桥接成真实 skill session,而不是让后续执行时丢上下文。 - ---- - -## 4. 四层上下文 - -当前 Agent 在规划和路由时,主要使用四层上下文: - -1. `Current reference summary` -2. `Execution state JSON` -3. `Recent conversation` -4. `Task state` - -它们现在被显式写进 planner prompt,相关逻辑在: -- [planner_runtime.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/planner_runtime.go:2950) - -当前优先级是: - -1. 当前引用对象 -2. 当前执行状态 -3. 最近对话 -4. 持久化压缩背景 - -这解决的是“明明刚才就在说某个 trader / strategy,但后面又像不认识了一样”的问题。 - ---- - -## 5. CurrentReferences、快照和持久引用记忆 - -### 5.1 CurrentReferences - -`CurrentReferences` 表示当前锁定的对象,例如: - -- 当前 trader -- 当前 model -- 当前 exchange -- 当前 strategy - -它会进入: - -- router prompt -- planner prompt -- active flow classifier -- flow extraction - -相关读取点包括: -- [llm_skill_router.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/llm_skill_router.go:38) -- [planner_runtime.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/planner_runtime.go:2950) -- [llm_flow_extractor.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/llm_flow_extractor.go:73) - -### 5.2 Suspended snapshots - -挂起任务快照用于: - -- 打断当前流程 -- 以后恢复到具体旧流程 -- 让 LLM 在“刚才那个”“前面那个”这种模糊指代下仍能选对上下文 - -快照信息会进入: - -- top-level router -- active flow classifier -- flow extraction - -### 5.3 Persistent reference memory - -现在 `CurrentReferences` 不只存在于 `ExecutionState` 里。 - -新增了持久引用记忆: -- [reference_memory.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/reference_memory.go) - -核心函数: - -- `semanticCurrentReferences` -- `semanticReferenceHistory` -- `rememberReferencesFromToolResult` - -这层的作用是: - -- 即使 `ExecutionState` 被清掉 -- 当前对象记忆仍可延续 -- 后续 follow-up 仍能命中“当前 trader / 当前 strategy” - -### 5.4 DB 活性校验 - -持久化记忆不能被 100% 信任,因为真实对象可能已经被前端或其他入口删除。 - -因此现在在真正执行实体更新前,会先做一次轻量级活性校验: - -- 若当前 `TargetRef` 指向的对象已经不存在 -- 不再盲目继续执行 -- 会清掉失效引用,并要求用户重新指定目标对象 - -这解决的是: - -- Agent 记得“当前策略 A” -- 但真实数据库里的 `Strategy A` 已被网页前端删掉 -- 后续再说“就按当前策略来”时,不会直接拿悬空 ID 去执行 - ---- - -## 6. Skill 体系 - -当前正式 management skill 有四个: - -- `trader_management` -- `exchange_management` -- `model_management` -- `strategy_management` - -Skill 定义的正式来源在: -- [agent/skills/trader_management.json](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/skills/trader_management.json) -- [agent/skills/exchange_management.json](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/skills/exchange_management.json) -- [agent/skills/model_management.json](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/skills/model_management.json) -- [agent/skills/strategy_management.json](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/skills/strategy_management.json) - ---- - -## 7. 统一 skill 上下文:单一真源 - -之前的问题是: - -- skill JSON 有一份简介 -- router prompt 又手写一份 -- workflow prompt 再手写一份 -- classifier / extraction 又各有自己的上下文说明 - -这会导致不同层看到的 skill 描述不一致。 - -现在已经收成统一 helper: -- [skill_registry.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/skill_registry.go) - -关键函数: - -- `buildSkillDefinitionSummary` -- `buildSkillDependencySummary` -- `buildSkillForbiddenSummary` -- `buildManagementSkillContext` - -### 7.1 buildManagementSkillContext - -这是现在 management skill 上下文的统一入口。 - -它输出两类信息: - -1. 四个 management skill 的简要说明 -2. 四个 management skill 的负向约束 -3. 当前 active skill 的依赖说明 - -例如对于 `trader_management:create`,它现在会明确告诉模型: - -- 创建 trader 依赖已启用交易所 -- 依赖已启用模型 -- 依赖可用策略 -- 修复这些依赖时,仍属于 trader create 的主流程 - -同时它也会告诉模型一些“不能做什么”的边界,例如: - -- `model_management` 不负责测试连接和诊断上游错误 -- `exchange_management` 不负责行情和交易执行 -- `strategy_management` 只负责模板管理,不负责直接运行 - -### 7.2 已接入的层 - -这个统一 helper 现在已经接入: - -- [llm_skill_router.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/llm_skill_router.go:39) -- [workflow.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/workflow.go:569) -- [llm_flow_extractor.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/llm_flow_extractor.go:73) -- [planner_runtime.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/planner_runtime.go:2010) -- [planner_runtime.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/planner_runtime.go:2951) - -也就是说,现在 router、workflow、classifier、extraction、planner 使用的是同一套 management skill 说明。 - ---- - -## 7.3 语义就绪检查 - -仅仅把消息路由到某个 skill 还不够,还要判断这条消息在“语义上是否已经准备好进入执行层”。 - -这层现在在: -- [skill_semantic_gate.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/skill_semantic_gate.go) - -关键点: - -- `evaluateHardSkillCandidate` -- `semanticReadinessMissingSlots` -- `skillSemanticReadinessSummary` - -设计目标是: - -- 如果 LLM/规则已经判到某个 skill/action -- 但当前消息还明显缺少核心必填字段 -- 就不要直接往 hard skill 执行层掉 - -例如: - -- 用户说“帮我新建一个模型配置” -- 但还没有 `provider / api_key / custom_model_name` - -这时系统会优先把控制权交给 planner / ask_user,而不是直接返回程序式“缺字段”提示。 - -这样做的价值是: - -- 减少生硬的 hard skill 报错 -- 让交互更像“LLM 正在推进表单” -- 避免路由下坠到执行层后再回滚 - ---- - -## 8. Active flow 内部是怎么继续的 - -如果顶层判断是 `continue_active`,当前消息不会直接执行 tool,而是进入当前 flow 的续接过程。 - -进一步地,当前只要已经进入某个 active `skill:action`,系统会优先沿着当前 action 继续推进。 -旧的 `detectManagementAction / has*Patch / detect*Patch` 这类文本 heuristics 仍然保留,但已经更明确地退到: - -1. 没有 active skill session 时,用于粗路由和兜底识别 -2. active skill session 内,只有在 session/patch 都无法给出结果时,才作为 fallback 参与判断 - -这保证了: - -- 先尊重已经由 LLM 和状态机确定下来的当前 flow -- 再在必要时使用旧 heuristics 补洞 -- 避免“已经在当前 skill 里了,却又被文本规则抢去改 action”的抖动 - -现在 active flow 的打断条件也更收紧了: - -- 单纯在当前 flow 里提到 `model / exchange / strategy` -- 或者在补依赖时顺带提到其他 domain 名词 - -不再默认视为“跳到新任务”。 - -只有当消息整体更像一个新的顶层请求时,跨 domain 提及才会触发中断和重新路由。 - -### 8.1 Skill session 续接 - -相关逻辑: -- [planner_runtime.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/planner_runtime.go:1583) -- [llm_flow_extractor.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/llm_flow_extractor.go:61) - -主要分两步: - -1. `classifySkillSessionIntentWithLLM` - - 判断是继续、取消、打断还是闲聊 -2. `extractSkillSessionFieldsWithLLM` - - 把这条消息抽成结构化字段 - -然后把结构化字段 merge 回当前 skill session。 - -### 8.1.1 对话驱动式 skill 收集 - -对于高价值的多轮 management flow,当前已经开始把“补槽”从代码猜测迁到 LLM 对话驱动器: -- [llm_skill_conversation.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/llm_skill_conversation.go) - -目前最先落地的是: -- `trader_management:create` -- `trader_management:update_bindings` -- `trader_management:configure_strategy` -- `trader_management:configure_exchange` -- `trader_management:configure_model` -- `model_management:update / update_status / update_endpoint / update_name` -- `exchange_management:update / update_status / update_name` -- `strategy_management:update / update_name / update_prompt / update_config / activate / duplicate` - -这层的设计目标不是“让代码先把用户的话拆碎”,而是: - -1. 先由 LLM 理解当前这句话在当前 flow 里到底是什么意思 -2. 再按需披露当前 `skill:action` 的规则书 -3. 再按当前缺失槽位,动态注入最相关的资源列表 -4. 最后由代码校验结果并落地执行 - -当前 `llmSkillConversationDriver` 会显式拿到: - -- 当前 active `skill:action` 的 contract -- 当前已收集字段 -- 当前缺失槽位 -- 最近一轮对话 -- 只和当前缺失槽位相关的资源列表(例如只缺 `model` 时,只注入模型列表) - -它返回的核心结果是: - -- `ready` -- `question` -- `extracted` -- `needs_clarification` -- `cancel` - -也就是说,现在 active skill 内部已经开始从: - -- `代码先猜字段` -- `模型后补救` - -迁移到: - -- `模型先理解当前回答的语义` -- `代码只做 guardrail 与执行` - -进一步地,执行层现在也开始优先消费 `skillSession` 里已经由 LLM 提取好的字段和目标对象。 -只有当 session 中还没有对应值时,才会退回到旧的文本解析 fallback。 - -更具体地说,当前高频 management update 动作的执行顺序已经开始统一成: - -1. 先消费 `session` 中已经由 LLM 提取好的字段/patch -2. 若 `session` 仍为空,再看当前整句是否能直接形成结构化 patch -3. 只有前两步都失败时,才退回到 `update_field + 单字段值` 这类旧文本猜测 - -这意味着旧的 `detect... / parse... / pick...` 路径仍然存在,但已经逐步退到真正的兜底层。 - -### 8.1.2 按需资源披露 - -对话驱动器不会每轮都把用户所有模型、交易所、策略全量塞进 Prompt。 - -现在这层已经改成: - -- 缺 `exchange` 才查并注入交易所列表 -- 缺 `model` 才查并注入模型列表 -- 缺 `strategy` 才查并注入策略列表 -- 某个槽位填完后,下一轮立即把对应资源列表从 Prompt 中移除 - -这就是“按需喂饭(Just-In-Time Context Injection)”: - -- 节省 token -- 降低延迟 -- 避免注意力稀释 -- 减少无关资源对当前推理的干扰 - -### 8.2 Execution state 到 skill session 的桥接 - -如果当前是 planner / execution waiting 状态,会尝试桥接成 skill session: -- [planner_runtime.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/planner_runtime.go:1211) - -这解决的是: - -- planner 已经问到一半 -- 用户回复了字段 -- 但后续 hard skill 执行时又像“没收到” - -现在系统已经能把 execution waiting 中收集到的信息投影回 skill session。 - -### 8.3 子任务成功后的父任务回流 - -现在快照不只是“可恢复存档”,还带有父任务信息。 - -相关结构在: -- [execution_state.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/execution_state.go) - -新增字段包括: - -- `intent_id` -- `parent_intent_id` -- `resume_on_success` -- `resume_triggers` - -构建点在: -- [planner_runtime.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/planner_runtime.go:2214) - -执行成功后的回流点在: -- [skill_dispatcher.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/skill_dispatcher.go) - -这解决的是: - -- 用户本来在 `trader_management:create` -- 中途去启用一个被禁用的交易所或模型 -- 子任务成功后,系统不再“断片” -- 会自动恢复父任务上下文,并继续提示主流程剩余缺失项 - -因此现在的 suspended snapshot 已更接近“带返回指针的任务栈”。 - -### 8.4 取消时的任务栈回溯清理 - -如果用户在子任务中途说: - -- `算了` -- `不改了` -- `换话题` - -系统现在不会只取消当前子任务就结束,而是会检查栈里是否还有父任务挂起。 - -如果存在父任务,会明确追问: - -- 当前子任务已经取消 -- 之前的父任务是否还要继续 -- 或者是否“一并取消” - -这样做是为了防止: - -- 父任务长期挂在栈底 -- 子任务被取消后无人接管 -- 最终形成僵尸任务和状态堆积 - ---- - -## 9. Trader create 为什么特殊重要 - -`trader_management:create` 是当前最复杂的 management flow 之一,因为它天然依赖另外三个 skill 的资源状态: - -- exchange -- model -- strategy - -因此它不是一个封闭 skill,而是一个“父 skill”。 - -用户在创建交易员时说: - -- 启用某个交易所 -- 换一个模型 -- 使用现有策略 - -这些都不应该默认被理解成新的平级 top-level 任务,而应优先理解成: - -- 为 `trader create` 补齐依赖 -- 然后继续主流程 - -目前这一层的 prompt 级理解已经通过统一 skill dependency summary 接入,但执行层的“修复依赖后自动回流主流程”还需要继续补强。 - ---- - -## 10. 名称和 ID 的连接 - -用户说的是自然语言名称,比如: - -- `test` -- `DeepSeek AI` -- `高频做空策略` -- `白开水` - -执行层需要的是稳定 ID。 - -当前这层连接主要做在: -- [skill_dispatcher.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/skill_dispatcher.go) - -核心函数: - -- `hydrateCreateTraderSlotReferences` -- `findOptionByIDOrName` - -设计原则是: - -1. 用户层允许说名字 -2. 系统尽快解析出唯一对象 -3. 一旦唯一,就落成真实 ID -4. 展示给用户时仍然优先显示友好名字 - -这解决的是“确认文案看起来正确,但真正执行又说缺字段”的问题。 - -### 10.1 歧义引用澄清 - -除了“名字映射到 ID”,系统现在也开始处理“多个候选对象同名或近似”的情况。 - -相关逻辑在: - -- [skill_dispatcher.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/skill_dispatcher.go) -- [skill_management_handlers.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/skill_management_handlers.go) - -核心做法是: - -1. 若唯一命中,直接解析成 ID -2. 若多个候选同时命中,不再静默选择 -3. 统一返回澄清问题,让用户明确要操作哪一个对象 - -这比“猜一个”更安全,也避免了对象误绑。 - ---- - -## 10.2 用户级串行化 - -同一个用户可能在网络卡顿或前端重发的情况下,几乎同时发出两条修改消息。 - -为了避免: - -- 两条消息并发进入同一个 active flow -- extraction 结果交叉 merge -- `skillSession` / `ExecutionState` 变成缝合状态 - -现在 `thinkAndAct` 和 `thinkAndActStream` 已经在用户维度上做了串行化处理。 - -也就是说: - -- 同一个 `userID` -- 任意时刻只允许一条主消息进入 flow merge/execute 链路 - -这比只在单个 `save*` 调用上加锁更有效,因为它保护的是整条“读状态 -> 理解 -> merge -> 执行 -> 写状态”的事务链。 - ---- - -## 11. Tool 层约束 - -之前一个根问题是:上层像是“创建成功”了,但底层实际上没拿到完整必填字段。 - -现在部分 create 约束已经下沉到 tool 层: -- [tools.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/tools.go) - -当前明确加了必填约束的包括: - -- `model_management:create` -- `exchange_management:create` - -这意味着: - -- 不再只靠上层 prompt 判断“够不够建” -- tool 自己也会拒绝缺关键字段的 create - -这能防止“草稿像成功了,但对象其实是半残”的情况。 - -### 11.1 Tool 层安全硬隔离 - -安全不能只靠 Prompt。 - -因此现在 Tool 层已经补了两类后端硬边界: - -1. 敏感凭证永不明文返回 -说明: -- `toolGetModelConfigs` -- `toolGetExchangeConfigs` -- 以及对应 create / update 响应 - -都会先走安全视图,再做一层递归敏感字段剥离。 -也就是说,像 `api_key`、`secret_key`、`passphrase`、私钥这类字段,不会因为 LLM 被注入而通过 Tool 明文吐回去。 - -系统只允许返回类似: - -- `has_api_key` -- `has_secret_key` -- `has_passphrase` - -这种布尔存在性信息。 - -2. 交易执行必须通过会话级授权 -说明: -- `execute_trade` 不再只靠“模型说要下单”就能执行 -- Tool 层现在会检查当前请求上下文里的会话权限 -- 没有交易执行权限的 session,会被后端直接拒绝 - -这意味着即使 Prompt 被注入,模型生成了合法的 `execute_trade` 调用,只要当前 token/session 没有对应权限,后端仍然不会执行。 - -当前实现上,这条边界先采用: - -- 已认证会话 -- 明确的 session policy -- 服务端 `AllowTradeExecution` 开关 - -的组合约束。 - -也就是说,真正的安全边界现在开始下沉到了 Tool / Session / Server Policy,而不是停留在提示词层。 - ---- - -## 11.1 Planner 的多槽补齐策略 - -语义就绪检查把“准备不足”的请求挡回 planner 后,如果 planner 还是一轮只问一个槽位,用户体验会很差。 - -因此现在 planner prompt 已经明确被要求: - -- 优先一次性询问多个核心缺失字段 -- 在安全且常见的场景下,可以同时提出合理默认值 - -目标不是简单的“防止 hard skill 报错”,而是: - -- 让补槽更像一次有组织的表单引导 -- 减少挤牙膏式的一问一答 - ---- - -## 12. 为什么要保留 planner、workflow、hard skill 三层 - -当前不是所有请求都应该直接落到 hard skill。 - -### 12.1 Hard skill - -适合: - -- 结构明确 -- skill 明确 -- action 明确 -- 必填足够 - -### 12.2 Workflow - -适合: - -- 多个 management action 串联 -- 存在依赖关系 - -### 12.3 Planner - -适合: - -- 开放式目标 -- 需要先探索当前状态 -- 结构还不够稳定 - -当前的设计方向是: - -- LLM 先判断当前在和哪个上下文说话 -- 再决定 route -- 再进入 skill / workflow / planner - -而不是一开始就靠 hard skill 猜。 - -### 12.4 Planner 的人格与职责 - -Planner 现在不只是“拆步骤”的模块,也共享了同一份 `NOFXi` 顾问式系统前缀。 - -这意味着 Planner 在生成计划时,会优先遵守这些原则: - -- 先保证配置正确、安全、逻辑一致 -- 先做状态诊断,而不是机械执行 -- 缺信息时,优先组织更像顾问的多槽追问和默认值建议 - -因此 Planner 现在承担的是: - -- 任务澄清 -- 风险控制 -- 配置诊断 -- 计划生成 - -这也是为什么统一语义网关和 Planner 必须共用同一份系统前缀。 - ---- - -## 13. 前端聊天页的运行形态 - -前端聊天页之前的问题是: - -- 切页就 abort 流式请求 -- 正在生成的消息会消失 - -现在这部分已经调整成: - -- 流式回复由更全局的 runtime/store 托管 -- 站内切页不会立刻中断流 -- 已生成内容会保留 - -这让 Agent 更接近“后台持续回复”,而不是“仅页面内临时回复”。 - ---- - -## 14. 这套结构是怎么一步步收出来的 - -当前架构不是一次性设计出来的,而是沿着这些问题逐步收口: - -### 阶段 1:先把快照恢复链打通 - -目标: - -- 挂起任务可恢复 -- `target_snapshot_id` 真能驱动恢复 - -结果: - -- router、flow extraction、runtime 都开始理解 snapshot - -### 阶段 2:把状态续接和全局路由收成统一语义网关 - -目标: - -- 不再一层判断“是不是当前流程”,另一层再重新猜一遍 - -结果: - -- 先做 `continue_active / resume_snapshot / start_new / cancel / instant_reply` -- 再进入具体执行层 - -### 阶段 3:让 CurrentReferences 真正成为“参考书” - -目标: - -- 当前对象不能只是埋在 JSON 里 -- 要显式进入 prompt 决策 - -结果: - -- router、planner、classifier、extraction 都看当前引用对象 - -### 阶段 4:把 skill 说明和依赖说明收成单一真源 - -目标: - -- 不再在每层 prompt 写一份不同的 skill 描述 - -结果: - -- `buildManagementSkillContext` 成为统一入口 - -### 阶段 5:把名字和 ID 连接起来 - -目标: - -- 用户交互说名字 -- 系统执行用 ID - -结果: - -- draft -> resolved object -> ID 的链路更稳 - ---- - -## 15. 当前已经验证过的方向 - -当前已经补过定向测试的方向包括: - -- 顶层 router prompt 包含 management skill summary -- 顶层 router / one-pass gateway / planner prompt 共享顾问式系统前缀 -- 顶层/flow prompt 包含 management skill negative constraints -- 顶层 router prompt 包含 current reference summary -- active flow extraction prompt 包含 suspended snapshots -- `trader create` 的依赖说明进入统一 skill context -- semantic readiness 会把未准备好的 create 请求挡回 planner -- Tool 层不会明文返回配置秘钥,只返回存在性标记 -- `execute_trade` 必须通过会话级授权和服务端开关 -- 子任务成功后会自动恢复父任务上下文 -- 名称歧义会触发澄清,而不是静默命中 -- execution waiting state 能桥接回 skill session -- persistent reference memory 在 execution state 清掉后仍能命中当前对象 -- `model/exchange` create 的 tool 必填约束生效 - -相关测试文件主要包括: - -- [llm_intent_router_test.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/llm_intent_router_test.go) -- [skill_dispatcher_test.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/skill_dispatcher_test.go) -- [skill_registry_test.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/skill_registry_test.go) -- [config_tools_test.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/config_tools_test.go) - -另外,仓库里现在已经有一套“AI 对练”种子回放骨架: - -- [self_play_replay_test.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/self_play_replay_test.go) -- [agent_self_play_seed.zh-CN.json](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/docs/qa/fixtures/agent_self_play_seed.zh-CN.json) -- [AGENT_AI_SELF_PLAY.zh-CN.md](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/docs/qa/AGENT_AI_SELF_PLAY.zh-CN.md) - -它的用途是: - -- 让代码助手或大模型根据产品说明生成极端对话场景 -- 把这些场景写成 JSON fixture -- 用统一回放器批量喂给 `thinkAndAct` -- 再把暴露的问题沉淀为: - - Skill JSON 说明 - - Validator / Resolver / Readiness Gate - - 按需上下文注入规则 - ---- - -## 16. 当前仍需要继续收的点 - -虽然主链已经比之前完整很多,但还有几块需要继续收: - -1. `configure_strategy / configure_exchange / configure_model` 这类 action 的语义落地 -说明: -这些已经在动作语义上更清晰,但要继续让 LLM 和执行层稳定对齐。 - -2. 更完整的 create 约束下沉 -说明: -`strategy / trader` 的部分约束还可以继续更严格地下沉到执行层和 tool 层。 - -3. 更完整的跨 skill 依赖图 -说明: -现在重点收了 `trader create` 的依赖图,未来可以继续扩展到其他多 skill 依赖场景。 - -4. 歧义消除的 LLM 参与度 -说明: -当前歧义澄清、活性校验、父任务回溯已经有了规则级保护;后续可以继续让 LLM 参与“如何问得更自然、如何结合上下文缩小候选范围”。 - -5. 更细粒度的事务型状态版本控制 -说明: -当前已经做了用户级串行化,足以挡住同一用户的大部分并发污染;后续如果要支持更复杂的多端并发或后台异步写入,可以继续升级成显式版本号或乐观锁。 - ---- - -## 17. 一句话总结 - -当前 NOFXi Agent 已经从“多个局部 if-else 叠起来的 chat handler”,逐步收成了一套: - -- 统一语义网关 -- 快照恢复 -- 当前对象引用记忆 -- 单一真源 skill context -- skill/workflow/planner 分层执行 - -的任务型 Agent 架构。 - -它现在最核心的设计原则是: - -- 先判断用户在和哪个上下文说话 -- 再判断在当前上下文里要做什么 -- 再把自然语言解析成结构化状态 -- 最后由对应 skill/workflow/tool 去安全执行 diff --git a/docs/architecture/AGENT_CURRENT_DESIGN.zh-CN.md b/docs/architecture/AGENT_CURRENT_DESIGN.zh-CN.md deleted file mode 100644 index 40f93977..00000000 --- a/docs/architecture/AGENT_CURRENT_DESIGN.zh-CN.md +++ /dev/null @@ -1,613 +0,0 @@ -# NOFXi Agent 当前设计说明 - -## 目的 - -本文描述当前 NOFXi Agent 的实际设计,而不是早期版本的理想设计。重点回答这些问题: - -- 用户消息从哪里进入 -- 什么请求会进入 planner -- 当前有哪些记忆层 -- planner 如何生成与执行 plan -- tool 现在是怎么设计的 -- 动态快照和当前引用分别解决什么问题 -- 为什么某些问题会出现“看起来有历史,但模型还是会追问” - -本文对应的主要实现文件: - -- `agent/agent.go` -- `agent/web.go` -- `api/agent_routes.go` -- `agent/planner_runtime.go` -- `agent/execution_state.go` -- `agent/memory.go` -- `agent/history.go` -- `agent/tools.go` - -## 一句话总览 - -当前 Agent 的运行模型可以概括为: - -1. 前端把消息发到 `/api/agent/chat/stream` -2. 后端把登录用户身份放进 context -3. Agent 除 `/clear` 和 `/status` 外,其他消息全部进入 planner -4. planner 结合多层记忆、动态快照和 tool schema 生成 plan -5. 执行 plan 中的 `tool / reason / ask_user / respond` -6. 在执行过程中持续更新执行态、短期原话、长期摘要和当前对象引用 - -## 请求入口 - -### 前端入口 - -前端 Agent 页面在: - -- `web/src/pages/AgentChatPage.tsx` - -当前聊天使用: - -- `POST /api/agent/chat/stream` - -请求体里会传: - -- `message` -- `lang` -- `user_key` - -### 后端路由入口 - -路由注册在: - -- `api/agent_routes.go` - -这里会: - -1. 经过 `authMiddleware` -2. 从登录态里取出 `user_id` -3. 通过 `agent.WithStoreUserID(...)` 写入 request context - -### Agent Web Handler - -真正的 HTTP handler 在: - -- `agent/web.go` - -主要入口: - -- `HandleChat(...)` -- `HandleChatStream(...)` - -再往下进入: - -- `HandleMessageForStoreUser(...)` -- `HandleMessageStreamForStoreUser(...)` - -## 最外层分流 - -当前外层分流已经被收口。 - -在 `agent/agent.go` 中,除了这两个命令之外,其他输入全部交给 planner: - -- `/clear` -- `/status` - -也就是说,现在这些都不再在外层直接处理: - -- setup flow -- trade confirmation -- direct trade regex -- 自然语言配置流程 -- 自然语言策略创建 - -这些都统一进入 planner。 - -这是当前设计里一个很重要的原则: - -- 外层分流越少,行为边界越清晰 -- 自然语言理解尽量统一交给 planner + tool - -## 当前的 5 层记忆 - -当前不是 3 层,也不是 4 层,而是 5 层: - -1. `chatHistory` -2. `TaskState` -3. `ExecutionState` -4. `CurrentReferences` -5. `Persistent Preferences` - -### 1. chatHistory - -定义位置: - -- `agent/history.go` - -作用: - -- 保存最近几轮用户 / assistant 原始消息 -- 给模型保留最近原话上下文 -- 为后续摘要成 `TaskState` 提供原始素材 - -特点: - -- 只保留短期原话 -- 内存态 -- `/clear` 时清空 - -适合存: - -- 最近几轮对话原文 -- 用户的最新措辞 -- 刚刚的自然语言上下文 - -不适合存: - -- 长期真相 -- 当前外部系统状态 -- 当前流程精确执行位置 - -### 2. TaskState - -定义位置: - -- `agent/memory.go` - -作用: - -- 保存跨轮次仍然有意义的高层摘要 -- 注入 planner / reasoning / final response - -持久化 key: - -- `agent_task_state_` - -字段: - -- `CurrentGoal` -- `ActiveFlow` -- `OpenLoops` -- `ImportantFacts` -- `LastDecision` -- `UpdatedAt` - -适合存: - -- 当前高层目标 -- 跨轮次仍然成立的未闭环事项 -- 关键事实 -- 最近一次重要决策及其原因 - -不适合存: - -- step 级待办 -- “下一步调用哪个 tool” -- 动态余额、持仓、配置存在性 -- 任何可以通过 tool 重新读取的实时状态 - -### 3. ExecutionState - -定义位置: - -- `agent/execution_state.go` - -作用: - -- 保存当前 plan 的执行态 -- 支持 `ask_user` 之后继续执行 -- 保存 plan、当前步骤、执行日志、等待状态等 - -持久化 key: - -- `agent_execution_state_` - -当前关键字段: - -- `SessionID` -- `Goal` -- `Status` -- `PlanID` -- `Steps` -- `CurrentStepID` -- `DynamicSnapshots` -- `ExecutionLog` -- `SummaryNotes` -- `Waiting` -- `CurrentReferences` -- `FinalAnswer` -- `LastError` - -### 4. CurrentReferences - -定义位置: - -- `agent/execution_state.go` - -作用: - -- 记录当前对话里“这个 / 那个 / 刚才那个”到底指的是谁 - -当前支持的引用对象: - -- `strategy` -- `trader` -- `model` -- `exchange` - -这是为了解决一种常见问题: - -- 用户明明前一轮刚说过“激进策略” -- 下一轮说“改一下这个策略” -- 如果没有结构化引用,模型虽然有聊天历史,也容易重新追问 - -`CurrentReferences` 不是系统状态快照,而是: - -- 当前对话焦点对象 -- 当前代词绑定对象 - -### 5. Persistent Preferences - -对应工具: - -- `get_preferences` -- `manage_preferences` - -作用: - -- 保存用户长期偏好 - -适合存: - -- 默认中文回复 -- 偏好激进风格 -- 更关注 BTC / ETH -- 不喜欢高频 -- 每天固定时间简报 - -它和 `TaskState` 的区别是: - -- `TaskState` 偏向当前任务摘要 -- `Persistent Preferences` 偏向长期用户画像 - -## DynamicSnapshots 是什么 - -`DynamicSnapshots` 是当前真实系统状态的快照。 - -它不是历史,也不是长期记忆,而是 planner 在规划前或执行中插入的“当前事实”。 - -当前会进入快照的典型信息包括: - -- 当前模型配置列表 -- 当前交易所配置列表 -- 当前策略列表 -- 当前 trader 列表 -- 当前余额 -- 当前持仓 -- 最近交易历史 - -作用: - -- 防止 planner 盲信旧结论 -- 避免“之前没配置,现在其实已经配好了却还说没有” -- 避免“之前余额是 A,现在拿旧 observation 继续回答” - -一句话: - -- `DynamicSnapshots` = 当前世界里真实有什么 - -## CurrentReferences 和 DynamicSnapshots 的区别 - -这两个容易混淆,但职责完全不同。 - -`DynamicSnapshots`: - -- 当前系统状态快照 -- 是候选集合 / 当前事实 -- 例如当前有两个策略:`激进`、`新策略` - -`CurrentReferences`: - -- 当前对话焦点对象 -- 是“这个”到底指谁 -- 例如用户现在说的“这个策略”就是 `激进` - -可以这样理解: - -- `DynamicSnapshots` 是地图 -- `CurrentReferences` 是你手指现在指着地图上的哪个点 - -## Planner 的输入 - -planner 主逻辑在: - -- `agent/planner_runtime.go` - -生成计划时,当前会把这些东西一起送给模型: - -- 当前用户请求 -- tool schema -- `Persistent Preferences` -- `TaskState` -- `ExecutionState` -- `Resume context` -- `Structured waiting state` -- `Observation context` - -其中 observation context 不是旧版单数组,而是分层后的: - -- `dynamic_snapshots` -- `execution_log` -- `summary_notes` - -## Plan 的结构 - -当前 planner 只允许这 4 类 step: - -- `tool` -- `reason` -- `ask_user` -- `respond` - -这意味着现在的 Agent 不是一个“自由发挥的回复器”,而是: - -- 先规划 -- 再执行步骤 -- 必要时重规划 - -## 步骤执行流程 - -`executePlan(...)` 的核心逻辑是: - -1. 找下一个 pending step -2. 标记 step 为 running -3. 执行对应类型 -4. 写回 `ExecutionState` -5. 必要时触发 replanning - -不同 step 类型行为如下: - -### tool - -- 调内部 tool -- 把结果写入 `ExecutionLog` -- 根据结果更新 `CurrentReferences` -- 必要时触发 replanner - -### reason - -- 发起一次短 reasoning 调用 -- 生成一段简短中间推理 -- 写入 `ExecutionLog` - -### ask_user - -- 进入 `waiting_user` -- 保存 `WaitingState` -- 把问题直接回给用户 - -### respond - -- 生成最终回答 -- 标记当前执行完成 - -## WaitingState 是什么 - -`WaitingState` 用来解决: - -- 用户回复 `是` -- 用户回复 `继续` -- 用户回复 `那个就行` - -这类短回复如果没有结构化等待状态,很容易丢上下文。 - -当前字段包括: - -- `Question` -- `Intent` -- `PendingFields` -- `ConfirmationTarget` -- `CreatedAt` - -它的作用是: - -- 告诉 planner 上一轮到底在等什么 -- 让这轮短回复更容易被理解成“对上一问的回答” - -## CurrentReferences 如何更新 - -当前是双路径更新: - -### 1. 用户消息命中对象名时更新 - -如果用户说: - -- `修改激进策略` -- `停止 lky` -- `用 DeepSeek` - -系统会去当前用户的策略 / trader / model / exchange 列表里尝试匹配名称或 ID。 - -匹配成功后,更新 `CurrentReferences`。 - -### 2. tool 成功返回对象时更新 - -比如: - -- `manage_strategy(create/update/activate)` -- `manage_trader(create/update)` -- `manage_model_config(update)` -- `manage_exchange_config(update)` - -只要 tool 返回了具体对象,系统就会把对应 ID / name 写回当前引用。 - -## Tool 设计 - -当前 tool 是“资源型 tool”设计,不是“页面动作型 tool”。 - -### 当前主要工具 - -配置资源: - -- `get_exchange_configs` -- `manage_exchange_config` -- `get_model_configs` -- `manage_model_config` - -策略资源: - -- `get_strategies` -- `manage_strategy` - -trader 资源: - -- `manage_trader` - -交易 / 查询资源: - -- `search_stock` -- `execute_trade` -- `get_positions` -- `get_balance` -- `get_market_price` -- `get_trade_history` - -### 为什么这么设计 - -优点: - -- tool schema 稳定 -- 行为边界清晰 -- planner 更容易学会 -- 资源增删改查统一 - -当前 `manage_strategy` 支持: - -- `list` -- `get_default_config` -- `create` -- `update` -- `delete` -- `activate` -- `duplicate` - -当前 `manage_trader` 支持: - -- `list` -- `create` -- `update` -- `delete` -- `start` -- `stop` - -## 为什么“创建策略”不该默认依赖交易所和模型 - -当前设计里,策略模板应该是独立资源: - -- `strategy` - -而运行态对象是: - -- `trader` - -更合理的边界是: - -- 创建策略模板:用 `manage_strategy` -- 把策略跑起来:用 `manage_trader` - -也就是说: - -- 策略不默认依赖交易所和模型 -- 只有当用户要求“运行 / 部署 / 创建 trader”时,才需要进一步关联 exchange / model / trader - -## 当前一个完整例子 - -用户输入: - -`帮我创建一个新的激进策略模板,名字就叫激进。创建完后,再把这个策略绑定到 trader lky。` - -当前大致流程: - -1. 前端请求 `/api/agent/chat/stream` -2. 后端注入 `store_user_id` -3. Agent 进入 planner -4. planner 刷新动态快照: - - 当前策略 - - 当前 trader -5. 生成 plan,例如: - - `get_strategies` - - `manage_strategy(create)` - - `manage_trader(update)` - - `respond` -6. 执行 `manage_strategy(create)` 后: - - 写入 `ExecutionLog` - - 更新 `CurrentReferences.strategy` -7. 执行 `manage_trader(update)` 时: - - 直接使用刚创建策略的 ID -8. 输出最终回复 - -如果此后用户继续说: - -`把这个策略的 prompt 改激进一点` - -系统会优先从 `CurrentReferences.strategy` 理解“这个策略”。 - -## 为什么看起来“有历史”,模型还是会追问 - -因为“有聊天历史”不等于“有结构化对象绑定”。 - -如果没有 `CurrentReferences`: - -- 模型只能依赖原话文本推断“这个策略”是谁 -- 一旦中间插入多条消息,或者有多个候选策略 -- 就容易重新追问 - -所以当前设计里,`CurrentReferences` 是补齐这一块的关键。 - -## 当前已知限制 - -### 1. 外层虽然已经大幅收口,但仍然不是纯 graph runtime - -现在比之前更统一,但整体仍然是: - -- Agent 主入口 -- Planner -- Tool 执行 - -而不是完整 node-graph 引擎。 - -### 2. ExecutionState 仍然是按 userID 单槽位 - -这意味着: - -- 同一用户的多个并行任务仍然可能相互影响 - -更彻底的方向应该是: - -- 按 thread / session 多实例存储 - -### 3. CurrentReferences 目前还是轻量实现 - -当前只覆盖: - -- strategy -- trader -- model -- exchange - -后面如果要更强,需要考虑: - -- 多候选冲突消解 -- 昵称映射 -- 跨更长会话的稳定实体绑定 - -## 当前设计的核心思想 - -一句话总结: - -- `chatHistory` 记原话 -- `Persistent Preferences` 记长期偏好 -- `TaskState` 记高层摘要 -- `ExecutionState` 记当前流程 -- `DynamicSnapshots` 记当前事实 -- `CurrentReferences` 记当前指代对象 -- `planner` 决定步骤 -- `tools` 执行落地动作 - -这就是当前 NOFXi Agent 的实际运行设计。 diff --git a/docs/architecture/AGENT_MEMORY_AND_PLANNING.md b/docs/architecture/AGENT_MEMORY_AND_PLANNING.md deleted file mode 100644 index 7179bb17..00000000 --- a/docs/architecture/AGENT_MEMORY_AND_PLANNING.md +++ /dev/null @@ -1,454 +0,0 @@ -# NOFXi Agent Memory And Planning Design - -## Purpose - -This document explains how the current NOFXi agent handles: - -- short-term conversation memory -- durable task memory -- durable execution / planning state -- planner execution and replanning -- state reset and resume behavior - -The implementation described here is primarily in: - -- `agent/history.go` -- `agent/memory.go` -- `agent/execution_state.go` -- `agent/planner_runtime.go` -- `agent/agent.go` - -## High-Level Model - -The current agent uses three different layers of state: - -1. `chatHistory` -Recent in-memory user/assistant turns for the live conversation. - -2. `TaskState` -Durable summarized context that should survive beyond recent turns. - -3. `ExecutionState` -Durable workflow state for the currently running or recently blocked plan. - -These three layers serve different purposes and should not be treated as the same thing. - -## State Layers - -### 1. `chatHistory` - -Defined in `agent/history.go`. - -Role: - -- stores recent `user` / `assistant` messages in memory -- keyed by `userID` -- used as short-term conversational context -- acts as the source material for later compression into `TaskState` - -Characteristics: - -- in-memory only -- capped by `maxTurns` -- cleared by `/clear` -- not suitable as durable truth - -Typical contents: - -- the last few user questions -- the last few assistant replies -- temporary conversational wording - -### 2. `TaskState` - -Defined in `agent/memory.go`. - -Role: - -- stores durable, structured, non-derivable context -- persisted through `system_config` -- injected into planning and reasoning prompts - -Storage key: - -- `agent_task_state_` - -Fields: - -- `CurrentGoal` -- `ActiveFlow` -- `OpenLoops` -- `ImportantFacts` -- `LastDecision` -- `UpdatedAt` - -Intended contents: - -- user goal that still matters across turns -- high-level unresolved issues that still matter across turns -- facts that tools cannot cheaply re-fetch -- latest important decision summary - -Explicitly not intended for: - -- step-level pending items such as "wait for API key" -- execution actions such as "call get_exchange_configs" -- live balances -- current positions -- current market prices -- mutable configuration availability - -Those should be checked from tools at planning time instead of being trusted from old summaries. - -### 3. `ExecutionState` - -Defined in `agent/execution_state.go`. - -Role: - -- stores the current execution workflow -- allows the agent to resume after `ask_user` -- persists plan steps, observations, and completion status - -Storage key: - -- `agent_execution_state_` - -Fields: - -- `SessionID` -- `UserID` -- `Goal` -- `Status` -- `PlanID` -- `Steps` -- `CurrentStepID` -- `Observations` -- `FinalAnswer` -- `LastError` -- `UpdatedAt` - -This is the planner's working state, not a general memory store. - -## Data Flow - -### Request Entry - -Entry points: - -- `HandleMessage(...)` -- `HandleMessageStream(...)` - -Flow: - -1. user message enters `agent` -2. slash commands and explicit direct branches are handled first -3. all other requests go into planner flow via `thinkAndAct(...)` / `thinkAndActStream(...)` - -### Planner Flow - -The planner pipeline in `agent/planner_runtime.go` is: - -1. append user message into `chatHistory` -2. emit `planning` SSE event -3. load `ExecutionState` -4. optionally reset stale `ExecutionState` -5. optionally refresh dynamic configuration snapshots -6. create a fresh execution plan with the LLM -7. execute steps one by one -8. persist `ExecutionState` after important transitions -9. append assistant answer into `chatHistory` -10. maybe compress old conversation into `TaskState` - -## Short-Term vs Durable Memory - -### What lives in `chatHistory` - -Good fits: - -- raw recent messages -- conversational wording -- latest assistant phrasing - -Bad fits: - -- long-lived truths -- current external system state - -### What lives in `TaskState` - -Good fits: - -- durable goal -- high-level unfinished work that remains relevant across turns -- important facts the user stated -- previous decisions and why they were made - -Bad fits: - -- pending steps inside the current plan -- execution-level reminders such as "wait for a field" or "call a tool" -- old conclusions about whether tools exist -- old conclusions about whether model/exchange config is present -- live operational state that can change outside the chat - -### What lives in `ExecutionState` - -Good fits: - -- current plan steps -- observations from tool calls -- blocked-on-user-input status -- exact current workflow state -- step-level pending work and block reasons - -Bad fits: - -- evergreen user profile -- long-term semantic memory - -## Planning Logic - -### Plan Creation - -`createExecutionPlan(...)` sends the following into the planner model: - -- available tool definitions -- persistent preferences -- `TaskState` context -- `ExecutionState` JSON -- current user request - -The planner must return JSON only with step types: - -- `tool` -- `reason` -- `ask_user` -- `respond` - -### Step Execution - -`executePlan(...)` executes the plan loop: - -- `tool` - call tool and append observation -- `reason` - run reasoning sub-call and append observation -- `ask_user` - save `waiting_user` state and return question -- `respond` - generate final answer and mark completed - -After each completed step, `replanAfterStep(...)` may: - -- continue -- replace remaining steps -- ask user -- finish - -## Resume Behavior - -When `ExecutionState.Status == waiting_user`, the next user turn is treated as a reply to the pending question. - -Current safeguards: - -- latest asked question is extracted from the stored plan -- the user reply is appended as a `user_reply` observation -- planner prompt receives explicit `Resume context` - -This prevents short replies like `是` from being misread as unrelated fresh intents as often as before. - -## Dynamic State Refresh - -Configuration and trader management requests are dynamic by nature. Their truth can change outside the current chat, for example: - -- user configures exchange in the UI -- user adds model in another tab -- user creates trader elsewhere - -Because of that, configuration/trader requests should not trust stale model conclusions. - -Current protection in `planner_runtime.go`: - -- detects config / trader intent with `isConfigOrTraderIntent(...)` -- clears `TaskState` context from the planner prompt for these requests -- refreshes `ExecutionState.Observations` with fresh snapshots from: - - `toolGetModelConfigs(...)` - - `toolGetExchangeConfigs(...)` - - `toolListTraders(...)` - -This makes the planner rely more on current system state and less on older narrative memory. - -## Reset Strategy - -The system currently resets or weakens stale execution state when: - -- user says retry-like phrases such as `再试`, `继续`, `try again`, `continue` -- request is config / trader related and old execution state is failed / completed / waiting - -Reset scope: - -- `ExecutionState` may be cleared -- `TaskState` is not globally deleted, but it is intentionally ignored for config/trader planning - -Manual reset: - -- `/clear` - -This clears: - -- short-term chat history -- task state -- execution state - -## Compression Design - -`maybeCompressHistory(...)` moves older short-term chat content into `TaskState` when: - -- recent message count exceeds the configured window -- estimated token count exceeds the threshold - -Compression strategy: - -1. keep recent conversation in `chatHistory` -2. summarize older turns into structured `TaskState` -3. persist new `TaskState` -4. replace `chatHistory` with recent slice - -Important design rule: - -- `TaskState` should keep durable context only -- it should not become a stale copy of mutable operational state - -## Current Architecture Diagram - -```mermaid -flowchart TD - U[User Message] --> A[HandleMessage / HandleMessageStream] - A --> B{Direct command?} - B -->|Yes| C[Direct branch or slash command] - B -->|No| D[thinkAndAct / thinkAndActStream] - - D --> E[Append user turn to chatHistory] - D --> F[Load ExecutionState] - F --> G{waiting_user?} - G -->|Yes| H[Attach user_reply observation] - G -->|No| I[Create fresh ExecutionState] - - H --> J[Refresh dynamic snapshots if config/trader intent] - I --> J - J --> K[createExecutionPlan via LLM] - K --> L[Execution plan] - L --> M[executePlan loop] - - M --> N[tool step] - M --> O[reason step] - M --> P[ask_user step] - M --> Q[respond step] - - N --> R[Append Observation] - O --> R - R --> S[replanAfterStep] - S --> M - - P --> T[Persist waiting_user ExecutionState] - T --> UQ[Return question to user] - - Q --> V[Persist completed ExecutionState] - V --> W[Append assistant turn to chatHistory] - W --> X[maybeCompressHistory] - X --> Y[Persist TaskState] - Y --> Z[Final response] -``` - -## Memory Relationship Diagram - -```mermaid -flowchart LR - CH[chatHistory\nin-memory\nrecent turns] - TS[TaskState\npersisted summary\nsystem_config] - ES[ExecutionState\npersisted workflow\nsystem_config] - PL[Planner Prompt] - - CH -->|recent raw turns| PL - ES -->|current workflow JSON| PL - TS -->|durable structured context| PL - - CH -->|old turns compressed| TS - PL -->|plan / observations / status| ES -``` - -## State Transition Diagram - -```mermaid -stateDiagram-v2 - [*] --> planning - planning --> running: plan created - running --> waiting_user: ask_user step - waiting_user --> planning: user replies - running --> completed: respond step finished - running --> failed: step error - failed --> planning: retry / continue / config-trader reset - completed --> planning: new relevant request or retry flow -``` - -## Known Design Tradeoffs - -### Strengths - -- separates short-term chat from durable task summary -- allows blocked flows to resume -- supports replanning after every meaningful step -- can recover from stale assumptions better for dynamic config/trader requests - -### Weaknesses - -- `TaskState` is still summary-driven, so summarization quality matters -- planner still depends on model compliance for some transitions -- `ExecutionState` is single-track per user, not multiple concurrent workflows -- config/trader intent detection is heuristic and keyword-based - -## Practical Guidance - -### When to trust `TaskState` - -Trust it for: - -- user intent continuity -- open loops -- durable facts - -Do not trust it for: - -- whether current exchange/model/trader config exists now -- whether a specific operational action is currently possible - -### When to trust `ExecutionState` - -Trust it for: - -- current plan continuity -- exact blocked step -- latest observation chain - -Do not trust it blindly when: - -- user has changed configuration outside the chat -- the system capabilities changed after deployment - -### When to fetch live state again - -Always prefer fresh tool snapshots before answering about: - -- existing model configs -- existing exchange configs -- existing traders -- whether trader creation can proceed - -## Suggested Future Improvements - -- add workflow versioning so capability changes invalidate stale `ExecutionState` -- separate `waiting_user_confirmation` from generic `waiting_user` -- introduce code-level handling for short confirmations such as `是`, `好`, `继续` -- move dynamic state refresh from heuristic to explicit planner preflight stage -- support multiple concurrent execution sessions per user if needed diff --git a/docs/architecture/AGENT_MEMORY_AND_PLANNING.zh-CN.md b/docs/architecture/AGENT_MEMORY_AND_PLANNING.zh-CN.md deleted file mode 100644 index 5dd1e2d8..00000000 --- a/docs/architecture/AGENT_MEMORY_AND_PLANNING.zh-CN.md +++ /dev/null @@ -1,453 +0,0 @@ -# NOFXi Agent 记忆与规划设计 - -## 目的 - -本文说明当前 NOFXi agent 是如何处理以下能力的: - -- 短期对话记忆 -- 持久化任务记忆 -- 持久化执行态 / 规划态 -- planner 的执行与重规划 -- 状态重置与恢复 - -本文主要对应以下实现文件: - -- `agent/history.go` -- `agent/memory.go` -- `agent/execution_state.go` -- `agent/planner_runtime.go` -- `agent/agent.go` - -## 总体模型 - -当前 agent 使用三层不同的状态: - -1. `chatHistory` -用于保存当前会话最近几轮的原始用户/助手对话,驻留内存。 - -2. `TaskState` -用于保存跨轮次仍然有价值的结构化摘要,持久化存储。 - -3. `ExecutionState` -用于保存当前规划流程的执行态,支持流程中断后的继续执行。 - -这三层职责不同,不能混为一谈。 - -## 三层状态 - -### 1. `chatHistory` - -定义位置:`agent/history.go` - -作用: - -- 按 `userID` 保存最近的 `user` / `assistant` 消息 -- 作为短期对话上下文 -- 作为后续压缩进 `TaskState` 的原始素材 - -特性: - -- 仅在内存中存在 -- 有 `maxTurns` 上限 -- `/clear` 时会清空 -- 不适合作为长期真相来源 - -典型内容: - -- 最近几轮用户问题 -- 最近几轮助手回答 -- 临时措辞与上下文表达 - -### 2. `TaskState` - -定义位置:`agent/memory.go` - -作用: - -- 保存持久化、结构化、不可轻易从工具重新推导出的上下文 -- 通过 `system_config` 持久化 -- 注入到 planner / reasoning prompt 中 - -存储 key: - -- `agent_task_state_` - -字段: - -- `CurrentGoal` -- `ActiveFlow` -- `OpenLoops` -- `ImportantFacts` -- `LastDecision` -- `UpdatedAt` - -适合存放: - -- 当前仍有效的用户目标 -- 跨轮次仍然成立的高层未闭环问题 -- 无法简单通过工具重新读取的重要事实 -- 最近一次关键决策及原因 - -不适合存放: - -- “等用户提供 API Key” 这类 step 级待办 -- “调用 get_exchange_configs” 这类执行动作 -- 实时余额 -- 当前持仓 -- 当前行情价格 -- 是否存在某个配置这类会变化的状态 - -这些动态信息应该在规划阶段通过工具重新检查,而不是相信旧摘要。 - -### 3. `ExecutionState` - -定义位置:`agent/execution_state.go` - -作用: - -- 保存当前执行中的工作流状态 -- 支持 `ask_user` 之后恢复执行 -- 持久化保存计划步骤、观察结果和最终状态 - -存储 key: - -- `agent_execution_state_` - -字段: - -- `SessionID` -- `UserID` -- `Goal` -- `Status` -- `PlanID` -- `Steps` -- `CurrentStepID` -- `Observations` -- `FinalAnswer` -- `LastError` -- `UpdatedAt` - -它是 planner 的“工作态”,不是通用记忆仓库。 - -## 数据流 - -### 请求入口 - -入口函数: - -- `HandleMessage(...)` -- `HandleMessageStream(...)` - -流程: - -1. 用户消息进入 `agent` -2. 优先处理 slash command 和显式直达分支 -3. 其余请求进入 planner 流程:`thinkAndAct(...)` / `thinkAndActStream(...)` - -### Planner 主流程 - -`agent/planner_runtime.go` 中的 planner 管线如下: - -1. 把用户消息加入 `chatHistory` -2. 发出 `planning` SSE 事件 -3. 加载 `ExecutionState` -4. 视情况重置过期的 `ExecutionState` -5. 视情况刷新动态配置快照 -6. 调用 LLM 生成新的执行计划 -7. 按步骤执行计划 -8. 在关键状态变化后持久化 `ExecutionState` -9. 把助手回答加入 `chatHistory` -10. 视情况把旧对话压缩进 `TaskState` - -## 短期记忆 vs 持久记忆 - -### `chatHistory` 里应该放什么 - -适合: - -- 最近原始消息 -- 对话措辞 -- 最近一轮助手的表达方式 - -不适合: - -- 长期真相 -- 外部系统当前状态 - -### `TaskState` 里应该放什么 - -适合: - -- 持续目标 -- 跨轮次仍有意义的高层未闭环事项 -- 用户明确讲过的重要事实 -- 历史关键决策和原因 - -不适合: - -- 当前 plan 中尚未执行的步骤 -- “等待某个字段”“调用某个 tool” 这类执行级待办 -- “系统有没有这个工具” 这种过时结论 -- “当前有没有模型/交易所配置” 这种可变化状态 -- 可以通过工具重新查询到的动态状态 - -### `ExecutionState` 里应该放什么 - -适合: - -- 当前计划步骤 -- 工具调用观察结果 -- 当前是否卡在等用户补充信息 -- 当前工作流的精确执行位置 -- step 级待办和阻塞原因 - -不适合: - -- 长期用户画像 -- 通用长期语义记忆 - -## 规划逻辑 - -### 计划生成 - -`createExecutionPlan(...)` 会把以下信息送给 planner 模型: - -- 当前可用 tool 定义 -- 持久化用户偏好 -- `TaskState` 上下文 -- `ExecutionState` JSON -- 当前用户请求 - -planner 必须返回 JSON,且步骤类型只能是: - -- `tool` -- `reason` -- `ask_user` -- `respond` - -### 步骤执行 - -`executePlan(...)` 的执行循环如下: - -- `tool` - 调用工具并写入 observation -- `reason` - 发起 reasoning 子调用并写入 observation -- `ask_user` - 保存 `waiting_user` 状态并把问题返回给用户 -- `respond` - 生成最终回答并标记完成 - -每个步骤结束后,`replanAfterStep(...)` 还可以决定: - -- continue -- replace_remaining -- ask_user -- finish - -## 恢复执行 - -当 `ExecutionState.Status == waiting_user` 时,下一条用户消息会被视为对上一轮追问的回复。 - -当前保护机制: - -- 从已有 plan 中提取最近一次追问内容 -- 将用户回复作为 `user_reply` observation 追加 -- 在 planner prompt 中注入显式的 `Resume context` - -这样可以减少用户只回复 `是` 这类短消息时,被错误理解成全新意图的情况。 - -## 动态状态刷新 - -配置类与 trader 管理类请求本质上是动态请求,它们的真相可能在聊天之外发生变化,例如: - -- 用户在 Web UI 中配置了交易所 -- 用户在另一个页面新增了模型 -- 用户在别处创建了 trader - -因此,这类请求不能依赖旧的模型结论。 - -当前在 `planner_runtime.go` 中的保护措施: - -- 通过 `isConfigOrTraderIntent(...)` 检测配置 / trader 意图 -- 这类请求在 planner prompt 中不再注入旧 `TaskState` -- 同时刷新 `ExecutionState.Observations` 中的实时快照: - - `toolGetModelConfigs(...)` - - `toolGetExchangeConfigs(...)` - - `toolListTraders(...)` - -这样 planner 会更多依赖当前系统状态,而不是依赖旧记忆中的描述。 - -## 重置策略 - -当前系统在以下场景会重置或弱化旧执行态: - -- 用户说了类似 `再试`、`继续`、`try again`、`continue` -- 当前请求是配置 / trader 相关,并且旧 `ExecutionState` 已经失败 / 完成 / 正在等待用户 - -重置范围: - -- `ExecutionState` 可能会被清空 -- `TaskState` 不会整体删除,但在配置 / trader 请求中会被主动忽略 - -手动清理: - -- `/clear` - -这条命令会清掉: - -- 短期 chat history -- task state -- execution state - -## 压缩设计 - -`maybeCompressHistory(...)` 会在以下条件满足时把旧的短期对话压缩进 `TaskState`: - -- 最近消息数超过窗口 -- 估算 token 数超过阈值 - -压缩流程: - -1. 保留最近若干轮对话在 `chatHistory` -2. 把更早的内容总结成结构化 `TaskState` -3. 持久化新的 `TaskState` -4. 用最近消息切片替换 `chatHistory` - -重要设计原则: - -- `TaskState` 只保留长期有效上下文 -- 不能把它变成动态运营状态的陈旧副本 - -## 当前架构图 - -```mermaid -flowchart TD - U[用户消息] --> A[HandleMessage / HandleMessageStream] - A --> B{是否命中直达分支?} - B -->|是| C[直接处理 slash command 或快捷分支] - B -->|否| D[thinkAndAct / thinkAndActStream] - - D --> E[写入 chatHistory] - D --> F[加载 ExecutionState] - F --> G{是否 waiting_user?} - G -->|是| H[追加 user_reply observation] - G -->|否| I[创建新的 ExecutionState] - - H --> J[若为配置或 trader 请求则刷新动态快照] - I --> J - J --> K[createExecutionPlan 调用 LLM] - K --> L[得到 execution plan] - L --> M[executePlan 循环执行] - - M --> N[tool step] - M --> O[reason step] - M --> P[ask_user step] - M --> Q[respond step] - - N --> R[写入 Observation] - O --> R - R --> S[replanAfterStep] - S --> M - - P --> T[持久化 waiting_user ExecutionState] - T --> UQ[向用户返回追问] - - Q --> V[持久化 completed ExecutionState] - V --> W[把 assistant 回复写入 chatHistory] - W --> X[maybeCompressHistory] - X --> Y[持久化 TaskState] - Y --> Z[返回最终回答] -``` - -## 记忆关系图 - -```mermaid -flowchart LR - CH[chatHistory\n内存态\n最近对话] - TS[TaskState\n持久化摘要\nsystem_config] - ES[ExecutionState\n持久化执行态\nsystem_config] - PL[Planner Prompt] - - CH -->|最近原始对话| PL - ES -->|当前工作流 JSON| PL - TS -->|长期结构化上下文| PL - - CH -->|旧消息压缩| TS - PL -->|计划 / 观察 / 状态| ES -``` - -## 状态转换图 - -```mermaid -stateDiagram-v2 - [*] --> planning - planning --> running: plan created - running --> waiting_user: ask_user step - waiting_user --> planning: user replies - running --> completed: respond step finished - running --> failed: step error - failed --> planning: retry / continue / config-trader reset - completed --> planning: new relevant request or retry flow -``` - -## 当前设计的取舍 - -### 优点 - -- 将短期对话与长期摘要分离 -- 支持在 `ask_user` 之后恢复执行 -- 每个关键步骤后都支持重规划 -- 对配置 / 创建 trader 这类动态请求,已经能更好抵抗旧结论污染 - -### 缺点 - -- `TaskState` 的质量仍然依赖总结效果 -- 某些恢复逻辑仍依赖模型是否听话 -- 每个用户当前只有一条 `ExecutionState`,不支持多个并发工作流 -- 配置 / trader 意图识别目前仍是关键词启发式 - -## 实践建议 - -### 什么时候该相信 `TaskState` - -应该相信它用于: - -- 延续用户目标 -- 跟踪未完成事项 -- 保留长期有效事实 - -不应该相信它用于: - -- 当前是否存在模型 / 交易所 / trader 配置 -- 当前是否能够执行某个操作 - -### 什么时候该相信 `ExecutionState` - -应该相信它用于: - -- 当前工作流是否仍然连续 -- 当前阻塞在哪一步 -- 最近的 observation 链条 - -不应该盲信它用于: - -- 用户在聊天外已经修改过配置的场景 -- 系统能力或工具集发生变化后的旧结论 - -### 什么时候必须重新获取实时状态 - -以下场景应该优先重新通过工具获取: - -- 当前模型配置 -- 当前交易所配置 -- 当前 trader 列表 -- 当前是否满足 trader 创建条件 - -## 后续建议 - -- 为 `ExecutionState` 增加版本号或能力签名,能力变化时自动失效 -- 将 `waiting_user_confirmation` 与通用 `waiting_user` 分开 -- 对 `是`、`好`、`继续` 这类短确认增加代码级识别 -- 将动态快照刷新从启发式升级为显式 planner 预检查阶段 -- 如果后续需要,支持一个用户多条并发执行会话 diff --git a/docs/qa/AGENT_SKILL_ACCEPTANCE_CHECKLIST.zh-CN.md b/docs/qa/AGENT_SKILL_ACCEPTANCE_CHECKLIST.zh-CN.md deleted file mode 100644 index 97390544..00000000 --- a/docs/qa/AGENT_SKILL_ACCEPTANCE_CHECKLIST.zh-CN.md +++ /dev/null @@ -1,272 +0,0 @@ -# Agent 4 Skill 验收清单 - -本文档用于验收 Agent 对 4 个管理类 skill 的字段认知、工具调用和用户可见行为是否与页面编辑能力对齐。 - -当前范围: -- `model_management` -- `exchange_management` -- `trader_management` -- `strategy_management` - -验收目标: -- 页面上能手动改的核心字段,Agent 也能稳定改 -- Agent 能回答页面上可见的字段与选项 -- 模糊请求不会被硬塞进错误 skill -- 多字段一句话更新时,不会被窄动作截断 - -## 0. 前置条件 - -- 已完成登录 -- 后端已启动 -- 至少准备 1 条可编辑的模型、交易所、交易员、策略数据 -- 测试前如果有旧上下文,先在 Agent 会话里执行 `/clear` - -建议先跑自动化回归: - -```bash -go test ./agent -run 'Test(ManageModelToolSchemaExposesEditableFields|ManageExchangeToolSchemaExposesEditableFields|ManageTraderToolSchemaExposesAdvancedFields|ManageStrategyToolSchemaExposesFieldLevelConfig|ModelManagementManualEditableFieldsAreCoveredByAgent|ExchangeManagementManualEditableFieldsAreCoveredByAgent|TraderManagementManualEditableFieldsAreCoveredByAgent|StrategyManagementManualEditableFieldsAreCoveredByAgent|ExchangeManagementUpdateSupportsManualFields|ModelManagementThinkAndActSupportsCompositeFieldUpdates|TraderManagementUpdateSupportsAdvancedManualFields|StrategyManagementThinkAndActSupportsGridAndRiskFields)' -``` - -对应测试主要在: -- [skill_dispatcher_test.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/skill_dispatcher_test.go) -- [config_tools_test.go](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/agent/config_tools_test.go) - -## 1. 自动化覆盖基线 - -通过以下检查后,才进入手工验收: - -- [ ] 4 个 skill 的 tool schema 已暴露字段级参数 -- [ ] 4 个 skill 的 manual editable field 集合都被 agent 字段目录覆盖 -- [ ] `model` 支持一句话同时改 `enabled + custom_api_url + custom_model_name` -- [ ] `exchange` 支持一句话同时改 `account_name + hyperliquid_wallet_addr + testnet` -- [ ] `trader` 支持高级字段更新 -- [ ] `strategy` 支持 grid/risk 多字段更新 - -## 2. Model Skill - -页面参考: -- [ModelConfigModal.tsx](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/web/src/components/trader/ModelConfigModal.tsx) - -核心字段: -- `provider` -- `name` -- `api_key` -- `custom_api_url` -- `custom_model_name` -- `enabled` - -手工验收: - -- [ ] 说“列出我的模型配置”时,能列出当前模型 -- [ ] 说“这个模型的接口地址改成 xxx,模型名称改成 yyy,并且禁用”时,能一次成功更新 -- [ ] 说“这个模型有哪些字段能改”时,回答至少覆盖 `API Key / 接口地址 / 模型名称 / 启用状态` -- [ ] 说“把这个模型启用”时,不会误触发重命名流程 -- [ ] 说“把这个模型改成最好的”这类抽象诉求时,不应硬造字段值;应该解释或引导 - -通过标准: -- 回复文本明确说明已更新模型配置 -- 页面刷新后字段真实变化 -- 不出现“我还需要你明确要操作哪个对象”这种错误兜底 - -## 3. Exchange Skill - -页面参考: -- [ExchangeConfigModal.tsx](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/web/src/components/trader/ExchangeConfigModal.tsx) - -核心字段: -- 公共字段: - - `exchange_type` - - `account_name` - - `enabled` - - `testnet` -- CEX: - - `api_key` - - `secret_key` - - `passphrase` -- Hyperliquid: - - `api_key` - - `hyperliquid_wallet_addr` -- Aster: - - `aster_user` - - `aster_signer` - - `aster_private_key` -- Lighter: - - `lighter_wallet_addr` - - `lighter_api_key_private_key` - - `lighter_api_key_index` - -手工验收: - -- [ ] 说“把 Dex 的账户名改成 Dex Pro,Hyperliquid 钱包改成 0xabc,testnet 打开”时,能一次成功更新 -- [ ] 说“这个交易所有哪些字段能改”时,能按当前交易所类型回答差异字段 -- [ ] 说“把这个交易所禁用”时,不会误进入改名分支 -- [ ] 说“列出我的交易所配置”时,能读出当前配置 -- [ ] 对缺少必填凭证的创建请求,会明确指出缺哪一项,而不是模糊失败 - -通过标准: -- 回复文本明确说明已更新交易所配置 -- 页面刷新后对应字段真实变化 -- 不因为对象解析失败而掉到“请明确对象” - -## 4. Trader Skill - -页面参考: -- [TraderConfigModal.tsx](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/web/src/components/trader/TraderConfigModal.tsx) - -页面核心字段: -- `name` -- `ai_model_id` -- `exchange_id` -- `strategy_id` -- `is_cross_margin` -- `show_in_competition` -- `scan_interval_minutes` -- `initial_balance` - -Agent 扩展字段: -- `btc_eth_leverage` -- `altcoin_leverage` -- `trading_symbols` -- `custom_prompt` -- `override_base_prompt` -- `system_prompt_template` -- `use_ai500` -- `use_oi_top` - -手工验收: - -- [ ] 说“把交易员 A 切换到策略 B,扫描间隔改成 8 分钟,全仓关闭,竞技场显示关闭”时,能一次成功更新 -- [ ] 说“把高级交易员的 BTC/ETH 杠杆改成 8,山寨币杠杆改成 4,交易对改成 BTC、ETH,自定义 prompt 改成 xxx,启用 AI500”时,能成功更新 -- [ ] 说“这个交易员有哪些字段能改”时,至少能回答页面核心字段和 Agent 扩展字段 -- [ ] 说“启动这个交易员”时,仍会保留高风险确认链路 -- [ ] 说“为什么我的交易员不交易”时,仍能走诊断 skill,不会被错误识别成 update - -通过标准: -- 回复文本明确说明更新了交易员配置或绑定 -- 页面刷新或查询结果能看到真实变化 -- `交易对` 提取不会误吞后半句自然语言 - -## 5. Strategy Skill - -页面参考: -- [StrategyStudioPage.tsx](/Users/zheweifang/Desktop/Nofx2/nofxi-dev/web/src/pages/StrategyStudioPage.tsx) - -编辑器模块: -- `grid_config` -- `coin_source` -- `indicators` -- `risk_control` -- `prompt_sections` -- `custom_prompt` -- `publish_settings` - -重点字段: -- 元信息: - - `name` - - `description` - - `strategy_type` - - `is_public` - - `config_visible` -- Grid: - - `symbol` - - `grid_count` - - `total_investment` - - `upper_price` - - `lower_price` - - `use_atr_bounds` - - `atr_multiplier` - - `distribution` - - `enable_direction_adjust` - - `direction_bias_ratio` - - `max_drawdown_pct` - - `stop_loss_pct` - - `daily_loss_limit_pct` - - `use_maker_only` -- Coin source: - - `source_type` - - `static_coins` - - `excluded_coins` - - `use_ai500` - - `ai500_limit` - - `use_oi_top` - - `oi_top_limit` - - `use_oi_low` - - `oi_low_limit` -- Risk: - - `max_positions` - - `min_confidence` - - `min_risk_reward_ratio` - - `btceth_max_leverage` - - `altcoin_max_leverage` - - `btceth_max_position_value_ratio` - - `altcoin_max_position_value_ratio` - - `max_margin_usage` - - `min_position_size` -- Indicators / timeframe: - - `primary_timeframe` - - `primary_count` - - `selected_timeframes` - - `ema_periods` - - `rsi_periods` - - `atr_periods` - - `boll_periods` - - `enable_ema` - - `enable_macd` - - `enable_rsi` - - `enable_atr` - - `enable_boll` - - `enable_volume` - - `enable_oi` - - `enable_funding_rate` -- Prompt: - - `role_definition` - - `trading_frequency` - - `entry_standards` - - `decision_process` - - `custom_prompt` - -手工验收: - -- [ ] 说“把策略 A 改成网格策略,网格数量改成 14,ATR 倍数改成 2.5,最大保证金使用率改成 0.6”时,能一次成功更新 -- [ ] 说“把选币来源改成静态,静态币改成 BTC、ETH,排除 DOGE,AI500 关闭”时,能成功更新 -- [ ] 说“选币来源有哪些”时,能回答当前面板的来源类型与相关选项,而不是重复草稿摘要 -- [ ] 说“这个策略里面的参数和 prompt 分别是什么样的”时,能走 explain/detail,不会误更新 -- [ ] 说“帮我创建一个不亏钱的策略”这类抽象请求时,不应直接强绑到字段创建;应该回退 planner 或引导细化 - -通过标准: -- 回复文本明确说明已更新策略参数或进入合理引导 -- Strategy Studio 刷新后真实反映更新 -- 不会把开放式目标误当作已可执行的精确配置 - -## 6. 跨 Skill 语义验收 - -- [ ] 模糊输入先过统一语义网关,再决定 `continue_active / resume_snapshot / start_new` -- [ ] 一个 skill 进行中时,问页面字段选项,优先走 explain,不要硬落 execute -- [ ] 开放式目标型请求在参数不足时,优先回 planner,不要强行进 hard skill -- [ ] 同一句话改多个字段时,不会只改其中一个窄字段 -- [ ] `/clear` 后,旧的 skill session / workflow / execution state / snapshots 都被清空 -- [ ] 切回旧话题时,snapshot restore 能恢复到正确对象,而不是凭 heuristics 误接 - -## 7. 回归记录模板 - -每次验收建议记录: - -- 日期: -- 提交版本: -- 后端 PID: -- 前端地址: -- 本轮执行人: - -逐项记录: -- 用例: -- 用户原话: -- 预期: -- 实际: -- 是否通过: -- 备注: - -## 8. 当前结论口径 - -当本文档第 1 节自动化基线和第 2-6 节核心手工项全部通过后,才建议对外宣称: - -“Agent 对 4 个 skill 已基本对齐当前页面可编辑能力,并具备稳定的 explain / execute / planner fallback 行为。” diff --git a/docs/qa/fixtures/agent_self_play_seed.zh-CN.json b/docs/qa/fixtures/agent_self_play_seed.zh-CN.json deleted file mode 100644 index 7acf7a09..00000000 --- a/docs/qa/fixtures/agent_self_play_seed.zh-CN.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "scenarios": [ - { - "name": "trader_create_reports_all_missing_prereqs", - "desc": "空白环境下创建交易员,应一次性报告所有必填槽位和依赖缺口。", - "turns": [ - { - "user": "帮我创建一个交易员", - "want_all": ["名称", "交易所", "模型", "策略", "当前还没有可用交易所配置", "当前还没有可用模型配置", "当前还没有可用策略"] - } - ] - }, - { - "name": "strategy_update_risk_control_clamp_requires_acceptance", - "desc": "策略参数越界时,应先给出风控收敛说明,再等待确认应用。", - "setup": [ - { - "tool": "manage_strategy", - "args": { - "action": "create", - "name": "风险策略", - "lang": "zh" - } - } - ], - "turns": [ - { - "user": "把风险策略的杠杆改成100", - "want_any": ["手动面板允许的范围", "按风控范围收敛"] - }, - { - "user": "确认应用", - "want_any": ["确认应用", "风控范围", "已更新策略参数"] - } - ] - } - ] -} diff --git a/web/node_modules b/web/node_modules deleted file mode 120000 index b6f5f7e8..00000000 --- a/web/node_modules +++ /dev/null @@ -1 +0,0 @@ -/Users/zheweifang/Desktop/Nofx2/nofxi/web/node_modules \ No newline at end of file