news 2026/11/4 2:09:07

智能体项目复盘 · 掌柜智库篇:设备手册 RAG 的完整工程——三段式切分、双向量混合检索、RRF + 断崖精排

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
智能体项目复盘 · 掌柜智库篇:设备手册 RAG 的完整工程——三段式切分、双向量混合检索、RRF + 断崖精排

智能体项目复盘 · 掌柜智库篇:设备手册 RAG 的完整工程——三段式切分、双向量混合检索、RRF + 断崖精排


💡这一篇对应课程的05_项目_掌柜智库。它是整个课程系列里第一个"有甲方"的项目:不是聊天机器人 Demo,而是要把 H3C 路由器手册、华为 MateBook 说明书、HAK180 烫金机安全手册、苏伯尓 5000W 电磁炉说明书这些东西,变成一个能回答"这个万用表怎么换电池"“烫金机怎么只转印顶部 50-170mm 区域”"面板按键在哪"的问答系统,而且答案里要带图。

它也是我见过的中文教学项目里,RAG 参数给得最全的一个:chunk 上限 2000 字符、短块合并阈值 500、稠密/稀疏权重 0.8/0.2、RRF 常数 k=60、主体确认双阈值 0.85/0.60、精排断崖 0.5 绝对差 + 25% 相对差、上下文预算 12000 字符。每一个数字都能在代码里找到出处。

但更有意思的是它的不完美:教案宣称 overlap 10~20%,代码里写的是chunk_overlap=0;注释说稠密稀疏"各占 50%",代码传的是(0.8, 0.2);Neo4j 图谱召回只有一堆空桩;两份 MongoDB 工具类并存,其中改进版没接线。这份代码是一个真实演进中的项目被截了个快照,我按快照写。


1. 一句话架构:两条 LangGraph 状态机 + 四类存储

先建立全局认知。掌柜智库自述"代码总行数 5507",骨架其实是两条完全独立的图。

【导入链路】PDF/Word --> node_entry(按扩展名分发) --> node_pdf_to_md(MinerU 云端解析) --> node_md_img(VLM 图片理解 + MinIO 上传 + 正则替换图片链接) --> node_document_split(三段式切分) --> node_item_name_recognition(文档主体识别) --> node_bge_embedding(BGE-M3 双向量) --> node_import_milvus 【查询链路】node_item_name_confirm(双阈值确认主体) --条件边并行扇出--> node_search_embedding / node_search_embedding_hyde / node_web_search_mcp --> node_rrf(带权重倒数排名融合) --> node_rerank(动态 TopK 断崖截断) --> node_answer_output(流式生成 + 回捞图片) --> END

教案把准确率工程归纳成六层闭环,这个总结我认可:

数据结构化 --> 语义切片 --> 多路召回 --> 混合检索 --> 假设增强(HyDE) --> 精排裁决

四类存储各自的角色分工很清楚,别混:

存储存什么为什么是它
Milvuschunk 的稠密 + 稀疏向量 + 元数据一个 collection 同时装FLOAT_VECTOR和SPARSE_FLOAT_VECTOR,原生支持混合检索
MongoDB只有chat_message会话历史半结构化、按 session 读写,不需要事务
MinIO手册里抽出来的图片图片要变成可外链 URL 塞进 Markdown
Neo4j——只有脚手架,见第 7 节

2. 技术栈与版本(都来自pyproject.toml,可核对)

