Agent 原理
Nephele 的 Agent 不是聊天机器人,而是一个能动手干活的助手。它理解你的意图后,会自己规划步骤、调用工具、观察结果、调整策略,直到把事情做完。
这套机制的核心是 ReAct 循环(Reasoning + Acting):先思考,再行动,观察结果,再思考下一步。但 Nephele 还会在这之前做一个快速规则检查——如果是很明确的简单指令,直接执行,不浪费 LLM 算力。
两条执行路径
Agent 处理你的请求时,会优先走第一条路径,走不通才进入第二条:
路径一:规则引擎(零延迟)
对于"打开 Chrome"、"列出桌面文件"这类意图明确的简单命令,Agent 先用内置的规则引擎直接解析,匹配到对应工具就立即执行。全程不调用 LLM,响应是瞬时的。
路径二:ReAct 循环(LLM 推理)
复杂或模糊的请求进入 ReAct 循环。Agent 和 LLM 之间多轮交互,每轮 LLM 决定调用什么工具,Agent 执行后把结果喂回去,直到任务完成或达到上限。
进 ReAct 之前还有一道免费的引导通道闸门先消化「软件怎么用」这类轻问题(见下文「分流与计费」),真正要动手干活的请求才进入完整的 Cloud MAX。
| 规则引擎 | ReAct 循环 | |
|---|---|---|
| 延迟 | 毫秒级 | 秒级(取决于模型和网络) |
| 使用 LLM | 否 | 是 |
| 适合场景 | 明确的开/关/查指令 | 分析、创作、多步任务 |
| 工具调用次数 | 1 次 | 最多 20 次 |
分流与计费
主输入框是一个统一入口,你打字后会按成本从低到高分三层处理:
| 层 | 处理者 | 用 LLM | 消耗 | 适合 |
|---|---|---|---|---|
| 规则引擎 | 本地,零延迟 | 否 | 零 | 明确的开/关/查命令 |
| 引导通道闸门 | 轻量模型 Axioma Zephyr | 是(轻量) | 免费,不扣 stamina | 软件用法、导航、一句话事实 |
| Cloud MAX | Axioma Breeze | 是 | 按云晶计费 | 分析、创作、多步任务 |
提示
分流对你是透明的——你不用手动选模式。规则引擎处理不了就交给引导通道免费消化一轮,仍处理不了才放行到 Cloud MAX。引导通道故障一律放行,绝不会卡住你的输入。Cloud MAX 联网推理,先扣疲劳值(Stamina),疲劳值用完再动云晶(Nepheline)。
唯一的"特殊工具"差异在 Cloud MAX:进入 Cloud MAX 模式后会额外注册 cloud_search(云端实时搜索)和 delegate_tasks(子任务委派)。
ReAct 循环:一步一脚印
进入 Cloud MAX 后,Agent 跑一个 ReAct 循环,一次完整交互如下:
- 构建请求 —— 把 system prompt(含工具说明、用户记忆、当前时间)+ 对话历史 + 你的新消息,作为 SSE 流式请求发给 Axioma Breeze
- 流式接收 —— 模型返回思维链(thinking)和正文(content),Agent 实时转发给 UI
- 工具调用 —— 如果模型决定调用工具,Agent 执行工具,把结果格式化后追加到对话历史;支持一次收集多个工具调用再批量执行(解决早期多工具丢失的 bug)
- 循环判断 —— 任务没完成就回到第 1 步,继续下一轮
迭代上限
硬上限是 20 次工具调用。达到上限后 Agent 会停止并告知你"任务可能未完全完成"。
停止机制
你可以随时点击停止按钮,Agent 会在以下位置检查取消信号:
- 每轮迭代开始前
- SSE 流接收过程中
- 串行工具执行间隙
停止后,已执行的工具结果不会被撤销,但后续工具调用会取消。
工具系统
意图感知的工具加载
Agent 工具数量在持续变化,但不会一次性把所有工具的详细参数都塞给模型,而是按需加载:初始只加载 Tier 1 核心工具(约二十个常用工具,含 tool_search),其余约四十个工具在 <available-tools> 块里按类别只列名字。模型需要时调用 tool_search 动态加载具体 schema。这会把每轮输入 token 从约 3000 降到约 500,省下大量上下文。
按云晶计费的云端工具(如 cloud_search、find_artist_works)在纯本地的快捷命令路径下根本不会暴露,是一道额外的防护。
并行执行
如果一轮里模型要求调用多个工具,Agent 会根据每个工具自身的 concurrency_safe 属性判断哪些可以并行——可并行的工具用 ThreadPoolExecutor(最多 4 个线程)同时执行,其余串行。
run_python 永远不会被并行,且执行前需要你在弹窗中确认代码内容(可编辑)。
记忆系统
Agent 的记忆是卡片化的:每条记忆是一个独立的 Markdown 文件,存放在本地 ~/.nephele_workshop/memory/ 目录下,附带简短的 frontmatter(标题、一句话摘要、类型)。
记忆的五种类型
Agent 通过 memory_write 工具把对话中值得长期保留的信息存成一条记忆,每条都归到下面五类之一:
- user —— 你是谁(创作风格、个人习惯)
- workflow —— 你怎么工作(常用流程、偏好设置)
- project —— 你在做什么(当前项目背景)
- reference —— 你的账号、常用路径等参照信息
- correction —— 对 Agent 行为的校正偏好
只有跨会话值得长期保留的内容才写入;本次会话的临时偏好、工具调用细节这类中间状态不会被存。
索引与按需读取
Agent 不会把所有记忆全文塞进上下文,而是只注入一份自动维护的索引(MEMORY.md)——索引里每条记忆只占一行(标题 + 一句话摘要),按类型分组、组内按最近更新排序。Agent 看索引就知道有哪些记忆可用,真正需要某条详情时再调 memory_load 读取全文。
记忆的增删改由 memory_write(新建或同名覆盖)、memory_update、memory_delete 三个工具完成。注入上下文的索引上限约 4000 字符,单条记忆摘要上限 200 字符、正文上限 6000 字符,超过会截断。没有任何记忆时,索引为空、完全不占 token。
技巧
所有记忆都只存在于你的本地设备,不上传服务器。
子 Agent 委派
遇到复杂任务时,Agent 可以调用 delegate_tasks 把任务拆成多个子任务。每个子任务由一个子 Agent 处理。
限制:
- 最多 6 个子任务
- 单个超时 120 秒
- 真正并行执行(ThreadPoolExecutor,最多 4 个并发)
- 仅 Cloud MAX 模式可用(
delegate_tasks是 Cloud MAX 专属工具)
子 Agent 有一些额外约束:
- 不能继续委派其他子 Agent(防止无限递归)
- 不能执行需要用户确认的操作(如
run_python)
内部还做了反模式检测:如果你要求找参考图,主 Agent 不应该用 delegate_tasks 拆成多个找图子任务,因为 find_references 内部已经并行搜索多个平台了。
安全与真实性约束
run_python 确认
执行 Python 代码前会弹出确认窗口,展示完整代码和描述。你可以取消、直接确认、或编辑后再确认。
图片压缩
Agent 接收图片附件时,会自动压缩到最长边 1536px、JPEG 质量 85%,减少 base64 传输体积和 token 消耗。GIF 等动画格式保持原样。
真实性硬约束(Cloud MAX)
Cloud MAX 的系统 prompt 中嵌入了最高优先级约束:
- 禁止编造任何 ID、URL、文件路径、图片信息
- 只能使用工具返回值中真实出现的数据
- 工具返回 0 结果时,如实告知"未找到",不要虚构数据填充
- 反搜 URL 必须经过
resolve_source_url解析才能作为"原作者"报告
工具错误自修正
工具失败后,Agent 会在结果前加上 [ERROR] 标签,并附加可操作的提示:
- "找不到文件" → 提示用
search_files确认路径 - "权限不足" → 提示尝试用户主目录下的路径
- "超时" → 提示可重试或换方式
事件流架构
Agent 不是"说完一段话再显示",而是实时流式输出:
- 思维链(thinking)实时显示
- 正文(content)逐字出现
- 工具调用开始/结束都有通知
- 配额、 stamina 消耗实时更新
Agent 核心通过纯生成器产出事件(AgentEvent 子类),再由 AgentWorker 转成 Qt Signal 发给 QML 界面。这种设计让 Agent 可以跑在后台线程,不会卡住 UI。
主要事件类型:
| 事件 | 说明 |
|---|---|
StreamChunk | 正文文本片段 |
ThinkingChunk | 思维链片段 |
ToolStart | 工具开始执行 |
ToolFinish | 工具执行完成(含成功/失败状态和结果) |
NavigateView | 需要切换界面视图 |
RateLimitUpdate | 疲劳值配额更新 |
StaminaCost | 单次请求 stamina 消耗 |
CreditsUpdate | 云晶余额更新 |
LoopError | 循环出错(网络/认证/服务不可用) |
LoopDone | 一轮对话完成 |
操作日志与撤销
每轮 Agent 对话会被记录到 OperationJournal,生成一个唯一 round ID。完成时会在消息末尾注入 <!--UNDO:round_id--> 标记。这意味着某些操作未来可能支持撤销(目前标记已埋入,UI 层待实现)。