阶段4(下):LangChain 1.x、提示词与注入防护、模型侧(路由/vLLM/LoRA)、AI 编程工具与验证、Dify/Coze 专题
This commit is contained in:
1 parent
caaec830b3
commit
7a32d2c9a6
38 files changed
+3059
-67
No files matched your search
@@ -0,0 +1,82 @@
|
||||
---
|
||||
id: ai.lowcode.dify-coze
|
||||
title: Dify / Coze 低代码 AI 平台:工作流、知识库、自定义工具和与代码开发的分工
|
||||
type: lesson
|
||||
domain: ai
|
||||
stack: [lowcode]
|
||||
tags: [Dify, Coze, 低代码, 工作流, 知识库, 自定义工具, OpenAPI]
|
||||
level: basic
|
||||
prerequisites: [ai.rag.pipeline-chunking]
|
||||
est_hours: 2.5
|
||||
related: [ai.lowcode.scenario.poc-to-production, ai.function-calling.tool-loop, ai.lowcode.interview]
|
||||
week: [13]
|
||||
order: 1
|
||||
---
|
||||
|
||||
# Dify / Coze 低代码 AI 平台:工作流、知识库、自定义工具和与代码开发的分工
|
||||
|
||||
> Dify、Coze 等平台迭代很快,界面和功能以官方文档为准:https://docs.dify.ai/ 、https://www.coze.cn/open/docs
|
||||
|
||||
## 解释说明
|
||||
|
||||
低代码 AI 平台把大模型应用的常见部件做成可视化组件:
|
||||
|
||||
| 部件 | 说明 |
|
||||
| --- | --- |
|
||||
| 应用类型 | 聊天助手、Agent、工作流(Workflow / Chatflow) |
|
||||
| 知识库 | 上传文档 → 自动切分、嵌入、检索(可配置切分规则、混合检索、重排) |
|
||||
| 工作流节点 | 大模型、知识检索、条件分支、代码节点、HTTP 请求、工具、变量处理 |
|
||||
| 工具 | 内置工具 + **自定义工具**(导入 OpenAPI 描述即可调用你的接口) |
|
||||
| 发布 | Web 页面、API、嵌入网页;部分平台可发布到飞书 / 企业微信 / 公众号等渠道 |
|
||||
| 运维 | 对话日志、标注、简单的效果统计 |
|
||||
|
||||
**Dify** 开源、可私有化部署(Docker Compose),适合企业内部;**Coze(扣子)** 是字节的平台,渠道发布方便,也有开源版本(以官方为准)。
|
||||
|
||||
### 和写代码怎么分工?
|
||||
|
||||
| 适合低代码 | 适合写代码 |
|
||||
| --- | --- |
|
||||
| 快速验证想法(PoC)、内部小工具 | 复杂业务逻辑、精细的权限控制 |
|
||||
| 业务人员需要自己调整提示词和流程 | 需要完整测试、评测门禁、版本管理 |
|
||||
| 标准的知识库问答 | 高并发、低延迟、自定义的检索优化 |
|
||||
|
||||
常见的企业做法是**组合**:平台负责编排和界面,核心业务能力用代码实现成接口,作为自定义工具接入平台。这样开发者掌握关键逻辑和权限,业务人员可以调整流程。
|
||||
|
||||
## 案例
|
||||
|
||||
运营团队想要一个“订单查询助手”。开发者用 FastAPI 写了订单查询接口(带 API Key 鉴权和店铺隔离),导出 OpenAPI 描述;运营在 Dify 中创建工作流:意图判断 → 调用订单查询工具 → 大模型组织回复,并接入知识库回答售后政策。两天上线试用,后续根据日志调整提示词。
|
||||
|
||||
## 代码示例
|
||||
|
||||
供 Dify 导入的自定义工具接口(完整版本 [examples/dify-tool-api/app.py](examples/dify-tool-api/app.py),带测试):
|
||||
|
||||
```python
|
||||
app = FastAPI(
|
||||
title="订单查询工具",
|
||||
version="1.0.0",
|
||||
servers=[{"url": "http://127.0.0.1:8100"}], # 导入时需要 servers,部署后改成实际地址
|
||||
)
|
||||
|
||||
|
||||
@app.get("/orders/{order_id}", operation_id="getOrderStatus", response_model=OrderStatus,
|
||||
summary="查询订单状态", description="根据订单号查询订单状态和预计送达时间。订单号形如 A1001。")
|
||||
def get_order_status(order_id: str, shop: str = Depends(auth)) -> OrderStatus:
|
||||
...
|
||||
```
|
||||
|
||||
要点:`operation_id` 会成为工具名;`summary` / `description` 就是模型看到的工具说明,要写清楚;鉴权用 API Key,每个调用方一个 Key,按 Key 隔离数据。在 Dify 中导入 `http://<地址>/openapi.json` 即可。
|
||||
|
||||
## 易错点
|
||||
|
||||
- 自定义工具接口没有鉴权,或者所有调用方共用一个 Key。
|
||||
- OpenAPI 中缺少 `servers`、`operationId`,导入失败或工具名难以理解。
|
||||
- 平台部署在内网,工具接口地址填了 `localhost`(平台容器里的 localhost 不是你的电脑)。
|
||||
- 把复杂业务逻辑都写在代码节点里,无法测试和复用。
|
||||
- 平台中的提示词和流程没有版本记录,改坏了无法回退:定期导出 DSL / 配置并放进 Git。
|
||||
- 私有化部署后忽视升级和安全补丁。
|
||||
|
||||
## 面试常问
|
||||
|
||||
- 用过 Dify / Coze 吗?做过什么?
|
||||
- 低代码平台和自己写代码怎么选?
|
||||
- 怎么把公司已有的接口接入 Dify?
|
||||
@@ -0,0 +1,49 @@
|
||||
# requires: fastapi, pydantic
|
||||
"""给 Dify / Coze 当“自定义工具”的后端接口:提供 OpenAPI 描述 + API Key 鉴权。
|
||||
|
||||
在 Dify 中:工具 → 自定义 → 创建自定义工具 → 填入 http://<你的地址>/openapi.json 导入,
|
||||
鉴权方式选 API Key(请求头 Authorization: Bearer <key>)。具体界面以 Dify 官方文档为准。
|
||||
本地运行:uvicorn app:app --port 8100(直接 python app.py 只做导入检查)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import secrets
|
||||
|
||||
from fastapi import Depends, FastAPI, HTTPException
|
||||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
API_KEY = os.environ.get("TOOL_API_KEY", "dev-only-key") # 生产环境从密钥管理读取
|
||||
|
||||
app = FastAPI(
|
||||
title="订单查询工具",
|
||||
version="1.0.0",
|
||||
description="供低代码平台调用的订单查询接口。只读,按调用方的店铺隔离数据。",
|
||||
servers=[{"url": "http://127.0.0.1:8100"}], # Dify 导入时需要 servers 字段,部署后改成实际地址
|
||||
)
|
||||
bearer = HTTPBearer()
|
||||
|
||||
ORDERS = {"A1001": {"shop": "s1", "status": "已发货", "eta": "明天"},
|
||||
"A1002": {"shop": "s2", "status": "待支付", "eta": None}}
|
||||
|
||||
|
||||
def auth(cred: HTTPAuthorizationCredentials = Depends(bearer)) -> str:
|
||||
if not secrets.compare_digest(cred.credentials, API_KEY):
|
||||
raise HTTPException(401, "无效的 API Key")
|
||||
return "s1" # 示例:一个 Key 对应一个店铺;真实项目查表
|
||||
|
||||
|
||||
class OrderStatus(BaseModel):
|
||||
order_id: str
|
||||
status: str = Field(description="订单状态")
|
||||
eta: str | None = Field(default=None, description="预计送达时间")
|
||||
|
||||
|
||||
@app.get("/orders/{order_id}", operation_id="getOrderStatus", response_model=OrderStatus,
|
||||
summary="查询订单状态", description="根据订单号查询订单状态和预计送达时间。订单号形如 A1001。")
|
||||
def get_order_status(order_id: str, shop: str = Depends(auth)) -> OrderStatus:
|
||||
o = ORDERS.get(order_id)
|
||||
if not o or o["shop"] != shop:
|
||||
raise HTTPException(404, "订单不存在")
|
||||
return OrderStatus(order_id=order_id, status=o["status"], eta=o["eta"])
|
||||
@@ -0,0 +1,21 @@
|
||||
# requires: fastapi, httpx, pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app import app
|
||||
|
||||
c = TestClient(app)
|
||||
H = {"Authorization": "Bearer dev-only-key"}
|
||||
|
||||
|
||||
def test_openapi_has_operation_and_server():
|
||||
spec = c.get("/openapi.json").json()
|
||||
op = spec["paths"]["/orders/{order_id}"]["get"]
|
||||
assert op["operationId"] == "getOrderStatus" and spec["servers"][0]["url"].startswith("http")
|
||||
assert "HTTPBearer" in spec["components"]["securitySchemes"]
|
||||
|
||||
|
||||
def test_auth_and_isolation():
|
||||
assert c.get("/orders/A1001").status_code in (401, 403)
|
||||
assert c.get("/orders/A1001", headers={"Authorization": "Bearer wrong"}).status_code == 401
|
||||
assert c.get("/orders/A1001", headers=H).json()["status"] == "已发货"
|
||||
assert c.get("/orders/A1002", headers=H).status_code == 404 # 其他店铺的订单
|
||||
@@ -1,15 +1,42 @@
|
||||
---
|
||||
id: ai.lowcode.index
|
||||
title: Dify / Coze 低代码平台
|
||||
title: 低代码 AI 平台(Dify / Coze)
|
||||
type: index
|
||||
domain: ai
|
||||
stack: [lowcode]
|
||||
tags: []
|
||||
tags: [Dify, Coze, 低代码, 工作流]
|
||||
week: [13]
|
||||
---
|
||||
|
||||
# Dify / Coze 低代码平台
|
||||
# 低代码 AI 平台(Dify / Coze)
|
||||
|
||||
知识库、工作流、插件,和写代码的取舍。
|
||||
部分岗位把 Dify / Coze / FastGPT / RAGFlow 列为加分项。目标:能搭一个带知识库和自定义工具的应用,讲清楚低代码和写代码的分工。
|
||||
|
||||
> 本专题建设中:课程、企业场景、面试题和示例代码会陆续补充。
|
||||
## 学习路线
|
||||
|
||||
| 顺序 | 课程 | 级别 | 预计 |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | [Dify / Coze 低代码 AI 平台:工作流、知识库、自定义工具和与代码开发的分工](01-dify-coze.md) | 基础 | 2.5 小时 |
|
||||
|
||||
## 企业场景
|
||||
|
||||
- [从 Dify 原型到生产:哪些留在平台、哪些改成代码](scenarios/poc-to-production.md)
|
||||
|
||||
## 面试题
|
||||
|
||||
- [低代码 AI 平台面试题](interview.md)
|
||||
|
||||
## 示例代码
|
||||
|
||||
- [examples/dify-tool-api](examples/dify-tool-api/):供 Dify / Coze 导入的自定义工具接口(FastAPI,OpenAPI 带 servers 和 operationId、API Key 鉴权、按调用方隔离数据),带测试
|
||||
|
||||
## 在 16 周计划中
|
||||
|
||||
- [第 13 周第 6~7 天:动手搭 Dify 或 Coze](../../../plan/week13-agent-m4-eval-lowcode.md)
|
||||
|
||||
## 官方资料
|
||||
|
||||
以官方文档为准:
|
||||
|
||||
- Dify:https://docs.dify.ai/
|
||||
- Coze(扣子):https://www.coze.cn/open/docs
|
||||
@@ -0,0 +1,61 @@
|
||||
---
|
||||
id: ai.lowcode.interview
|
||||
title: 低代码 AI 平台面试题
|
||||
type: interview
|
||||
domain: ai
|
||||
stack: [lowcode]
|
||||
tags: [Dify, Coze, 低代码, 面试]
|
||||
level: basic
|
||||
related: [ai.lowcode.dify-coze]
|
||||
week: [13, 16]
|
||||
---
|
||||
|
||||
# 低代码 AI 平台面试题
|
||||
|
||||
## 基础
|
||||
|
||||
### 【基础】Dify 是什么?主要能做什么?
|
||||
|
||||
**参考答案**:开源的大模型应用开发平台,可视化地搭建聊天助手、Agent 和工作流,内置知识库(文档切分、嵌入、检索)、工具、模型管理和对话日志,可以私有化部署,并以 API 或网页的形式发布。
|
||||
|
||||
**追问**:Dify 和 Coze 有什么区别?→ Dify 开源、私有化部署友好;Coze 发布到各渠道方便、生态插件多。具体功能以官方为准,选型看部署要求和使用场景。
|
||||
|
||||
### 【基础】怎么把公司已有的接口接入 Dify?
|
||||
|
||||
**参考答案**:为接口编写 OpenAPI 描述(包含 servers、operationId、清晰的 summary / description、参数说明),在 Dify 中创建自定义工具导入;配置 API Key 鉴权;在工作流或 Agent 中使用。
|
||||
|
||||
**追问**:平台部署在 Docker 中,工具地址怎么填?→ 不能填 localhost,要填平台容器能访问到的地址(宿主机地址或服务名)。
|
||||
|
||||
### 【基础】低代码平台和自己写代码怎么选?
|
||||
|
||||
**参考答案**:快速验证、标准知识库问答、业务人员需要自助调整时用平台;复杂业务逻辑、精细权限、高性能要求、需要完整测试和评测门禁时写代码。企业里常常组合使用。
|
||||
|
||||
**追问**:平台能做评测吗?→ 平台有日志和标注功能,系统化的评测通常还要通过 API 批量调用自己实现。
|
||||
|
||||
## 进阶
|
||||
|
||||
### 【进阶】Dify 知识库的效果不好,可以怎么调?
|
||||
|
||||
**参考答案**:调整切分方式(按结构、段落长度、重叠);清洗文档(去页眉页脚、表格处理);开启混合检索和重排;调整 top-k 和相似度阈值;优化提示词中引用资料的方式;用评测集对比调整前后的效果。
|
||||
|
||||
**追问**:平台知识库满足不了需求怎么办?→ 用代码实现检索服务(自定义切分、权限过滤、混合检索),作为工具或外部知识库接口接入平台。
|
||||
|
||||
### 【进阶】平台上的应用怎么做版本管理?
|
||||
|
||||
**参考答案**:导出应用配置(DSL)存入 Git,修改前后对比;重要修改先在测试应用上验证并跑评测;记录每次发布的版本和时间。
|
||||
|
||||
**追问**:多人同时修改同一个应用怎么办?→ 约定负责人和修改流程,在测试应用中修改,验证后再同步到正式应用。
|
||||
|
||||
## 场景题
|
||||
|
||||
### 【场景题】业务部门用 Dify 做的原型要推广到全公司,你怎么评估和改造?
|
||||
|
||||
**参考答案**:检查权限(知识库是否需要按部门隔离)、密钥(是否写死在节点中)、效果(建立评测集)、性能(压测)、运维(版本管理、监控)。把权限相关的检索和业务系统查询改成代码服务,作为自定义工具接入;流程和提示词留在平台。详见[从原型到生产](scenarios/poc-to-production.md)。
|
||||
|
||||
**追问**:什么情况下应该完全迁移出平台?→ 需要复杂的多 Agent 协作、人工审批、精细的状态管理,或者平台成为性能瓶颈时。
|
||||
|
||||
### 【场景题】你在项目中用过低代码平台吗?如果没有,怎么回答?
|
||||
|
||||
**参考答案**:如实说明。可以讲:按计划搭建过一个 Dify 应用(知识库 + 自定义工具调用自己写的接口),对比了它和自己用代码实现的 RAG 在开发速度、可控性、效果上的差异,以及什么场景下会选择哪种方式。
|
||||
|
||||
**追问**:对比下来你的结论是什么?→ 用自己的实际体验回答,例如平台搭建很快,但权限和评测需要代码补充。
|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
id: ai.lowcode.scenario.poc-to-production
|
||||
title: 从 Dify 原型到生产:哪些留在平台、哪些改成代码
|
||||
type: scenario
|
||||
domain: ai
|
||||
stack: [lowcode, fastapi, rag]
|
||||
tags: [PoC, 低代码, 私有化部署, 自定义工具, 迁移, 评测]
|
||||
level: intermediate
|
||||
prerequisites: [ai.lowcode.dify-coze]
|
||||
est_hours: 2
|
||||
related: [ai.lowcode.interview, ai.agent-ops.scenario.agent-quality-gate]
|
||||
week: [13]
|
||||
---
|
||||
|
||||
# 从 Dify 原型到生产:哪些留在平台、哪些改成代码
|
||||
|
||||
## 业务背景与问题
|
||||
|
||||
业务部门用私有化部署的 Dify 搭了一个“合同条款问答”原型,两周内在部门内部很受欢迎,准备推广到全公司。评估时发现:
|
||||
|
||||
1. 知识库是所有合同混在一起,没有按部门和密级做权限;
|
||||
2. 回答效果没有量化,改提示词全凭感觉;
|
||||
3. 某些问题需要查合同管理系统的实时状态,平台的 HTTP 节点直接写了系统的内部账号;
|
||||
4. 用户量扩大 20 倍后,平台的响应变慢。
|
||||
|
||||
## 约束
|
||||
|
||||
- 业务部门希望继续能自己调整提示词和流程。
|
||||
- 合同属于敏感数据,权限必须严格。
|
||||
|
||||
## 方案设计
|
||||
|
||||
1. **能力拆分**:
|
||||
- 留在平台:对话流程编排、提示词、界面、通用知识(公开的制度);
|
||||
- 改成代码服务:**带权限的合同检索**(按用户部门和密级过滤,见 [RAG 权限场景](../../rag/scenarios/permission-aware-kb.md))、合同系统查询(用户身份透传),以自定义工具接入平台。
|
||||
2. **评测**:从原型的对话日志中整理 100 条问题和标准答案,形成评测集;每次修改提示词后通过 API 批量调用平台应用跑评测。
|
||||
3. **配置版本化**:定期导出应用配置(DSL)存入 Git,修改前后对比。
|
||||
4. **性能**:自定义工具服务独立扩容;平台按官方文档做多实例部署;高频问题加缓存(注意权限维度)。
|
||||
5. **退出路径**:如果平台无法满足(例如需要复杂的多 Agent 和人工审批),核心服务已经是独立代码,迁移到 LangGraph 的成本可控。
|
||||
|
||||
## 关键代码
|
||||
|
||||
通过 API 批量调用平台应用做评测(Dify 应用 API 的路径和参数以官方文档为准,示意):
|
||||
|
||||
```python
|
||||
async def ask(client: httpx.AsyncClient, question: str, user: str) -> str:
|
||||
r = await client.post(
|
||||
f"{DIFY_BASE}/v1/chat-messages",
|
||||
headers={"Authorization": f"Bearer {APP_API_KEY}"},
|
||||
json={"inputs": {}, "query": question, "user": user, "response_mode": "blocking"},
|
||||
timeout=60,
|
||||
)
|
||||
r.raise_for_status()
|
||||
return r.json()["answer"]
|
||||
|
||||
|
||||
results = await asyncio.gather(*(ask(client, c["q"], "eval-bot") for c in CASES))
|
||||
report = score(CASES, results) # 复用 Agent 评测专题中的打分和门禁逻辑
|
||||
```
|
||||
|
||||
自定义工具接口示例:[examples/dify-tool-api](../examples/dify-tool-api/)。
|
||||
|
||||
## 取舍
|
||||
|
||||
| 选择 | 优点 | 缺点 |
|
||||
| --- | --- | --- |
|
||||
| **平台编排 + 代码服务(本方案)** | 业务可自助调整,关键逻辑可控 | 两套系统,要定义清楚边界 |
|
||||
| 全部留在平台 | 最快 | 权限、评测、性能受平台能力限制 |
|
||||
| 全部重写为代码 | 完全可控 | 失去业务自助能力,开发周期长 |
|
||||
|
||||
## 易错点
|
||||
|
||||
- 在平台的 HTTP 节点中写死系统账号和密钥。
|
||||
- 原型的知识库直接用于全公司,没有权限。
|
||||
- 评测时用的平台应用版本和线上不一致。
|
||||
- 推广前没有压测。
|
||||
|
||||
## 面试怎么讲
|
||||
|
||||
> “Dify 原型验证了需求之后,我做的是拆分:流程、提示词和界面留在平台,让业务自己调;带权限的合同检索和合同系统查询写成代码服务,用用户身份调用,再作为自定义工具接入。用原型日志整理了评测集,通过平台的 API 批量跑;平台配置定期导出进 Git。这样既保留了低代码的效率,权限和质量又在我们控制之下。”
|
||||
Reference in new issue
Block a user