层选型版本 / 关键值
WebFastAPI + uvicorn(不是 Flask)导入服务:8000,查询服务:8001,两个独立进程
编排LangGraph 1.1.2 + LangChain 1.2.12StateGraph/TypedDict状态 /add_conditional_edges
向量库Milvus(pymilvus[model]2.6.10)MilvusClient+AnnSearchRequest+WeightedRanker
文档库MongoDB(pymongo4.16)
对象存储MinIO(fput_object)
LLMChatOpenAI走兼容接口,默认qwen3-32benable_thinking: False通过extra_body透传关掉千问思考链
VLMVL_MODEL,测试用例见qwen-vl-plus只用于图片描述
EmbeddingBAAI/bge-m31024 维稠密 + 稀疏,normalize_embeddings=True
Rerankbge-reranker-large(FlagEmbedding.FlagReranker)
文档解析MinerU 在线 API(mineru.net,model_version="vlm")本地装了magic-pdf 1.3.12但流水线没走本地
联网搜索MCP(openai-agents0.4.2,Streamable HTTP)调百炼bailian_web_search
环境uv+uv.toml清华镜像,Python 3.11.env+.env.example,load_dotenv(override=True)
日志loguru统一封装含穿透调用栈修正name/function/line
可视化grandalf给 LangGraph 的_ascii用

架构上限先说:项目里没有 Celery / Redis 队列 / Kafka。导入任务状态是task_utils.py里 4 个进程内 dict(_tasks_running_list/_done_list/_status/_result)。这意味着——单进程内存态,重启即丢,不可水平扩展。做 Demo 完全够,当生产架构就是天花板。


3. 导入链路:三段式切分是这半边的核心

这一节有全项目最值得抄的一段代码。

3.1 PDF → Markdown:MinerU 三步走

取上传签名 URL --> PUT 上传文件 --> 轮询 batch 结果(间隔 3s,5xx 重试,超时按 30/60/120s 分档)--> 下载 zip --> 解压取 md

3.2 图片处理:把"看图"变成"可检索文本"

手册类文档的图片承载了关键信息(面板图、接线图),丢了图片等于丢了答案。做法是node_md_img:扫描 MD 里的图片引用 → 取图片上下各 100 字符作为语境 → 喂给 VLM 出中文摘要 → 上传 MinIO → 正则把![原图名](本地路径)替换成![VL描述](MinIO URL)。

提示词长这样(image_summary.prompt逐字):

这是"{root_folder}"文件中的一张图片,图片上文部分为"{image_content[0]}", 下文部分为"{image_content[1]}",请用中文简要总结这张图片的内容, 用于 Markdown 图片标题,控制在50字以内。

三个设计点值得注意:显式喂上文/下文窗口(做视觉-文本对齐,不给语境 VLM 会瞎说)、点明用途(“用于 Markdown 图片标题”)、50 字上限(防止摘要污染 chunk 预算)。

3.3 三段式切分:标题优先 + 长切短合

不是定长切,是三段:

① 标题树初切 正则 ^\s*#{1,6}\s+.+,但必须用 in_code_block 标志跳过 ```和 ~~~ 里的伪标题 无标题则整篇降级为单节 "无标题" ② 超长章节二切 DEFAULT_MAX_CONTENT_LENGTH = 2000 RecursiveCharacterTextSplitter( chunk_size = 2000 - len(f"{title}\n\n"), # 给标题留位 chunk_overlap = 0, separators = ["\n\n","\n","。","!","?",";",".","!","?",";"," "]) 每块回贴标题前缀,命名 f"{title}-{idx}",带 parent_title / part ③ 短块合并 MIN_CONTENT_LENGTH = 500,只合并"同 parent_title 且当前块 <500"的相邻块 合并时剥掉下一块开头重复的父标题

这里有个教案与代码的直接冲突,必须先点出来:

教案文档里写"chunk 之间保留10%~20% overlap",但代码里chunk_overlap=0。

真实的语义重叠是靠**“每个子块回贴父标题前缀 + 同父短块合并”**实现的,不是滑动窗口重叠。

我认为这个做法比 overlap 更聪明:重叠的目的本来就是"让每块自带上下文",贴标题比贴上一段的尾巴信息密度高得多,而且不产生重复 token。如果你照抄"10~20% overlap"去理解这个项目,方向就错了。

其他兜底细节:标题本身超预算(available_len <= 0)直接返回原章节;\r\n归一为\n(Windows 语料不归一会让标题正则和段落分隔双双失效);part缺省补 0(Milvus 必填);结果落local_dir/chunks.json备份。

