Files
2026-09-22 15:42:25 +08:00

187 lines
13 KiB
Markdown
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 阶段三 · 小点 6:其他主流方案(选学)
> 所属:阶段三 主流 Agent 开发框架
> 定位:前 5 讲覆盖了"代码框架派"的主力。这一讲补齐三块拼图:OpenAI 官方的**托管式**(Assistants API)、微软的**插件化**(Semantic Kernel)、以及**低代码平台**(Dify)。它们各有最适配场景,读完你会对"什么时候该用什么"有完整判断力。
## 精简大纲
1. OpenAI Assistants API(托管式 Agent)
2. Semantic Kernel(微软插件化框架)
3. Dify 低代码平台
4. 选型边界总结
## 学习内容详情
### 1. OpenAI Assistants API(快速原型 / Demo)
#### 1.1 三个核心对象
```mermaid
graph TD
A[Assistant 助理: 角色+工具定义在云端] --> D[Thread 会话线程: 历史存云端]
D --> E[Run 一次执行]
E --> F{状态轮询}
F -->|queued/in_progress| E
F -->|completed| G[结束]
F -->|requires_action| H[要你执行函数调用后回传] --> E
```
- **Assistant(助理):** 角色 + 工具全部定义在云端。
- **Thread(会话线程):** 托管式会话(历史存 OpenAI 云端,对照 LangGraph 的 thread_id + Checkpointer,只是托管方换成 OpenAI)。
- **Run(一次执行):** 异步任务轮询,状态含 `queued → in_progress → completed / failed / requires_action`(要你执行函数调用后回传)。
```python
from openai import OpenAI
client = OpenAI(api_key="sk-xxx")
# ① 建一个"助理" (云端保存角色+工具)
asst = client.beta.assistants.create(
name="数据分析助手",
instructions="你是数据分析助理, 只说结论与依据", # 角色设定存云端
model="gpt-4o",
)
# ② 建一个"会话线程"
thread = client.beta.threads.create()
# ③ 发消息 + 触发"一次执行"
client.beta.threads.messages.create(
thread.id, role="user", content="帮我分析销售数据"
)
run = client.beta.threads.runs.create(thread.id, assistant_id=asst.id)
# ④ 轮询 Run 状态, 直到完成
while run.status not in ("completed", "failed", "requires_action"):
run = client.beta.threads.runs.retrieve(thread.id, run.id)
print("最终状态:", run.status)
```
> 🔬 **深度理解 · Assistants API 的 Assistant / Thread / Run 三对象**:
> 1. **本质**:这是 OpenAI 提供的「托管式 Agent」建模——你在云端定义"这个 AI 是谁、会哪些工具"(Assistant)、"一段会话的历史"(Thread)、"一次具体的执行与推进"(Run),状态与恢复都由服务端替你管理。
> 2. **机制**:Assistant 把角色/工具定义存于云端;Thread 存会话消息,天然对标 LangGraph 的 thread_id + Checkpointer,只是托管方换成 OpenAI;Run 是异步任务,需轮询其状态,遇到 `requires_action` 表示要你执行函数调用后回传 `tool_outputs` 并继续。
> 3. **为什么重要**:它极大降低演示 / 原型的搭建成本——不用自己管状态与工具循环;但代价是「模型思考」与「工具执行」之间无法插入自定义逻辑,可控性被锁在黑盒里。
> 4. **易错点**:误以为 Run 是一次性同步调用,实际要轮询;`requires_action` 后必须回传工具结果再 poll 才会继续;也容易忽略 Thread 有创建数量上限、用完要清理。
> ⏳ **短期可不深究**:Run 那套 `queued → in_progress → requires_action` 状态机与 `tool_outputs` 回传的轮询写法细节,第一遍知道「它是异步任务、要轮询、要你执行工具后回传」即可;开原型时照着官方示例抄就行。
- 多轮对话:继续往同一 `thread` 加消息即可;用完记得清理(Assistants/Threads 有数量上限)。
#### 1.2 黑盒代价清单(为什么生产不推荐)
| 代价 | 说明 |
|-|-|
| 无法插入自定义逻辑 | 「模型思考」和「工具执行」之间不能加审批 / 路由 / 状态校验 |
| Bad-case 排查弱 | Run 内部执行细节不完全可见 |
| 深度绑定 OpenAI | 换模型 = 重写集成层;国内合规数据出境是硬伤 |
| 对照 | LangGraph 等价能力全部在你掌控之下 |
> **一句话**:Assistants API 适合快速验证"对话式 Agent"原型,但凡是生产要插逻辑 / 要可控 / 要换模型,就回到 LangGraph。
### 2. Semantic Kernel(SK,微软)
> ⚠️ **状态提示(2026)**:微软已将 Semantic Kernel 与 AutoGen 合并为 **Microsoft Agent Framework(MAF)**,SK 进入维护模式,新项目建议转向 MAF。本节保留 SK 的「插件化编排」思想,用于理解其与代码框架的差异。
#### 2.1 插件化编排
```mermaid
graph LR
U[用户意图] --> P[Planner 规划器: 自动串联插件]
P --> A[Plugin 调模型]
P --> B[Plugin 查库]
P --> C[Plugin 发邮件]
```
- 插件化编排框架:把每个能力(调模型 / 查库 / 发邮件)封装成 Plugin,由 **Planner(规划器)**按用户意图自动串联插件。
- Python / C# 双语言一等支持——团队技术栈是 .NET 或 Python/.NET 混合时优先考虑;纯 Python 团队生态和社区不如 LangChain 系。
> 🔬 **深度理解 · Semantic Kernel 的插件化编排(Plugin + Planner)**:
> 1. **本质**:SK 把「一个可复用的能力单元」(调模型 / 查库 / 发邮件)抽象成 Plugin,再由 Planner 按用户意图自动把这些插件串成一条执行计划——把「技能封装」和「技能调度」分离开。
> 2. **机制**:每个 Plugin / Kernel Function 声明名称、语义描述与参数;Planner 面向用户意图,调用 LLM 决定「需要哪些插件、按什么顺序、传什么参数」,再按计划执行。这与 LangChain「手写 LCEL 管道」的确定式编排形成对照——SK 偏向「运行时动态规划」。
> 3. **为什么重要**:它让「能力」与「编排」解耦、可复用,动态调度适合意图多变的场景;但动态计划不如手写管道可控、可复现。
> 4. **易错点**:Planner 可能规划出错或加载过多插件导致上下文膨胀;且 SK 已进维护模式(被 MAF 合并),新项目路径应跟着 MAF 走,别在 SK 老 API 上深挖。
> ⏳ **短期可不深究**:SK 的 Planner 底层「怎么套用 LLM 生成执行计划」的实现细节偏复杂,且 SK 已进维护模式(被 MAF 合并),新项目建议直接看 MAF——这里只需领会「技能封装 + 动态调度」这个思想差异即可。
### 3. Dify(低代码平台)
- 拖拽式编排 Agent,适合非技术团队快速验证想法;但灵活性受平台限制。
```mermaid
graph LR
A[想法验证期: Dify 拖拽 一小时出Demo] -->|需求变复杂: 要加循环/审批/自定义重试| B[迁移到 LangGraph 代码框架]
```
- **低代码 vs 代码框架的边界:** 想法验证期用 Dify 快速试(一小时出 Demo);验证成功、需求变复杂后迁移到 LangGraph。
- **判断信号:** 当你在 Dify 里想「加个循环」「人工审批」「自定义重试逻辑」却做不到时,就是迁移时机。
### 4. 选型边界总结
| 需求 | 首选 |
|-|-|
| 快速验证想法 | Dify 或手写 Demo |
| 托管式会话原型 | Assistants API |
| Python/.NET 混合团队 | Semantic Kernel |
| 生产级可控 Agent | LangGraph |
| 文档知识为核心 | LlamaIndex |
```python
# 一个"按需求返回选型"的决策助手(对照阶段二第4讲的决策树)
def choose_engine(needs: dict) -> str:
if needs["doc_core"]:
return "LlamaIndex + LangGraph" # 文档知识为核心
if needs["managed_session"]:
return "Assistants API (仅原型)" # 要托管会话
if needs["dotnet_stack"]:
return "Semantic Kernel" # .NET混合团队
if needs["no_code_team"]:
return "Dify → 复杂后迁 LangGraph" # 非技术团队
if needs["need_control"] or needs["prod"]:
return "LangGraph" # 生产/要控制
return "手写 ReAct 或 Dify Demo" # 快速验证
print(choose_engine({"prod": True, "need_control": True, "doc_core": False,
"managed_session": False, "dotnet_stack": False, "no_code_team": False}))
# LangGraph
```
## 本节自检
- [ ] 能说清 Assistants API 的黑盒代价与 LangGraph 的对照
- [ ] 能判断低代码平台何时该迁移到代码框架
## 本节配套思考题(快速入门的检验)
1. Assistants API 的 Thread 和 LangGraph 的 Checkpointer + thread_id 有什么本质相似与不同(谁托管、谁掌控)?
2. 为什么"要求在模型调用工具前插入人工审批"就判了 Assistants API 的死刑?
3. Dify 这类低代码平台,出现什么"信号"说明该迁到 LangGraph 了?举一个你认同的例子。
4. Semantic Kernel 的准确适配场景是什么?纯 Python 团队为什么未必优先选它?
## 本节常见面试题(深度解析)
> 针对本节核心知识的面试高频点,配合"本质+机制"式理解,能让你答得既有深度又有广度。
### 面试题 1:Assistants API 的 Thread 与 LangGraph 的 Checkpointer + thread_id 本质相似与不同是什么?
- **面试官想考察**:是否理解"托管的会话状态 vs 自掌控的状态持久化"这一核心差异。
- **专业作答(含深度)**:
1. 相似:两者都以"会话 ID"(Thread / thread_id)维持续航状态,都支持多轮记忆与恢复,都是"对话状态"的载体。
2. 不同:是谁托管——Thread 的状态存在 OpenAI 云端、你通过 API 间接操作;LangGraph 的 Checkpointer 由你指定存储后端(本地 / Redis / Postgres)、完全掌控。
3. 含义:Assistants 更省事但不可迁移(换模型 = 换平台)、难以定制;LangGraph 更灵活可控、可水平扩展、可审计。
4. 结论:托管式适合快速原型和"状态无所谓"的 Demo;要自定义逻辑、控制存储位置、可运维,选自托管代码框架。
- **加分亮点 / 深度追问**:提"国内合规数据出境"这一现实约束;追问常是"Thread 能加自定义业务字段吗"——答:托管式会话基本只能存消息,自定义状态能力弱,这正是其黑盒代价之一。
### 面试题 2:为什么"要求在模型调用工具前插入人工审批"就判了 Assistants API 的死刑?
- **面试官想考察**:对"是否允许在图的节点间插入自定义逻辑"这一编排自由度关键点的理解。
- **专业作答(含深度)**:
1. Assistants API 把「模型思考 → 工具执行」封装在 Run 内部,Run 作为一个原子动作要么 `requires_action` 要你回传、要么跑完,你**不能在两者之间插入审批 / 路由 / 状态校验**这类自定义步骤。
2. 等价能力在 LangGraph:把"人工审批"做成一个普通 Node 放在「工具节点」之前,用 `interrupt` 挂起等人工确认,再 `resume` 放行——你想插什么都行。
3. 本质差异是「黑盒 vs 白盒」:托管式给你"托管能力"但拿走"干预能力";只要业务需要精确控制每一步,托管式就不适用。
4. 结论:这是判断"要不要上代码框架"的一条硬性信号——有审批 / 自定义路由 / 状态校验需求就别用托管式。
- **加分亮点 / 深度追问**:明确"人工审批本质是在图的状态流里加一个等待人工输入的节点";追问常是"Demo 阶段可以先用 Assistants 吗"——答:可以,只要接受后期要重写集成层。
### 面试题 3:托管式 / 插件化(SK)/ 低代码(Dify)/ 代码框架(LangGraph)各自主导什么场景?出现什么"信号"说明该往代码框架迁移?
- **面试官想考察**:对 Agent 技术栈宏观选型与"复杂度迁移时机"的判断力。
- **专业作答(含深度)**:
1. 定位梳理:Assistants 适合托管会话原型;Dify 适合非技术团队快速验证想法;SK / MAF 适合需要插件复用与 .NET/Python 混合栈;LangGraph 是生产级可控 Agent 的主选。
2. 迁移信号:当你发现 "加个循环做不到""加人工审批做不到""自定义重试做不到""跨会话状态难以管理"时,就说明当前方案的表达力已到天花板,该迁到能自由编排的代码框架。
3. 判断原则:先问"是否需要精确控制、是否要自定义逻辑、是否要换模型 / 数据出境";需要的用代码框架,纯验证期的可用低代码 / 托管式。
4. 演进路径常见:Dify / Assistants 验证 → 迁 LangGraph + LlamaIndex 组合成生产架构。
- **加分亮点 / 深度追问**:讲"低代码 / 托管的优点恰恰也是它的约束来源——上手快 = 可定制范围小";追问常是"给一个具体迁移例子"——答:在 Dify 里想做跨步骤循环与审批做不到时,就是迁移时点。