# pasm-framework **Repository Path**: arronzheng/pasm-framework ## Basic Information - **Project Name**: pasm-framework - **Description**: PASM 应用开发框架(产品/应用层):CognitiveAssembler/CognitiveService/BaseApplication/BaseSkill/CapabilityDiscovery 等。依赖 pasm-skills 基座。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-20 - **Last Updated**: 2026-09-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # pasm-framework PASM 应用开发框架 —— 产品智能体 / 应用与认知引擎之间的**防腐层(Anti-Corruption Layer)**。 本包于 **v0.1.0** 从基座 [`pasm-skills`](https://gitee.com/arronzheng/pasm-skills) 的 `pasm_skills.framework` 子包独立成仓。 > 注意:本包是「**应用开发**框架」(给产品智能体 / 应用用); > `pasm-skills` 里还有一个同名概念「验证器框架」`pasm_skills.agent`(给自检 / 守护智能体用), > 两者职责不同,请勿混淆。 ## 它解决什么问题 PASM V1 → V2 升级时,**不重写 4 个产品智能体 + 3 个技能**。手段是建立一组**稳定表面**, 让应用只依赖表面、不依赖引擎内部;引擎大改时只动"唯一变动点"。 ## 导出的稳定表面 | 表面 | 作用 | | --- | --- | | `CognitiveAssembler` / `CognitiveService` | 引擎 ↔ 应用装配(**V1↔V2 唯一变动点**) | | `DomainAdapter` | 领域知识 / 规则注入契约 | | `CapabilityDiscovery` / `Capability` | 能力声明与统一发现 | | `BaseApplication` | 通用 AI 应用底座(建在 `BaseAgent` 上);`handle()` / **`stream()`** / **`ingest()`** | | `SimpleApplication` / `@capability` | 3 行起步的极简应用写法(v0.2.1) | | `BaseSkill` / `SkillManifest` | 技能包代码化底座 | `CognitiveBackend` 协议的**单一真相源仍在基座** `pasm_skills.sdk.backend`,本包只做重导出。 ## 流式与工具调用(v0.3.0) **真流式(SSE)** —— `stream()` 与 `handle()` **共用同一条管线**,不会行为漂移: ```python for ev in app.stream("怎么退货?", session_id="u1"): if ev["type"] == "delta": # 增量片段,可直接追加显示 print(ev["text"], end="", flush=True) elif ev["type"] == "replace": # 护栏/润色改写过 → 整条替换 print("\n[已修正]", ev["text"]) ``` 网关侧对应 `POST /api/chat/stream`(`text/event-stream`,零依赖); 客户端有 `PasmClient.chat_stream()`(Python)与 `chatStream()`(Node)。 > **护栏不会被流式绕过**:流式是在*生成中*外推的,而护栏在*生成后*才跑。 > 若收尾改写了内容(例如脱敏),框架补发 `replace` 事件让客户端纠正 —— > 所以"唯一出口"承诺对 `handle` 和 `stream` 同时成立。 **多轮工具调用** —— 应用的 `Capability` 自动暴露为 OpenAI 兼容 `tools`: ```python app = BaseApplication(..., backend_config={ "llm_responder": {"enabled": True, "config": { "provider": "deepseek", "api_key": "...", "tools": True, # 把能力交给模型调用(默认开) "max_tool_rounds": 3, # 工具环上限 }}}) ``` 模型说"要调 `cap_1`" → 框架真的执行该能力 → 结果回填 `role=tool` → 再请求。 中文能力名会转成合法 tool 名(`cap_1`…),原名保留在 `description` 里。 上游对 `tools` / `stream` 返回 400 时**自动降级**为纯对话重试,不会挂。 ## 插件库(v0.2.0 新增,即插即用) 框架自带 **7 个通用插件**,全部零强制外部依赖,**可在后端开关**("用户选择是否使用"): 通过 `BaseApplication(..., backend_config={...})` 控制启用与配置。 | 插件 | 作用 | 默认 | | --- | --- | --- | | `knowledge_base` | 站点数据 → 资料库,自学 / 记忆 / 成长(客服核心) | ✅ 开 | | `sessions` | 会话 / 租户隔离,记住每个客户上下文 | ✅ 开 | | `warmth` | 情绪驱动回复润色,做到"有温度" | ✅ 开 | | `safety` | prompt 注入拦截 + PII 脱敏 | ✅ 开 | | `observability` | 指标 + 健康(`/healthz`) | ✅ 开 | | `llm_responder` | 可选 LLM 接入(OpenAI 兼容 / DeepSeek / Ollama) | ⬜ 关 | | `web_gateway` | 零依赖 HTTP 网关(iframe / REST 外部链接) | ⬜ 关 | Hook 链:`on_init → on_message_in → on_retrieve → on_reply → on_reply_final → on_learn → on_shutdown`。 **不启用任何插件时,`handle` 行为与 v0.1.0 完全一致**(能力路由 → 回落 chat)。 `on_reply_final` 是**唯一出口**:能力结果 / LLM 回复 / 模板兜底 / 被拦截,四条路径 出站前都经过它恰好一次 —— 护栏因此不可能被某条路径绕过。 ### 用插件开关"定制应用" ```python from pasm_framework import BaseApplication class MyAgent(BaseApplication): def action_pool(self): return ["reply"] def _render_reply(self, text, facts, mood): return "答:%s" % text agent = MyAgent( "demo", {"name": "小智"}, backend_config={ "knowledge_base": {"enabled": True, "config": {"kb_dir": "./kb"}}, "llm_responder": {"enabled": True, "config": { "provider": "deepseek", "api_key": "sk-...", "model": "deepseek-chat"}}, "web_gateway": {"enabled": True, "config": {"port": 8080}}, }, ) agent.handle("你好", session_id="u1") # 走插件链 agent.serve(port=8080) # 站点