3.4 主体识别:给每个 chunk 贴"这是哪个商品的"

取前 5 个切片(DEFAULT_ITEM_NAME_CHUNK_K=5)| 单片截断 800 字符 | 总上下文 2500 字符 --> product_recognition_system(system) + item_name_recognition(human) --> item_name --> 空返回 / 异常一律回退 file_title

item_name有两个用途:贴到该文档所有 chunk 上当元数据,同时单独向量化写进item_name_collection(文档级索引)。后者是查询链路能做"先确认主体再检索"的前提。

3.5 入库 schema 与索引

dense_vector FLOAT_VECTOR(dim=1024)# 索引:HNSW + COSINE, M=16, efConstruction=200sparse_vector SPARSE_FLOAT_VECTOR# 索引:SPARSE_INVERTED_INDEX + IP,# DAAT_MAXSCORE, normalize=Truecontent/title/parent_title/file_title/item_name VARCHAR(65535)part INT8,chunk_id INT64 PK auto_id,enable_dynamic_fields=True

待嵌入文本 =item_name+content拼接(文本增强)。这一步很关键:手册里"第 3 步:长按电源键 5 秒"这种句子,脱离商品名之后在向量空间里和几百个商品的同类句子挤在一起。

插入前按item_name删旧数据,实现重跑幂等。


4. 查询链路:三路并行召回 → RRF → 断崖精排

这一节是整个项目的技术核心,五步。

4.1 第一步:查询重写 + 指代消解(一次 LLM 调用干两件事)

多轮对话里用户会说"那它支持 5G 吗",必须先重写成独立问题并抽出主体。返回 JSON:

{"item_names":["商品A","商品B"],"rewritten_query":"关于商品A和商品B,..."}

4.2 第二步:主体确认,双阈值分流(0.85 / 0.60)

用item_names去item_name_collection做混合检索,然后:

score >= 0.85 --> 确认集(直接作为检索过滤条件) 0.60 <= score < 0.85 --> 可选集(可能相关,但不确定) 确认集为空 --> 提前写入 answer 反问用户,走条件边直达 node_answer_output

这一步的价值是把"检索不到"变成"问清楚再检索"。而 LangGraph 的意图路由就在这里,靠的是条件边返回元组:

defroute_after_node_item_name_confirm(state):ifstate.get('answer'):return"node_answer_output"# 主体不明 → 提前退出反问return("node_search_embedding","node_search_embedding_hyde","node_web_search_mcp")# 返回元组 = 并行扇出

注意:本项目完全没有 text-to-SQL / text-to-Mongo / NL2Query。MongoDB 的查询全是手写 PyMongo,自然语言理解发生在"提取item_names→ 用item_name in [...]做 Milvus 标量过滤"这条路上。如果你想在简历里把这个项目写成"支持自然语言查询数据库",那是写错了。

4.3 第三步:三路并行召回

① 向量混合检索 hybrid_search(ranker_weights=(0.8, 0.2), norm_score=True, limit=5) 稠密 COSINE + 稀疏 IP,AnnSearchRequest 各取 limit=10 ② HyDE 让 LLM 先写一篇 ≤300 字"回答范文",再把 query + hyde_doc 拼一起向量化, 走同样的混合检索 ③ 联网搜索 MCP:MCPServerStreamableHttp 调百炼 bailian_web_search,count=5, max_retry_attempts=3

HyDE 解决的是一对具体矛盾:用户 query 短(“怎么换电池”),手册文档长(一整节),两者不在同一个语义粒度上,向量天然不对齐。让模型先写一段"假装知道答案的回答",这段假答案和真手册的向量距离就近得多。

hyde_prompt.prompt里有一条约束特别好:

要求: 3. 不要使用"假设"、"可能"等不确定的词汇 5. 使用中文回答且不超过300字

禁"不确定词"是因为模糊语气会让假设文档的向量偏离真实手册文档的语义空间——手册是陈述句写的。300 字是防止范文过长反而稀释原 query。

4.4 第四步:RRF 融合,k=60

