@eoasmxd/freya 0.3.0 → 0.4.0
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/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 +2 -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-web/package.json +1 -1
- package/plugins/plugin-wecom-channel/package.json +1 -1
- package/plugins/plugin-weixin-channel/package.json +1 -1
package/README.md
CHANGED
|
@@ -59,11 +59,17 @@ pnpm start
|
|
|
59
59
|
|
|
60
60
|
为了便于开发者深入了解 Freya 的底座原理与扩展机制,系统在 [doc/](doc/_index.md) 物理目录下提供了完整的技术文档库:
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
* 📝 **[提示词管理系统](doc/prompt-system.md)**:介绍 6 大维度提示词管理方案、动态 Prompt Composer 拼装结构与 Dual-Read 探针机制。
|
|
62
|
+
### 🛠️ 技术规范与指南
|
|
63
|
+
|
|
65
64
|
* 🚀 **[快速使用指引](doc/getting-started.md)**:图形化 LLM 提供商配置、插件开启控制与会话快捷指令。
|
|
66
65
|
* 🛠️ **[安装与构建运行](doc/installation-guide.md)**:分步说明环境准备、安装、编译与控制台开发模式。
|
|
66
|
+
* 🏗️ **[架构设计说明](doc/specifications/architecture-design.md)**:包含 Monorepo 物理结构、核心 ReAct 调用链路图、核心组件职责及 EventBus 异步通信机制。
|
|
67
|
+
* ⚙️ **[配置与数据隔离规范](doc/specifications/config-spec.md)**:介绍 `~/.freya/` 运行时目录结构、配置/数据物理隔离及 Schema 动态合并策略。
|
|
68
|
+
* 📝 **[提示词管理系统](doc/specifications/prompt-system.md)**:介绍 6 大维度提示词管理方案、动态 Prompt Composer 拼装结构与 Dual-Read 探针机制。
|
|
69
|
+
|
|
70
|
+
### 🎓 白盒开发教程
|
|
71
|
+
|
|
72
|
+
* 👉 **[智能体开发实战教程](doc/tutorials/_index.md)**:白盒解剖智能体底座,包含 13 个章节硬核教程,从 Next-Token Prediction 到底层 ReAct 循环、多轮会话以及多智能体协同协作等原理解密。
|
|
67
73
|
|
|
68
74
|
---
|
|
69
75
|
|
package/core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eoasmxd/freya-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"clean": "rm -rf dist"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@eoasmxd/freya-sdk": "^0.
|
|
19
|
+
"@eoasmxd/freya-sdk": "^0.4.0",
|
|
20
20
|
"ws": "^8.18.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
package/doc/_index.md
CHANGED
|
@@ -10,17 +10,30 @@ description: "Freya 项目技术文档与开发使用指南。"
|
|
|
10
10
|
|
|
11
11
|
## 📖 文档导航
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
### 🚀 快速开始
|
|
14
|
+
|
|
15
|
+
- 🧭 **[快速使用指引](getting-started.md)**
|
|
16
|
+
提供系统首次启动配置、插件管理与日常操作快捷指令。
|
|
17
|
+
|
|
18
|
+
- 🛠️ **[安装与构建运行](installation-guide.md)**
|
|
19
|
+
提供开发环境要求、本地依赖安装、项目编译打包与服务运行调试指南。
|
|
20
|
+
|
|
21
|
+
### 🏗️ 技术规范与设计参考
|
|
22
|
+
|
|
23
|
+
- 🧱 **[Freya 架构设计说明](specifications/architecture-design.md)**
|
|
14
24
|
介绍系统的物理模块划分、核心组件职责分工、调用执行链路与异步通信机制。
|
|
15
25
|
|
|
16
|
-
- ⚙️ **[配置与数据隔离规范](config-spec.md)**
|
|
26
|
+
- ⚙️ **[配置与数据隔离规范](specifications/config-spec.md)**
|
|
17
27
|
介绍系统的运行时目录结构、配置与数据的隔离设计及初始化合并规范。
|
|
18
28
|
|
|
19
|
-
- 📝 **[提示词管理系统说明](prompt-system.md)**
|
|
29
|
+
- 📝 **[提示词管理系统说明](specifications/prompt-system.md)**
|
|
20
30
|
介绍多维度提示词管理方案、运行时 Prompt 拼装结构与动态加载覆盖机制。
|
|
21
31
|
|
|
22
|
-
-
|
|
23
|
-
|
|
32
|
+
- 🎛️ **[大模型接口参数规范](specifications/llm-interface-params.md)**
|
|
33
|
+
介绍大语言模型统一代理层的配置参数与多厂商协议适配规则。
|
|
34
|
+
|
|
35
|
+
### 🎓 开发实战教程
|
|
36
|
+
|
|
37
|
+
- 📚 **[智能体通用原理与开发实战](tutorials/_index.md)**
|
|
38
|
+
完全以智能体通用底层原理、通信协议与架构机制为主线的白盒实战开发教程。
|
|
24
39
|
|
|
25
|
-
- 🛠️ **[安装与构建运行](installation-guide.md)**
|
|
26
|
-
提供开发环境要求、本地依赖安装、项目编译打包与服务运行调试指南。
|
package/doc/getting-started.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "架构设计说明"
|
|
3
3
|
weight: 10
|
|
4
4
|
description: "说明项目目录结构、~/.freya 运行时存放规则、插件依赖界限、核心 ReAct 调用链路与 EventBus 异步解耦模式。"
|
|
5
5
|
---
|
|
@@ -41,15 +41,18 @@ freya/
|
|
|
41
41
|
│ ├── sdk/ # 插件开发标准 SDK
|
|
42
42
|
│ │ ├── src/
|
|
43
43
|
│ │ │ ├── index.ts # 模块入口与集中导出
|
|
44
|
-
│ │ │ └── types
|
|
44
|
+
│ │ │ └── types/ # 统一的接口定义目录
|
|
45
45
|
│ │ └── package.json
|
|
46
46
|
│ │
|
|
47
47
|
│ └── ui/ # 独立的前端 Web 交互页面
|
|
48
48
|
│ └── package.json
|
|
49
49
|
│
|
|
50
50
|
├── plugins/ # 插件根目录
|
|
51
|
+
│ ├── plugin-gemini/ # Gemini 大模型插件
|
|
51
52
|
│ ├── plugin-openai/ # 对接 OpenAI 标准 API 的大模型插件
|
|
52
53
|
│ ├── plugin-telegram-channel/ # Telegram 频道插件
|
|
54
|
+
│ ├── plugin-wecom-channel/ # 企业微信频道插件
|
|
55
|
+
│ ├── plugin-weixin-channel/ # 微信频道插件
|
|
53
56
|
│ ├── plugin-tool-fs/ # 文件系统工具插件
|
|
54
57
|
│ ├── plugin-tool-memory/ # 记忆工具插件
|
|
55
58
|
│ └── plugin-tool-web/ # 网页工具插件
|
|
@@ -115,8 +118,8 @@ graph TD
|
|
|
115
118
|
|
|
116
119
|
底座组件之间跨边界异步通信统一通过 **`EventBus` (事件总线)** 异步事件驱动:
|
|
117
120
|
|
|
118
|
-
* **出站路由**:`Agent` 推理产生的流式 Delta 或最终文本不会被直接投递给 `Channel`。底座仅需广播 `'connection:reply'` / `'connection:reply:delta'` 事件;各个 `Channel` 插件自行订阅事件,读取对应的 `
|
|
119
|
-
* **多方协同与计费解耦**:当大模型输出产生 `'token:consumed'` 事件时,计费服务(Billing
|
|
121
|
+
* **出站路由**:`Agent` 推理产生的流式 Delta 或最终文本不会被直接投递给 `Channel`。底座仅需广播 `'connection:reply'` / `'connection:reply:delta'` 事件;各个 `Channel` 插件自行订阅事件,读取对应的 `connectionId`(连接 ID)过滤并各自向用户的物理长连接发送。
|
|
122
|
+
* **多方协同与计费解耦**:当大模型输出产生 `'token:consumed'` 事件时,计费服务(Billing)通过订阅该事件核算费用并触发 `'billing:session:add'`。会话管理器(SessionManager)监听该事件累加更新会话数据后广播 `'session:billing:update'`,最终底座连接层捕获此更新并通过 `'connection:event'` 向前端 WebSocket 实时推送 `server:billing` 事件。
|
|
120
123
|
|
|
121
124
|
|
|
122
125
|
---
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "LLM 插件调用接口与参数规范"
|
|
3
3
|
weight: 18
|
|
4
4
|
description: "定义 Freya 统一的大模型(LLM)插件调用接口参数规范。"
|
|
5
5
|
---
|
|
@@ -18,7 +18,7 @@ description: "定义 Freya 统一的大模型(LLM)插件调用接口参数
|
|
|
18
18
|
async chat(
|
|
19
19
|
messages: LLMMessage[],
|
|
20
20
|
tools?: ToolDefinition[],
|
|
21
|
-
options?:
|
|
21
|
+
options?: LLMPluginOptions
|
|
22
22
|
): Promise<{
|
|
23
23
|
message: LLMMessage;
|
|
24
24
|
usage?: LLMTokenUsage;
|
|
@@ -31,7 +31,7 @@ async chat(
|
|
|
31
31
|
|
|
32
32
|
为了屏蔽不同大模型服务商在参数命名上的差异(如 `max_tokens` 与 `maxOutputTokens`),Freya 规定了一套**驼峰命名(CamelCase)**的通用生成参数标准。
|
|
33
33
|
|
|
34
|
-
在调用 `llm.chat` 时,应通过 `options.modelParams`
|
|
34
|
+
在调用 `llm.chat` 时,应通过 `options.modelParams` 传递这些参数。各插件仅负责从其中提取支持的属性,并准确转换为服务商 API 要求的格式。
|
|
35
35
|
|
|
36
36
|
### 统一参数字段一览
|
|
37
37
|
|
|
@@ -87,22 +87,22 @@ if (typeof params.maxTokens === 'number' && params.maxTokens > 0) {
|
|
|
87
87
|
|
|
88
88
|
---
|
|
89
89
|
|
|
90
|
-
##
|
|
90
|
+
## 5. 大模型消息结构与属性规范 (`LLMMessage`)
|
|
91
91
|
|
|
92
92
|
Freya 内核通过统一的 `LLMMessage` 对象来表示对话历史中的每一个消息节点。为了兼容和抽象不同大模型服务商在多轮工具调用(Function Calling)以及推理校验上的核心流派差异,`LLMMessage` 中的主要属性字段定义及职责如下:
|
|
93
93
|
|
|
94
|
-
###
|
|
94
|
+
### 5.1 基础属性
|
|
95
95
|
* **`role`** (`'user' | 'assistant' | 'system' | 'tool'`):消息在对话中的角色。
|
|
96
96
|
* *映射规范*:对于不支持显式 `'tool'` 角色的厂商 API(如 Gemini REST 接口),插件层应当在转换对话历史时将其统一映射为 `"user"` 以符合接口的协议规范。
|
|
97
97
|
* **`content`** (`string`):消息的文本正文。
|
|
98
|
-
* **`attachments`** (`
|
|
98
|
+
* **`attachments`** (`FreyaAttachment[]`):消息附带的多模态附件(如图像等)。
|
|
99
99
|
|
|
100
|
-
###
|
|
100
|
+
### 5.2 工具调用关联属性(基于 ID 关联流派)
|
|
101
101
|
主要服务于以 OpenAI 协议为代表、在多轮工具调用中通过特定的**唯一 ID** 关联工具调用与工具执行结果的流派:
|
|
102
102
|
* **`toolCalls`** (`LLMToolCall[]`):大模型在 `'assistant'` 消息中输出的工具调用指令列表。每个 `LLMToolCall` 包含 `id`、`name`(工具名)与 `arguments`(参数)。
|
|
103
103
|
* **`toolCallId`** (`string`):在 `'tool'` 角色的消息中,用来指定该条工具执行结果所对应的工具调用 `id`。
|
|
104
104
|
|
|
105
|
-
###
|
|
105
|
+
### 5.3 推理校验与工具原名属性(基于名称与签名校验流派)
|
|
106
106
|
主要服务于以 Gemini 协议为代表、在多轮工具调用中通过**工具名称**关联响应,且必须回传推理状态签名的流派:
|
|
107
107
|
* **`thoughtSignature`** (`string`):由支持 stateless 思考(Reasoning)的模型在响应中输出的加密思考签名。
|
|
108
108
|
* *插件职责*:解析响应时,将模型返回的签名捕获并挂载在 `message.thoughtSignature` 根属性上;回传历史消息时,按照厂商 API 规定的结构(如 Gemini 要求其作为同级属性嵌套在对应的 `functionCall` Part 元素中并列发送)回传。
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "智能体通用原理与开发实战"
|
|
3
|
+
linkTitle: "首页"
|
|
4
|
+
weight: 1
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 智能体通用原理与开发实战
|
|
8
|
+
|
|
9
|
+
欢迎来到《智能体通用原理与开发实战》教程!
|
|
10
|
+
|
|
11
|
+
## 🎯 教程定位
|
|
12
|
+
|
|
13
|
+
本教程完全以 **AI Agent(智能体)的通用底层原理、通信协议与架构机制**为主线,将 Freya 定位为学员透视这些机制的“透明白盒沙箱”,提供平缓的学习曲线和丰富的动手实验。
|
|
14
|
+
|
|
15
|
+
本教程拒绝浮于表面的概念科普,采用高密度的深度硬核写作风格。全书包含 13 个完整章节,力求做到“底层原理讲透、白盒源码剖析清晰、一线避坑指南实用”,为您拼全智能体开发的底层心智与工程拼图。
|
|
16
|
+
|
|
17
|
+
## 🗺️ 课程自学通关路线图
|
|
18
|
+
|
|
19
|
+
### 📦 [第零部分:AI 基础概念与“文字接龙”的秘密](part0_basic/_index.md)
|
|
20
|
+
* **第 0 章:揭开 AI 的神秘面纱 —— 大语言模型运作本质**
|
|
21
|
+
* [0.1 概率预测与 Next-Token Prediction](part0_basic/0.1_probability_prediction.md) —— *自回归大模型与 Token 切分、计费的底层秘密*
|
|
22
|
+
* [0.2 算力与窗口的物理极限](part0_basic/0.2_attention_and_context.md) —— *Attention 机制平方复杂度与 KV Cache 显存深渊*
|
|
23
|
+
* [0.3 随机与严谨的博弈](part0_basic/0.3_generation_parameters.md) —— *Temperature, Top-P 等采样参数的数学物理本质*
|
|
24
|
+
* [0.4 调试与避坑指南:本地 Token 消耗排查](part0_basic/0.4_debugging_token.md) —— *中英文混淆、JSON 格式 Token 刺客与 API 限流估算*
|
|
25
|
+
* **第 1 章:对话的舞台 —— 大模型聊天接口与三种角色**
|
|
26
|
+
* [1.1 鱼的记忆与无状态网络](part0_basic/1.1_stateless_and_history.md) —— *网络无状态本质与多轮会话拼接的底层逻辑*
|
|
27
|
+
* [1.2 聊天数据结构解析](part0_basic/1.2_chat_data_structure.md) —— *API 请求与响应 Message/Response 物理格式解析*
|
|
28
|
+
* [1.3 三大核心角色分工](part0_basic/1.3_system_user_assistant.md) —— *System/User/Assistant 三大角色分工、Prefilling 与注入防御*
|
|
29
|
+
* [1.4 【沙箱对照】阅读与调试模型代理配置](part0_basic/1.4_freya_model_proxy.md) —— *底座统一代理配置与异构参数清洗抹平*
|
|
30
|
+
|
|
31
|
+
### 🧠 [第一部分:Agent 的心智模型 —— 探秘 ReAct 决策环与沙箱物理隔离](part1_react/_index.md)
|
|
32
|
+
* **第 2 章:智能体架构演进 —— 从聊天助手到能动的主体**
|
|
33
|
+
* [2.1 能动性(Agency)的诞生](part1_react/2.1_agency_vs_chatbot.md) —— *Chatbot 与 Agent 控制流革命及四大物理要素*
|
|
34
|
+
* [2.2 ReAct 心智模型与推演](part1_react/2.2_react_mind_model.md) —— *Thought-Action-Observation 三元环时序与 Prompt 模板*
|
|
35
|
+
* [2.3 【白盒剖析】决策循环与 agent-executor 源码](part1_react/2.3_freya_agent_executor.md) —— *主循环控制流与闲置工具箱动态淘汰算法*
|
|
36
|
+
* [2.4 调试与避坑指南:ReAct 自循环失控熔断](part1_react/2.4_debugging_loop_deadlock.md) —— *动手实验复现鬼打墙及内核防爆网设计*
|
|
37
|
+
* **第 3 章:系统提示词的动态织造与零硬编码规范**
|
|
38
|
+
* [3.1 提示词工程的痛点](part1_react/3.1_hardcoded_prompt_pain.md) —— *硬编码提示词的四大工程灾难与解耦世界观*
|
|
39
|
+
* [3.2 零硬编码解耦架构](part1_react/3.2_decoupled_architecture.md) —— *零硬编码物理目录树规范与热加载双缓冲原子替换*
|
|
40
|
+
* [3.3 【白盒剖析】双通道动态提示词合并](part1_react/3.3_freya_dual_read_probe.md) —— *双通道探针内存编织与 composeSystemPrompt 运行时插值*
|
|
41
|
+
* [3.4 调试与避坑指南:动态 Prompt 拼装与模板报错排查](part1_react/3.4_debugging_composition_placeholder.md) —— *占位符解析失效、Prompt 捕获探针及安全模板替换器*
|
|
42
|
+
|
|
43
|
+
### 🔌 [第二部分:连接物理世界 —— 智能体如何掌控“工具” (Tool Call)](part2_tools/_index.md)
|
|
44
|
+
* **第 4 章:大模型感知与选择工具的底层技术本质**
|
|
45
|
+
* [4.1 语言到动作的转换](part2_tools/4.1_json_schema_mapping.md) —— *JSON Schema 描述符、受约束生成与高质量 Description 准则*
|
|
46
|
+
* [4.2 【白盒剖析】Tool Call Raw 数据包结构](part2_tools/4.2_tool_call_raw_packet.md) —— *非流式 JSON 标本、流式 arguments 拼接与并行调用风暴*
|
|
47
|
+
* [4.3 【白盒剖析】工具安全防线与本地执行](part2_tools/4.3_freya_tool_execution.md) —— *FreyaToolRegistry 结构、动态过滤授权沙箱与 EventBus 状态流转*
|
|
48
|
+
* [4.4 调试与避坑指南:错误 Observation 与自我修正](part2_tools/4.4_debugging_observation_fix.md) —— *引导性错误 Observation 纠错、堆栈过滤与海量数据截断*
|
|
49
|
+
* **第 5 章:大厂 Function Calling 协议差异与多轮关联流派**
|
|
50
|
+
* [5.1 工具执行结果的归流](part2_tools/5.1_observation_injection.md) —— *反向注入注意力时序重建与 tool_calls 消息保留红线*
|
|
51
|
+
* [5.2 两大厂商协议流派交锋](part2_tools/5.2_openai_vs_gemini_protocol.md) —— *OpenAI 显式 call_id 强关联 vs Gemini 函数名隐式关联*
|
|
52
|
+
* [5.3 【白盒剖析】Freya 大模型代理层协议映射](part2_tools/5.3_freya_llm_proxy_mapping.md) —— *LLM 统一代理与插件契约、通用消息与各厂商原生请求体转换*
|
|
53
|
+
* [5.4 调试与避坑指南:并发多工具调用关联混乱排错](part2_tools/5.4_debugging_parallel_call_chaos.md) —— *并发工具调用乱序报错复现、时序重组与局部崩溃隔离*
|
|
54
|
+
|
|
55
|
+
### 💾 [第三部分:大脑的心流与记忆机制 —— 会话与上下文管理](part3_memory/_index.md)
|
|
56
|
+
* **第 6 章:智能体的短期记忆、多轮会话与持久化安全隔离**
|
|
57
|
+
* [6.1 会话管理生命周期与数据结构](part3_memory/6.1_session_state_lifecycle.md) —— *会话物理生命周期、Session 数据结构与 LRU 缓存设计*
|
|
58
|
+
* [6.2 【沙箱设计】数据与源码物理隔离](part3_memory/6.2_physical_sandbox_separation.md) —— *混合存储物理灾难、Freya 运行时物理沙箱隔离划分与初始化*
|
|
59
|
+
* [6.3 【白盒剖析】物理持久化存储机制](part3_memory/6.3_freya_session_storage.md) —— *优化吞吐延迟加载、并发更新排队锁与异步压缩调度*
|
|
60
|
+
* [6.4 调试与避坑指南:高并发会话串线与写入锁排查](part3_memory/6.4_debugging_session_concurrency.md) —— *异步模型下 Session 串线复现、AsyncLocalStorage 隔离与磁盘写冲突文件锁*
|
|
61
|
+
* **第 7 章:上下文窗口溢出危机:压缩、滚动与摘要算法**
|
|
62
|
+
* [7.1 上下文溢出的毁灭性后果与窗口危机](part3_memory/7.1_context_overflow_loss.md) —— *溢出崩溃路径、静默截断三大灾难与量化模型窗口缩减陷阱*
|
|
63
|
+
* [7.2 上下文压缩机制:滑动窗口与递归摘要算法](part3_memory/7.2_sliding_window_vs_summary.md) —— *滑动窗口淘汰、主动递归摘要与时序失真的摘要模板防御*
|
|
64
|
+
* [7.3 【白盒剖析】Compactor 与淘汰算法](part3_memory/7.3_freya_compactor_impl.md) —— *双轨压缩判定、安全截断点回溯算法与轻量正则 Token 预估*
|
|
65
|
+
* [7.4 调试与避坑指南:递归摘要“套娃死锁”防御](part3_memory/7.4_debugging_summarize_deadlock.md) —— *套娃死锁触发与复现、硬性计数闸与摘要 Token 边界保护*
|
|
66
|
+
|
|
67
|
+
### ⚡ [第四部分:智能体的血脉与交互体验 —— 流式通信与事件驱动](part4_streaming/_index.md)
|
|
68
|
+
* **第 8 章:用户交互期望:流式响应 (Streaming Delta) 的传输秘密**
|
|
69
|
+
* [8.1 SSE 协议本质与首字延迟革命](part4_streaming/8.1_sse_protocol_basics.md) —— *首字延迟 (TTFT) 交互革命、SSE 单向长连接抓包与 Nginx 憋尿效应防范*
|
|
70
|
+
* [8.2 隐藏中间推理的工程艺术](part4_streaming/8.2_hiding_thoughts_in_stream.md) —— *双轨管道过滤、隐藏推理流实现与切碎 XML 标签防范*
|
|
71
|
+
* [8.3 【白盒剖析】EventBus 事件广播与响应推送](part4_streaming/8.3_freya_event_bus.md) —— *EventBus 广播 reply 信号机制与事件重播缓冲区机制*
|
|
72
|
+
* [8.4 调试与避坑指南:反代缓存与流式 UTF-8 字符截断排错](part4_streaming/8.4_debugging_stream_decoder.md) —— *TCP 分片与 UTF-8 半字截断、StringDecoder 妙用与流式 JSON 稳定提取*
|
|
73
|
+
* **第 9 章:计费解耦、状态监测与异步中断 (Abort)**
|
|
74
|
+
* [9.1 链路级刹车机制](part4_streaming/9.1_abort_signal_braking.md) —— *AbortSignal 刹车拉线、底座多路刹车分发与 TCP Leak 僵尸连接防范*
|
|
75
|
+
* [9.2 异步事件通信机制](part4_streaming/9.2_async_event_channels.md) —— *三层事件解耦架构、微信通道事件流转与监听器内存泄露*
|
|
76
|
+
* [9.3 【白盒剖析】中断流转与抢救性结算](part4_streaming/9.3_freya_abort_billing.md) —— *中断生命周期控制链、部分响应抢救落盘与父子智能体异步级联刹车*
|
|
77
|
+
* [9.4 调试与避坑指南:中断抢占死锁与句柄释放排查](part4_streaming/9.4_debugging_abort_lock_deadlock.md) —— *中断抢占 Pending Deadlock 死锁复现、finally 释放防线与状态机通道复位*
|
|
78
|
+
|
|
79
|
+
### 📱 [第五部分:触达物理世界 —— 微内核、插件契约与通道适配](part5_plugins/_index.md)
|
|
80
|
+
* **第 10 章:微内核与通道插件的设计哲学:屏蔽 IM 协议差异**
|
|
81
|
+
* [10.1 微内核架构解耦与插件契约设计](part5_plugins/10.1_microkernel_decoupling.md) —— *Core 内核事件分发、Monorepo 依赖边界单向铁律与循环依赖检测*
|
|
82
|
+
* [10.2 依赖边界与安全沙箱](part5_plugins/10.2_plugin_metadata_security.md) —— *静态元数据下沉声明优势、默认关闭零信任安全启停与越权排查*
|
|
83
|
+
* [10.3 【白盒剖析】通道插件开发与消息转换](part5_plugins/10.3_channel_plugin_development.md) —— *Connection ID 物理路由绑定、微信多模态二进制解密与双向事件桥接*
|
|
84
|
+
* [10.4 调试与避坑指南:物理连接假死与指数退避重连](part5_plugins/10.4_debugging_channel_reconnection.md) —— *静默假死成因、复现网络黑洞挂起、超时熔断与指数退避及消息风暴防御*
|
|
85
|
+
|
|
86
|
+
### 🚀 [第六部分:前沿展望与架构演进 —— 走向更高级的 Agent](part6_advanced/_index.md)
|
|
87
|
+
* **第 11 章:超越 ReAct:自我反思 (Self-Reflection) 与复杂规划 (Planning)**
|
|
88
|
+
* [11.1 ReAct 决策环的物理缺陷](part6_advanced/11.1_react_model_flaws.md) —— *长链路逻辑依赖缺陷、误差累积与高频 Tool Call 重复拦截器*
|
|
89
|
+
* [11.2 进阶反思心智模型解析](part6_advanced/11.2_reflexion_mind_model.md) —— *从挫败中归纳经验、Reflexion 三原色角色分工与反思记忆注入控制*
|
|
90
|
+
* [11.3 动手实验:反射循环开发](part6_advanced/11.3_reflexion_hands_on.md) —— *高难度温度转换器任务设计、编写 Reflexion 闭环控制与 eval 安全防范*
|
|
91
|
+
* [11.4 调试与避坑指南:评估反思开销与收敛成功率](part6_advanced/11.4_debugging_reflexion_convergence.md) —— *Critique Loop 两大物理痛点、反思轨迹追踪器及代码膨胀熔断机制*
|
|
92
|
+
* **第 12 章:从单体走向多智能体协作 (Multi-Agent Systems)**
|
|
93
|
+
* [12.1 独木难支:单 Agent 的能力与认知限界](part6_advanced/12.1_single_agent_limits.md) —— *单体工具爆炸与角色污染、社会化分工及分布式状态死锁防范*
|
|
94
|
+
* [12.2 多智能体协作经典范式](part6_advanced/12.2_multi_agent_patterns.md) —— *集中式 Hub-and-Spoke 星形控制 vs 分布式 P2P 网状对等协作及 Hop Counter*
|
|
95
|
+
* [12.3 【白盒剖析】基于事件总线的多体路由](part6_advanced/12.3_freya_multi_agent_routing.md) —— *SpawnSubagentTool 工具定义、路由指纹与子代生命周期 runSubAgent 接管*
|
|
96
|
+
* [12.4 动手实验与三体协同工作流](part6_advanced/12.4_multi_agent_hands_on.md) —— *三体协同软件交付流水线、Swarms集群展望与全局链路费用熔断闸防范*
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "0.1 概率预测与 Next-Token Prediction"
|
|
3
|
+
weight: 10
|
|
4
|
+
description: "解密自回归模型的底层概率机制与 Tokenizer 分词原理,剖析中英文 Token 差异对 Agent 开发的物理影响。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1 概率预测与 Next-Token Prediction
|
|
8
|
+
|
|
9
|
+
当我们与各种号称具备“通用人工智能(AGI)”的智能体(Agent)对话时,它们那行云流水、仿佛充满智慧的回答常常让我们产生一种错觉:大语言模型(LLM)正像人类一样在思考。
|
|
10
|
+
|
|
11
|
+
然而,拉开这层温润的拟人化面纱,智能体的大脑深处其实只在物理性地重复着一个单调而朴素的动作 —— **文字接龙**。
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 一、 概率预测与自回归(Autoregressive)机制
|
|
16
|
+
|
|
17
|
+
大语言模型(LLM)的本质,是一个基于海量文本训练出来的**概率预测概率分布模型**。它的终极任务非常简单:**给定一段已知的上文,预测下一个可能出现的词(或字符)的概率分布**。
|
|
18
|
+
|
|
19
|
+
### 1. 自回归的物理数学公式
|
|
20
|
+
在数学上,这一过程被称为**自回归(Autoregressive)**模型。其概率计算公式可以表示为:
|
|
21
|
+
|
|
22
|
+
$$P(w_t \mid w_1, w_2, \dots, w_{t-1})$$
|
|
23
|
+
|
|
24
|
+
其中:
|
|
25
|
+
* $w_1, w_2, \dots, w_{t-1}$ 代表输入给大模型的历史所有文本(即上下文,Context)。
|
|
26
|
+
* $w_t$ 代表即将生成的第 $t$ 个词。
|
|
27
|
+
* $P$ 则是在给定上述已知历史的条件下,生成 $w_t$ 的概率。
|
|
28
|
+
|
|
29
|
+
当模型通过这一公式预测出第 $t$ 个词后,会立即将这个新词拼接到原本的输入上,重新作为新的“已知上下文”,再次喂给大模型,去预测第 $t+1$ 个词。这种“左手倒右手、自我回归、循环迭代”的生成机制,就是大模型产生连续文本的底层逻辑。
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
已知输入: "今天天气真" ───> 【LLM 大脑】 ───> 预测下一个字概率: {"好": 85%, "晴": 10%, "糟糕": 5%}
|
|
33
|
+
│
|
|
34
|
+
▼ (选中 "好")
|
|
35
|
+
新输入: "今天天气真好" ───> 【LLM 大脑】 ───> 预测下一个字概率: {",": 90%, "。": 8%, "了": 2%}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 2. 为什么自回归机制决定了 Agent 的基本形态?
|
|
39
|
+
这种“Next-Token Prediction(下一个词预测)”的物理局限性,直接决定了 Agent 的两个最底层特性:
|
|
40
|
+
1. **无状态性(Stateless)**:大模型就像一个函数计算,对于相同的输入和参数,它吐出的概率分布是确定的。它本身是不具备“时间”概念的,每次请求它都记不得上一次你是谁。因此,多轮会话(Session)的记忆完全依赖于我们在客户端源源不断地把历史聊天记录拼接成一个巨大的上下文重新发送。
|
|
41
|
+
2. **累积误差(Error Accumulation)**:因为第 $t$ 个词的生成依赖第 $t-1$ 个词。一旦大模型在中间某一步预测出了一个逻辑错误的词,这个“错误”就会被当作既定事实重新塞回输入,引发后面的多米诺骨牌效应。这也就是为什么智能体在规划任务时容易陷入“鬼打墙”或中途跑偏的原因。
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 二、 什么是 Token 与 Tokenizer 的工作原理
|
|
46
|
+
|
|
47
|
+
大模型是不能直接看懂“今天天气真好”或者 "Hello World" 这些自然语言字符的。在大模型内部,所有的文字都需要被转化成高维的数学向量(Embeddings)。而在这两者之间起到翻译官作用的,就是 **Tokenizer(分词器)**。
|
|
48
|
+
|
|
49
|
+
### 1. Token 的定义
|
|
50
|
+
**Token** 是大语言模型处理文本的最小语义单元。一个 Token 可以是一个完整的单词(如 `apple`)、一个词根(如 `un`)、一个单字(如 `好`),甚至可以是一个标点符号,或者一串空格。
|
|
51
|
+
|
|
52
|
+
大模型在训练前会确定一个**词表(Vocabulary)**,词表里收集了几万到几十万个常用的 Token 单元,每个 Token 都有一个唯一的整数 ID 对应。例如:
|
|
53
|
+
* `"the"` 对应 ID `1824`
|
|
54
|
+
* `"apple"` 对应 ID `7362`
|
|
55
|
+
* `"好"` 对应 ID `32890`
|
|
56
|
+
|
|
57
|
+
### 2. Byte-Pair Encoding (BPE) 算法机制
|
|
58
|
+
现代大模型(如 GPT-4, Llama 3)大多使用 **BPE(字节对编码)** 算法来切分 Token。BPE 的核心逻辑是从字节级别开始,通过统计学方法逐步合并高频出现的字符对:
|
|
59
|
+
|
|
60
|
+
1. **初始化**:将词表初始化为所有基本的字符(如 256 个 ASCII 码或 UTF-8 基础字节)。
|
|
61
|
+
2. **统计与合并**:扫描训练语料,统计相邻字符对(如 `e` 和 `s`)的出现频次,将最高频的组合合并成一个新的 Token(如 `es`)。
|
|
62
|
+
3. **循环往复**:重复合并步骤,直到词表大小达到设定阈值(例如 100,000 个 Token)。
|
|
63
|
+
|
|
64
|
+
通过这种方式,高频单词如 `"the"`、`"and"` 会被合并为一个 Token,而低频词或生僻词(如 `"antigravity"`)则会被拆分为多个 Token(如 `anti` + `gravity`)。这保证了词表既不会无限膨胀,又不会因为遇到生僻词而无法解析。
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 三、 中英文 Token 的底层物理差异
|
|
69
|
+
|
|
70
|
+
作为 Agent 开发者,我们需要深刻意识到中英文在 Tokenize 上的物理差异。这种差异**本质上取决于分词器(Tokenizer)的词表大小与训练语料比例的设计,而非语言或模型能力本身的缺陷**。由于大模型 API 的**上下文限制(Context Window)**和**计费**都是基于 Token 数量而非字符数计算的,因此分词器的设计对 Agent 的研发成本和窗口管理起着决定性作用。
|
|
71
|
+
|
|
72
|
+
### 不同分词器下的中英文密度差异
|
|
73
|
+
|
|
74
|
+
* **旧世代分词器的设计局限(以 OpenAI `cl100k_base` 为例)**:
|
|
75
|
+
由于早期的分词器训练语料中英文占比超过 95%,且词表容量较小(如 100k),导致英文的切分效率极高(通常 **1 个 Token 约等于 4 个英文字符**,或者 0.75 个英文单词)。而中文由于紧凑且没有物理空格,大部分汉字无法在词表中合并为词组,甚至部分汉字会因找不到而退化为原始 UTF-8 字节进行解析(在 UTF-8 中 1 个汉字占 3 字节,直接变成 3 个 Token 的惨烈消耗)。
|
|
76
|
+
在此类分词器下,在表达相同的语义信息量时,中文往往比英文需要多消耗约一倍的 Token 数量,这也影响了会话窗口的留存深度。
|
|
77
|
+
|
|
78
|
+
* **大词表与多语言优化分词器(以 `o200k_base` 及国产模型分词器为例)**:
|
|
79
|
+
随着词表容量扩充(如 GPT-4o 采用的 200k 词表)以及中文训练语料占比的大幅提升,新一代分词器和国产大模型(如 DeepSeek、Qwen 等)对中文分词效率进行了针对性的深度优化。
|
|
80
|
+
在这些新型分词器中,大量的中文常用单字和词组被直接收录为单个 Token(1 个汉字平均仅消耗 0.3 到 0.6 个 Token)。在表达相同语义时,中文与英文的 Token 消耗量已基本处于对等状态,甚至在特定的精炼中文表述中,中文的 Token 承载率会比英文更高。
|
|
81
|
+
|
|
82
|
+
在进行 Agent 架构设计和预算预估时,应当针对所选模型的分词器特性进行实际测试,以获得准确的 Token 消耗模型。
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 四、 【代码实验】中英文 Token 密度的物理测量
|
|
87
|
+
|
|
88
|
+
为了严谨,我们直接用代码在本地测试不同文本的 Token 切分情况,拒绝自我想象。
|
|
89
|
+
|
|
90
|
+
在 Node.js 环境下,我们可以使用纯 JavaScript 编写的官方分词器 **`js-tiktoken`** 。
|
|
91
|
+
|
|
92
|
+
在运行本段实验前,您需要先在脚本所在的目录下执行以下命令安装该依赖包:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
npm install js-tiktoken
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 1. 实验代码 (token_test.js)
|
|
99
|
+
```javascript
|
|
100
|
+
const { getEncoding } = require("js-tiktoken");
|
|
101
|
+
|
|
102
|
+
// 初始化 GPT-4 (cl100k_base) 和 GPT-4o (o200k_base) 分词器
|
|
103
|
+
const cl100k = getEncoding("cl100k_base");
|
|
104
|
+
const o200k = getEncoding("o200k_base");
|
|
105
|
+
|
|
106
|
+
const englishText = "Hello, World! Welcome to the world of AI Agents.";
|
|
107
|
+
const chineseText = "你好,世界!欢迎来到智能体的物理世界。";
|
|
108
|
+
|
|
109
|
+
console.log("==================== 1. 英文文本测试 ====================");
|
|
110
|
+
console.log(`文本内容: "${englishText}"`);
|
|
111
|
+
console.log(`字符长度 (Length): ${englishText.length}\n`);
|
|
112
|
+
|
|
113
|
+
const eng100k = cl100k.encode(englishText);
|
|
114
|
+
const eng200k = o200k.encode(englishText);
|
|
115
|
+
|
|
116
|
+
console.log(`[旧版 cl100k_base (GPT-4)] -> Token 数: ${eng100k.length} | 密度比: ${(englishText.length / eng100k.length).toFixed(2)}`);
|
|
117
|
+
console.log(`[新版 o200k_base (GPT-4o)] -> Token 数: ${eng200k.length} | 密度比: ${(englishText.length / eng200k.length).toFixed(2)}\n`);
|
|
118
|
+
|
|
119
|
+
console.log("==================== 2. 中文文本测试 ====================");
|
|
120
|
+
console.log(`文本内容: "${chineseText}"`);
|
|
121
|
+
console.log(`字符长度 (Length): ${chineseText.length}\n`);
|
|
122
|
+
|
|
123
|
+
const ch100k = cl100k.encode(chineseText);
|
|
124
|
+
const ch200k = o200k.encode(chineseText);
|
|
125
|
+
|
|
126
|
+
console.log(`[旧版 cl100k_base (GPT-4)] -> Token 数: ${ch100k.length} | 密度比: ${(chineseText.length / ch100k.length).toFixed(2)}`);
|
|
127
|
+
console.log(`[新版 o200k_base (GPT-4o)] -> Token 数: ${ch200k.length} | 密度比: ${(chineseText.length / ch200k.length).toFixed(2)}`);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
在终端执行以下命令运行该脚本:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
node token_test.js
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 2. 测量结果与痛点分析
|
|
137
|
+
运行上述代码,你将直观地看到:
|
|
138
|
+
* **英文文本表现稳定**:在两代分词器下,英文字符数均为 48 个,切分出的 Token 数量均为 **12 个**(字符/Token 密度比均为 **4.00**),说明词表容量升级对结构成熟的英文文本压缩影响不大。
|
|
139
|
+
* **中文文本优化显著**:中文字符数为 19 个。在旧版 `cl100k_base` 下,由于高频词未合并,切分出多达 **24 个 Token**(密度比仅为 **0.79**);而在新版 `o200k_base` 下,因为常用汉字与词组并入词表,Token 数量暴降至 **13 个**,密度比直接拉升到 **1.46**,降幅达到近 45%。
|
|
140
|
+
|
|
141
|
+
> [!NOTE]
|
|
142
|
+
> 需要注意的是,本实验仅展示了以 OpenAI 模型体系为代表的两代分词器。在实际的 Agent 研发中,不同的模型厂商会使用完全不同的分词器。特别是专门针对中文语料进行深度优化的国产大模型(如 DeepSeek、Qwen 等),其分词器对中文汉字的压缩率通常会更高(一个汉字有时仅消耗 0.3 到 0.5 个 Token)。因此在对接其他厂商的模型时,应当根据其对应分词器的真实表现进行评估。
|
|
143
|
+
>
|
|
144
|
+
> 此外,虽然本教程(Freya 项目)为了便于教学讲解,其内置系统提示词均采用中文编写,但这并不意味着中文提示词在指令遵循和推理性能上优于英文。现阶段对于大多数国际主流基座模型而言,英文提示词在逻辑推理、格式约束和长文本遵循上依然更具优势。在生产环境部署中,建议开发者根据所使用模型的语言偏好,将提示词优化并翻译为英文以追求更佳的性能。
|
|
145
|
+
|
|
146
|
+
### 3. “Token 刺客”排查防范
|
|
147
|
+
在 Agent 实际工程中,有以下两个最容易被忽略的“Token 刺客”,它们会在暗中吃掉你的上下文配额:
|
|
148
|
+
1. **JSON 缩进与冗余字符**:
|
|
149
|
+
为了方便阅读,我们常常将 API 传递的数据格式化为带有换行和四个空格缩进的 JSON。在大模型眼中,**连续的空格和换行符同样也是 Token**。一个格式化优美的 JSON 数据可能会包含成百上千个无意义的空格 Token。
|
|
150
|
+
* *防御手段*:在喂给大模型前,必须使用 `JSON.stringify(data)` 进行紧凑压缩,抹去所有换行和缩进。
|
|
151
|
+
2. **Markdown 表格与标点**:
|
|
152
|
+
复杂的表格边框符号(如 `|`、`-`)会产生高频碎片 Token。
|
|
153
|
+
* *防御手段*:非必要时不传大量原始表格数据,可以转换为更紧凑的 CSV 格式或简明文本列表送入。
|
|
154
|
+
|
|
155
|
+
通过本节的物理剖析,你应该明白:**大模型是用概率在“接龙”,而它的世界尺度是 Token。** 建立起这个物理认知,是我们后续开发任何高内聚 Agent 架构(如 ReAct、记忆池)的重要逻辑基石。
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "0.2 算力与窗口的物理极限"
|
|
3
|
+
weight: 20
|
|
4
|
+
description: "解剖自注意力机制的平方复杂度与 KV Cache 显存占用,透视 Context Window 的硬件瓶颈与 Lost in the Middle 现象。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.2 算力与窗口的物理极限
|
|
8
|
+
|
|
9
|
+
在 0.1 节中我们了解到,大模型是通过不断“接龙”来产生连续回答的。这自然引出了一个直观的问题:**为什么我们不能直接把一整本书、甚至整个数据库的历史记录一次性喂给大模型?为什么大模型一定要设置上下文窗口(Context Window)的上限?**
|
|
10
|
+
|
|
11
|
+
许多人以为这仅仅是厂商为了多收费而设置的软件限制,但实际上,这是一个受制于现代半导体物理、数学算法以及 GPU 显存容量的**硬核物理极限**。
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 一、 Attention 机制的平方复杂度 $O(N^2)$
|
|
16
|
+
|
|
17
|
+
现代大语言模型(如 GPT、Llama、Mistral)无一例外都是基于 **Transformer** 架构构建的。而 Transformer 的核心引擎,就是 **Self-Attention(自注意力机制)**。
|
|
18
|
+
|
|
19
|
+
### 1. 什么是自注意力机制?
|
|
20
|
+
自注意力机制的本质是:**计算输入序列中任意两个 Token 之间的语义相关性(权重)**。
|
|
21
|
+
|
|
22
|
+
当大模型在预测下一个 Token 时,它需要回看前面所有的历史 Token。大模型通过将每个 Token 转化为三种角色向量来进行“匹配”:
|
|
23
|
+
* **Query (Q, 查询)**:我想找什么?
|
|
24
|
+
* **Key (K, 键)**:我这里有什么,可以被别人匹配?
|
|
25
|
+
* **Value (V, 值)**:我所代表的实际语义内容是什么?
|
|
26
|
+
|
|
27
|
+
对于长度为 $N$ 的输入文本,模型需要计算 $Q$ 与 $K$ 之间的相关性权重矩阵。这意味着**每一个 Token 都要和前面所有的 Token 做一次点积(Dot Product)计算**。
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
输入序列长度 N = 4: ["今", "天", "天", "气"]
|
|
31
|
+
|
|
32
|
+
相关性计算矩阵 (N x N):
|
|
33
|
+
今 天 天 气
|
|
34
|
+
今 [•] [•] [•] [•] ──> "今" 与所有字关联
|
|
35
|
+
天 [•] [•] [•] [•] ──> "天" 与所有字关联
|
|
36
|
+
天 [•] [•] [•] [•]
|
|
37
|
+
气 [•] [•] [•] [•] ──> 共需要计算 4 x 4 = 16 次相关权重
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. $O(N^2)$ 的物理诅咒
|
|
41
|
+
如果上下文长度为 $N$:
|
|
42
|
+
* 当 $N = 1,000$ 时,注意力权重矩阵的大小是 $1,000 \times 1,000 = 1,000,000$(100万次关联计算)。
|
|
43
|
+
* 当 $N = 10,000$ 时,计算量暴增至 $10,000 \times 10,000 = 100,000,000$(1亿次关联计算!)。
|
|
44
|
+
* 当 $N = 100,000$ 时,计算量将达到恐怖的 **100亿次**。
|
|
45
|
+
|
|
46
|
+
这种随着上下文长度 $N$ 的增加,计算复杂度和所需的**临时激活显存(Activation Memory)**呈**平方级暴增**的现象,在算法上被称为 **$O(N^2)$ 复杂度**。
|
|
47
|
+
|
|
48
|
+
这也是为什么当智能体的多轮对话历史变得极长时,大模型的推理速度(首字延迟 TTFT,Time-to-First-Token)会发生肉眼可见的急剧下滑,且服务器的计算开销呈指数飙升的底层原因。
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 二、 Context Window 与 KV Cache 的显存深渊
|
|
53
|
+
|
|
54
|
+
为了解决每次“接龙”新 Token 时重复计算历史 Token 的 $Q, K, V$ 矩阵所带来的巨大算力浪费,工程上引入了一个核心优化技术:**KV Cache(键值缓存)**。但这个技术也带来了新的物理瓶颈。
|
|
55
|
+
|
|
56
|
+
### 1. 什么是 KV Cache?
|
|
57
|
+
当大模型生成第 $t$ 个 Token 时,前 $t-1$ 个 Token 的 Key(K)和 Value(V)向量其实已经在前面的步骤中计算过了,并且不会随着新 Token 的加入而改变。
|
|
58
|
+
|
|
59
|
+
因此,推理引擎会把前 $t-1$ 个 Token 的 $K$ 和 $V$ 矩阵保存在 GPU 的显存中(这个缓存区就叫 KV Cache)。当生成第 $t$ 个 Token 时,模型只需要计算这一个新 Token 的 $Q, K, V$,然后直接去和显存里存好的历史 $K, V$ 做注意力点积。
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
[步骤 t-1] 生成了 "好":
|
|
63
|
+
将 "今", "天", "天", "气", "真", "好" 的 K, V 矩阵存入显存 (KV Cache)
|
|
64
|
+
│
|
|
65
|
+
▼
|
|
66
|
+
[步骤 t] 准备生成下一个字:
|
|
67
|
+
仅计算新字 "。" 的 Q, K, V ───> 与显存中的历史 K, V 进行 Attention 计算 ───> 吐出下一个字
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. KV Cache 显存占用公式
|
|
71
|
+
KV Cache 极大地节省了算力,但它是一个贪婪的**显存吞噬者**。我们可以用公式来精确计算 KV Cache 占用的显存字节数:
|
|
72
|
+
|
|
73
|
+
$$\text{Memory}_{\text{KV\_Cache}} = 2 \times B \times L \times H \times D \times N \times \text{Precision}$$
|
|
74
|
+
|
|
75
|
+
其中:
|
|
76
|
+
* $2$ 代表 Key 和 Value 两个矩阵。
|
|
77
|
+
* $B$ 代表并发会话的 Batch Size(批大小)。
|
|
78
|
+
* $L$ 代表模型的层数(Layers,如 Llama 3-8B 有 32 层)。
|
|
79
|
+
* $H$ 代表注意力头的个数(Heads)。
|
|
80
|
+
* $D$ 代表每个头的维度(Dimension)。
|
|
81
|
+
* $N$ 代表当前的上下文 Token 数量。
|
|
82
|
+
* $\text{Precision}$ 代表参数精度占用的字节数(如 FP16 占用 2 字节,BF16 占用 2 字节)。
|
|
83
|
+
|
|
84
|
+
以一个经典的 **Llama-3-8B** 模型在单用户($B=1$)、精度为 FP16(2字节)下运行,上下文长度 $N = 8,000$ 为例:
|
|
85
|
+
* 层数 $L = 32$
|
|
86
|
+
* K, V 注意力头数 $H = 8$(使用了 GQA 机制)
|
|
87
|
+
* 维度 $D = 128$
|
|
88
|
+
* 计算:$2 \times 1 \times 32 \times 8 \times 128 \times 8,000 \times 2 \approx 1,048,576,000 \text{ 字节} \approx \mathbf{1 \text{ GB}}$
|
|
89
|
+
|
|
90
|
+
这意味着,**仅仅为了缓存这 8,000 个 Token 的记忆,在推理时就需要额外在 GPU 显存中霸占 1 GB 的空间**。这还没算模型本身参数占用的 16 GB 固化显存。如果高并发下有 64 个用户同时在线,光是 KV Cache 就会吃掉 64 GB 的显存,瞬间把一张顶级卡(如 A100 80GB)挤爆。
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 三、 长上下文的“大海捞针”瓶颈
|
|
95
|
+
|
|
96
|
+
即便近年来通过 **FlashAttention** 算法优化了显存读写,以及通过 **RoPE 旋转位置编码**外推技术让模型号称支持 128k、1M 甚至 2M 的上下文窗口,但在物理上,长上下文的检索能力依然存在严重的瓶颈。
|
|
97
|
+
|
|
98
|
+
### 1. 什么是“大海捞针”测试?
|
|
99
|
+
**“大海捞针”(Needle in a Haystack)**是测试长文本模型检索能力的标准实验。其方法是:在一篇长达数十万字的无聊小说(Haystack,干草堆)的随机位置,塞入一句完全不相干的秘密陈述(Needle,针,例如“小明最喜欢吃苹果”),然后将整个文本输入给大模型,要求它找出这句话。
|
|
100
|
+
|
|
101
|
+
### 2. Lost in the Middle(迷失在中间)现象
|
|
102
|
+
经过大量学术界和工业界的评测,人们发现了一个残酷的物理事实:
|
|
103
|
+
当上下文长度达到极限时,模型对于首部(Prompt 开头)和尾部(Prompt 结尾)的信息检索准确率接近 100%。但是,**对于处于上下文中段(Middle)的信息,检索准确率会发生断崖式下跌,甚至直接漏掉**。
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
信息检索准确率曲线 (U型曲线):
|
|
107
|
+
|
|
108
|
+
准确率 100% | \ /
|
|
109
|
+
| \ /
|
|
110
|
+
| \ /
|
|
111
|
+
| \ /
|
|
112
|
+
| \ Lost /
|
|
113
|
+
| \ in the Middle /
|
|
114
|
+
0% | \____________[降温区]_________/
|
|
115
|
+
+---------------------------------------------------
|
|
116
|
+
0% (文档开头) 50% (文档中段) 100% (文档结尾)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
这是因为 Transformer 的 Attention 权重在面对庞大序列时,长距离的信号会受到稀释和干扰,导致模型“注意力涣散”。因此,**支持 1M 的上下文窗口,并不等于模型能够真正消化 1M 的全部信息**。
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 四、 【架构防范】上下文膨胀与 Token 费用失控控制
|
|
124
|
+
|
|
125
|
+
在 Agent 系统开发中,由于 Agent 会频繁调用外部工具并带回大量的 Observation 结果,会导致上下文(Context)极速膨胀。如果不做策略防御,会导致 API 计费风暴(Token 刺客)与请求报错。
|
|
126
|
+
|
|
127
|
+
### 1. API 计费风暴与窗口超限
|
|
128
|
+
|
|
129
|
+
当我们调用云端大模型 API(如 OpenAI、Gemini 或国产的 DeepSeek、Qwen 等)时,每次发送新的对话请求,推理引擎都需要对所有的历史文本、多模态附件以及工具返回结果进行重新读取和处理。这意味着:
|
|
130
|
+
* **输入计费线性滚雪球**:随着会话轮数的增加,每一轮你都需要为“历史对话和所有工具返回”重复买单。Input Token 计费会像滚雪球一样线性暴增,即使大模型单次只吐出几个字的回复,前台的账单也会非常昂贵。
|
|
131
|
+
* **超出窗口极限报错(400 Bad Request)**:当总 Token 数超过大模型 API 所允许的最大输入限制时,请求会直接被大模型关口拦截并报错挂死。
|
|
132
|
+
* **静默截断导致智能体“脑残”**:部分厂商的 API 在超限时不会报错,而是采取“后进先出”的机制静默截断头部历史(这往往会把最顶部的系统设定 `System Prompt` 强行丢弃),导致 Agent 瞬间丧失身份设定或工具规范。
|
|
133
|
+
|
|
134
|
+
### 2. Agent 成本与窗口控制策略
|
|
135
|
+
|
|
136
|
+
为了让 Agent 在预算和物理窗口的双重极限内健康运转,我们在 Freya 架构设计中必须采取以下防御机制:
|
|
137
|
+
|
|
138
|
+
1. **主动上下文监控与滚动摘要(Compactor)**:
|
|
139
|
+
在底座发起大模型 API 调用前,实时计算当前会话的消息总 Token 数。一旦逼近安全限额或预设的预算上限,主动触发 Compactor 机制对历史长文本进行精炼摘要,释放大量上下文配额,从而降低每轮的 Input Token 账单。
|
|
140
|
+
2. **闲置工具动态淘汰机制**:
|
|
141
|
+
在 Agent 开发中,工具箱的定义(JSON Schema)会作为 System Prompt 的一部分在每轮中被重算。如果挂载了几十个工具,即便不调用,也会持续消耗大量的 Input Token 费用。应当实时监测工具调用频率,自动动态卸载(Deactivate)连续多轮未被调用的工具箱,大幅精简 Prompt 体积。
|
|
142
|
+
3. **计费监控与死循环费用熔断(Billing & Abort Safeguards)**:
|
|
143
|
+
在 Agent 大脑主循环(ReAct 循环)中,必须配置全局计费监控。一旦检测到单次会话或单轮交互的 Token 累积费用超出安全阈值(例如触发了无限工具调用死循环),底座必须立即强行向 LLM 发送 `AbortSignal` 进行“紧急刹车”,物理熔断扣费。
|
|
144
|
+
|
|
145
|
+
通过本节的物理剖析,我们必须清醒地认识到:**API 窗口是有极限的,Token 是极其昂贵的**。在后续的架构开发中,我们将看到 Freya 如何在 `SessionManager` 中通过精密的物理限额、闲置工具动态淘汰和 Compactor 机制,在满足业务需求的同时,牢牢守住开发者的资金安全底线。
|