ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Dify外部知识库API接入Milvus:从部署到检索的完整实践

Dify外部知识库API接入Milvus:从部署到检索的完整实践 前段时间有个朋友跑来问我团队已经有一套基于 Milvus 的 RAG 检索服务里面沉淀了上百万条业务文档现在公司统一用 Dify 搭智能体怎么才能让 Dify 的知识库直接用上这套 Milvus这话听着简单真正动手做才发现有好几条岔路。我最终选择的是 Dify 官方支持的“外部知识库 API”路线把 Milvus 检索服务安全地桥接进 Dify数据不进 Dify 内置存储文档权限、分段、重排都由自己掌控。这篇文章就把整个接入过程拆开来讲包括 Milvus 单机部署、Collection 设计、API 服务实现、Dify 控制台配置以及我踩过的几个坑。适合已经跑通 Dify、想把知识库能力替换或外接的开发者尤其是那些对内置知识库的召回能力、存储可控性不满意的场景。1. 先分清两条路线内置向量库还是外部知识库 API1.1 “把 Milvus 装进 Dify”和“让 Dify 调用 Milvus”是两回事很多人在搜索里找“Dify 部署 Milvus”其实背后有两种完全不同的诉求。诉求 ADify 自带的知识库功能希望在后台通过 Milvus 存储向量。这种方式下Dify 负责自动切片、向量化、召回Milvus 只是一个存储底座。部分 Dify 版本确实支持通过环境变量切换向量数据库可以把存储指向 Milvus。诉求 B自己已经有或打算自己搭一套基于 Milvus 的知识检索服务希望 Dify 应用在回答时调用这套服务拿资料。数据如何切分、如何向量化、如何召回完全由你自己的服务决定Dify 不插手。本文聚焦的是诉求 B也就是标题里“外部知识库”所指的方向。因为只有这条路能让你已有的 Milvus 存量数据被 Dify 应用直接复用而不是把所有文档重新灌进 Dify 内置知识库。外部知识库 API 是 Dify 提供的开放检索代理它不关心你的向量库是 Milvus、ES 还是别的什么只要你提供一个 HTTP 检索接口Dify 把用户的 query 和检索参数交给这个接口接口返回候选片段即可。1.2 为什么我不推荐硬改 Dify 的后端存储网上有一些文章教人把 Dify 默认向量存储改成其他数据库甚至是自己魔改部署配置。我不敢说这种方法完全不可行但只要你深入用过一段时间大概率会遇到这几类问题Dify 内置的切分逻辑、召回逻辑跟版本强绑定升级 Dify 后存储层一旦不兼容知识库表结构对不上所有数据等于白灌。docker compose up -d升级时Dify 会把自己依赖的多个镜像一起拉取更新如果你改过底层存储编排升级时极容易冲突经常出现容器不停重启。内置知识库的数据隔离、权限过滤不是为“自定义底层存储”设计的真要改到生产可用等于自己维护一套 fork后续每次升级都要重新适配。外部知识库 API 的好处是接口稳定Dify 只关心你返回的结构化片段。哪怕 Dify 升了好几个大版本你外面这套 Milvus 服务依旧能正常跑。数据在自己手里检索逻辑在自己手里升级这件事的焦虑会小很多。1.3 什么场景值得花精力做外部知识库不是所有项目都需要绕这么一圈。我的建议是以下场景才值得投入这个成本已有海量存量数据在 Milvus 或其他向量库不想再重灌一份到 Dify 内置库。检索前需要做业务过滤比如按部门、客户级别、文档权限控制召回范围。希望加入自己的召回增强逻辑比如 query 改写、敏感词过滤、业务重排、多路召回融合。需要多租户隔离每个租户的数据和检索范围完全分开。团队里已经有独立的 RAG 服务只想把 Dify 当作应用编排和对话管理平台。反过来如果只是个人项目、几百条文档、刚接触 Dify那你完全没必要上外部知识库 API。内置知识库操作简单、界面友好学习成本低得多等规模上来了再迁移也不迟。2. 单机版 Milvus 落地Docker Compose 部署与镜像拉取排坑2.1 Milvus Standalone 不是一个容器是三件套Milvus 单机版不是一个大容器而是一套三件套etcd 负责元数据存储MinIO 负责对象存储真正的 milvus standalone 才是查询和索引引擎。所以用 Docker Compose 部署时实际上要拉好几个镜像这也是部署时最容易出问题的地方。常见端口要注意19530 是 gRPC 端口pymilvus 默认连这个9091 是 HTTP 端口健康检查、RESTful API、可视化工具通常会用到。Dify 外部知识库 API 服务通过 pymilvus 连接 Milvus 时走的是 19530。如果本地端口被占用比如 19530 已经被别的程序占了可以在 docker-compose.yml 里把宿主机映射改成19531:19530客户端连接地址也同步改成 19531。这个看似简单但经常有人被卡住。2.2 用 docker compose 拉起一套单机 Milvus我的做法是新建一个目录专门放 Milvus 编排文件不要和 Dify 的 docker 目录混在一起方便单独管理。操作步骤大致如下创建目录并进入mkdir milvus cd milvus从 Milvus 官方仓库的 standalone 目录下载 docker-compose.yml也可以自己写一份精简版。执行docker compose up -d。观察状态docker compose ps三个服务都变成 healthy 才算正常。验证健康检查curl http://localhost:9091/healthz返回正常状态才算是真的起来了。用 pymilvus 做最小连接测试。官方那份 compose 文件里etcd、minio、milvus 三个服务的镜像 tag 是互相配套的强烈建议直接用官方给的那份不要自己去拼版本。我见过有人把 minio 换成别的 tag结果 Milvus 日志里一直在报对象存储连接失败。这种环境问题排查起来非常浪费时间。2.3 镜像拉取失败与内存不足怎么处理Milvus 主镜像体积好几个 GBDify 全家桶镜像就更不用说。网络条件一般的情况下第一次docker compose up很容易出现镜像拉取超时或中途失败。我的经验是先单独把镜像 pull 一遍全部到齐了再docker compose up而不是让 compose 边拉边起。这样哪一步失败看得清清楚楚重试也不至于反复半途而废。如果网络确实差可以给 Docker 配置 registry mirror或者在有网机器上docker save打包镜像、再拿到目标机器docker load导入离线环境基本都是这个思路。内存方面etcd 加 minio 加 milvus 三个容器本身就吃资源如果再叠加 Dify 全家桶本机 Docker 最好给到 8GB 以上至少也要 4GB。我之前在一台只给了 2GB 的机器上跑Milvus 隔一段时间就崩溃一次日志里全是 etcd timeout 之类的报错后来把内存调上去就再也没出现过。Windows 用户特别注意一点一定要让 Docker Desktop 跑在 WSL2 backend 上别用旧的 Hyper-V 模式。Milvus 容器对文件系统 IO 比较敏感WSL2 下整体稳定很多。如果你发现 Milvus 容器反复重启先去看看 Docker Desktop 的 WSL 设置和内存分配。2.4 用 Attu 和 pymilvus 做一次体检部署完先别急着接 Dify先确认 Milvus 本身可用。我一般用两个工具AttuMilvus 官方 GUI可视化查看 collection、索引、检索结果。运行方式和连接地址根据你用的 Attu 版本略有不同新版桌面端一般可以直接填 Milvus 地址连接 19530 的 gRPC 或者 9091 的 HTTP 都行看你当前版本支持哪种。pymilvus写几行脚本连一下创建一个临时 collection插入一条向量再 search 一次。链路通不通一目了然。等 Milvus 本身确认没问题再进入下一阶段。这一步别省很多人最后查了半天发现不是 Dify 的问题而是 Milvus 根本没正常起来。3. Collection 设计要趁早字段、维度、距离度量与 score 转换3.1 先想清楚 Dify 需要你返回哪些字段外部知识库返回给 Dify 的核心字段一般是 content、source、scoretitle 可选。所以你的 Milvus collection 里至少要有 content 和 source否则检索完凑不齐响应字段。我常用的 schema 设计如下你可以根据业务增减字段名类型说明idVARCHAR(64)主键用 uuid 或业务文档 idcontentVARCHAR分段后的文本内容sourceVARCHAR文档来源文件名、URL、文档标识都可以titleVARCHAR可选文档标题tenant_idVARCHAR可选多租户过滤字段vectorFLOAT_VECTOR维度取决于 embedding 模型有个细节要注意Milvus 的 VARCHAR 字段有最大长度限制默认能到 65535 字节中文按 UTF-8 算一个汉字 3 个字节所以大约能存两万多个汉字。存一个分段文本完全够但如果你打算把整篇长文档塞进一个字段那就要小心了。更合理的做法是在写入前就把文档切好段每段控制在几百字左右既不会超出长度限制也给后面的 LLM 上下文省 token。3.2 向量维度与 embedding 模型必须提前锁死这是一个非常容易踩的坑开发环境用 bge-m3 模型向量维度是 1024生产环境换了 OpenAI text-embedding-3-small向量维度变成 1536。结果想要在同一个 collection 里建索引发现维度对不上要么重建 collection要么全部重新向量化白折腾一趟。正确做法是先确定 embedding 服务再定 collection 维度写死在配置里运行期不要随意改。如果你的 Dify 内置知识库也在用 embedding建议和外部 API 用同一个模型这样后续做内置知识库和外部知识库的效果对比时结果才有可比性。如果两边模型差得很远检索排序风格完全不同你很难判断到底是哪一步出了问题。3.3 距离度量选 COSINE 还是 IP以及 score 换算陷阱Milvus 支持多种距离度量文本检索场景我几乎都用 COSINE。原因是余弦相似度对向量模长不敏感文档长一点短一点影响相对小。但 COSINE 的原始分数范围是 -1 到 1越接近 1 表示越相似。这里有个很容易忽略的问题Dify 的 score_threshold 通常按“相似度分数”来理解比如你设 0.5意思是相似度低于一半的不要。但如果你直接把 Milvus 的 cos 距离值原封不动塞给 Dify那中间那些 0.1、0.2 甚至负数的分数就完全失去直觉意义阈值等于白设。我的做法是在外部 API 返回前做一次换算similarity (cosine_score 1) / 2把原始分数映射到 0 到 1 之间再填进响应的 score 字段。这样 Dify 里的阈值设置才符合直觉。如果你用的是 IP 内积分数可能超过 1那换算逻辑还要再调整用 L2 的话距离越小越相似和 Dify 的阈值语义本身就是反的更得处理。所以如果没有特殊理由文本检索直接用 COSINE 最省心。3.4 索引参数、写入批次与日常维护数据量在 100 万条以内HNSW 索引就足够更大规模可以再考虑 IVF_FLAT 或 PQ。HNSW 的两个核心参数是 M 和 efConstruction我一般用 M16、efConstruction200 起步效果和性能比较均衡。写入数据时建议按批次插入每批 500 到 1000 条左右插入完成后调用一次 flush确保数据落盘可查。不要一条一条 insert 到海量数据里性能差而且容易把 etcd 打到瓶颈。如果数据更新频繁collection 的 dynamic field 建议关掉避免字段无限膨胀。4. 手写一个外部知识库检索接口请求进来、向量匹配、结果回去4.1 外部知识库 API 的请求与响应格式Dify 调用外部 API 时常见请求体大致长这样以官方最新文档为准我这里给出的是 1.x 实测中常见的结构{ query: 用户的问题, top_k: 5, score_threshold: 0.5, knowledge_id: 创建外部知识库时填的 ID }你的 FastAPI 服务接收到这个请求后要自己完成 query 向量化、Milvus 检索、阈值过滤然后返回候选片段列表。常见的响应格式是一个 JSON 数组[ { content: 匹配到的文本片段, source: 文档来源, score: 0.82, title: 文档标题 } ]不同 Dify 版本对响应格式的要求可能略有差异。有些版本要求包一层{records: [...]}你以自己部署版本对应的接口文档为准。如果 Dify 报了响应解析错误最快的确认方式就是在你的 API 服务端把收到的请求打日志再看 Dify 端期望的结构两分钟就能对上。4.2 FastAPI 检索服务完整骨架我习惯用 FastAPI 来写这个外部知识库服务轻量、文档自动生成、调试方便。核心代码如下# requirements: fastapi uvicorn pymilvus sentence-transformers from fastapi import FastAPI, Header, HTTPException from pydantic import BaseModel, Field from pymilvus import MilvusClient MILVUS_URI http://localhost:19530 COLLECTION_NAME dify_kb EXPECTED_API_KEY dify-issued-key # 在 Dify 控制台里生成的 key client MilvusClient(uriMILVUS_URI) app FastAPI() class RetrievalRequest(BaseModel): query: str top_k: int Field(default5, ge1, le20) score_threshold: float | None None knowledge_id: str | None None # 有些版本会传这个字段 class RetrievalDoc(BaseModel): content: str source: str score: float title: str def verify_api_key(authorization: str Header(default)) - None: expected fBearer {EXPECTED_API_KEY} if authorization ! expected: raise HTTPException(status_code401, detailinvalid api key) def embed_query(text: str) - list[float]: # 这里替换成你实际的 embedding 调用方式 # 以开源 bge-m3 为例 from sentence_transformers import SentenceTransformer model SentenceTransformer(BAAI/bge-m3) return model.encode(text, normalize_embeddingsTrue).tolist() app.post(/retrieval, response_modellist[RetrievalDoc]) def retrieval(req: RetrievalRequest, authorization: str Header(default)): verify_api_key(authorization) query_vec embed_query(req.query) filter_expr None if req.knowledge_id: # 如果 knowledge_id 对应业务中的租户/知识库标识这里可以拼过滤条件 filter_expr ftenant_id {req.knowledge_id} hits client.search( collection_nameCOLLECTION_NAME, data[query_vec], limitreq.top_k, output_fields[content, source, title], filterfilter_expr, search_params{metric_type: COSINE, params: {ef: 128}}, )[0] result [] for hit in hits: # Milvus 2.4 的 client.search 返回 dict 结构 raw_distance hit.get(distance, 0.0) # COSINE 分数映射到 0~1和 Dify 阈值语义对齐 similarity (raw_distance 1) / 2.0 if req.score_threshold is not None: if similarity req.score_threshold: continue entity hit.get(entity, {}) result.append(RetrievalDoc( contententity.get(content, ), sourceentity.get(source, ), titleentity.get(title, ), scoreround(similarity, 4), )) return result这套代码里最关键的两处转化一是把外部 API Key 当作 Bearer Token 校验和 Dify 生成 Key 的机制对应上二是把 Milvus 的原始距离换算成 0 到 1 的相似度分数保证 Dify 的 score_threshold 有实际意义。embedding 部分我没有写死成某一个服务实际部署时你可以接 OpenAI、Xinference、Ollama 或者本地 sentence-transformers只要保证 query 向量和 collection 里的向量来自同一个模型即可。4.3 超时、缓存与异常兜底Dify 调用外部 API 是有超时时间的外部 API 必须在几秒内返回结果否则 Dify 会判定调用失败。所以你的 Milvus search 操作也要设置合理的 timeout不要让一个慢查询拖垮整个请求。Milvus 的 search 支持 timeout 参数建议设置成 5 秒比 Dify 的超时时间短提前暴露问题。另外embedding 模型如果部署在远端重复生成 query 向量的成本也不低。我的做法是给 embedding 结果加一层缓存比如用字典缓存相同 query 的向量或者上 Redis这样短时间内重复的问题不会反复打 embedding 模型。还有一点非常实用如果 Milvus 检索异常不要直接返回 500 把 Dify 那边也搞挂。更稳妥的做法是捕获异常返回空数组。这样 Dify 会继续走“没有检索到内容”的路径而不是整个应用直接报错。生产环境里这个兜底逻辑能省去大量线上事故。5. 控制台配置与首次唤醒让 Dify 应用真正用上 Milvus5.1 在 Dify 里创建外部知识库 API 凭证外部 API 服务写好并启动后回到 Dify 控制台。1.x 版本的入口一般是在“知识库”页面里找到“外部知识库 API”相关按钮点击创建。需要填的内容有名称给你的外部 API 起个名比如 “milvus-production”。API Endpoint填你外部 API 服务的完整地址比如http://your-api-host:8000/retrieval。API KeyDify 会生成一串 Key这串 Key 在 Dify 调用你的 API 时会放到请求头的 Authorization 字段里格式是 Bearer Token由你自己的服务去校验。这里有个容易忽略的点如果你的外部 API 服务和 Dify 跑在同一台机器上Dify 容器内部访问localhost是访问不到你宿主机的服务的。你要么把 API 服务也容器化放到同一个 Docker 网络里使用容器服务名作为 endpoint要么在 Docker Compose 里配置extra_hosts之类的规则让容器能通过宿主机地址访问到外部 API。最简单省事的方式是把 API 也打成镜像和 Dify 放同一个 compose 网络endpoint 直接写服务名。5.2 新建外部知识库并关联 API创建完 API 凭证后在知识库页面“添加知识库”时选择“连接外部知识库”。这时候需要填知识库名称Dify 内部展示用比如 “业务文档库”。关联的外部知识库 API选择刚才创建的那个凭证。External Knowledge ID这个 ID 会原样传给外部 API 服务用来区分到底是哪个知识库发起的检索。建议直接填你 Milvus collection 里的租户标识或业务库标识这样外部 API 可以根据它做过滤。如果你有多个 Milvus collection 对应多套业务知识库就多建几个外部知识库每个填不同的 External Knowledge ID外部 API 根据这个 ID 选择不同的 collection 或过滤条件。5.3 用工作流里的知识检索节点测试链路外部知识库创建完成后在 Chatflow 或工作流里拖一个“知识检索”节点知识库类型选择“外部知识库”然后选中你刚建的那个外部知识库。检索输入一般直接接开始节点的 query 变量。如果需要在检索前对问题做改写可以在前面加一个 LLM 节点用它生成更利于召回的检索词再用变量赋值器把结果传给知识检索节点。这一步对提高召回准确率很有帮助尤其是用户提问口语化严重的时候。参数方面top_k 可以先设 5score_threshold 先不要设或者设一个很低的阈值。跑一次查询后在外观 API 服务端看日志确认 Dify 的请求有没有发过来返回的片段是不是符合预期。链路通了以后再调整阈值和 top_k。5.4 链路不通时怎么快速定位我摸索出一个简单的判断逻辑能帮你快速定位问题外部 API 没收到任何请求多半是 Endpoint 配置错了或者 Dify 容器访问不到你的 API 服务地址。外部 API 收到了请求但 Dify 报解析错误响应格式和 Dify 版本要求的不一致抓接口日志对比一下。外部 API 正常返回但 Dify 知识检索节点显示空结果大概率是 score_threshold 过滤太狠或者响应里的 score 语义反了。先把阈值调低甚至直接去掉阈值试试。整个调试过程里外部 API 服务端打印请求日志是最关键的。Dify 到底传了哪些字段、期望什么结构看一次真实请求就什么都清楚了比自己猜文档快得多。6. 检索质量翻车排查top_k、score_threshold 与重排的配合6.1 先排查最基础的匹配问题如果你接完以后发现检索结果乱七八糟先别急着调重排先排查两个基础项第一query 向量和 collection 里的向量必须来自同一个 embedding 模型。模型不一致维度可能对不上即使维度碰巧一样向量空间分布也完全不同检索结果必然没有意义。第二content 字段里装的内容粒度要合适。如果一段文本塞了一整页文档检索命中后返回给 LLM 的上下文太杂模型很难从中提取准确信息。分段长度建议控制在 300 到 500 字左右每段尽量是一个完整语义块比如按标题层级、段落边界切分段落之间可以加一点重叠字符防止关键信息被拦腰截断。6.2 score_threshold 到底怎么调很多人拿到知识库先把 score_threshold 设成 0.7 或 0.8结果发现经常检索不到内容然后怀疑 Milvus 坏了。其实阈值这个东西不能一上来就凭感觉定。我常用的调法分三步先不传 score_threshold用 top_k20 跑一批 query看看召回的相似度分数分布范围。根据分布选一个起步值比如大部分相关结果都在 0.6 以上那就从 0.6 开始。结合业务反馈逐步收紧或放宽目标是让“噪声结果”被过滤掉同时不把“有效结果”挡在门外。另外要再强调一次 score 语义问题。如果你在外部 API 里没有把 COSINE 分数映射到 0 到 1那 Dify 里设阈值大概率是失灵或误伤的。先确认你自己 API 返回的 score 是“越高越相似”且大致落在 0 到 1 区间再去做阈值微调。6.3 重排粗排召回一批、精排只留几条向量检索本质上是粗排它能快速从海量文档里捞出候选集但排序质量未必符合你的业务预期。要进一步提升准确率高效的做法是在外部 API 里加一层重排。我的做法是先用 Milvus 召回 top_k50 的候选再用一个 reranker 模型比如 bge-reranker 或 cross-encoder对候选片段和用户 query 做精排最后只取 top 5 返回给 Dify。这一步增加的网络和计算开销不大但对检索准确率的提升非常明显。热搜里有人在问 langchain4j milvus 混合检索实际上也属于这条优化方向。Milvus 从 2.4 开始支持 dense 加 sparse 的混合检索语义召回和精确关键词召回可以并行再通过 RRF 等融合策略合并结果。如果你的业务里经常出现产品型号、人名、订单号这类精确匹配需求只靠纯向量检索很容易漏掉关键内容这时候混合检索就很有价值。如果你在 Java 生态里用 LangChain4j它本身封装了 Milvus 混合检索的调用但要注意返回结果如何转换成 Dify 外部 API 要求的响应格式。6.4 用一批业务 query 来评估改动效果调参最忌讳只看一两个例子因为一两个例子说明不了召回率的整体变化。我的建议是准备 100 到 200 条真实的业务 query人工标好哪些文档应该被命中然后每次改动都跑一遍这批数据统计命中率、首位准确率等相关指标。评估结果可以做成一张简单表格记录数据版本、top_k、score_threshold、是否混合检索、是否重排、命中率、平均响应耗时。这样每次调整都有数据支撑不会改完以后心里没底。这个习惯我强烈建议养成很多知识库项目上线后效果不稳定就是因为缺少这套评估基准。7. 容易被忽略的实践细节多租户、版本升级与离线部署7.1 外部知识库的多租户隔离要自己做Dify 社区版在 1.10 之后多租户相关能力有所增强但外部知识库的隔离仍然得你自己在做。最简单的方式是在 Milvus collection 里加一个 tenant_id 字段写入数据时给每一条记录打上租户标识检索时通过 filter 条件强制过滤filter_expr ftenant_id {tenant_id} hits client.search( collection_nameCOLLECTION_NAME, data[query_vec], limittop_k, filterfilter_expr, output_fields[content, source, title], )这里的 tenant_id 可以从 Dify 传来的 External Knowledge ID 映射过来。你可以选择一租户一个 collection也可以所有租户共用一个 collection 靠字段过滤。前者隔离性最好后者资源利用率高各有利弊。我的经验是小规模团队先用一个 collection 加字段过滤等某个租户的数据量明显变大再拆库。7.2 Dify 版本升级后要重新检查什么Dify 社区版更新频率不低升级以后外部知识库 API 的 Key 一般不会被重置但接口字段偶尔会有变化。我的习惯是每次升级后做这样几件事检查 changelog看看外部知识库相关的接口协议有没有调整。在知识库页面确认外部 API 凭证还在并且 Endpoint 没有被重置。跑一条真实检索确认 Dify 发出的请求体字段和你的外部 API 能对得上。确认 Milvus 容器没有跟着 Dify 一起被意外重建或重命名导致连接地址变化。如果你把外部 API 和 Dify 放同一个 Docker 网络升级时更要小心网络配置Dify 重新创建容器后和外部 API 之间的网络连通性需要重新验证。7.3 离线环境下的镜像与模型部署很多企业内部环境不允许直接访问外网这时候 Dify 和 Milvus 的部署策略要调整。我的做法是在一台有网机器上先把 Dify 相关镜像、Milvus 相关镜像全部docker pull下来然后docker save打包成 tar 文件带到内网用docker load导入。导入后确认镜像 tag 完整再执行docker compose up -d。这里特别要注意 tag 不要用 latest因为离线环境一旦镜像不全无法临时拉取必须保证 tag 和 compose 文件里写的一致。embedding 模型同样要提前准备。如果外部 API 使用开源模型比如 bge-m3需要把模型文件提前下载好放到离线机器上加载也可以用 Ollama 或 Xinference 在内网部署本地模型服务。总之离线的核心原则是所有依赖包括镜像、模型、pip 包都要在进内网之前准备齐全否则一个包缺失都可能卡住整个项目。Dify 和外部 API 服务之间的调用关系也要提前想清楚。如果都在同一个 compose 网络里endpoint 直接用服务名如果外部 API 跑在内网其他机器上要确保 Dify 容器能访问到那台机器的网络。这些网络细节看起来不起眼但在离线环境里排查起来特别费劲建议一开始就画清楚依赖关系。最后说一个我自己的建议。如果这是你第一次接外部知识库不要一上来就追求完整效果。先用外部 API 返回两条写死的文档在 Dify 里把链路跑通再逐步接入 Milvus 检索、阈值控制、重排。这个过程里你会快速熟悉 Dify 的调用结构后续真正优化时也不会一头雾水。Milvus 和 Dify 都是成熟工具卡住你的往往不是工具本身而是接口两边字段对不齐这类小问题。遇到问题就先看日志再看文档大部分坑都能在两小时内填平。
返回列表