自实现的带权重倒数排名融合(没有用 Milvus 内置 ranker,因为要多路 + 联网混合):

score(d) = Σ_i weight_i × 1 / (k + rank_i(d)) k = 60, 两路权重各 1.0, max_results = 10

工程细节比公式重要:_as_entity_list()要把 pymilvus 的Hit/ 嵌套 dict / 扁平 dict三种返回形态统一成 entity dict;主键取chunk_id or id。

为什么要or id:Milvus 在 API 层把主键统一叫id,而 schema 里定义的是chunk_id。不处理这一条,RRF 去重会静默失效。

4.5 第五步:精排 + 动态 TopK 断崖截断

FlagReranker.compute_score([[question, text], ...])。本地切片(rrf_chunks)和联网结果(web_search_docs)先合并成统一的{text, source, chunk_id, url, title}结构再一起打分。

断崖算法是这个项目我最想抄走的一段:

RERANK_MAX_TOPK = 10, RERANK_MIN_TOPK = 1 GAP_ABS = 0.5 相邻两条分差的绝对值阈值 GAP_RATIO = 0.25 相邻两条分差的相对值阈值 从第 2 条起逐条比较:gap >= 0.5 or gap / (|s1| + 1e-6) >= 0.25 --> 立即截断

为什么这比"固定 Top-K=5"好得多:不同问题的证据密度不一样。"这个型号支持几个 G"可能只有 1 篇文档讲;"整机不工作怎么排查"可能散在 8 篇里。固定 K 要么带进噪声要么截掉证据,断崖截断让相关性分布自己决定取几条。

配套的另一条保命逻辑:reranker 模型异常时降级返回原序、score=0.0,绝不中断链路。精排是增益环节,不是必要环节,不能让它变成单点故障。

4.6 生成:上下文预算与"图片回捞"

MAX_CONTEXT_CHARS = 12000(字符数,不是 token,中文要自己折算) 每篇资料渲染成:[i] [local|web] [chunk_id=...] [url=...] [score=0.xxxx] [title=...] + 正文

图片 URL 不采信模型输出,而是_extract_images_from_docs(reranked_docs)从精排文档里回捞。原因写在answer_out.prompt里:

2 ...图片只能来自于本地切片文本中的图片,请在答案最后追加一个独立的图片区块,格式严格如下: 【图片】 <图片URL1> (每行一个URL;如果没有合适图片则不要输出【图片】区块)

【图片】是一个可解析的分隔标记,代码用_IMAGE_BLOCK_MARKER把它拆出来交给前端渲染,最后用FINAL事件把answer + image_urls一起推下去。

这套"模型只负责文字,图片由代码回捞"的分工,是所有多模态 RAG 都该采用的模式——让模型生成 URL 必然会产生幻觉链接。


5. 六个 .prompt 文件:把提示词当接口定义写

课程目录里有 24 个.prompt,但 md5 比对后只有 6 个唯一文件——它们在day01/代码/prompts、day02/代码/prompts、掌柜智库项目/代码/PythonProject16/prompts、掌柜智库项目/资料/prompts各存了一份副本(每天代码是全量快照)。

结构约定:UTF-8 纯文本,无 frontmatter、无元数据,文件名即用途,由load_prompt(name, **kwargs)读入后str.format填坑。内容一律是四段式:

任务说明 + 编号约束清单 + 输出格式契约 + 无法确定时的兜底

角色边界单拆一个*_system.prompt。product_recognition_system.prompt全文只有一句:

你是商品识别专家,只输出识别的字符串即可

**“把角色和任务拆成 system / human 两条消息”**这个做法我单独提,因为它比写在同一段里省 token,且模型对 system 的遵循度更高。

最有代表性的是主体识别的item_name_recognition.prompt:

文件名:{file_title} 正文切片(用于辅助识别):{context} 1. 返回内容为字符串形式,最好是带品牌、型号和名称的完整商品名称。比如:苏伯尓5000W大功率电磁炉; 3. 如果无法识别商品名称,请返回空字符串。

