@eoasmxd/freya 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -3
- package/core/dist/command/commands/skill-commands.js +5 -4
- package/core/dist/config/config-manager.d.ts +5 -1
- package/core/dist/config/config-manager.js +13 -1
- package/core/dist/kernel.js +2 -2
- package/core/dist/skill/skill-registry.d.ts +12 -2
- package/core/dist/skill/skill-registry.js +89 -8
- package/core/dist/tools/meta/index.d.ts +3 -1
- package/core/dist/tools/meta/index.js +9 -1
- package/core/dist/web/config-api.js +18 -0
- package/core/package.json +2 -2
- package/doc/_index.md +20 -7
- package/doc/getting-started.md +1 -1
- package/doc/installation-guide.md +2 -2
- package/doc/{architecture-design.md → specifications/architecture-design.md} +7 -4
- package/doc/{config-spec.md → specifications/config-spec.md} +1 -1
- package/doc/{llm-interface-params.md → specifications/llm-interface-params.md} +8 -8
- package/doc/{prompt-system.md → specifications/prompt-system.md} +1 -1
- package/doc/tutorials/_index.md +96 -0
- package/doc/tutorials/part0_basic/0.1_probability_prediction.md +155 -0
- package/doc/tutorials/part0_basic/0.2_attention_and_context.md +145 -0
- package/doc/tutorials/part0_basic/0.3_generation_parameters.md +132 -0
- package/doc/tutorials/part0_basic/0.4_debugging_token.md +99 -0
- package/doc/tutorials/part0_basic/1.1_stateless_and_history.md +143 -0
- package/doc/tutorials/part0_basic/1.2_chat_data_structure.md +179 -0
- package/doc/tutorials/part0_basic/1.3_system_user_assistant.md +147 -0
- package/doc/tutorials/part0_basic/1.4_freya_model_proxy.md +203 -0
- package/doc/tutorials/part0_basic/_index.md +28 -0
- package/doc/tutorials/part1_react/2.1_agency_vs_chatbot.md +127 -0
- package/doc/tutorials/part1_react/2.2_react_mind_model.md +144 -0
- package/doc/tutorials/part1_react/2.3_freya_agent_executor.md +233 -0
- package/doc/tutorials/part1_react/2.4_debugging_loop_deadlock.md +160 -0
- package/doc/tutorials/part1_react/3.1_hardcoded_prompt_pain.md +104 -0
- package/doc/tutorials/part1_react/3.2_decoupled_architecture.md +138 -0
- package/doc/tutorials/part1_react/3.3_freya_dual_read_probe.md +152 -0
- package/doc/tutorials/part1_react/3.4_debugging_composition_placeholder.md +97 -0
- package/doc/tutorials/part1_react/_index.md +28 -0
- package/doc/tutorials/part2_tools/4.1_json_schema_mapping.md +119 -0
- package/doc/tutorials/part2_tools/4.2_tool_call_raw_packet.md +105 -0
- package/doc/tutorials/part2_tools/4.3_freya_tool_execution.md +145 -0
- package/doc/tutorials/part2_tools/4.4_debugging_observation_fix.md +154 -0
- package/doc/tutorials/part2_tools/5.1_observation_injection.md +131 -0
- package/doc/tutorials/part2_tools/5.2_openai_vs_gemini_protocol.md +125 -0
- package/doc/tutorials/part2_tools/5.3_freya_llm_proxy_mapping.md +162 -0
- package/doc/tutorials/part2_tools/5.4_debugging_parallel_call_chaos.md +135 -0
- package/doc/tutorials/part2_tools/_index.md +28 -0
- package/doc/tutorials/part3_memory/6.1_session_state_lifecycle.md +143 -0
- package/doc/tutorials/part3_memory/6.2_physical_sandbox_separation.md +108 -0
- package/doc/tutorials/part3_memory/6.3_freya_session_storage.md +139 -0
- package/doc/tutorials/part3_memory/6.4_debugging_session_concurrency.md +161 -0
- package/doc/tutorials/part3_memory/7.1_context_overflow_loss.md +109 -0
- package/doc/tutorials/part3_memory/7.2_sliding_window_vs_summary.md +85 -0
- package/doc/tutorials/part3_memory/7.3_freya_compactor_impl.md +142 -0
- package/doc/tutorials/part3_memory/7.4_debugging_summarize_deadlock.md +160 -0
- package/doc/tutorials/part3_memory/_index.md +28 -0
- package/doc/tutorials/part4_streaming/8.1_sse_protocol_basics.md +119 -0
- package/doc/tutorials/part4_streaming/8.2_hiding_thoughts_in_stream.md +132 -0
- package/doc/tutorials/part4_streaming/8.3_freya_event_bus.md +104 -0
- package/doc/tutorials/part4_streaming/8.4_debugging_stream_decoder.md +158 -0
- package/doc/tutorials/part4_streaming/9.1_abort_signal_braking.md +162 -0
- package/doc/tutorials/part4_streaming/9.2_async_event_channels.md +142 -0
- package/doc/tutorials/part4_streaming/9.3_freya_abort_billing.md +122 -0
- package/doc/tutorials/part4_streaming/9.4_debugging_abort_lock_deadlock.md +187 -0
- package/doc/tutorials/part4_streaming/_index.md +28 -0
- package/doc/tutorials/part5_plugins/10.1_microkernel_decoupling.md +142 -0
- package/doc/tutorials/part5_plugins/10.2_plugin_metadata_security.md +125 -0
- package/doc/tutorials/part5_plugins/10.3_channel_plugin_development.md +149 -0
- package/doc/tutorials/part5_plugins/10.4_debugging_channel_reconnection.md +160 -0
- package/doc/tutorials/part5_plugins/_index.md +21 -0
- package/doc/tutorials/part6_advanced/11.1_react_model_flaws.md +111 -0
- package/doc/tutorials/part6_advanced/11.2_reflexion_mind_model.md +103 -0
- package/doc/tutorials/part6_advanced/11.3_reflexion_hands_on.md +182 -0
- package/doc/tutorials/part6_advanced/11.4_debugging_reflexion_convergence.md +108 -0
- package/doc/tutorials/part6_advanced/12.1_single_agent_limits.md +100 -0
- package/doc/tutorials/part6_advanced/12.2_multi_agent_patterns.md +121 -0
- package/doc/tutorials/part6_advanced/12.3_freya_multi_agent_routing.md +143 -0
- package/doc/tutorials/part6_advanced/12.4_multi_agent_hands_on.md +176 -0
- package/doc/tutorials/part6_advanced/_index.md +28 -0
- package/doc/tutorials/preface.md +30 -0
- package/package.json +3 -2
- package/plugins/plugin-gemini/package.json +1 -1
- package/plugins/plugin-openai/package.json +1 -1
- package/plugins/plugin-telegram-channel/package.json +1 -1
- package/plugins/plugin-tool-fs/package.json +1 -1
- package/plugins/plugin-tool-memory/package.json +1 -1
- package/plugins/plugin-tool-mysql/config/prompts/plugin.prompt.mysql.md +9 -0
- package/plugins/plugin-tool-mysql/config/prompts/plugin.prompt.mysql.select.audit.md +26 -0
- package/plugins/plugin-tool-mysql/dist/audit.d.ts +13 -0
- package/plugins/plugin-tool-mysql/dist/audit.js +87 -0
- package/plugins/plugin-tool-mysql/dist/index.d.ts +14 -0
- package/plugins/plugin-tool-mysql/dist/index.js +34 -0
- package/plugins/plugin-tool-mysql/dist/pool-manager.d.ts +32 -0
- package/plugins/plugin-tool-mysql/dist/pool-manager.js +113 -0
- package/plugins/plugin-tool-mysql/dist/tools.d.ts +11 -0
- package/plugins/plugin-tool-mysql/dist/tools.js +88 -0
- package/plugins/plugin-tool-mysql/package.json +33 -0
- package/plugins/plugin-tool-mysql/schema.json +83 -0
- package/plugins/plugin-tool-web/package.json +1 -1
- package/plugins/plugin-wecom-channel/package.json +1 -1
- package/plugins/plugin-weixin-channel/package.json +1 -1
- package/src/packages/core/src/command/commands/skill-commands.ts +6 -5
- package/src/packages/core/src/config/config-manager.ts +15 -1
- package/src/packages/core/src/kernel.ts +3 -2
- package/src/packages/core/src/skill/skill-registry.ts +100 -8
- package/src/packages/core/src/tools/meta/index.ts +9 -1
- package/src/packages/core/src/web/config-api.ts +20 -0
- package/src/packages/ui/src/features/config/ConfigModal.tsx +13 -1
- package/src/packages/ui/src/features/config/panels/SkillConfigPanel.tsx +137 -0
- package/src/plugins/plugin-tool-mysql/src/audit.ts +103 -0
- package/src/plugins/plugin-tool-mysql/src/index.ts +44 -0
- package/src/plugins/plugin-tool-mysql/src/pool-manager.ts +132 -0
- package/src/plugins/plugin-tool-mysql/src/tools.ts +100 -0
- package/ui/assets/{index-Be0cAgdB.js → index-BqPQMflk.js} +14 -14
- package/ui/index.html +1 -1
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "11.1 ReAct 决策环的物理缺陷"
|
|
3
|
+
weight: 10
|
|
4
|
+
description: "探讨经典 ReAct 决策环在复杂业务下的三大物理局限,分析临场短视、误差传播与高频空转成因,设计工具重复调用频率拦截器。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 11.1 ReAct 决策环的物理缺陷
|
|
8
|
+
|
|
9
|
+
在前面的第一至第五部分中,我们围绕 **ReAct(Reasoning + Acting)** 决策自循环(Thought-Action-Observation 环)构建了智能体底座的全部基石。ReAct 几乎是当今所有智能体框架(包括 LangChain、AutoGPT 和 Freya)的黄金默认控制流。
|
|
10
|
+
|
|
11
|
+
然而,当我们试图让基于 ReAct 的智能体去处理一些高度复杂、多步迭代、且容错率极低的工业级任务(例如:编写复杂的代码重构方案、跨多系统的综合财务账单审计、或长文本研究报告的真伪核验)时,我们会迅速撞上 ReAct 架构的**物理天花板**。
|
|
12
|
+
|
|
13
|
+
智能体会表现出令人抓狂的“愚笨”:陷入死循环、在同一个错误工具参数上撞墙 20 次直至额度耗尽、或者推导到一半彻底跑偏。
|
|
14
|
+
|
|
15
|
+
本节我们将以**前沿认知科学家与系统架构师的双重视角**,深度解剖经典 ReAct 决策环面临的三大物理局限,探讨记忆误差传播的机理,并引入工具调用去重拦截防线。
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 一、 ReAct 决策环的线性短视局限 (Myopic Reasoning)
|
|
20
|
+
|
|
21
|
+
ReAct 协议本质上是一种**“单向线性自回归接龙”**。智能体在每一步(Turn $k$)做出的 Thought 决策,在物理上仅仅依赖于上下文(Messages 数组)里前 $k-1$ 步留下的“既定事实”。
|
|
22
|
+
|
|
23
|
+
这种时序迭代存在一个致命硬伤:**缺乏全局先期规划与回溯推翻机制。**
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
[Turn 1] Thought: "我认为是 A..." ──> Action: 调用 A ──> Obs: 报错
|
|
27
|
+
│
|
|
28
|
+
▼ (线性顺延,无法反悔)
|
|
29
|
+
[Turn 2] Thought: "既然 A 报错,那我就调试 A 的参数..." ──> Action: 再次调用 A (深陷泥潭)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
1. **临场短视(Myopic Search)**:大模型在生成当前的 Thought 时,就像一个下意识抓取概率的接龙机器。它无法在推理中像人类一样“停下来,把之前画的设计图全部擦掉,重新思考全局路线”。
|
|
33
|
+
2. **局部最优死胡同(Local Optima Deadlock)**:如果大模型在第一步做出了一个错误的“先导假设”(例如:主观臆测用户查的是小明的国内订单,而用户其实查的是跨境订单),一旦这个错误假设引发的 Tool Call 历史写入了 Session 数据库,大模型在后面的步骤中就极难跳出这个心智框架,它只会顺着错路越走越远,直至把步数撞到 `maxTurns` 物理上限被底座强行熔断。
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 二、 记忆中的误差累积与自我确认 (Error Propagation)
|
|
38
|
+
|
|
39
|
+
自回归模型的注意力机制会受到上下文历史文本的强力拉拽(Attention Pull)。在 ReAct 循环中,**所有的失败动作、错误的参数尝试、以及报错堆栈,全都被无差别地 append 进了 Messages 历史。**
|
|
40
|
+
|
|
41
|
+
这引发了严重的**误差累积(Error Propagation)与大模型“自我确认”灾难**:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
用户提问 ──> 【错误 Thought 1】 ──> 【错误 Tool Call】 ──> 【报错 Observation】
|
|
45
|
+
│
|
|
46
|
+
▼ (Attention 持续扫描错误历史)
|
|
47
|
+
【错误 Thought 2】 <── (大模型注意力点积被上一步的错误文本强力偏置,导致其继续确信错误方向)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
* **物理成因**:由于大模型在生成第 $k$ 步时,其注意力点积计算会将之前写好的“错误 Thought”和“报错 Observation”作为高权重特征引入。大模型越看自己之前写的胡话,就越觉得自己之前的方向是对的(认知失调中的自我辩护)。这会导致后续生成的 Thought 发生严重的概率倾斜,使智能体丧失了客观中立评估任务进展的能力。
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 三、 高频无意义的 Tool Call 试错 (Token Cost Runaway)
|
|
55
|
+
|
|
56
|
+
在缺乏“反思过滤层”的 ReAct 架构中,大模型在遇到模糊甚至错误的指令时,倾向于盲目试错:
|
|
57
|
+
* 用户输入了一个拼写错误的 API 参数名。
|
|
58
|
+
* 大模型开始胡乱猜测参数并调用接口。
|
|
59
|
+
* 接口报错,大模型换个参数再次调用。
|
|
60
|
+
* **后果**:在一轮交互中,大模型空转调用了 15 次接口,不仅导致用户的等待时间(TTFT)拉长到几分钟,而且每一次多轮往返都在高频燃烧输入 Token(每一次带回的历史都在翻倍),产生了极其高昂且毫无产出的 API 费用账单。
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 四、 【避坑防线】工具重复调用频率拦截器
|
|
65
|
+
|
|
66
|
+
为了拯救深陷 ReAct 试错泥潭、高频空转的智能体,我们不能仅仅期盼大模型自己变得更聪明。**底座核心必须在物理层面充当大模型大脑的“行为监察御史”**。
|
|
67
|
+
|
|
68
|
+
在 Freya 中,除了通过 `agent-executor.ts` 中的 `maxTurns` 轮数上限(超出时自动挂载 `core.prompt.max_turns`)进行硬熔断外,我们还可以设计**工具调用重复性拦截防线(Tool Duplicate Invocation Blocker)**:
|
|
69
|
+
|
|
70
|
+
* **参数哈希监控**:每次大模型输出 Tool Call 意图时,底座在执行前,将 `(toolName + arguments)` 计算一个 SHA-256 签名。
|
|
71
|
+
* **死锁判定**:如果检测到智能体在最近几轮内,**以完全相同的参数反复调用同一个工具且持续报错**,底座判定智能体陷入了“认知鬼打墙”。
|
|
72
|
+
* **零硬编码纠错注入**:底座拦截该 Tool Call 执行,拒绝向大模型发送无意义报错,而是通过 `FreyaPromptRegistry` 提取物理模板,反向往 Message 历史中灌入一条强制的 **System 纠错信(Critique Injection)**:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import crypto from 'node:crypto';
|
|
76
|
+
import type { FreyaPromptRegistry } from '../prompt/prompt-registry.js';
|
|
77
|
+
|
|
78
|
+
// 💡 底座级的工具死循环拦截与纠错注入
|
|
79
|
+
export class ToolDeadlockInterceptor {
|
|
80
|
+
private callHistory = new Map<string, Array<{ argsHash: string; timestamp: number }>>();
|
|
81
|
+
|
|
82
|
+
constructor(private promptRegistry: FreyaPromptRegistry) {}
|
|
83
|
+
|
|
84
|
+
checkAndInject(sessionId: string, toolName: string, argsStr: string): string | null {
|
|
85
|
+
const hash = crypto.createHash('sha256').update(toolName + argsStr).digest('hex');
|
|
86
|
+
const userHistory = this.callHistory.get(sessionId) || [];
|
|
87
|
+
|
|
88
|
+
// 1. 过滤最近 3 轮内的重复调用记录
|
|
89
|
+
const duplicates = userHistory.filter(h => h.argsHash === hash);
|
|
90
|
+
|
|
91
|
+
if (duplicates.length >= 2) {
|
|
92
|
+
// 2. 💡 严格遵循零硬编码规范,从物理模板加载反思引导语
|
|
93
|
+
const template = this.promptRegistry.get('core.prompt.tool_deadlock') || '';
|
|
94
|
+
return template
|
|
95
|
+
.replace('{toolName}', toolName)
|
|
96
|
+
.replace('{count}', String(duplicates.length + 1));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 记录本次调用
|
|
100
|
+
userHistory.push({ argsHash: hash, timestamp: Date.now() });
|
|
101
|
+
this.callHistory.set(sessionId, userHistory);
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 物理安全效果:
|
|
108
|
+
当大模型在下一轮推理中扫描到这条系统反思警告时,其注意力矩阵的权重会被强行重置偏置,迫使其从自负的盲目接龙中醒悟过来,主动向用户承认错误或回退方案,成功消灭了高昂的账单空转。
|
|
109
|
+
|
|
110
|
+
本节我们解剖了经典 ReAct 决策环面临的线性短视、误差累积与高频空转缺陷,并引入了底座级的死锁拦截器。为了彻底让智能体具备“回溯推翻、自我审判”的高阶心智,在下一小节中,我们将推开自我反思(Reflexion)心智模型的大门。
|
|
111
|
+
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "11.2 进阶反思心智模型解析"
|
|
3
|
+
weight: 20
|
|
4
|
+
description: "探秘前沿 Reflexion(反思)架构的设计哲学,解剖 Actor-Evaluator-SelfReflection 三原色角色分工与非对称多阶模型防自圆其说设计。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 11.2 进阶反思心智模型解析
|
|
8
|
+
|
|
9
|
+
在 11.1 节中,我们深度剖析了经典 ReAct 决策环在处理复杂业务时,由于线性短视和注意力偏置导致的“自我强化犯错”和“空转死锁”缺陷。为了打碎这一物理天花板,智能体的心智模型必须从“下意识的反射弧(ReAct)”升级为具备**“自我审判与回溯归因(Reflexion)”**的高阶架构。
|
|
10
|
+
|
|
11
|
+
**Reflexion(反思模型)**是由麻省理工学院(MIT)等机构于 2023 年提出的一种先进智能体架构。它允许智能体在任务失败时,不停下来沮丧,而是通过一个独立的“虚拟反思器”对先前的失败轨迹进行无情解剖,生成反思记忆,并在下一轮尝试中实施精准的自我纠错(Self-Correction)。
|
|
12
|
+
|
|
13
|
+
本节我们将详细拆解 Reflexion 模型的底层设计哲学、三原色角色分工,以及在工程上防范大模型反思时“自圆其说”的非对称架构设计。
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 一、 Reflexion 模型的设计哲学:从挫败中归纳经验
|
|
18
|
+
|
|
19
|
+
经典的 ReAct 如果任务失败,只会得到一句来自环境的冷冰冰报错(如 `Error: Type mismatch`)。大模型只能在一边看着报错,一边手忙脚乱地生成下一个 Token,这极其考验模型的临场接龙心智。
|
|
20
|
+
|
|
21
|
+
而 Reflexion 的核心哲学是:**引入后台归因整理(Attribution Analysis)**。
|
|
22
|
+
|
|
23
|
+
当任务受挫时,底座会切断 Actor 的直接执行流,把“刚才做了什么(轨迹)”和“哪里报错了(反馈)”打包成反思任务。通过调用大模型,归纳出一段纯文本的**“反思记忆(Reflexion Memory)”**:
|
|
24
|
+
`“我刚才在执行代码重构时,把变量 x 的声明放在了 await 之后,导致了未定义报错。我必须在下一次生成时,无条件把 x 移到 await 之前。”`
|
|
25
|
+
|
|
26
|
+
这段反思记忆将被物理持久化,并在下一轮对话中作为强力约束注入上下文。
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 二、 Reflexion 的三原色角色分工
|
|
31
|
+
|
|
32
|
+
在物理实现上,一个完整的 Reflexion 智能体由以下三个相互协作的“虚拟角色”联合缝合而成:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
┌───────────────── 用户输入 ─────────────────┐
|
|
36
|
+
│ │
|
|
37
|
+
▼ ▼
|
|
38
|
+
┌──────────────────────────────────────┐ ┌──────────────────────────────────────┐
|
|
39
|
+
│ Actor (执行者) ├────>│ Evaluator (评审裁判) │
|
|
40
|
+
└──────────────────▲───────────────────┘ └──────────────────┬───────────────────┘
|
|
41
|
+
│ │
|
|
42
|
+
│ 注入反思记忆 │ 判定失败 (False)
|
|
43
|
+
│ ▼
|
|
44
|
+
┌──────────────────┴───────────────────┐ ┌──────────────────────────────────────┐
|
|
45
|
+
│ Reflexion Memory (反思记忆库) │<────┤ Self-Reflection (自我反思器) │
|
|
46
|
+
└──────────────────────────────────────┘ └──────────────────────────────────────┘
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 1. Actor(执行者 / 行动派)
|
|
50
|
+
* **职责**:负责与环境进行真实的 ReAct 往返。它调用工具、收集 Observation,并产生初步的回答(Answer)或代码方案。
|
|
51
|
+
* **物理特点**:它拥有快速行动力,但在遇到复杂阻碍时容易迷失。
|
|
52
|
+
|
|
53
|
+
### 2. Evaluator(评估者 / 评审裁判)
|
|
54
|
+
* **职责**:负责对 Actor 产出的最终结果进行客观判定。
|
|
55
|
+
* **物理实现**:它可以是一个纯代码的**硬性断言器(Oracle / Hard Assertions)**(例如:直接运行 `jest` 单元测试脚本,查看测试是否 100% 通过);也可以是一个高阶模型的**软性评审器**(大模型判定其格式与安全性是否合规)。它最终输出一个 `True/False` 信号与一份详尽的报错评估报告。
|
|
56
|
+
|
|
57
|
+
### 3. Self-Reflection(自我反思器 / 思想家)
|
|
58
|
+
* **职责**:一旦 Evaluator 返回 `False`(判定失败),自我反思器被瞬间激活。
|
|
59
|
+
* **物理实现**:它读取 Actor 的整个 `choices` 轨迹和 Evaluator 的报错报告,进行自我审判归因,回答两个核心问题:`“我的哪个前置假设错了?我应该如何避免?”`,并将生成的反思文本写入 `Reflexion Memory` 缓存数据库。
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 三、 反思记忆(Reflexion Memory)的物理注入控制
|
|
64
|
+
|
|
65
|
+
当 Self-Reflection 产生了一段反思文本(例如 `Reflexion_1`)后,底座在开启下一轮交互时,**必须将这段反思记忆强行拼接到 Actor 的 System Prompt 尾部**:
|
|
66
|
+
|
|
67
|
+
```markdown
|
|
68
|
+
# SYSTEM PROMPT (Actor 导演剧本)
|
|
69
|
+
你是一个高级代码重构助理...
|
|
70
|
+
|
|
71
|
+
# ⚠️ 历史失败经验与自我反思 (YOUR PAST FAILURE REFLECTIONS)
|
|
72
|
+
在之前的尝试中,你犯了以下错误并导致任务失败。请在本次推理中无条件吸取教训,绝对不要重蹈覆辙:
|
|
73
|
+
- [反思历史 1]: {Reflexion_1}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
* **注意力物理偏置**:由于这段反思记忆位于 System Prompt 尾部,大模型在计算自注意力矩阵时,对“过去失败点”的注意力点积权重会被强行拉升。这在物理层面上切断了大模型重复犯错的概率路径,使其自我纠错的成功率呈几何级级数提升。
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 四、 【架构调试避坑】防范低阶模型的“自圆其说”认知陷阱
|
|
81
|
+
|
|
82
|
+
在工程落地 Reflexion 架构时,最容易踩进的一个致命大坑是:**反思器的自我认知欺骗(Cognitive Rationalization)**。
|
|
83
|
+
|
|
84
|
+
### 1. 认知陷阱:自圆其说
|
|
85
|
+
如果你的 `Actor` 和 `Self-Reflection` 使用的是同一种低阶或量化大模型(如 Llama-3-8B):
|
|
86
|
+
当任务失败、Evaluator 抛出报错时,作为反思器的 Llama-3 在进行归因时,由于心智带宽不足,会开始本能地为自己刚才写的垃圾代码“寻找客观借口”自圆其说:
|
|
87
|
+
`“我认为我的代码没有任何问题。报错是因为测试用例编写得太严苛了。所以我决定在下一步中直接无视这个报错,继续维持原答案。”`
|
|
88
|
+
* **后果**:反思流产,智能体在接下来的尝试中继续错下去,整个 Reflexion 循环彻底沦为摆设。
|
|
89
|
+
|
|
90
|
+
### 2. 避坑策略:高低阶非对称模型搭配 (Hierarchical Evaluation)
|
|
91
|
+
为了击碎低阶模型的逻辑盲区,我们在架构设计上必须采取**非对称模型装配策略**:
|
|
92
|
+
|
|
93
|
+
* **Actor (低成本执行器)**:采用低成本、高并发、响应极速的模型(如 GPT-4o-mini 或本地 Llama-3-8B)。它们负责干重活,频繁调用工具进行代码撰写。
|
|
94
|
+
* **Self-Reflection & Evaluator (高阶严厉导师)**:采用逻辑心智处于行业金字塔顶端的顶级模型(如 GPT-4o、Claude 3.5 Sonnet 或 DeepSeek-R1)。
|
|
95
|
+
* **效果**:当 Actor 的垃圾方案报错时,高阶的“导师模型”会对低阶模型的执行轨迹进行严厉的降维审判,生成一针见血的反思归因,并以强制 System 规范强加给低阶 Actor。
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
[低阶 Actor 出方案 (便宜/快)] ──> 【高阶 Evaluator 降维审判 (心智极高)】 ──> 精准反思 ──> 指导低阶 Actor 纠错
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
通过这一层非对称的模型梯队装配,底座以极低的 Token 成本代价,换取了 100% 稳健的自我反思纠错质量,实现了生产级别的降维控本。
|
|
102
|
+
|
|
103
|
+
本节我们深入解刨了 Reflexion 架构的 Actor-Evaluator-SelfReflection 三原色分工与非对称多阶模型防自圆其说设计。在下一小节中,我们将卷起袖子,实际动手在本地开发一个完整的反射纠错智能体。
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "11.3 动手实验:反射循环开发"
|
|
3
|
+
weight: 30
|
|
4
|
+
description: "动手编写一个完整的 Actor-Evaluator-Reflection 自纠错代码修复 Agent,解析 eval 带来的 RCE 安全死穴与 vm 沙箱物理隔离防御。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 11.3 动手实验:反射循环开发
|
|
8
|
+
|
|
9
|
+
在 11.2 节中,我们从理论和架构高度解析了 Reflexion 反思模型的设计哲学与三原色角色分工。本节我们将通过一个**硬核的本地动手实验**,亲自用 JavaScript/TypeScript 编写一个具备“自我审查(Critic)”与“反思修复(Self-Correction)”闭环的代码自动改错智能体。
|
|
10
|
+
|
|
11
|
+
我们将设计一个极易让普通大模型写出 Bug 的“边界条件代码编写任务”,并让智能体在单元测试裁判的无情打击下,通过自我反思,在第二轮中瞬间修正 Bug。
|
|
12
|
+
|
|
13
|
+
此外,我们还将针对动态评估代码时极易触发的**本地远程代码执行(RCE)安全漏洞**提供虚拟机沙箱防护方案。
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 一、 实验任务设计:高难度温度转换器
|
|
18
|
+
|
|
19
|
+
我们给智能体下发一个任务:
|
|
20
|
+
`“请编写一个 Node.js 函数 convertTemperature(val, scale),支持摄氏度('C')与华氏度('F')的双向转换。”`
|
|
21
|
+
|
|
22
|
+
### 物理测试用例 (Evaluator 规则):
|
|
23
|
+
为了测试大模型是否粗心,我们的单元测试裁判(Evaluator)设立了三个严苛的边界用例:
|
|
24
|
+
1. **输入数字**:`convertTemperature(25, 'C')` 必须正确返回华氏度 `77.00`。
|
|
25
|
+
2. **字符串容错**:输入字符串形式的数字 `convertTemperature("25", 'C')` 也必须自动转换返回 `77.00`。
|
|
26
|
+
3. **非法输入拦截**:当输入非数字(如 `"abc"`)或未知单位时,**必须无条件抛出 `TypeError` 异常**。
|
|
27
|
+
|
|
28
|
+
普通大模型在第一轮接龙中,极易忽视第 2 点的类型转换和第 3 点的异常抛出,从而写出脆弱的 Bug 代码。
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 二、 动手实验:编写 Reflexion 闭环控制脚本
|
|
33
|
+
|
|
34
|
+
让我们在本地新建一个 `reflexion_demo.js` 脚本,完整实现三原色的闭环转译:
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
const { OpenAI } = require("openai"); // 假设引入标准的 OpenAI SDK
|
|
38
|
+
const vm = require("node:vm"); // Node.js 内置虚拟机安全沙箱
|
|
39
|
+
|
|
40
|
+
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
|
|
41
|
+
|
|
42
|
+
// 模拟 Evaluator (单元测试裁判)
|
|
43
|
+
function evaluateCode(codeString) {
|
|
44
|
+
try {
|
|
45
|
+
// 1. 💡 物理安全隔离:使用 node:vm 虚拟机沙箱执行,剥夺访问 process 和 fs 的物理特权
|
|
46
|
+
const sandbox = {};
|
|
47
|
+
vm.createContext(sandbox);
|
|
48
|
+
vm.runInContext(codeString, sandbox);
|
|
49
|
+
const fn = sandbox.convertTemperature;
|
|
50
|
+
|
|
51
|
+
if (typeof fn !== 'function') {
|
|
52
|
+
return { success: false, error: "未在代码中找到名为 'convertTemperature' 的导出函数。" };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 用例 1:数值转换
|
|
56
|
+
const r1 = fn(25, 'C');
|
|
57
|
+
if (r1 !== 77) throw new Error(`用例 1 失败:输入 25°C 期望返回 77,但得到了 ${r1}`);
|
|
58
|
+
|
|
59
|
+
// 用例 2:字符串容错
|
|
60
|
+
const r2 = fn("25", 'C');
|
|
61
|
+
if (r2 !== 77) throw new Error(`用例 2 失败:输入字符串 "25" 期望自动兼容转为 77,但得到了 ${r2}`);
|
|
62
|
+
|
|
63
|
+
// 用例 3:异常拦截
|
|
64
|
+
try {
|
|
65
|
+
fn("abc", 'C');
|
|
66
|
+
throw new Error(`用例 3 失败:输入 "abc" 应该抛出 TypeError,但函数静默通过了。`);
|
|
67
|
+
} catch (e) {
|
|
68
|
+
if (!(e instanceof TypeError)) {
|
|
69
|
+
throw new Error(`用例 3 失败:输入 "abc" 期望抛出 TypeError,但抛出了 ${e.name}: ${e.message}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return { success: true };
|
|
74
|
+
} catch (err) {
|
|
75
|
+
return { success: false, error: err.message };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 主反射循环控制流
|
|
80
|
+
async function runReflexionLoop() {
|
|
81
|
+
let reflectionMemory = []; // 反思记忆库
|
|
82
|
+
let attempts = 0;
|
|
83
|
+
const maxAttempts = 3;
|
|
84
|
+
|
|
85
|
+
while (attempts < maxAttempts) {
|
|
86
|
+
attempts++;
|
|
87
|
+
console.log(`\n================ 第 ${attempts} 轮尝试 ================`);
|
|
88
|
+
|
|
89
|
+
// 1. 组装带有反思记忆的 System Prompt
|
|
90
|
+
let systemPrompt = "你是一个精确的 JavaScript 代码编写助手。请输出纯 JS 代码,不要带任何 Markdown 网页标签或解释。";
|
|
91
|
+
if (reflectionMemory.length > 0) {
|
|
92
|
+
systemPrompt += "\n\n⚠️ 历史失败反思经验(请在本次生成中严格遵守并纠正):\n" +
|
|
93
|
+
reflectionMemory.map((r, i) => `- [反思 ${i+1}]: ${r}`).join("\n");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 2. 调用 Actor 生成方案
|
|
97
|
+
const actorResponse = await openai.chat.completions.create({
|
|
98
|
+
model: "gpt-4o-mini", // Actor 使用快速便宜的模型
|
|
99
|
+
messages: [
|
|
100
|
+
{ role: "system", content: systemPrompt },
|
|
101
|
+
{ role: "user", content: "请编写 convertTemperature(val, scale) 函数。" }
|
|
102
|
+
]
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const generatedCode = actorResponse.choices[0].message.content.replace(/```javascript|```/g, "").trim();
|
|
106
|
+
console.log("🤖 [Actor 生成的代码草稿]:\n", generatedCode);
|
|
107
|
+
|
|
108
|
+
// 3. Evaluator 动态跑测试用例
|
|
109
|
+
const evalResult = evaluateCode(generatedCode);
|
|
110
|
+
if (evalResult.success) {
|
|
111
|
+
console.log("✅✅✅ [Evaluator 判定]: 测试用例 100% 通过!代码修复成功!");
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
console.log("❌ [Evaluator 判定]: 测试失败,报错信息为:", evalResult.error);
|
|
116
|
+
|
|
117
|
+
// 4. 激活 Self-Reflection (高阶大脑自审)
|
|
118
|
+
console.log("🧠 [Self-Reflection 启动]: 正在归因分析并生成反思记忆...");
|
|
119
|
+
const reflectorResponse = await openai.chat.completions.create({
|
|
120
|
+
model: "gpt-4o", // 反思器使用高阶极智模型
|
|
121
|
+
messages: [
|
|
122
|
+
{
|
|
123
|
+
role: "system",
|
|
124
|
+
content: "你是一个代码审计裁判。请对比用户写的 Bug 代码与测试用例报错,指出根本原因,并生成一句话的反思,教他下次怎么写。"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
role: "user",
|
|
128
|
+
content: `【Bug 代码】:\n${generatedCode}\n\n【测试报错】:\n${evalResult.error}`
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const reflection = reflectorResponse.choices[0].message.content.trim();
|
|
134
|
+
console.log(`💡 [提炼出的反思记忆]: "${reflection}"`);
|
|
135
|
+
reflectionMemory.push(reflection); // 存入记忆库,等待下一轮注入
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
runReflexionLoop();
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 三、 反射纠错日志跟踪输出分析
|
|
145
|
+
|
|
146
|
+
运行上面的脚本,你会在控制台清晰目睹智能体的大脑蜕变过程:
|
|
147
|
+
* **第一轮**:Actor 忽略了边界,只写了简单的乘除公式,没有兼容字符串输入,也没有抛出 `TypeError`。测试用例 2 或 3 直接报错挂起。
|
|
148
|
+
* **反思激活**:GPT-4o 裁判洞察到了“代码没有对 string 参数执行 parseFloat/Number 转化,且没有对非数抛出 TypeError”。生成反思记忆存入数组。
|
|
149
|
+
* **第二轮**:Actor 的 System 头部被注入了刚才的反思。大模型注意力矩阵被“强制纠正偏置”。Actor 重新接龙,写出了高度安全的带有 `Number(val)` 与 `throw new TypeError` 校验的防弹代码,测试用例瞬间 100% 绿灯通过,完美闭环!
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 四、 【避坑指南】防范 eval 动态执行代码带来的 RCE 漏洞
|
|
154
|
+
|
|
155
|
+
在上面的 Evaluator 实现中,我们使用了一个极其致命的架构防线:**绝对禁止直接调用 Node.js 原生的 `eval(codeString)` 方法!**
|
|
156
|
+
|
|
157
|
+
### 1. RCE(远程代码执行)死穴
|
|
158
|
+
大模型生成的代码是不可控的。如果大模型在长对话中被用户恶意诱导,或者模型本身发生严重幻觉,生成了以下代码:
|
|
159
|
+
```javascript
|
|
160
|
+
const fs = require('fs');
|
|
161
|
+
fs.rmSync('/', { recursive: true }); // 物理删库!
|
|
162
|
+
```
|
|
163
|
+
如果 Evaluator 直接用 `eval()` 在当前进程内跑这段代码,整个宿主服务器会被瞬间“物理抹除”,密钥泄露。
|
|
164
|
+
|
|
165
|
+
### 2. 避坑策略:虚拟机 VM 沙箱隔离
|
|
166
|
+
正如我们在 `evaluateCode` 里的写法,**必须使用 Node.js 的核心 `node:vm` 模块**,创建一个与主线程隔离的、拥有完全空白 Context 的轻量级虚拟机:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
const vm = require('node:vm');
|
|
170
|
+
const sandbox = {}; // 创建一个完全不包含 process, require, fs 的空白沙箱上下文对象
|
|
171
|
+
vm.createContext(sandbox);
|
|
172
|
+
|
|
173
|
+
// 限制运行时间最大为 1000ms,防止死循环耗尽 CPU
|
|
174
|
+
vm.runInContext(generatedCode, sandbox, { timeout: 1000 });
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
通过这一层虚拟机隔离防御,生成代码即使包含恶意的删库和越权逻辑,也会因为在 sandbox 命名空间里找不到 `process` 或 `require` 而在第一步直接抛出 ReferenceError 异常被底座安全捕获,牢牢捍卫了服务器宿主的物理安全。
|
|
178
|
+
|
|
179
|
+
本节我们通过编写 Actor-Evaluator-Reflection 闭环完成了本地自纠错实验,并利用 `node:vm` 沙箱锁死了 RCE 越权漏洞。
|
|
180
|
+
|
|
181
|
+
在下一小节中,我们将深入实战调试反思回路在生产环境下的收敛性退化、Token 账单膨胀与熔断降级防线。
|
|
182
|
+
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "11.4 调试与避坑指南:评估反思开销与收敛成功率"
|
|
3
|
+
weight: 40
|
|
4
|
+
description: "实战调试反思回路收敛性退化与 Token 账单暴涨灾难,设计反思消退因子与代码长度异常膨胀的熔断降级防线。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 11.4 调试与避坑指南:评估反思开销与收敛成功率
|
|
8
|
+
|
|
9
|
+
在 11.3 节中,我们动手开发了 Actor-Evaluator-Reflection 闭环纠错实验,并解决了 eval 执行时的 RCE 安全漏洞。
|
|
10
|
+
|
|
11
|
+
在反射型智能体(Reflexion Agent)的实际生产落地中,我们将遭遇两个极其棘手的物理性能陷阱 —— **收敛性退化(Convergence Degradation)** 与 **Token-Delay 恶性暴涨(Token-Delay Inflation)**:
|
|
12
|
+
* **反思不收敛**:Actor 面对测试报错,改了 3 次改不对,陷入逻辑鬼打墙,甚至写出了越来越多 Bug 的废话代码(逻辑发散)。
|
|
13
|
+
* **账单与延迟超限**:每一次反思重试,都在后台以指数级级数消耗 Token;同时,用户眼巴巴地盯着屏幕转圈了 30 秒才收到结果(首字时间 TTFT 退化为整体推理耗时),用户体验彻底崩溃。
|
|
14
|
+
|
|
15
|
+
本节我们将实际建立反思轨迹追踪器(Critique Tracer),解决收敛性卡死,并设计反思消退因子与代码膨胀熔断两道物理防波堤。
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 一、 反思回路(Critique Loop)的两大物理痛点
|
|
20
|
+
|
|
21
|
+
### 1. 收敛性退化与“反思发散(Divergence)”
|
|
22
|
+
大模型在面对持续的报错时,如果没有好的经验记忆输入,它的推理会发生“认知过载”。
|
|
23
|
+
它在第三轮生成的 Thought 可能会开始彻底偏离最初的主干任务,尝试去引入各种奇奇怪怪、毫不相干的库和复杂控制流(例如为了转换一个数字,强行引入了一整套 lodash 工具链)。代码体积变大,Bug 翻倍。
|
|
24
|
+
|
|
25
|
+
### 2. 费用与延迟大雪崩
|
|
26
|
+
单轮普通的 ReAct 往返需要 1 秒,消费 1000 Token。如果开启了 Reflexion 反思,重试 3 次意味着:
|
|
27
|
+
* **计算开销**:$3 \times \text{Actor 推理} + 3 \times \text{Evaluator 执行} + 3 \times \text{Reflection 提炼}$。
|
|
28
|
+
* **后果**:首字渲染时间直接被拖长到 20 秒以上,且单次用户提问所产生的 Token 账单会暴涨 10 倍以上,在商业运营上是难以承受的财务漏洞。
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 二、 调试实战:建立底座级反思轨迹追踪器 (Critique Tracer)
|
|
33
|
+
|
|
34
|
+
为了能够精确看清智能体每一步反思是在“往好转”还是在“空转”,我们必须在本地建立**反思轨迹追踪器**。
|
|
35
|
+
|
|
36
|
+
在底座的 `agent-service.ts` 或者是反射管理器中,我们可以在每次 Evaluator 判定和 Self-Reflection 后,往持久化数据目录 `~/.freya/data/sessions/<sessionId>/` 下写入一笔 JSON 格式的**反思审计快照(Audit Snapshot)**:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"sessionId": "code_refactor_101",
|
|
41
|
+
|
|
42
|
+
"timestamp": "2026-07-26T10:45:00Z",
|
|
43
|
+
"attempts": [
|
|
44
|
+
{
|
|
45
|
+
"round": 1,
|
|
46
|
+
"generatedCodeSize": 450,
|
|
47
|
+
"testPassed": false,
|
|
48
|
+
"errorReport": "TypeError: Cannot read properties of undefined (reading 'split')",
|
|
49
|
+
"reflection": "我上一次忽略了参数可能为 undefined 的非空校验,我必须在下一步首行加入 if (!val) 判断。",
|
|
50
|
+
"tokenUsage": { "prompt": 1200, "completion": 250, "cost": 0.0029 }
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"round": 2,
|
|
54
|
+
"generatedCodeSize": 520,
|
|
55
|
+
"testPassed": true,
|
|
56
|
+
"errorReport": null,
|
|
57
|
+
"reflection": null,
|
|
58
|
+
"tokenUsage": { "prompt": 1650, "completion": 180, "cost": 0.0031 }
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"totalCost": 0.0060,
|
|
62
|
+
"isConverged": true
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
通过这一层物理快照追踪器,开发者可以在不修改业务代码的情况下,通过 tail 监控日志实时洞察反思的每一次呼吸,看清大模型的思维是否在往正确的方向快速收敛。
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 三、 捍卫账单:收敛性与 Token 消耗的平衡策略
|
|
71
|
+
|
|
72
|
+
为了在保障智能体能“自我纠错”的前提下,守住 API 账单和响应速度的底线,我们必须配置以下两条物理防线:
|
|
73
|
+
|
|
74
|
+
### 1. 强制最大反思阈值线 (Hard Max Attempt Watermark)
|
|
75
|
+
* **工程经验**:大模型如果前 2 次重试都没改对,第 3 次之后能改对的概率会暴跌至 **$5\%$ 以下**。
|
|
76
|
+
* **防守手段**:把 `maxAttempts` 严格设定为 **2 次**。2 次反思不通过,底座必须强行熔断并向用户抛出测试报错详情,绝对禁止其在后台继续空转,及时止损。
|
|
77
|
+
|
|
78
|
+
### 2. 反思消退因子(Critique Decay Factor)
|
|
79
|
+
如果我们将每一次重试产生的 Reflection 记忆全部堆在 System Prompt 头部,上下文会急速膨胀。
|
|
80
|
+
* **防守手段**:底座在拼接反思记忆时,只保留**最近 2 轮**的反思内容。陈旧的反思内容被自动淘汰丢弃(消退机制);或者在后台调用高阶模型,将历史 3 条反思无损压缩合并为一条单体摘要反思,防止上下文的无序膨胀。
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 四、 【避坑防线】代码长度异常膨胀熔断机制
|
|
85
|
+
|
|
86
|
+
在调试反射代码修复时,经常会发生**代码大雪崩(Code Explosion)**:
|
|
87
|
+
* **现象**:Actor 在面对 Evaluator 的测试报错时,为了规避报错,在代码里开始堆砌大量的 if-else 补丁代码,代码长度从第一轮的 100 行狂飙到第三轮的 500 行。这是大模型逻辑彻底陷入发散的“高危红色警报”。
|
|
88
|
+
|
|
89
|
+
为了防御这一发散隐患,底座在每次接收到 Actor 新生成的代码后,**必须进行字符长度和 Token 变化率的动态自检拦截**:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// 💡 代码长度膨胀硬熔断拦截器
|
|
93
|
+
function checkCodeLengthExplosion(firstAttemptLength: number, currentAttemptLength: number): boolean {
|
|
94
|
+
// 物理红线:如果当前重试代码长度超过了第一版代码的 1.5 倍
|
|
95
|
+
// 判定大模型陷入了盲目堆砌补丁的代码发散状态
|
|
96
|
+
if (currentAttemptLength > firstAttemptLength * 1.5) {
|
|
97
|
+
console.warn(`[ReflexionGuard] 检测到生成代码长度异常膨胀 (${currentAttemptLength}B > 原始 ${firstAttemptLength}B * 1.5),触发防线熔断拦截!`);
|
|
98
|
+
return true; // 触发熔断
|
|
99
|
+
}
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
一旦 `checkCodeLengthExplosion` 触发,底座强制切断 while 循环,中止后续的反思大模型调用,直接向终端用户报告失败,以物理手段彻底捍卫了系统的 CPU 负载与 Token 财务安全。
|
|
105
|
+
|
|
106
|
+
本节我们通过反思轨迹追踪器、最大阈值线、反思消退因子与代码异常膨胀自检拦截,彻底扫清了 Reflexion 反思型智能体落地的性能与费用大坑。
|
|
107
|
+
|
|
108
|
+
在下一章中,我们将踏入智能体交互的最高殿堂,去探秘从“单智能体孤岛”走向“多智能体(Multi-Agent)高并发协作”的拓扑与路由奥秘。
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "12.1 独木难支:单 Agent 的能力与认知限界"
|
|
3
|
+
weight: 10
|
|
4
|
+
description: "解密单智能体在复杂场景下所面临的“工具爆炸”与“人设重叠”两大认知瓶颈,确立多智能体社会化分工的必要性。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 12.1 独木难支:单 Agent 的能力与认知限界
|
|
8
|
+
|
|
9
|
+
在前五部分和第 11 章的 Reflexion 自纠错设计中,我们所有的讨论都默认基于一个前提:由一个**单体智能体(Single Agent)**去接管所有的思考、行动和反思。
|
|
10
|
+
|
|
11
|
+
这种“个人英雄主义”的设计在解决独立、垂直的单一任务时表现极佳。但是,当我们将智能体系统推向复杂的企业级真实业务流(例如:一个既要能查询企业 ERP 数据库、又要能在沙箱编译运行代码、还要能对输出文档进行多模态安全审计的智能体系统)时,单智能体结构会瞬间面临崩溃。
|
|
12
|
+
|
|
13
|
+
大模型不是万能的神。单体智能体在物理和数学层面上,存在着无法逾越的**认知限界**。
|
|
14
|
+
|
|
15
|
+
本节我们将深度拆解单智能体在面对“工具爆炸”与“人设重叠”时的认知极限,并探讨向多智能体(Multi-Agent)社会化分工演进的物理必要性。
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 一、 局限一:工具爆炸与自注意力稀释 (Tool Explosion)
|
|
20
|
+
|
|
21
|
+
在 Function Calling 的底层原理(4.1 节)中我们知道,为了让大模型学会使用工具,我们必须将所有工具的 JSON Schema 说明书拼入 System Prompt 发给它。
|
|
22
|
+
|
|
23
|
+
### 1. 工具声明对 Context Window 的撑爆
|
|
24
|
+
如果我们要让智能体具备 30 个不同的物理能力(如文件读写、SQL 执行、HTTP 发包、邮件发送、各微服务接口等)。
|
|
25
|
+
* **物理瓶颈**:30 个工具的 JSON Schema 定义体积可能高达 8,000 Token。每一次对话往返,底座都要强行为这 8,000 Token 的说明书买单,导致账单费用暴涨。
|
|
26
|
+
|
|
27
|
+
### 2. 数学本质:自注意力稀释(Attention Dilution)
|
|
28
|
+
当大模型在阅读这 8,000 Token 庞杂的工具 Schema 并结合用户提问进行注意力权重计算时:
|
|
29
|
+
* **注意力熵增**:自注意力层计算出的 softmax 概率分布会变得极其平缓(Entropy 增加),注意力分布被 30 个复杂的参数描述极度摊薄稀释。
|
|
30
|
+
* **后果**:大模型开始在提取参数时张冠李戴,误将 A 工具的参数格式传给 B 工具,甚至在需要调用工具时直接发生“幻觉失忆”。在真实压测中,**挂载工具数超过 15 个后,Tool Call 的整体召回对齐率会呈现断崖式下跌(直奔 $40\%$ 以下)**。
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 二、 局限二:人设冲突与“认知角色污染” (Identity Pollution)
|
|
35
|
+
|
|
36
|
+
在智能体开发中,我们常用 System Prompt 为模型塑造“心智人格(Persona)”。
|
|
37
|
+
|
|
38
|
+
但是在同一个大模型实例(同一个 Session 上下文)中,不同的业务需求会产生**逻辑相悖的人设冲突**:
|
|
39
|
+
* **安全审计员(Auditor Persona)**:核心约束是“冷酷无情,凡是遇到非规范的数据,一律拦截报错,绝对不发散”。
|
|
40
|
+
* **文案撰写员(Writer Persona)**:核心约束是“极富创意,逻辑发散,多用修辞手法,尽量迎合读者”。
|
|
41
|
+
|
|
42
|
+
### 物理污染机理:
|
|
43
|
+
如果你强行在同一个 System Prompt 里塞入这两个相互矛盾的规则:
|
|
44
|
+
`“你既是一个严格的安全审计员,又是一个发散的文案撰写员...”`
|
|
45
|
+
|
|
46
|
+
自回归大模型在做接龙预测时,注意力点积计算会陷入混乱,安全审计的收敛概率与文案生成的发散概率会在语义空间发生物理中和。
|
|
47
|
+
最终表现为:**智能体生成了一篇毫无创意的死板文案,且漏掉了最致命的 SQL 注入安全审计,人设遭到污染。**
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 三、 多智能体协作:社会化分工 (Multi-Agent Cooperation)
|
|
52
|
+
|
|
53
|
+
为了彻底打碎单智能体的认知边界,我们必须放弃“全能英雄”的幻想,将系统升级为**社会化分工协作(Social Division of Labor)**:
|
|
54
|
+
|
|
55
|
+
将 30 个工具和冲突的人设,拆分为 3 个高度内聚、人设单一的独立智能体角色:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
[ 用户复杂业务指令 ]
|
|
59
|
+
│
|
|
60
|
+
▼ (分流路由)
|
|
61
|
+
┌─────────────────────────────────────┴─────────────────────────────────────┐
|
|
62
|
+
│ │ │
|
|
63
|
+
▼ ▼ ▼
|
|
64
|
+
┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐
|
|
65
|
+
│ Data Agent (数据员) │ │ Writer Agent (文案) │ │ Security Agent(审计) │
|
|
66
|
+
├──────────────────────┤ ├──────────────────────┤ ├──────────────────────┤
|
|
67
|
+
│ 挂载: 3 个 SQL 工具 │ │ 挂载: 2 个文本工具 │ │ 挂载: 2 个安全正则 │
|
|
68
|
+
│ 人设: 极度严谨冷酷 │ │ 人设: 极富文采创意 │ │ 人设: 死板的安全判官 │
|
|
69
|
+
└──────────────────────┘ └──────────────────────┘ └──────────────────────┘
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
每个 Agent 的 System Prompt 极小(Token 消耗暴跌),注意力高度聚焦。Tool Call 的召回率在各自垂直领域瞬间**重回 99% 的工业级水准**。
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 四、 【避坑指南】防范多 Agent 并发导致的“分布式状态死锁”
|
|
77
|
+
|
|
78
|
+
在多智能体体系中,父智能体(如 Coordinator Agent)经常会拉起子智能体(如 Sub Agent)进行并发计算(我们在 9.3 节解剖过 `runSubAgent`)。
|
|
79
|
+
|
|
80
|
+
在此处,我们会撞上分布式系统最经典的噩梦 —— **状态争抢死锁(State Deadlock)**:
|
|
81
|
+
|
|
82
|
+
### 1. 状态争抢死锁的成因
|
|
83
|
+
如果开发人员偷懒,让子智能体共享使用父智能体的同一个 `sessionId`。
|
|
84
|
+
* **物理冲突**:父智能体在 `updateLocks`(Promise 写锁)中排队。同时,子智能体在执行工具时,也试图去更新同一个 `sessionId` 的状态。
|
|
85
|
+
* **后果**:子 Agent 的更新操作卡在父 Agent 的 Pending 锁中,而父 Agent 又在同步等待子 Agent 返回结果,形成**互锁(Deadlock)**,整套多体系统瞬间永久卡死僵死。
|
|
86
|
+
|
|
87
|
+
### 2. 避坑策略:子会话物理绝对隔离
|
|
88
|
+
子智能体在被创建的那一微秒起,**必须拥有完全隔离的、独立 UUID 命名的 `childSessionId`**(如 9.3 节所示):
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
// 💡 强行进行子智能体会话 UUID 物理隔离,防止状态互锁
|
|
92
|
+
await this.sessionManager.createSession(childSessionId, {
|
|
93
|
+
parentId: parentSessionId, // 仅通过 parentId 逻辑关联,隔离物理 Memory 指针
|
|
94
|
+
prompt: options.subPrompt
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
通过这一层子会话物理隔离,子 Agent 拥有专属的 `updateLocks` 队列和独立的 `history` 数据库,各子体在各自的沙箱里飞速并发运行,计算完毕后再由底座将最终 content 回传给父体,从根本上物理封锁了分布式死锁的发生。
|
|
99
|
+
|
|
100
|
+
本节我们解剖了单智能体所面临的“工具爆炸”与“人设重叠”两大认知瓶颈,确立了多智能体社会分工的架构必要性。在下一小节中,我们将重点研究多智能体协作的经典交互范式,看懂它们之间是如何打交道的。
|