这次我们来看一个把知识库做成工业级工具链的方案:DeepSeek Harness 构建 LLM Wiki。它不是简单做一个“文档问答机器人”,而是把知识库的构建、索引、问答、更新、评估串成一条完整流水线。核心能力是知识图谱、可溯源问答、增量编译、在线评估四个模块,配合提示词迭代,把散乱文档变成有结构、可追溯、可增量维护的知识资产。
这篇文章会直接讲清楚:DeepSeek Harness 是什么、凭什么能做工业级 LLM Wiki、10 轮提示迭代怎么落地、知识图谱怎么构建、可溯源问答怎么设计、增量编译和在线评估怎么实现,以及环境准备、API 调用、资源占用、常见问题排查。
如果你正在做私域知识库、团队文档问答、RAG 增强、企业智能问答,或者想用 LLM 管理大量技术文档,这篇内容可以直接作为落地参考。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | LLM 知识库工具链,围绕 LLM Wiki 范式构建 |
| 核心功能 | 知识图谱构建、可溯源问答、增量编译、在线评估 |
| 工作流模式 | 多轮提示词驱动,从文档到知识图谱再到问答闭环 |
| 启动方式 | 命令行、Web 端、桌面端(具体以实际发布版为准) |
| 依赖管理 | 社区使用中常见 Node/pnpm 工程结构 |
| 知识存储 | 文档源 + 分块索引 + 图谱关系存储 |
| 是否支持 API | 从工具链服务化设计看支持接口调用,需以实际文档为准 |
| 是否支持批量任务 | 增量编译和在线评估天然适合批量处理 |
| 硬件要求 | 取决于所接入的 LLM 和向量化服务,需按实际环境测试 |
| 适合场景 | 技术文档知识库、研发规范问答、产品 FAQ、运营资料归集 |
从材料看,这套工具的核心价值不是“多轮对话”,而是把知识库当作一套可持续编译、可回归评估的工程系统。这和传统“把 PDF 灌进向量库就完事”的思路有明显区别。
2. 适用场景与使用边界
DeepSeek Harness 适合的典型场景有以下几类:
- 团队内部技术文档库:把分散的 Markdown、Confluence、Notion 文档统一成知识图谱,支持研发问答和规范检索。
- 产品与运营 FAQ:把产品说明、常见问题、客服话术转化为可溯源问答,回答时能指出出处。
- 研发规范与审计需求:需要回答结果可回溯到具体文档章节,方便后续人工复核。
- 持续更新的文档库:文档每周都在变,不能每次全量重建,需要增量编译机制。
不适合的场景也要说清楚:
- 轻量级个人笔记检索:单文件、低数量、不追求溯源,用简单 RAG 或本地搜索更省事。
- 海量实时流式数据问答:知识图谱构建有延迟,不适合即时抓取并回答。
- 没有内容授权或数据脱敏条件:不建议把敏感、版权不明的内容直接灌进知识库。
合规边界必须注意。知识库里的内容可能来自第三方文档、内部培训材料或他人原创文章,构建前要确认内容授权和来源合法。涉及个人信息、商业机密的内容需要做脱敏处理。可溯源问答虽然方便复核,但不能替代人工审查,对外发布和商用前必须做效果复核,不能把模型生成内容当成权威结论直接发布。
3. LLM Wiki 思路与 DeepSeek Harness 的模块关系
LLM Wiki 的核心思想,是让 LLM 从“只会聊天”变成“能维护一份动态知识库”。传统 Wiki 靠人维护词条,LLM Wiki 靠提示词和工具链自动抽取实体、关系、摘要、引用,再按需求更新和维护。
DeepSeek Harness 是这个思路的工程化实现。从网络检索材料看,它和 Karpathy 提出的“LLM Wiki 范式”有关,社区讨论里也常把它看作把文档编译成知识库的工具。整体模块关系可以理解为:
文档采集与清洗 ↓ 文档分块 + 元数据标注 ↓ 实体/关系抽取(知识图谱构建) ↓ 图谱存储 + 向量索引 ↓ 可溯源问答(检索 + 图谱查询 + 答案生成) ↓ 增量编译(变更检测 + 局部重建) ↓ 在线评估(评估集 + 指标 + 回归)这套链路中,最关键的两个差异点:
一是“知识图谱”。普通 RAG 只做向量相似度检索,回答缺少结构化关系。DeepSeek Harness 会把“员工 A 属于团队 B”“模块 C 依赖服务 D”这类关系抽出来,放入图谱。用户问“某个服务影响了哪些模块”,图谱可以直接通过关系路径回答,而不是靠向量检索拼凑。
二是“增量编译”。知识库不是一次性产物。文档更新后,只对变更部分重新抽取关系、重算向量,而不是整个库重新跑一遍。这对工业级使用非常重要,能明显降低更新成本和出错概率。
4. 环境准备与前置条件
4.1 基础环境检查清单
不管具体项目怎么打包,建议先确认以下环境项:
| 检查项 | 建议 |
|---|---|
| 操作系统 | Windows 10/11、Linux、macOS 均可,实际看官方支持矩阵 |
| Node.js 与包管理器 | 常见工程使用 Node 和 pnpm,建议安装 LTS 版 Node |
| Python 环境 | 若涉及本地抽取模型、向量化、评估脚本,需要 Python 3.9+ |
| 模型服务 | 接入 DeepSeek API 或本地模型服务,确保 key 或 endpoint 可用 |
| 图数据库 | 可选,知识图谱较大时建议使用 Neo4j 等图数据库 |
| 向量数据库 | 根据项目默认配置选择,如 Chroma、Milvus、Qdrant 等 |
| 磁盘空间 | 按文档量和模型缓存估算,建议预留 20GB 以上 |
| 端口 | 常见 Web 服务端口 3000、7860、8080,注意冲突 |
4.2 安装命令示例
下面给出一套通用安装流程,实际命令需要按项目实际发布信息调整:
# 克隆项目,仓库地址以实际发布为准 git clone <project-url> cd deepseek-harness # 安装依赖,常见工程使用 pnpm pnpm install # 安装 Python 依赖,如果涉及本地方案 pip install -r requirements.txt如果下载依赖时速度很慢,可以配置 pnpm 镜像源或使用 Python 包镜像源,避免直接卡在依赖拉取环节。
4.3 模型服务配置
LLM Wiki 的核心是 LLM,配置模型时要注意:
# 模型配置文件示例 llm: provider: deepseek api_key: ${DEEPSEEK_API_KEY} model: deepseek-chat temperature: 0.2 embedding: provider: local model: bge-m3 dimension: 1024 graph_db: provider: neo4j uri: bolt://localhost:7687 user: neo4j password: ${NEO4J_PASSWORD}如果使用本地模型,还要确认显存和模型精度问题。LLM 推理中 FP16、BF16、FP32 对显存占用和结果精度影响很大,本地部署时建议先用小模型跑通,再切换大模型。
5. 10 轮提示迭代总览
标题里的“10 轮提示”不是随便写 10 个 prompt,而是一条从文档到知识库再到评估的完整迭代路线。直接看表:
| 轮次 | 目标 | 输入 | 输出 |
|---|---|---|---|
| 第 1 轮 | 定义领域边界 | 文档集、需求说明 | 领域范围说明、排除哪些内容 |
| 第 2 轮 | 设计知识图谱 Schema | 领域实体、关系、属性示例 | 实体类型、关系类型、属性清单 |
| 第 3 轮 | 准备种子语料 | 原始文档 | 清洗后的高质量种子文档 |
| 第 4 轮 | 确定分块策略 | 清洗后文档 | 分块脚本和元数据模板 |
| 第 5 轮 | 实体抽取提示词 | 文档块 | 结构化实体 JSON |
| 第 6 轮 | 关系抽取提示词 | 实体 JSON + 文档块 | 关系三元组 |
| 第 7 轮 | 图谱入库与校验 | 三元组 | 可查询的知识图谱 |
| 第 8 轮 | 可溯源问答提示词 | 用户问题 + 图谱证据 | 带引用的答案 |
| 第 9 轮 | 增量编译机制 | 新文档、变更文档 | 局部重建的索引和图谱 |
| 第 10 轮 | 在线评估与回归 | 评估问题集 | 指标报告和回归结果 |
为什么是 10 轮?因为每一轮都在解决一个独立问题,且前一轮的输出是后一轮的输入。比如第 5 轮的实体抽取质量,直接决定第 6 轮的关系抽取;第 6 轮的三元组质量,又决定第 7 轮图谱能不能被问答链路查询。如果直接跳到问答环节,后面排查的成本会非常高。
每一轮提示词都有固定结构:角色约束 + 输入格式 + 输出格式 + 示例。下面重点拆解其中几个关键轮的实战细节。
6. 知识图谱构建实战
6.1 定义实体与关系 Schema
知识图谱不是把文档里的词全部抽出来,而是先设计一套适合业务领域的 Schema。假设我们要构建“研发团队文档知识库”,可以定义:
| 实体类型 | 属性 |
|---|---|
| 团队成员 | 姓名、岗位、部门 |
| 服务 | 名称、负责人、技术栈 |
| 文档 | 标题、路径、更新时间 |
| 业务模块 | 名称、依赖、负责人 |
| 规范 | 名称、适用范围、版本 |
| 关系类型 | 说明 |
|---|---|
| USE | 服务使用某种技术栈 |
| DEPENDS_ON | 模块依赖服务 |
| OWNED_BY | 服务/模块由团队成员负责 |
| MENTIONED_IN | 实体在文档中被提及 |
| FOLLOWS | 规范适用于某个模块 |
6.2 实体抽取提示词模板
实体抽取是第 5 轮,也是后续所有环节的基础。提示词怎么写很关键:
你是一个知识图谱实体抽取器。 给定一篇技术文档片段,抽取其中与研发团队知识库相关的实体。 要求: 1. 只抽取与 Schema 中定义的类型匹配的实体。 2. 输出严格 JSON 数组,格式为 [{"name": "实体名", "type": "实体类型", "attributes": {}}] 3. 属性只能从原文中提取,不能推测。 4. 没有匹配实体时输出 []。 文档片段: {chunk_text}输出示例:
[ { "name": "订单服务", "type": "服务", "attributes": { "负责人": "张三", "技术栈": "Go" } }, { "name": "支付模块", "type": "业务模块", "attributes": { "依赖": "订单服务" } } ]6.3 关系抽取提示词模板
有了实体,第 6 轮就是抽实体之间的关系:
你是一个知识图谱关系抽取器。 给定文档片段和实体列表,抽取实体之间的关系。 要求: 1. 只抽取 Schema 中已有的关系类型。 2. 输出 JSON 数组,格式为 [{"source": "实体A", "relation": "关系类型", "target": "实体B", "evidence": "原文证据"}] 3. evidence 必须是原文中的原句。 实体列表: {entities_json} 文档片段: {chunk_text}关系抽取的核心是“证据”。每条三元组都要能回溯到原文,这正是后续可溯源问答的基础。如果关系没有原文证据,宁可不入库,也不能靠模型脑补。
6.4 图谱入库与校验
三元组生成后,需要写入图数据库。以 Neo4j 为例:
from neo4j import GraphDatabase driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "password")) def create_relationship(tx, source, relation, target): query = ( "MERGE (a:Entity {name: $source}) " "MERGE (b:Entity {name: $target}) " "MERGE (a)-[r:REL {type: $relation}]->(b)" ) tx.run(query, source=source, relation=relation, target=target) triples = [ {"source": "订单服务", "relation": "DEPENDS_ON", "target": "支付模块"}, {"source": "订单服务", "relation": "OWNED_BY", "target": "张三"}, ] with driver.session() as session: for triple in triples: session.execute_write(create_relationship, triple["source"], triple["relation"], triple["target"]) driver.close()入库后要校验:统计三元组数量、检查孤立实体、检查关系类型是否合法。从实际经验看,最容易出问题的不是抽取,而是实体对齐。同一实体在不同文档里写法不同,比如“订单服务”和“订单系统”,需要做实体归一化。
7. 可溯源问答链路
知识图谱构建完成后,问答就不能只靠向量检索了。理想链路是:
- 用户提问。
- 语义检索定位候选文档块。
- 图谱查询获取相关实体和关系路径。
- 把文档证据和图谱证据拼接成上下文。
- LLM 根据证据生成答案,并标注引用来源。
7.1 问答提示词设计
可溯源问答的提示词要强调“证据优先”和“引用标记”:
你是企业知识库问答助手。 回答问题前,先使用提供的文档片段和图谱证据。 要求: 1. 答案必须基于证据,不能编造。 2. 每个关键结论后面加上引用标记,格式为 [来源ID]。 3. 如果证据不足,直接回答“当前知识库中没有找到相关信息”。 4. 保持答案简洁,不要展开无关内容。 图谱证据: {graph_evidence} 文档片段: {chunk_evidence} 用户问题: {question}7.2 Python 调用示例
import requests url = "http://127.0.0.1:8080/api/chat" payload = { "question": "订单服务依赖哪些模块?", "enable_graph": True, "enable_rag": True, "top_k": 5 } response = requests.post(url, json=payload, timeout=60) print(response.json())预期返回结构:
{ "answer": "订单服务依赖支付模块和用户模块。[DOC_001]", "references": [ { "source_id": "DOC_001", "title": "订单服务架构说明", "chunk_index": 12, "evidence": "订单服务依赖支付模块完成交易结算。" } ], "graph_paths": [ { "source": "订单服务", "relation": "DEPENDS_ON", "target": "支付模块" } ] }从实际使用角度看,判断问答链路是否成功的标准有三个:答案是否与原文一致、引用是否能定位到具体文档块、图谱路径是否帮助补充了文档中没有直接出现的关联信息。三个条件缺一不可。
8. 增量编译机制
增量编译是工业级 LLM Wiki 和玩具级知识库的分水岭。只有几千个文档时全量重建可能还行,但文档到几万、几十万时,全量重建的时间和成本完全不可接受。
8.1 增量编译思路
核心思想是“变更检测 + 局部重建”:
- 维护一个文档状态表,记录每个文档的哈希值、上次编译时间、分块数量。
- 新文档或修改文档时,只重新抽取该文档、重算向量、更新图谱。
- 删除文档时,只删除该文档涉及的实体关系和向量索引。
- 下游依赖变更时,比如 Schema 改了,才触发相关范围的局部重建。
8.2 配置示例
incremental_compile: enabled: true watch_dirs: - ./docs/ - ./specs/ poll_interval_seconds: 60 hash_algorithm: sha256 sqlite_db: ./state.db max_batch_chunks: 200 on_change: ["parse", "extract_entities", "extract_relations", "embed", "update_graph"]8.3 编译流程代码逻辑
import hashlib import json def compute_hash(filepath): with open(filepath, "rb") as f: return hashlib.sha256(f.read()).hexdigest() def should_compile(filepath, state): current_hash = compute_hash(filepath) return state.get(filepath) != current_hash def compile_document(filepath): # 1. 读取文档 # 2. 分块 # 3. 实体关系抽取 # 4. 更新向量索引 # 5. 更新知识图谱 # 6. 更新状态表 pass增量编译的关键是状态表必须稳定。进程崩溃、数据库损坏、文件重命名都会影响状态判断。稳妥做法是:状态表落盘、每批任务记录日志、编译完成后统一提交状态,避免半途失败产生脏状态。
9. 在线评估与回归
没有评估的知识库就是黑盒。在线评估的目的是回答三个问题:检索找得到吗?答案答得对吗?引用给得准吗?
9.1 构建评估数据集
评估数据集建议按真实业务问题整理,格式如下:
[ { "question": "订单服务依赖哪些模块?", "expected_entities": ["支付模块", "用户模块"], "expected_answer_keywords": ["支付模块", "用户模块"], "expected_source_ids": ["DOC_001"], "difficulty": "easy" }, { "question": "服务出现故障应该找谁?", "expected_entities": ["张三"], "expected_answer_keywords": ["张三", "负责人"], "expected_source_ids": ["DOC_003"], "difficulty": "medium" } ]9.2 自动化评估脚本
import json import requests eval_set = json.load(open("eval_set.json")) def evaluate_question(q): response = requests.post( "http://127.0.0.1:8080/api/chat", json={"question": q["question"]}, timeout=60 ) data = response.json() answer = data.get("answer", "") refs = data.get("references", []) hit_entities = any(e in answer for e in q["expected_entities"]) has_source = any(r.get("source_id") in q["expected_source_ids"] for r in refs) return { "question": q["question"], "hit_entities": hit_entities, "has_source": has_source, "pass": hit_entities and has_source } results = [evaluate_question(q) for q in eval_set] pass_rate = sum(r["pass"] for r in results) / len(results) print(f"Pass Rate: {pass_rate:.2%}")9.3 常见评估指标
| 指标 | 说明 |
|---|---|
| 实体命中率 | 答案是否包含预期实体 |
| 来源命中率 | 引用是否包含预期文档 |
| 答案相关性 | 答案与问题是否相关,需要人工抽检 |
| 图谱支持度 | 答案是否能从图谱路径推导 |
| 未命中率 | 知识库没有答案时是否正确拒绝 |
在线评估的常见问题是评估集太少。建议每个业务模块至少准备 20 到 50 个问题,并定期补充。评估不能只在发布前跑,每次增量编译后都要跑回归,防止“改一个文档,坏一片回答”。
10. 接口 API 与批量任务
10.1 服务启动
如果项目提供服务化启动方式,常见模式是:
# 启动 Web 服务,具体命令以实际项目为准 pnpm dsh web如果启动过程卡在pnpm dsh web,优先检查依赖是否安装完整、端口是否被占用、启动日志中是否有请求阻塞。
10.2 通用 API 调用模板
下面给出通用调用模板,实际接口路径和参数需要按项目文档调整:
import requests BASE_URL = "http://127.0.0.1:8080" # 文档上传示例 def upload_document(filepath): with open(filepath, "rb") as f: response = requests.post( f"{BASE_URL}/api/documents", files={"file": f}, data={"title": filepath} ) return response.json() # 批量问答示例 def batch_ask(questions): results = [] for q in questions: response = requests.post( f"{BASE_URL}/api/chat", json={"question": q}, timeout=120 ) results.append(response.json()) return results questions = [ "订单服务依赖哪些模块?", "支付模块的负责人是谁?", "部署流程规范是怎样的?" ] answers = batch_ask(questions) print(json.dumps(answers, ensure_ascii=False, indent=2))10.3 批量任务设计建议
批量任务最容易遇到的问题是大批量请求时服务超时、限流、资源耗尽。建议:
- 批量请求控制在 20 到 50 个一组,分批执行。
- 每批之间加短暂间隔,避免突发流量。
- 记录每个请求的日志,包括问题、耗时、状态码、回答摘要。
- 失败的请求自动重试,重试最多 3 次。
- 批量完成后汇总异常,统一排查。
11. 资源占用与性能观察
11.1 观察哪些指标
运行 DeepSeek Harness 时,重点观察以下指标:
| 指标 | 观察方式 |
|---|---|
| CPU 占用 | 系统监控工具或top、任务管理器 |
| 内存占用 | 同上,注意向量索引常驻内存 |
| 显存占用 | nvidia-smi或任务管理器 GPU 信息 |
| 磁盘 IO | 增量编译时注意读写 |
| 接口耗时 | API 返回时间,重点看 p95 |
| 索引构建耗时 | 单文档分块到入库的耗时 |
| 图谱更新延迟 | 新文档到图谱可查询的延迟 |
11.2 显存占用与模型精度
如果你使用本地 LLM,显存占用和模型精度直接相关。FP16 和 BF16 是目前本地部署的主流方式,显存占用大约是 FP32 的一半。BF16 的指数范围和 FP32 一致,训练和推理稳定性更好;FP16 在数值动态范围上有上限,容易出现溢出。实际选用哪种精度,要看模型的训练方式和推理框架支持情况,不能只看显存数字。
更稳妥的判断是:先用 API 服务把整套流程跑通,再根据成本和隐私要求决定是否切换到本地模型。知识图谱构建和增量编译阶段对显存要求不一定高,真正吃显存的是大模型的推理和向量化。资源不足时,可以外接 API,本地只跑检索和图谱查询。
11.3 性能优化方向
- 文档分块大小从 512 降到 256,检索更准但索引量更大。
- 实体抽取使用小模型,问答使用大模型,分层推理。
- 增量编译改成事件触发,不用轮询。
- 向量索引使用 HNSW 参数调优,提高检索速度。
- 图谱查询加缓存,高频问题走缓存。
12. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
pnpm dsh web启动卡住 | 依赖未安装完整、端口被占、网络请求阻塞 | 查看启动日志,检查端口占用 | 重装依赖,换端口,或检查网络连接 |
| 依赖下载慢 | 网络源不稳定 | 查看包管理器日志 | 配置国内镜像源,使用加速源 |
| 模型服务连接失败 | API Key 错误、endpoint 不可达 | 测试模型服务连通性 | 检查配置文件和网络策略 |
| 实体抽取结果为空 | 提示词约束过严、文档无法解析 | 直接测试单条文档块 | 放宽输出要求,检查文档格式 |
| 三元组没有入库 | 关系类型不符合 Schema | 查看抽取日志 | 修正关系类型定义 |
| 回答没有引用来源 | 提示词未强调引用,或检索没有返回证据 | 检查上下文是否包含证据片段 | 调整提示词,增加检索力度 |
| 增量编译不触发 | 文档状态哈希未变化、监听目录错误 | 查看状态表和编译日志 | 检查文件路径、状态表 |
| 评估通过率低 | 评估集和文档口径不一致、提示词不稳定 | 抽检错误case | 补充评估集,优化输出格式 |
| 显存不足 | 模型过大或推理并发过高 | nvidia-smi查看显存 | 降低模型规模,减少并发,或切换 API |
最值得注意的问题是“实体抽取”和“关系抽取”的稳定性。LLM 输出天然有随机性,同样的输入两次结果可能不同。工业级使用一定要做“结构化输出校验”,抽取出 JSON 后先做格式校验,再做 Schema 校验,不合格的重新抽取或人工修复。
13. 最佳实践与合规建议
13.1 工程实践
先把最小闭环跑通:一份文档 → 抽取实体 → 建图谱 → 问答带引用 → 更新文档 → 增量编译 → 评估通过。这 7 个步骤都通了,再扩大文档量。
建议目录结构:
project/ ├── docs/ # 原始文档 ├── chunks/ # 分块结果 ├── entities/ # 实体抽取结果 ├── relations/ # 关系抽取结果 ├── graph/ # 图谱导入脚本与备份 ├── eval/ # 评估数据集与结果 ├── logs/ # 运行日志 └── state.db # 增量编译状态表批量任务一定要加日志和失败重试。知识库更新不应该静默失败,增量编译的每个环节都要有可追踪日志。接口服务要限制访问范围,至少做访问控制,避免内部知识库暴露到公网。
13.2 合规提醒
涉及知识图谱、文档检索、可溯源问答时,不要忽略内容来源。常见合规风险有两类:
一是版权风险。文档库中如果包含他人文章、教程、书籍内容,构建知识图谱和问答系统时不能直接商用,需要确认授权范围。即使是内部使用,也要注意来源标注。
二是隐私与敏感信息。个人信息、账号信息、内部安全信息不应该进入知识库。建议在文档入库前做敏感信息扫描,启用数据脱敏,设置访问权限。可溯源问答的“证据”设计,反过来也要求系统能定位到具体文档,所以必须有审计能力和删除能力——用户要求删除某条数据时,图数据库、向量索引和文档副本要能同步清除。
14. 总结与下一步
DeepSeek Harness 做 LLM Wiki 的完整链路,最有价值的点在于把知识库从“能问能答”提升到“可增量维护、可评估回归”的工程系统。10 轮提示迭代作为方法论,每一轮都解决一个独立问题,最终把文档变成知识图谱加可溯源问答的闭环。
如果你要上手,最先应该验证的是知识图谱构建和可溯源问答。这两个功能直接决定知识库有没有超出普通向量检索的价值。最容易踩的坑是文档分块策略和实体抽取的稳定性,建议先小规模测试,再逐步扩大范围。
下一步可以尝试的方向包括:把评估集扩充到更多业务模块、接入更多向量模型做效果对比、让知识图谱支持多版本文档对比、增加多轮对话中的上下文记忆、将评估结果接入 CI 实现每次文档更新自动回归。增量编译和在线评估都跑通后,这套 LLM Wiki 方案才真正具备工业级落地条件。