它给的是一个具体命名范式的 few-shot(品牌 + 功率 + 品类),而不是抽象描述"要完整"。而"返回空字符串"这个契约,对应代码里"空则回退file_title"——prompt 的兜底路径和代码的兜底路径必须一一对应,否则模型返回空你只能崩。

一个必踩的格式坑:因为用str.format,prompt 里所有 JSON 示例的花括号必须双写成{{ }},否则load_prompt直接KeyError。这是"用文本模板做结构化输出"最常见的隐性成本。


6. 服务端与工程细节

SSE 事件协议(day06 用sse_step_1/2.py|html递进教学,day07 定型):

ready --> progress* --> delta* --> final --> (__close__ | error)

SSEEvent定义这 6 类事件,_session_stream: Dict[str, queue.Queue]按session_id路由:线程池里的图节点put,协程生成器yield。这是跨线程做流式推送的标准解法——queue.Queue线程安全,queue.SimpleQueue或asyncio.Queue在这里都不对。

查询服务接口:

接口作用
GET /chat.html对话页
POST /query提交问题,BackgroundTasks后台跑query_app
GET /stream/{session_id}StreamingResponse,SSE 通道
GET /history/{session_id}拉会话历史
DELETE /history/{session_id}清空
GET /health健康检查

MongoDB 会话历史:

create_index([("session_id",ASCENDING),("ts",DESCENDING)])# 复合索引find({"session_id":sid}).sort("ts",ASCENDING).limit(10)# 索引降序,读取升序

索引建降序、读用升序——因为查询要"最近 10 条"(靠索引高效定位),但喂给 LLM 时要按对话时间正序(模型对时序敏感)。这个细节值得记。

写入用save_chat_message(有message_id走update_one+$set,无则insert_one),回填用update_message_item_names批量补主体名。

两份 Mongo 工具类并存:mongo_history_utils.py(含image_urls参数,$in无条件覆盖)与mongo_history_utils_new.py(去掉image_urls,但更新加了$or: [{item_names:{$exists:false}}, {item_names:[]}, {item_names:null}]守卫,只回填尚未设置主体名的历史消息)。线上跑的是旧版,改进版没接线。典型的教学演进型代码库遗迹。

一个真实可改进点:day07 把时间戳拼进指代消解的 prompt 时,塞的是原始 Unix 浮点数:

聊天角色:{role},回答内容:{text},重写问题:{rewritten_query},关联主体:{...},时间:1774520425.627

模型读不出这个数是什么意思。这行要么格式化成2026-09-29 03:14,要么直接删掉。


7. 踩坑清单(20 条,全部可溯源到代码或教案)

