pasm-framework 0.3.0__tar.gz

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.
Files changed (35) hide show
  1. pasm_framework-0.3.0/LICENSE +21 -0
  2. pasm_framework-0.3.0/PKG-INFO +281 -0
  3. pasm_framework-0.3.0/README.md +253 -0
  4. pasm_framework-0.3.0/pasm_framework/__init__.py +509 -0
  5. pasm_framework-0.3.0/pasm_framework/__main__.py +282 -0
  6. pasm_framework-0.3.0/pasm_framework/adapter.py +80 -0
  7. pasm_framework-0.3.0/pasm_framework/application.py +426 -0
  8. pasm_framework-0.3.0/pasm_framework/config.py +319 -0
  9. pasm_framework-0.3.0/pasm_framework/demo.py +85 -0
  10. pasm_framework-0.3.0/pasm_framework/discovery.py +91 -0
  11. pasm_framework-0.3.0/pasm_framework/errors.py +26 -0
  12. pasm_framework-0.3.0/pasm_framework/plugins/__init__.py +42 -0
  13. pasm_framework-0.3.0/pasm_framework/plugins/builtins/__init__.py +30 -0
  14. pasm_framework-0.3.0/pasm_framework/plugins/builtins/knowledge_base.py +319 -0
  15. pasm_framework-0.3.0/pasm_framework/plugins/builtins/llm_responder.py +443 -0
  16. pasm_framework-0.3.0/pasm_framework/plugins/builtins/observability.py +64 -0
  17. pasm_framework-0.3.0/pasm_framework/plugins/builtins/safety.py +89 -0
  18. pasm_framework-0.3.0/pasm_framework/plugins/builtins/sessions.py +82 -0
  19. pasm_framework-0.3.0/pasm_framework/plugins/builtins/warmth.py +97 -0
  20. pasm_framework-0.3.0/pasm_framework/plugins/builtins/web_gateway.py +457 -0
  21. pasm_framework-0.3.0/pasm_framework/plugins/core.py +420 -0
  22. pasm_framework-0.3.0/pasm_framework/plugins/registry.py +80 -0
  23. pasm_framework-0.3.0/pasm_framework/py.typed +0 -0
  24. pasm_framework-0.3.0/pasm_framework/scaffold.py +292 -0
  25. pasm_framework-0.3.0/pasm_framework/service.py +154 -0
  26. pasm_framework-0.3.0/pasm_framework/simple.py +174 -0
  27. pasm_framework-0.3.0/pasm_framework/skill.py +77 -0
  28. pasm_framework-0.3.0/pasm_framework.egg-info/PKG-INFO +281 -0
  29. pasm_framework-0.3.0/pasm_framework.egg-info/SOURCES.txt +33 -0
  30. pasm_framework-0.3.0/pasm_framework.egg-info/dependency_links.txt +1 -0
  31. pasm_framework-0.3.0/pasm_framework.egg-info/entry_points.txt +2 -0
  32. pasm_framework-0.3.0/pasm_framework.egg-info/requires.txt +1 -0
  33. pasm_framework-0.3.0/pasm_framework.egg-info/top_level.txt +1 -0
  34. pasm_framework-0.3.0/pyproject.toml +51 -0
  35. pasm_framework-0.3.0/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 arronzheng
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,281 @@
1
+ Metadata-Version: 2.4
2
+ Name: pasm-framework
3
+ Version: 0.3.0
4
+ Summary: PASM 应用开发框架 —— 产品智能体/应用与认知引擎之间的防腐层(V1↔V2 唯一变动点)
5
+ Author: arronzheng
6
+ License: MIT
7
+ Project-URL: Homepage, https://gitee.com/arronzheng/pasm-framework
8
+ Project-URL: Repository, https://github.com/arronJack/pasm-framework
9
+ Project-URL: Source, https://gitee.com/arronzheng/pasm-framework
10
+ Project-URL: Issues, https://gitee.com/arronzheng/pasm-framework/issues
11
+ Keywords: pasm,agent,application-framework,anti-corruption-layer,cognitive,capability,skill,domain-adapter
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
22
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: pasm-skills>=0.5.1
27
+ Dynamic: license-file
28
+
29
+ # pasm-framework
30
+
31
+ PASM 应用开发框架 —— 产品智能体 / 应用与认知引擎之间的**防腐层(Anti-Corruption Layer)**。
32
+ 本包于 **v0.1.0** 从基座 [`pasm-skills`](https://gitee.com/arronzheng/pasm-skills) 的
33
+ `pasm_skills.framework` 子包独立成仓。
34
+
35
+ > 注意:本包是「**应用开发**框架」(给产品智能体 / 应用用);
36
+ > `pasm-skills` 里还有一个同名概念「验证器框架」`pasm_skills.agent`(给自检 / 守护智能体用),
37
+ > 两者职责不同,请勿混淆。
38
+
39
+ ## 它解决什么问题
40
+
41
+ PASM V1 → V2 升级时,**不重写 4 个产品智能体 + 3 个技能**。手段是建立一组**稳定表面**,
42
+ 让应用只依赖表面、不依赖引擎内部;引擎大改时只动"唯一变动点"。
43
+
44
+ ## 导出的稳定表面
45
+
46
+ | 表面 | 作用 |
47
+ | --- | --- |
48
+ | `CognitiveAssembler` / `CognitiveService` | 引擎 ↔ 应用装配(**V1↔V2 唯一变动点**) |
49
+ | `DomainAdapter` | 领域知识 / 规则注入契约 |
50
+ | `CapabilityDiscovery` / `Capability` | 能力声明与统一发现 |
51
+ | `BaseApplication` | 通用 AI 应用底座(建在 `BaseAgent` 上);`handle()` / **`stream()`** / **`ingest()`** |
52
+ | `SimpleApplication` / `@capability` | 3 行起步的极简应用写法(v0.2.1) |
53
+ | `BaseSkill` / `SkillManifest` | 技能包代码化底座 |
54
+
55
+ `CognitiveBackend` 协议的**单一真相源仍在基座** `pasm_skills.sdk.backend`,本包只做重导出。
56
+
57
+ ## 流式与工具调用(v0.3.0 新增)
58
+
59
+ **真流式(SSE)** —— `stream()` 与 `handle()` **共用同一条管线**,不会行为漂移:
60
+
61
+ ```python
62
+ for ev in app.stream("怎么退货?", session_id="u1"):
63
+ if ev["type"] == "delta": # 增量片段,可直接追加显示
64
+ print(ev["text"], end="", flush=True)
65
+ elif ev["type"] == "replace": # 护栏/润色改写过 → 整条替换
66
+ print("\n[已修正]", ev["text"])
67
+ ```
68
+
69
+ 网关侧对应 `POST /api/chat/stream`(`text/event-stream`,零依赖);
70
+ 客户端有 `PasmClient.chat_stream()`(Python)与 `chatStream()`(Node)。
71
+
72
+ > **护栏不会被流式绕过**:流式是在*生成中*外推的,而护栏在*生成后*才跑。
73
+ > 若收尾改写了内容(例如脱敏),框架补发 `replace` 事件让客户端纠正 ——
74
+ > 所以"唯一出口"承诺对 `handle` 和 `stream` 同时成立。
75
+
76
+ **多轮工具调用** —— 应用的 `Capability` 自动暴露为 OpenAI 兼容 `tools`:
77
+
78
+ ```python
79
+ app = BaseApplication(..., backend_config={
80
+ "llm_responder": {"enabled": True, "config": {
81
+ "provider": "deepseek", "api_key": "...",
82
+ "tools": True, # 把能力交给模型调用(默认开)
83
+ "max_tool_rounds": 3, # 工具环上限
84
+ }}})
85
+ ```
86
+
87
+ 模型说"要调 `cap_1`" → 框架真的执行该能力 → 结果回填 `role=tool` → 再请求。
88
+ 中文能力名会转成合法 tool 名(`cap_1`…),原名保留在 `description` 里。
89
+ 上游对 `tools` / `stream` 返回 400 时**自动降级**为纯对话重试,不会挂。
90
+
91
+ ## 插件库(v0.2.0 新增,即插即用)
92
+
93
+ 框架自带 **7 个通用插件**,全部零强制外部依赖,**可在后端开关**("用户选择是否使用"):
94
+ 通过 `BaseApplication(..., backend_config={...})` 控制启用与配置。
95
+
96
+ | 插件 | 作用 | 默认 |
97
+ | --- | --- | --- |
98
+ | `knowledge_base` | 站点数据 → 资料库,自学 / 记忆 / 成长(客服核心) | ✅ 开 |
99
+ | `sessions` | 会话 / 租户隔离,记住每个客户上下文 | ✅ 开 |
100
+ | `warmth` | 情绪驱动回复润色,做到"有温度" | ✅ 开 |
101
+ | `safety` | prompt 注入拦截 + PII 脱敏 | ✅ 开 |
102
+ | `observability` | 指标 + 健康(`/healthz`) | ✅ 开 |
103
+ | `llm_responder` | 可选 LLM 接入(OpenAI 兼容 / DeepSeek / Ollama) | ⬜ 关 |
104
+ | `web_gateway` | 零依赖 HTTP 网关(iframe / REST 外部链接) | ⬜ 关 |
105
+
106
+ Hook 链:`on_init → on_message_in → on_retrieve → on_reply → on_reply_final → on_learn → on_shutdown`。
107
+ **不启用任何插件时,`handle` 行为与 v0.1.0 完全一致**(能力路由 → 回落 chat)。
108
+
109
+ `on_reply_final` 是**唯一出口**:能力结果 / LLM 回复 / 模板兜底 / 被拦截,四条路径
110
+ 出站前都经过它恰好一次 —— 护栏因此不可能被某条路径绕过。
111
+
112
+ ### 用插件开关"定制应用"
113
+
114
+ ```python
115
+ from pasm_framework import BaseApplication
116
+
117
+ class MyAgent(BaseApplication):
118
+ def action_pool(self): return ["reply"]
119
+ def _render_reply(self, text, facts, mood): return "答:%s" % text
120
+
121
+ agent = MyAgent(
122
+ "demo", {"name": "小智"},
123
+ backend_config={
124
+ "knowledge_base": {"enabled": True, "config": {"kb_dir": "./kb"}},
125
+ "llm_responder": {"enabled": True, "config": {
126
+ "provider": "deepseek", "api_key": "sk-...", "model": "deepseek-chat"}},
127
+ "web_gateway": {"enabled": True, "config": {"port": 8080}},
128
+ },
129
+ )
130
+ agent.handle("你好", session_id="u1") # 走插件链
131
+ agent.serve(port=8080) # 站点 <iframe src="http://host:8080/">
132
+ agent.close() # 跑 on_shutdown,停网关
133
+ ```
134
+
135
+ ### 写自己的插件
136
+
137
+ ```python
138
+ from pasm_framework import BasePlugin, PluginContext
139
+
140
+ class SlaPlugin(BasePlugin):
141
+ name, version = "sla", "0.1.0"
142
+ def on_reply_final(self, ctx: PluginContext) -> None:
143
+ # 收尾阶段:对已经定稿的回复做后处理
144
+ if ctx.message.reply:
145
+ ctx.message.reply += "\n(本次回复已记录)"
146
+ ```
147
+
148
+ **注册方式一(推荐):配置里内联,不用发包**
149
+
150
+ ```python
151
+ app = MyApp("demo", {"name": "小智"}, backend_config={
152
+ "sla": {"enabled": True, "class": SlaPlugin},
153
+ })
154
+ ```
155
+
156
+ **注册方式二:发布成可发现包**,安装即被自动发现
157
+
158
+ ```toml
159
+ [project.entry-points."pasm_framework.plugins"]
160
+ sla = "my_pkg.my_module:SlaPlugin"
161
+ ```
162
+
163
+ ⚠️ 插件名**拼错不会静默通过**:`app.plugins.unknown()`、`app.app_summary()["plugin_config_unknown"]`
164
+ 以及 `pasm-framework doctor` 都会报告。
165
+
166
+ ## 参考实现:站点智能客服
167
+
168
+ `apps/customer_service.py` 用插件组合出一个可上线的客服 Agent(零 LLM 也能回答)。
169
+ `docs/customer-service-plugin.md` 是可行性与部署形态研究(iframe / REST / WebSocket)。
170
+
171
+ ```bash
172
+ python -m apps.customer_service # 演示问答 + 自学习统计
173
+ python -m apps.customer_service --serve # 起 HTTP 网关:http://0.0.0.0:8080/
174
+ ```
175
+
176
+ ## 依赖方向(单一、无环)
177
+
178
+ ```
179
+ pasm-agents (产品) → pasm-framework → pasm_skills.sdk → 引擎(pasm.*)
180
+ ```
181
+
182
+ - 动:`CognitiveAssembler.v2`(V2.0 落地时新增)+ `PasmV2Backend`
183
+ - 不动:`BaseApplication`、4 智能体、3 技能、`DomainAdapter`、`CapabilityDiscovery`、`BaseSkill`
184
+
185
+ ## 安装
186
+
187
+ ```bash
188
+ pip install pasm-framework
189
+ # 基座会被自动作为依赖装上:pasm-skills>=0.5.1
190
+ ```
191
+
192
+ ## 配置系统(v0.2.1 新增)
193
+
194
+ 开关表可以来自**预设 / 文件 / 环境变量 / 代码**,优先级由低到高:
195
+
196
+ ```python
197
+ from pasm_framework import load
198
+
199
+ cfg = load("server.json", # 文件(.json / .yaml)
200
+ preset_name="chatbot", # 场景预设打底
201
+ env=True, # 叠加 PASM_* 环境变量
202
+ web_gateway={"config": {"port": 9000}}) # 代码覆盖一切
203
+
204
+ app = MyApp("demo", {"name": "小智"}, backend_config=cfg)
205
+ ```
206
+
207
+ 6 套场景预设:`minimal`(全关,退回 0.1.0 行为)· `default` ·
208
+ `chatbot`(护栏 block + 开网关)· `game_npc`(离线优先)·
209
+ `api`(回复不润色)· `desktop`(只监听本机)。
210
+
211
+ 环境变量:`PASM_PLUGINS` / `PASM_KB_DIR` / `PASM_SAFETY_MODE` /
212
+ `PASM_LLM_PROVIDER` `PASM_LLM_MODEL` `PASM_LLM_API_KEY` /
213
+ `PASM_HTTP_HOST` `PASM_HTTP_PORT` `PASM_HTTP_TOKEN`。
214
+
215
+ ## CLI
216
+
217
+ ```bash
218
+ pasm-framework # 自检 + 用法
219
+ pasm-framework doctor # 环境体检(出问题先跑这个)
220
+ pasm-framework new myapp --kind chatbot # 生成可跑的项目
221
+ pasm-framework serve --port 8080 # 起一个演示客服
222
+ pasm-framework plugins # 看内置插件与默认开关
223
+ pasm-framework config --preset api --env # 看最终解析出的配置
224
+ ```
225
+
226
+ ## 最小示例
227
+
228
+ 最省事(v0.2.1 起,3 行起步):
229
+
230
+ ```python
231
+ from pasm_framework import SimpleApplication, capability, load
232
+
233
+ class MyApp(SimpleApplication):
234
+ @capability(keywords=("帮助", "help"))
235
+ def help(self, text):
236
+ return "我能回答资料库里的问题。"
237
+
238
+ app = MyApp("demo", {"name": "小智"},
239
+ backend_config=load(preset_name="chatbot"))
240
+ print(app.ask("帮助"))
241
+ ```
242
+
243
+ 需要完全控制时,继承 `BaseApplication`:
244
+
245
+ ```python
246
+ from pasm_framework import BaseApplication, Capability
247
+
248
+ class MyApp(BaseApplication):
249
+ def action_pool(self):
250
+ return ["a1", "a2"]
251
+ def _render_reply(self, text, facts, mood):
252
+ return "reply:%s" % text
253
+
254
+ app = MyApp(agent_id="demo", persona={"name": "demo"}, persist_dir="/tmp/demo")
255
+ print(app.handle("你好")) # → "reply:你好"(回落 chat)
256
+ ```
257
+
258
+ ## 快速自检
259
+
260
+ ```bash
261
+ python -m pasm_framework selftest # 44 项
262
+ python -m pasm_framework doctor # 真装配一遍插件并报拼错的名字
263
+ python -m pasm_framework version
264
+ ```
265
+
266
+ ## 文档
267
+
268
+ | 文档 | 内容 |
269
+ | --- | --- |
270
+ | [`docs/tutorials/`](docs/tutorials/README.md) | **开发教程**:快速上手 → 能力/插件 → 客服/LLM/部署 → 游戏 NPC → 多语言 |
271
+ | [`docs/capability-matrix-2026-09-20.md`](docs/capability-matrix-2026-09-20.md) | 能力就绪度复检:能做/不能做、剩余问题、性能实测 |
272
+ | [`docs/polyglot-strategy.md`](docs/polyglot-strategy.md) | C#/Java/PHP 怎么接入(协议优先,不移植引擎) |
273
+ | [`docs/cross-platform-strategy.md`](docs/cross-platform-strategy.md) | 桌面端跨 Linux/macOS、手机端换架构方案 |
274
+ | [`docs/customer-service-plugin.md`](docs/customer-service-plugin.md) | 智能客服可行性与部署形态研究 |
275
+ | [`docs/audit-2026-09-20.md`](docs/audit-2026-09-20.md) | v0.2.0 体检报告 |
276
+ | [`docs/openapi.yaml`](docs/openapi.yaml) | HTTP 契约(单一真相源) |
277
+ | [`sdks/`](sdks/README.md) | C# / Java / PHP / Node / Go / Python 客户端 |
278
+
279
+ ## 许可证
280
+
281
+ MIT —— 与 `pasm-skills` / `pasm-agents` 一致。
@@ -0,0 +1,253 @@
1
+ # pasm-framework
2
+
3
+ PASM 应用开发框架 —— 产品智能体 / 应用与认知引擎之间的**防腐层(Anti-Corruption Layer)**。
4
+ 本包于 **v0.1.0** 从基座 [`pasm-skills`](https://gitee.com/arronzheng/pasm-skills) 的
5
+ `pasm_skills.framework` 子包独立成仓。
6
+
7
+ > 注意:本包是「**应用开发**框架」(给产品智能体 / 应用用);
8
+ > `pasm-skills` 里还有一个同名概念「验证器框架」`pasm_skills.agent`(给自检 / 守护智能体用),
9
+ > 两者职责不同,请勿混淆。
10
+
11
+ ## 它解决什么问题
12
+
13
+ PASM V1 → V2 升级时,**不重写 4 个产品智能体 + 3 个技能**。手段是建立一组**稳定表面**,
14
+ 让应用只依赖表面、不依赖引擎内部;引擎大改时只动"唯一变动点"。
15
+
16
+ ## 导出的稳定表面
17
+
18
+ | 表面 | 作用 |
19
+ | --- | --- |
20
+ | `CognitiveAssembler` / `CognitiveService` | 引擎 ↔ 应用装配(**V1↔V2 唯一变动点**) |
21
+ | `DomainAdapter` | 领域知识 / 规则注入契约 |
22
+ | `CapabilityDiscovery` / `Capability` | 能力声明与统一发现 |
23
+ | `BaseApplication` | 通用 AI 应用底座(建在 `BaseAgent` 上);`handle()` / **`stream()`** / **`ingest()`** |
24
+ | `SimpleApplication` / `@capability` | 3 行起步的极简应用写法(v0.2.1) |
25
+ | `BaseSkill` / `SkillManifest` | 技能包代码化底座 |
26
+
27
+ `CognitiveBackend` 协议的**单一真相源仍在基座** `pasm_skills.sdk.backend`,本包只做重导出。
28
+
29
+ ## 流式与工具调用(v0.3.0 新增)
30
+
31
+ **真流式(SSE)** —— `stream()` 与 `handle()` **共用同一条管线**,不会行为漂移:
32
+
33
+ ```python
34
+ for ev in app.stream("怎么退货?", session_id="u1"):
35
+ if ev["type"] == "delta": # 增量片段,可直接追加显示
36
+ print(ev["text"], end="", flush=True)
37
+ elif ev["type"] == "replace": # 护栏/润色改写过 → 整条替换
38
+ print("\n[已修正]", ev["text"])
39
+ ```
40
+
41
+ 网关侧对应 `POST /api/chat/stream`(`text/event-stream`,零依赖);
42
+ 客户端有 `PasmClient.chat_stream()`(Python)与 `chatStream()`(Node)。
43
+
44
+ > **护栏不会被流式绕过**:流式是在*生成中*外推的,而护栏在*生成后*才跑。
45
+ > 若收尾改写了内容(例如脱敏),框架补发 `replace` 事件让客户端纠正 ——
46
+ > 所以"唯一出口"承诺对 `handle` 和 `stream` 同时成立。
47
+
48
+ **多轮工具调用** —— 应用的 `Capability` 自动暴露为 OpenAI 兼容 `tools`:
49
+
50
+ ```python
51
+ app = BaseApplication(..., backend_config={
52
+ "llm_responder": {"enabled": True, "config": {
53
+ "provider": "deepseek", "api_key": "...",
54
+ "tools": True, # 把能力交给模型调用(默认开)
55
+ "max_tool_rounds": 3, # 工具环上限
56
+ }}})
57
+ ```
58
+
59
+ 模型说"要调 `cap_1`" → 框架真的执行该能力 → 结果回填 `role=tool` → 再请求。
60
+ 中文能力名会转成合法 tool 名(`cap_1`…),原名保留在 `description` 里。
61
+ 上游对 `tools` / `stream` 返回 400 时**自动降级**为纯对话重试,不会挂。
62
+
63
+ ## 插件库(v0.2.0 新增,即插即用)
64
+
65
+ 框架自带 **7 个通用插件**,全部零强制外部依赖,**可在后端开关**("用户选择是否使用"):
66
+ 通过 `BaseApplication(..., backend_config={...})` 控制启用与配置。
67
+
68
+ | 插件 | 作用 | 默认 |
69
+ | --- | --- | --- |
70
+ | `knowledge_base` | 站点数据 → 资料库,自学 / 记忆 / 成长(客服核心) | ✅ 开 |
71
+ | `sessions` | 会话 / 租户隔离,记住每个客户上下文 | ✅ 开 |
72
+ | `warmth` | 情绪驱动回复润色,做到"有温度" | ✅ 开 |
73
+ | `safety` | prompt 注入拦截 + PII 脱敏 | ✅ 开 |
74
+ | `observability` | 指标 + 健康(`/healthz`) | ✅ 开 |
75
+ | `llm_responder` | 可选 LLM 接入(OpenAI 兼容 / DeepSeek / Ollama) | ⬜ 关 |
76
+ | `web_gateway` | 零依赖 HTTP 网关(iframe / REST 外部链接) | ⬜ 关 |
77
+
78
+ Hook 链:`on_init → on_message_in → on_retrieve → on_reply → on_reply_final → on_learn → on_shutdown`。
79
+ **不启用任何插件时,`handle` 行为与 v0.1.0 完全一致**(能力路由 → 回落 chat)。
80
+
81
+ `on_reply_final` 是**唯一出口**:能力结果 / LLM 回复 / 模板兜底 / 被拦截,四条路径
82
+ 出站前都经过它恰好一次 —— 护栏因此不可能被某条路径绕过。
83
+
84
+ ### 用插件开关"定制应用"
85
+
86
+ ```python
87
+ from pasm_framework import BaseApplication
88
+
89
+ class MyAgent(BaseApplication):
90
+ def action_pool(self): return ["reply"]
91
+ def _render_reply(self, text, facts, mood): return "答:%s" % text
92
+
93
+ agent = MyAgent(
94
+ "demo", {"name": "小智"},
95
+ backend_config={
96
+ "knowledge_base": {"enabled": True, "config": {"kb_dir": "./kb"}},
97
+ "llm_responder": {"enabled": True, "config": {
98
+ "provider": "deepseek", "api_key": "sk-...", "model": "deepseek-chat"}},
99
+ "web_gateway": {"enabled": True, "config": {"port": 8080}},
100
+ },
101
+ )
102
+ agent.handle("你好", session_id="u1") # 走插件链
103
+ agent.serve(port=8080) # 站点 <iframe src="http://host:8080/">
104
+ agent.close() # 跑 on_shutdown,停网关
105
+ ```
106
+
107
+ ### 写自己的插件
108
+
109
+ ```python
110
+ from pasm_framework import BasePlugin, PluginContext
111
+
112
+ class SlaPlugin(BasePlugin):
113
+ name, version = "sla", "0.1.0"
114
+ def on_reply_final(self, ctx: PluginContext) -> None:
115
+ # 收尾阶段:对已经定稿的回复做后处理
116
+ if ctx.message.reply:
117
+ ctx.message.reply += "\n(本次回复已记录)"
118
+ ```
119
+
120
+ **注册方式一(推荐):配置里内联,不用发包**
121
+
122
+ ```python
123
+ app = MyApp("demo", {"name": "小智"}, backend_config={
124
+ "sla": {"enabled": True, "class": SlaPlugin},
125
+ })
126
+ ```
127
+
128
+ **注册方式二:发布成可发现包**,安装即被自动发现
129
+
130
+ ```toml
131
+ [project.entry-points."pasm_framework.plugins"]
132
+ sla = "my_pkg.my_module:SlaPlugin"
133
+ ```
134
+
135
+ ⚠️ 插件名**拼错不会静默通过**:`app.plugins.unknown()`、`app.app_summary()["plugin_config_unknown"]`
136
+ 以及 `pasm-framework doctor` 都会报告。
137
+
138
+ ## 参考实现:站点智能客服
139
+
140
+ `apps/customer_service.py` 用插件组合出一个可上线的客服 Agent(零 LLM 也能回答)。
141
+ `docs/customer-service-plugin.md` 是可行性与部署形态研究(iframe / REST / WebSocket)。
142
+
143
+ ```bash
144
+ python -m apps.customer_service # 演示问答 + 自学习统计
145
+ python -m apps.customer_service --serve # 起 HTTP 网关:http://0.0.0.0:8080/
146
+ ```
147
+
148
+ ## 依赖方向(单一、无环)
149
+
150
+ ```
151
+ pasm-agents (产品) → pasm-framework → pasm_skills.sdk → 引擎(pasm.*)
152
+ ```
153
+
154
+ - 动:`CognitiveAssembler.v2`(V2.0 落地时新增)+ `PasmV2Backend`
155
+ - 不动:`BaseApplication`、4 智能体、3 技能、`DomainAdapter`、`CapabilityDiscovery`、`BaseSkill`
156
+
157
+ ## 安装
158
+
159
+ ```bash
160
+ pip install pasm-framework
161
+ # 基座会被自动作为依赖装上:pasm-skills>=0.5.1
162
+ ```
163
+
164
+ ## 配置系统(v0.2.1 新增)
165
+
166
+ 开关表可以来自**预设 / 文件 / 环境变量 / 代码**,优先级由低到高:
167
+
168
+ ```python
169
+ from pasm_framework import load
170
+
171
+ cfg = load("server.json", # 文件(.json / .yaml)
172
+ preset_name="chatbot", # 场景预设打底
173
+ env=True, # 叠加 PASM_* 环境变量
174
+ web_gateway={"config": {"port": 9000}}) # 代码覆盖一切
175
+
176
+ app = MyApp("demo", {"name": "小智"}, backend_config=cfg)
177
+ ```
178
+
179
+ 6 套场景预设:`minimal`(全关,退回 0.1.0 行为)· `default` ·
180
+ `chatbot`(护栏 block + 开网关)· `game_npc`(离线优先)·
181
+ `api`(回复不润色)· `desktop`(只监听本机)。
182
+
183
+ 环境变量:`PASM_PLUGINS` / `PASM_KB_DIR` / `PASM_SAFETY_MODE` /
184
+ `PASM_LLM_PROVIDER` `PASM_LLM_MODEL` `PASM_LLM_API_KEY` /
185
+ `PASM_HTTP_HOST` `PASM_HTTP_PORT` `PASM_HTTP_TOKEN`。
186
+
187
+ ## CLI
188
+
189
+ ```bash
190
+ pasm-framework # 自检 + 用法
191
+ pasm-framework doctor # 环境体检(出问题先跑这个)
192
+ pasm-framework new myapp --kind chatbot # 生成可跑的项目
193
+ pasm-framework serve --port 8080 # 起一个演示客服
194
+ pasm-framework plugins # 看内置插件与默认开关
195
+ pasm-framework config --preset api --env # 看最终解析出的配置
196
+ ```
197
+
198
+ ## 最小示例
199
+
200
+ 最省事(v0.2.1 起,3 行起步):
201
+
202
+ ```python
203
+ from pasm_framework import SimpleApplication, capability, load
204
+
205
+ class MyApp(SimpleApplication):
206
+ @capability(keywords=("帮助", "help"))
207
+ def help(self, text):
208
+ return "我能回答资料库里的问题。"
209
+
210
+ app = MyApp("demo", {"name": "小智"},
211
+ backend_config=load(preset_name="chatbot"))
212
+ print(app.ask("帮助"))
213
+ ```
214
+
215
+ 需要完全控制时,继承 `BaseApplication`:
216
+
217
+ ```python
218
+ from pasm_framework import BaseApplication, Capability
219
+
220
+ class MyApp(BaseApplication):
221
+ def action_pool(self):
222
+ return ["a1", "a2"]
223
+ def _render_reply(self, text, facts, mood):
224
+ return "reply:%s" % text
225
+
226
+ app = MyApp(agent_id="demo", persona={"name": "demo"}, persist_dir="/tmp/demo")
227
+ print(app.handle("你好")) # → "reply:你好"(回落 chat)
228
+ ```
229
+
230
+ ## 快速自检
231
+
232
+ ```bash
233
+ python -m pasm_framework selftest # 44 项
234
+ python -m pasm_framework doctor # 真装配一遍插件并报拼错的名字
235
+ python -m pasm_framework version
236
+ ```
237
+
238
+ ## 文档
239
+
240
+ | 文档 | 内容 |
241
+ | --- | --- |
242
+ | [`docs/tutorials/`](docs/tutorials/README.md) | **开发教程**:快速上手 → 能力/插件 → 客服/LLM/部署 → 游戏 NPC → 多语言 |
243
+ | [`docs/capability-matrix-2026-09-20.md`](docs/capability-matrix-2026-09-20.md) | 能力就绪度复检:能做/不能做、剩余问题、性能实测 |
244
+ | [`docs/polyglot-strategy.md`](docs/polyglot-strategy.md) | C#/Java/PHP 怎么接入(协议优先,不移植引擎) |
245
+ | [`docs/cross-platform-strategy.md`](docs/cross-platform-strategy.md) | 桌面端跨 Linux/macOS、手机端换架构方案 |
246
+ | [`docs/customer-service-plugin.md`](docs/customer-service-plugin.md) | 智能客服可行性与部署形态研究 |
247
+ | [`docs/audit-2026-09-20.md`](docs/audit-2026-09-20.md) | v0.2.0 体检报告 |
248
+ | [`docs/openapi.yaml`](docs/openapi.yaml) | HTTP 契约(单一真相源) |
249
+ | [`sdks/`](sdks/README.md) | C# / Java / PHP / Node / Go / Python 客户端 |
250
+
251
+ ## 许可证
252
+
253
+ MIT —— 与 `pasm-skills` / `pasm-agents` 一致。