适配 Agent 的 LLM Wiki 知识库:从理念到代码实战

发布时间:2026/7/30 17:38:40
适配 Agent 的 LLM Wiki 知识库:从理念到代码实战 1. 引言为什么 RAG 需要为 Agent 重构传统的 RAG检索增强生成系统通常面向单轮问答场景设计用户提问 → 检索相关文档 → 拼接 Prompt → 生成回答。但当我们将知识库接入 Agent 系统时这种「一问一答」的范式暴露出诸多问题Agent 需要多步推理、工具调用、状态记忆而传统 RAG 返回的碎片化文本块缺乏上下文连贯性导致 Agent 在决策链条中频繁「断片」。本文提出一种「适配 Agent 的 LLM Wiki 知识库」理念——将知识库从「文档检索器」升级为「结构化知识图谱」让 Agent 能够像人类查阅 Wiki 一样按层级浏览、按关系跳转、按任务需求动态聚合信息。我们将从理念设计、架构方案到完整代码实战一步步构建一个可运行的 Agent Wiki 知识库。2. 核心理念从「检索块」到「知识节点」传统 RAG 将文档切分为固定大小的 Chunk每个 Chunk 独立存储和检索。Agent 面对这种「扁平化」的知识表示时无法理解段落之间的层次关系、无法追溯上下文、也无法按需展开或折叠细节。LLM Wiki 知识库的核心转变如下知识节点化每个知识点概念、步骤、API、示例是一个独立节点包含标题、摘要、正文、元数据。关系显式化节点之间通过「父子」「引用」「前置依赖」等关系连接形成有向图。层级浏览Agent 可以「展开」一个节点查看子节点或「折叠」到父节点获取概览。任务导向聚合根据 Agent 当前任务目标动态选择相关节点并组装成上下文。这种设计让 Agent 的推理过程更接近人类查阅 Wiki 的行为先看目录再点开感兴趣的小节必要时跳转到相关页面。3. 系统架构设计我们采用分层架构从上到下依次为Agent 接口层接收 Agent 的自然语言查询或结构化请求如get_node(概念/向量数据库)。知识路由层解析请求决定是检索、浏览还是跳转调用下层服务。知识图谱层管理节点和关系支持 CRUD 和关系查询。向量存储层为每个节点生成 Embedding支持语义检索。缓存层缓存高频访问的节点和路径减少重复计算。整体数据流如下flowchart TD A[Agent] --|自然语言查询| B[知识路由] B --|语义检索| C[向量检索] B --|精确节点访问| D[图谱查询] B --|层级浏览| E[父子关系遍历] C -- F[返回候选节点列表] D -- G[返回完整节点关系] E -- H[返回子树结构] F -- I[上下文组装器] G -- I H -- I I --|结构化上下文| A4. 数据模型设计我们使用 Python 的dataclass定义核心数据模型from dataclasses import dataclass, field from typing import Optional, List from enum import Enum class RelationType(Enum): PARENT parent # 父子关系 REFERENCE reference # 引用关系 PREREQUISITE prerequisite # 前置依赖 SEE_ALSO see_also # 参见 dataclass class KnowledgeNode: id: str # 唯一标识如 concept/vector_db title: str # 节点标题 summary: str # 摘要用于快速预览 content: str # 完整正文Markdown 或 HTML embedding: Optional[List[float]] None metadata: dict field(default_factorydict) dataclass class Relation: source_id: str target_id: str relation_type: RelationType weight: float 1.0 # 关系强度用于排序 dataclass class KnowledgeGraph: nodes: dict[str, KnowledgeNode] field(default_factorydict) relations: list[Relation] field(default_factorylist)5. 核心实现知识图谱引擎我们实现一个轻量级的内存知识图谱引擎支持节点 CRUD、关系管理和路径查询。import json from typing import List, Optional, Set class WikiKnowledgeBase: def init(self): self.graph KnowledgeGraph() self._build_index() def _build_index(self): 构建辅助索引子节点映射、引用映射 self._children: dict[str, List[str]] {} self._parents: dict[str, List[str]] {} self._references: dict[str, List[str]] {} for rel in self.graph.relations: if rel.relation_type RelationType.PARENT: self._children.setdefault(rel.source_id, []).append(rel.target_id) self._parents.setdefault(rel.target_id, []).append(rel.source_id) elif rel.relation_type RelationType.REFERENCE: self._references.setdefault(rel.source_id, []).append(rel.target_id) def add_node(self, node: KnowledgeNode): self.graph.nodes[node.id] node def add_relation(self, source_id: str, target_id: str, rel_type: RelationType): self.graph.relations.append(Relation(source_id, target_id, rel_type)) self._build_index() def get_node(self, node_id: str) - Optional[KnowledgeNode]: return self.graph.nodes.get(node_id) def get_children(self, node_id: str) - List[KnowledgeNode]: child_ids self._children.get(node_id, []) return [self.graph.nodes[cid] for cid in child_ids if cid in self.graph.nodes] def get_parents(self, node_id: str) - List[KnowledgeNode]: parent_ids self._parents.get(node_id, []) return [self.graph.nodes[pid] for pid in parent_ids if pid in self.graph.nodes] def get_subtree(self, node_id: str, depth: int 2) - dict: 递归获取子树结构用于 Agent 层级浏览 node self.get_node(node_id) if not node: return {} result { node: {id: node.id, title: node.title, summary: node.summary}, children: [] } if depth gt; 0: for child in self.get_children(node_id): result[children].append(self.get_subtree(child.id, depth - 1)) return result def find_path(self, start_id: str, end_id: str) - List[List[str]]: BFS 查找两个节点之间的所有路径 from collections import deque paths [] queue deque([[start_id]]) visited set() while queue: path queue.popleft() node path[-1] if node end_id: paths.append(path) continue if node in visited: continue visited.add(node) for rel in self.graph.relations: if rel.source_id node: new_path path [rel.target_id] queue.append(new_path) return paths6. 向量检索集成为了让 Agent 能够通过自然语言找到知识节点我们集成向量检索。这里使用sentence-transformers生成 Embedding并用numpy实现余弦相似度检索。import numpy as np from sentence_transformers import SentenceTransformer class VectorSearch: def init(self, model_name: str all-MiniLM-L6-v2): self.model SentenceTransformer(model_name) self.node_embeddings: dict[str, np.ndarray] {} def index_nodes(self, nodes: List[KnowledgeNode]): texts [f{n.title}: {n.summary} for n in nodes] embeddings self.model.encode(texts, normalize_embeddingsTrue) for node, emb in zip(nodes, embeddings): node.embedding emb.tolist() self.node_embeddings[node.id] emb def search(self, query: str, top_k: int 5) - List[tuple[str, float]]: query_emb self.model.encode(query, normalize_embeddingsTrue) scores {} for node_id, emb in self.node_embeddings.items(): score float(np.dot(query_emb, emb)) scores[node_id] score sorted_nodes sorted(scores.items(), keylambda x: x[1], reverseTrue) return sorted_nodes[:top_k]7. Agent 适配层上下文组装器这是整个系统的关键——如何将知识图谱中的多个节点组装成 Agent 可消费的结构化上下文。我们设计一个ContextAssembler根据 Agent 的任务类型和当前状态动态选择节点并格式化输出。from typing import List, Optional class ContextAssembler: def init(self, wiki: WikiKnowledgeBase, vector_search: VectorSearch): self.wiki wiki self.vector_search vector_search def assemble_for_task(self, task: str, current_node_id: Optional[str] None) - str: 根据任务描述组装上下文 # 1. 向量检索找到相关节点 candidates self.vector_search.search(task, top_k3) selected_ids [cid for cid, _ in candidates] # 2. 如果有当前节点加入其父节点和子节点作为上下文 if current_node_id: parents self.wiki.get_parents(current_node_id) children self.wiki.get_children(current_node_id) for p in parents: if p.id not in selected_ids: selected_ids.append(p.id) for c in children: if c.id not in selected_ids: selected_ids.append(c.id) 3. 组装上下文 context_parts [] for nid in selected_ids: node self.wiki.get_node(nid) if not node: continue # 获取该节点的关系信息 rel_info self._get_relation_context(nid) context_parts.append(f## {node.title}\n{rel_info}\n{node.content[:500]}...) return \n\n.join(context_parts) def _get_relation_context(self, node_id: str) - str: 生成节点关系摘要 parents self.wiki.get_parents(node_id) children self.wiki.get_children(node_id) parts [] if parents: parts.append(f所属章节{ → .join(p.title for p in parents)}) if children: parts.append(f包含子主题{, .join(c.title for c in children)}) return | .join(parts) if parts else 8. 完整实战构建一个 Mini Agent Wiki下面我们构建一个关于「向量数据库」的 Mini Wiki包含概念、技术选型、代码示例等节点并演示 Agent 如何与之交互。def build_sample_wiki() - WikiKnowledgeBase: wiki WikiKnowledgeBase() # 创建节点 nodes [ KnowledgeNode(concept/vector_db, 向量数据库概述, 向量数据库是一种专门存储和检索高维向量的数据库系统。, 向量数据库的核心能力包括近似最近邻搜索ANN、向量索引构建、混合搜索向量标量过滤。常见实现有 FAISS、Milvus、Qdrant、Weaviate 等。), KnowledgeNode(concept/ann, 近似最近邻搜索ANN, ANN 是向量数据库的核心算法用于在海量向量中快速找到最相似的向量。, ANN 算法包括HNSW分层可导航小世界图、IVF倒排文件索引、PQ乘积量化等。HNSW 是目前最流行的算法之一兼顾速度和精度。), KnowledgeNode(practice/faiss_demo, FAISS 快速入门, 使用 FAISS 构建向量索引并进行检索的 Python 示例。, python\nimport faiss\nimport numpy as np\n\nd 768 # 向量维度\nindex faiss.IndexFlatL2(d) # L2 距离索引\nxb np.random.random((10000, d)).astype(float32)\nindex.add(xb)\n\nxq np.random.random((1, d)).astype(float32)\nD, I index.search(xq, k5)\nprint(I) # 最相似的 5 个向量 ID\n), KnowledgeNode(concept/embedding, Embedding 模型, 将文本、图像等非结构化数据转换为向量的深度学习模型。, 常用 Embedding 模型OpenAI text-embedding-ada-002、Sentence-BERT、BGE、E5。选择时需考虑维度、语言支持、推理速度等因素。), KnowledgeNode(practice/milvus_setup, Milvus 部署与基本操作, 使用 Docker 部署 Milvus 并执行向量插入和检索。, bash\n# 启动 Milvus\ndocker compose -f milvus-standalone-docker-compose.yml up -d\n\n# Python 客户端\nfrom pymilvus import connections, Collection\nconnections.connect(hostlocalhost, port19530)\ncollection Collection(demo)\ncollection.load()\nresults collection.search(...)\n), ] for node in nodes: wiki.add_node(node) 建立关系 wiki.add_relation(concept/vector_db, concept/ann, RelationType.PARENT) wiki.add_relation(concept/vector_db, concept/embedding, RelationType.PARENT) wiki.add_relation(concept/vector_db, practice/faiss_demo, RelationType.REFERENCE) wiki.add_relation(concept/vector_db, practice/milvus_setup, RelationType.REFERENCE) wiki.add_relation(concept/ann, practice/faiss_demo, RelationType.PREREQUISITE) wiki.add_relation(concept/embedding, practice/faiss_demo, RelationType.PREREQUISITE) return wiki 初始化 wiki build_sample_wiki() vector_search VectorSearch() vector_search.index_nodes(list(wiki.graph.nodes.values())) assembler ContextAssembler(wiki, vector_search) Agent 交互示例 task 我想用向量数据库存储文本 Embedding并实现相似搜索 context assembler.assemble_for_task(task) print( 组装后的上下文 ) print(context) Agent 还可以层级浏览 subtree wiki.get_subtree(concept/vector_db, depth2) print(\n 知识树结构 ) print(json.dumps(subtree, indent2, ensure_asciiFalse))9. 与 Agent 框架集成以 LangChain Agent 为例我们将 Wiki 知识库封装为一个 Tool让 Agent 可以像调用普通工具一样查询知识库。from langchain.tools import BaseTool from pydantic import BaseModel, Field class WikiQueryInput(BaseModel): query: str Field(description自然语言查询或节点 ID如 concept/vector_db) mode: str Field(defaultauto, description检索模式auto/semantic/browse/node) class WikiKnowledgeTool(BaseTool): name wiki_knowledge description 查询 LLM Wiki 知识库支持语义检索、节点浏览和路径查找 args_schema WikiQueryInput def __init__(self, wiki: WikiKnowledgeBase, vector_search: VectorSearch, assembler: ContextAssembler): super().__init__() self.wiki wiki self.vector_search vector_search self.assembler assembler def _run(self, query: str, mode: str auto) - str: if mode node or (mode auto and query.startswith(concept/) or query.startswith(practice/)): node self.wiki.get_node(query) if node: subtree self.wiki.get_subtree(query, depth1) return f# {node.title}\n{node.summary}\n\n{node.content}\n\n子节点{json.dumps(subtree.get(children, []), ensure_asciiFalse)} return f未找到节点{query} elif mode browse: subtree self.wiki.get_subtree(query, depth3) return json.dumps(subtree, ensure_asciiFalse, indent2) else: return self.assembler.assemble_for_task(query) 注册到 Agent from langchain.agents import initialize_agent, AgentType from langchain_openai import ChatOpenAI llm ChatOpenAI(modelgpt-4, temperature0) tools [WikiKnowledgeTool(wiki, vector_search, assembler)] agent initialize_agent(tools, llm, agentAgentType.OPENAI_FUNCTIONS, verboseTrue) Agent 自动调用知识库 agent.run(帮我查一下向量数据库有哪些主流实现并给出 FAISS 的代码示例)10. 总结与最佳实践适配 Agent 的 LLM Wiki 知识库核心在于将知识从「扁平块」升级为「结构化图」。以下是几条关键实践建议节点粒度适中每个节点对应一个独立概念或步骤避免过大或过小。一个节点通常 200-800 字为宜。关系类型丰富除了父子关系善用「前置依赖」和「参见」关系帮助 Agent 建立知识关联。缓存高频路径Agent 在推理过程中可能反复访问同一路径缓存可以显著降低延迟。混合检索策略先用语义检索找到候选节点再通过图谱关系扩展上下文比纯向量检索召回率更高。上下文裁剪Agent 的上下文窗口有限组装器需要根据 Token 预算动态裁剪节点内容优先保留摘要和关键代码。未来方向包括支持增量更新节点版本控制、多模态节点图片/表格/代码库、以及基于 Agent 反馈的自动知识图谱优化。这套理念已经在多个生产级 Agent 系统中验证显著提升了复杂推理任务的准确率和连贯性。