#坑说明
1注释与代码不符node_search_embedding传ranker_weights=(0.8, 0.2),紧跟的注释写"稠/稀疏权重各占 50%"。照注释理解会误判调参方向
2教案说 overlap 10~20%,代码是 0真实重叠靠回贴标题 + 同父合并
3str.format与 JSON 花括号冲突prompt 里必须{{ }}
4模型结构化输出要四层防御day08 注释原话:“1 设置 json 格式化 2 提示词中明确 3 一定要给模型参考示例 4 做好返回格式的校验”。对应json_mode=True→ 剥 ```json 围栏 →if "item_names" not in dict→rewritten_query缺省回落原问题
5numpy 类型不可序列化 / 不可哈希稀疏向量必须.tolist():np.int64→int(做 dict key)、np.float32→float(做 JSON/Milvus 值),否则TypeError。稠密同理
6Milvus 主键在 API 层叫id,schema 里叫chunk_idRRF 去重要item.get("chunk_id") or item.get("id"),缺 ID 的打 warning 跳过
7Milvus filter 表达式注入商品名含引号/换行会炸掉item_name in [...]。必须走escape_milvus_string(\→\\、"→\"、\r\n\t→空格)
8WeightedRanker不开norm_score=True权重会失效稠密 COSINE 与稀疏 IP 量纲不同,不归一化时稀疏分数会"劫持"结果
9FlagReranker.compute_score的(query, passage)顺序不可颠倒代码注释用整段强调:“颠倒会导致打分结果失真”
10并行节点只能返回局部 deltanode_web_search_mcp注释明写"并行的不要直接返回 state";day07 的node_item_name_confirm却return state,正是 day08 要修的地方
11模块加载期异常不能抛Mongo 预连接若raise会导致整个包 import 失败、进程起不来 →try/except只warning+ 懒加载兜底。create_index天然幂等,不用先判断存在
12正则替换要用 lambdapattern.sub(f"![{summary}]({url})", ...)里 summary/URL 含\$会被当反向引用。教案说"想写防御性代码请坚持使用 Lambda 写法"——但它自己的示例代码最终仍用了 f-string 版
13上下文预算是共享的used在"资料"和"历史对话"之间累加,资料过长会静默把历史截光
14图片 URL 无法从 state 回读教案注释:“没办法直接从 result state 里拿到 image_urls,因为它是作为 SSE 推送出去的,或者存库了” → 每轮重新从reranked_docs抽
15VLM 调用要限速deque+apply_api_rate_limit(max_requests, window_seconds=60)阻塞式time.sleep做滑动窗口,会拖慢整条导入流水线
16MinIO 对象名里的反斜杠被编码成%5C访问 URL 要手工按protocol://endpoint/bucket/object拼;重跑前必须clean_minio_directory清旧前缀,否则同名图片内容混淆
17代码块内的#被误判为标题切分器必须维护in_code_block状态,````和~~~` 都要处理
18\r\n不归一标题正则与段落分隔双双失效
19enable_thinking要显式关千问思考链走extra_body: {"enable_thinking": False}。不关的话延迟和 token 都翻倍,而这个任务不需要思考链
20教学代码遗留脏 importday07node_item_name_confirm.py里有from mpmath import limit、未使用的os。别当范式照搬
Q:Neo4j 图谱召回到底做了没有?

没有。需要诚实标注:

clients/neo4j_utils.py --> 存在(脚手架 + .env 里 NEO4J_* 已配好) node_query_kg.py --> time.sleep(1) 空桩 node_import_kg --> 只存在于"中文节点名字典"里,无实现文件 node_multi_search / node_join --> 预留未实现

写博客或简历时把它说成"已实现图谱召回"是不成立的。

Q:day 编号到几?目录名会骗你。

这个目录实际是day01–day10,不是到 day07。而且 day08(item 确认打分 + 向量查询)、day09(RRF / MCP / Rerank 真实现)、day10(答案输出 + 总结 + 面试题)才是查询模块的核心——只看目录名到"day07_查询模块_web和时间以及mongodb"就收工,会得到一个只有空桩的版本。同理,day07 的node_web_search_mcp只是time.sleep(1)返回{"web_search_docs": []},真正的百炼 MCP 在 day09 才补上。

另外那 345 个.pdf绝大多数是语料不是课件:H3C 路由器/无线网关、华为 MateBook、Aolynk Cable 网桥、CS2610DNW、HAK180 烫金机、万用表安全手册(另有一个 317MB 的《设备手册汇总.zip》重复出现 3 次)。教案.zip也无需解压——它的 22 个.md已原样存在于day10_.../教案/教案/,zip 里其余是约 100 张配图。


最后总结

  • 这个项目值得学的不是"用了 RAG",是它把 RAG 拆成了六层可独立调参的环节:结构化切片(标题树 + 2000/500)→ 主体标签(item_name双向量)→ 多路召回(向量 + HyDE + 联网)→ 混合检索(0.8/0.2 + 归一化)→ 融合(RRF k=60)→ 裁决(bge-reranker + 断崖 TopK)。每一层都能单独评测、单独换。
  • 两个最值得直接抄走的机制:①断崖式动态 TopK(绝对差 0.5 / 相对差 25% 立即截断),让相关性分布自己决定取几条;②图片由代码回捞、不由模型生成,把多模态 RAG 最容易出幻觉的一环封死。
  • 三个"低成本高收益"的技巧:把item_name拼进待嵌文本(解决手册短指令句的向量歧义)、chunk 回贴父标题代替 overlap(重叠区信息密度更高)、HyDE 提示词禁"假设/可能"(保持与真文档同一语义空间)。
  • 双阈值(0.85/0.60)确认主体,是把"检索不到"变成"反问用户"的关键一步。绝大多数 RAG 系统体验差,不是因为检索不准,是因为在主体都不确定的时候硬答。
  • 架构上的天花板要心里有数:进程内 dict 存任务状态(重启即丢、不能横向扩展)、上下文预算按字符不按 token、VLM 限流是阻塞 sleep。当 Demo 满分,当生产要重做这三处。
  • 读教学项目代码的正确姿势:以最后一天的快照为"最终态",把中间日期当过程遗迹;注释、教案、代码三者互相核对,本篇 20 个坑里有 5 个就是"文档与实现不一致"。
  • 笔者(后端 & 架构)的判断:如果只能从这个项目里学一件事,我学**“把提示词当接口定义写”**——输入变量、输出契约、兜底路径、格式校验四层防御一一对应。这套做法我后来在 deepagents 和智能客服两个项目里都见到了,而且都是同一批人在强调它。

下一篇讲智能客服系统:当 RAG 遇上多轮流程型对话,架构要再加一层"对话栈"。


参考资料 & 致谢

[1] Milvus - GitHub
[2] BGE-M3 - Hugging Face
[3] bge-reranker-large - Hugging Face
[4] FlagEmbedding - GitHub
[5] MinerU(文档解析)- GitHub
[6] LangGraph 官方文档
[7] Reciprocal Rank Fusion 原始论文 - arXiv
[8] Precise Zero-Shot Dense Retrieval without Relevance Labels (HyDE) - arXiv
[9] Model Context Protocol - 官网
[10] 阿里云百炼 Web Search MCP - 官方文档
[11] FastAPI - 官方文档
[12] [尚硅谷大模型智能体线上速成班 V2.0 · Day05《项目:掌柜智库》课件、源码与教案]

注:项目.env中出现的是 38 个变量名(OPENAI_API_KEY、MILVUS_URL、MINERU_API_TOKEN、NEO4J_*等),本文未引用任何密钥值。文中的准确率、阈值、参数均为课程快照(2026 年 2 月)配置,实际调优请以自己的评测集为准。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/4 2:06:45

用C++11开发PHP 7扩展:ppts_for_php2017韩天峰77页完整教程详解

【免费下载链接】ppts_for_php2017 2017 第三届PHP全球开发者大会PPT/Keynote 项目地址&#xff1a; https://gitcode.com/gh_mirrors/ppt/ppts_for_php2017 点击查看 免费下载 本文带你吃透 ppts_for_php2017 开源仓库中收录的 77 页演讲 PPT——《使用C11开发PHP7扩展》&…

作者头像 李华
网站建设 2026/11/4 2:06:16

DSH Desktop 故障排查:从崩溃循环到更新失败的三步自救清单

DSH Desktop 故障排查&#xff1a;从崩溃循环到更新失败的三步自救清单 【免费下载链接】deepseek-harness-desktop 为 DeepSeek Harness (DSH) 插件生态打造的现代化桌面端解决方案。万物皆「插件」&#xff0c;桌面本身也是「插件」。 项目地址: https://gitcode.com/gh_mi…

作者头像 李华
网站建设 2026/11/4 2:04:49

误删的笔记还能找回来吗?obsidian-git 历史回溯 3 个实战技巧

误删的笔记还能找回来吗&#xff1f;obsidian-git 历史回溯 3 个实战技巧 【免费下载链接】obsidian-git Integrate Git version control with automatic commit-and-sync and other advanced features in Obsidian.md 项目地址: https://gitcode.com/gh_mirrors/ob/obsidian…

作者头像 李华
网站建设 2026/11/4 2:04:25

AngusInsight 是什么:产品与用户行为分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华