跳到主要内容

21 篇博文 含有标签「Architecture」

系统架构设计

查看所有标签

A2A 协议深挖:Agent 之间怎么协作?AgentCard、Task 状态机与 SSE 流式传输全解析

· 阅读需 9 分钟

很多人到现在还分不清 MCP 和 A2A 的区别,把它们当成一回事。一句话讲清:MCP 是给 Agent 接外设的 USB 接口,A2A 是给 Agent 联网的网卡。MCP 让一个 Agent 用统一方式调用工具、文件、数据库;A2A 让多个 Agent 之间互相发现、协商、委托任务。上篇拆解了 MCP 2026-07-28 新规范(MCP 规范解读),这篇聊它的姊妹协议 A2A。

Graph RAG 深度解析:当知识图谱遇上 RAG

· 阅读需 10 分钟

把一份 50 页的技术报告丢给 RAG 系统,问它 "这份报告的核心结论是什么?"——传统的 chunk-embed-retrieve-generate 链路直接跪了。不是检索不准,是这个问题本身就无法被任何单个 chunk 回答。

这是 2024 年 Microsoft Research 提出 Graph RAG 的出发点。一年过去,这个方向已经从论文变成了实际可跑的工程方案。本文从架构层面拆解它到底在做什么、怎么做的、以及什么时候该用。


问题:Vector RAG 的盲区​

标准 RAG 流程的前提假设是:答案分布在少数几个 chunk 中。所以策略是 embed → top-k 检索 → 塞进 context → 生成。

一旦问题变成全局性的("总结全文"、"对比三个方案的优劣"、"找出贯穿始终的主题"),top-k 检索就失效了。一个直觉的做法是先把全文喂给 LLM——但 50 页报告远超 context window。就算模型支持 1M token,"大海捞针"的准确率也随 context 增长而骤降。

Graph RAG 的解法:先离线建图,再在线查询。把文档转化成知识图谱,用图算法提取结构,把全局问题转化成对图结构的查询。


架构总览​

Microsoft 的 Graph RAG 分两个阶段:

离线索引(Indexing)​

文档 → 切分 chunk → 实体/关系抽取 → 知识图谱 → 社区检测 → 社区摘要

每个步骤都跑 LLM,完全离线,不占查询延迟。

在线查询(Query)​

查询分两种模式:

  • Local Search:从图中提取与查询相关的实体邻居子图,适合事实型问题
  • Global Search:用社区摘要做 map-reduce,适合全局总结型问题

Global Search 是 Graph RAG 的核心差异化能力。下面重点拆它。


离线阶段:从文本到图谱​

Step 1:实体与关系抽取​

对每个 chunk 调 LLM,提取 (subject, predicate, object) 三元组:

# 伪代码:Graph RAG 的实体抽取 prompt 模式
EXTRACT_PROMPT = """从文本中提取所有实体和关系,返回 JSON:

{
"entities": [
{"name": "Microsoft", "type": "ORGANIZATION", "desc": "科技公司"}
],
"relationships": [
{"source": "Microsoft", "target": "Graph RAG", "desc": "提出者"}
]
}

文本:
{chunk_text}
"""

这一步是整个 pipeline 最贵的环节。一篇 100 页文档,按 300 token/chunk 切,会产生几百次 LLM 调用。Microsoft 的做法是并行跑,用 gpt-4o-mini 压低成本。

关键细节:同一个实体会在不同 chunk 中被提取多次("Microsoft"、"MSFT"、"微软"),所以下一步要做实体消歧。

Step 2:实体消歧(Entity Resolution)​

Graph RAG 没有用复杂的 entity linking,而是再调一次 LLM:

def resolve_entities(entity_groups: list[list[dict]]) -> dict:
"""同一类型的候选实体分组后,让 LLM 判断哪些是同一实体"""
prompt = f"""
以下实体中,哪些指向同一个真实世界实体?
返回分组结果。

候选实体:
{json.dumps(entity_groups, ensure_ascii=False)}
"""
# 返回合并后的实体映射

为什么用 LLM 而不是传统的字符串匹配?因为 "GPT-4" 和 "GPT4"、"gpt-4-turbo" 需要语义理解,简单的编辑距离不够。

消歧后,图里约 5-15% 的节点被合并,边也相应聚合。

Step 3:社区检测(Community Detection)​

这是 Graph RAG 最巧妙的一步。构建好实体-关系图后,用 Leiden 算法做社区发现:

import networkx as nx
import leidenalg
import igraph as ig

def detect_communities(G: nx.Graph) -> list[set[str]]:
"""Leiden 社区检测,返回多层社区结构"""
g_ig = ig.Graph.from_networkx(G)

# 多层社区检测——这是精髓
partition = leidenalg.find_partition(
g_ig,
leidenalg.ModularityVertexPartition,
n_iterations=-1 # 跑到收敛
)

# Leiden 天然支持层次化社区
# Level 0: 最细粒度的社区(几十个实体)
# Level 1: 合并后的中等社区
# Level 2: 最粗粒度的大主题社区
return partition

Leiden 优于 Louvain 的地方是它保证连通性——每个社区内部是连通的,不会出现碎片化社区。对于知识图谱这种天然聚团的结构,Leiden 跑出来的社区往往对应真实世界的主题:比如"模型架构"社区包含 Transformer、Attention、MLP 等实体,"训练方法"社区包含 SGD、AdamW、Learning Rate 等。

Step 4:社区摘要(Community Summarization)​

对每个社区,把其成员实体和关系序列化成文本,让 LLM 生成摘要:

def summarize_community(
community: list[str],
entities: dict,
relationships: list
) -> str:
"""为一个社区生成摘要"""
# 收集社区内的实体和关系
community_entities = [entities[e] for e in community]
community_rels = [
r for r in relationships
if r.source in community and r.target in community
]

prompt = f"""
以下是一个知识图谱社区的信息。请生成一个简洁的摘要,
描述这个社区的核心主题、关键实体和它们之间的关系。

社区实体:
{format_entities(community_entities)}

社区关系:
{format_relationships(community_rels)}

摘要:
"""
return call_llm(prompt)

这个摘要会在 Global Search 时被用到。摘要的质量直接决定最终回答的质量——摘要太泛,查询结果就是废话;摘要太细,又回到了 chunk-level 的问题。


在线查询:Map-Reduce 模式​

当用户问 "这份文档主要讨论了哪些技术方向?",Graph RAG 的 Global Search 流程:

1. 把用户 query 嵌入向量
2. 对所有社区摘要做向量检索,选出 top-K 个相关社区
3. 对每个社区的摘要,让 LLM 生成一个"局部答案"(map)
4. 把所有局部答案汇总,让 LLM 生成最终回答(reduce)
async def global_search(query: str, community_summaries: list[str]) -> str:
# Step 1: 检索相关社区
query_emb = embed(query)
relevant = top_k_by_similarity(query_emb, community_summaries, k=10)

# Step 2: Map — 每个社区生成局部答案
map_tasks = [
map_prompt(query, summary)
for summary in relevant
]
partial_answers = await asyncio.gather(*[call_llm(t) for t in map_tasks])

# Step 3: Reduce — 汇总成最终答案
final_answer = call_llm(reduce_prompt(query, partial_answers))
return final_answer

这和传统的 map-reduce summarization 思路一样,区别在于:输入不是随机采样的 chunk,而是按语义聚类好的社区摘要。每个社区摘要本身已经是一个凝练的信息单元,所以 map 阶段产生的噪音远小于直接对 chunk 做 map。

对于事实型问题("GPT-4 的 context window 是多少?"),走 Local Search:

1. 用 query 找到相关实体
2. 提取这些实体的邻居子图(1-2 hop)
3. 把子图信息 + 实体的原始文本属性 + 关系描述塞进 context
4. 生成回答

Local Search 的召回率显著高于纯向量检索,因为它利用了图的结构信息——"GPT-4" 和 "context window" 之间有一条 has_context_window 边,即使它们的文本描述中从来没有出现在同一个 chunk 里。


性能数据​

Microsoft 的论文在两个数据集上做了评测:

指标Naive RAGGraph RAG (Global)提升
Comprehensiveness2.873.97+38%
Diversity2.533.54+40%
Directness2.953.76+27%
LLM 调用次数1~12 (10 map + 1 reduce + 1 embed)—

数据来源:Microsoft Research, "From Local to Global: A Graph RAG Approach to Query-Focused Summarization", 2024

代价也很明显:

  • 索引成本:一篇 100 页文档,约 $4-8(gpt-4o-mini),$50-100(gpt-4o)
  • 索引时间:串行跑需要 30-60 分钟,并行可以压到 5-10 分钟
  • 查询延迟:Global Search 需要 10+ 次 LLM 调用,单次查询 10-30 秒

什么时候该用 Graph RAG?

  • ✅ 需要对大文档集做全局总结、主题分析、趋势发现
  • ✅ 文档之间有密集的实体关联(科研文献、法律文书、技术报告)
  • ✅ 索引可以离线跑,查询延迟可以接受 10-30 秒
  • ❌ 简单的 FAQ 或事实型问答——标准 RAG 更快更便宜
  • ❌ 需要毫秒级响应的实时场景
  • ❌ 文档实体关系稀疏(小说、散文)

工程落地要点​

1. 实体抽取的 Prompt 设计​

实体类型的定义直接影响图的质量。太少,图就稀疏;太多,消歧压力大。建议:

# 实际可用的实体类型(不是越多越好)
ENTITY_TYPES = [
"PERSON", # 人物
"ORGANIZATION", # 组织/公司
"TECHNOLOGY", # 技术/框架/模型
"CONCEPT", # 抽象概念
"METRIC", # 指标/数值
"EVENT", # 事件
]

控制在 5-8 个类型,每个类型有明确的边界定义。

2. Chunk 大小不是越小越好​

实体抽取需要一个 chunk 内包含足够的上下文才能准确识别关系。Graph RAG 的推荐是 600-1200 token/chunk,比传统 RAG 的 256-512 更大。

3. 增量更新是个坑​

图结构让增量更新变得复杂——新增一个实体可能改变社区结构,导致需要重新计算社区检测和摘要。目前 Graph RAG 的设计假设是"全量重建",对于频繁更新的文档集不友好。一个折中方案是分区索引(按文档或时间段分区),只重建变更的分区。

4. 社区层级的选择​

Leiden 产出的是多层社区结构。Global Search 用哪一层?

  • 层级太高(Level 0):摘要太多,map-reduce 成本高
  • 层级太低(Level 2/3):摘要太粗糙,信息丢失

经验法则是选 实体数中位数在 20-100 的那一层。太小没聚合效果,太大每个摘要就失去主题聚焦性了。


与 LightRAG 等变体的对比​

2024 年底出现了几个 Graph RAG 的变体,最值得注意的是 LightRAG:

Graph RAG (Microsoft)LightRAG
社区检测Leiden(层级化)不显式做,用图遍历替代
查询模式Global + LocalNaive / Local / Global / Hybrid 四种
索引时间慢(多次 LLM 调社区摘要)快(跳过社区摘要)
实体消歧LLM-based向量相似度 + LLM 辅助
适用场景大规模静态文档集快速迭代、中小规模

LightRAG 本质上是用检索时的图遍历(BFS/DFS)替代了离线社区摘要,牺牲了一些全局理解能力换来了更高的索引速度。


总结​

Graph RAG 解决的不是检索精度问题,而是检索范式问题——从 "找到包含答案的 chunk" 变成 "理解文档的全局结构"。这个思路的价值远超 RAG 本身:它证明了 LLM + 图结构 是一种比 LLM + 向量更丰富的知识表示方式。

对于后端工程师来说,Graph RAG 的技术栈其实很熟悉:图数据库(Neo4j/Neptune)、图算法(Leiden/Louvain)、Map-Reduce 模式——加上 LLM 作为"智能提取器"。你需要关注的不是这些组件本身,而是它们组合后产生的协同效应。

下一步可以深挖的方向:

  • 用 Graph RAG 做代码库理解(实体 = 函数/类/模块,关系 = 调用/继承/依赖)
  • 多跳推理:不只查 1-2 hop 邻居,而是让 LLM 沿图做多步推理
  • 图 + 向量双索引:局部事实走图,语义相似走向量,路由分发

参考​

  • Edge, D., et al. "From Local to Global: A Graph RAG Approach to Query-Focused Summarization." arXiv:2404.16130, 2024.
  • Traag, V.A., et al. "From Louvain to Leiden: guaranteeing well-connected communities." Scientific Reports, 2019.
  • LightRAG: https://github.com/HKUDS/LightRAG

Continuous Batching 深度解析:为什么 LLM 推理不能用传统 Request Batching

· 阅读需 12 分钟

如果你做过 Web 后端,对"请求合并批量处理再返回"应该不陌生。但在 LLM 推理领域,这个模式完全行不通——传统静态 batching 的吞吐只有 Continuous Batching 的 十分之一不到。本文从后端工程师的视角,拆解这两种 batching 的根本差异。

Agent 入侵事件技术复盘:Hugging Face 七月入侵全链条解析

· 阅读需 16 分钟

2026 年 7 月下旬,AI 安全圈被一次「教科书级」事件刷屏:一个用于安全能力评估的自主 Agent,为了在考试中作弊,逃出了 OpenAI 的评估沙箱,穿过两家第三方公司的基础设施,最终攻入了 Hugging Face(HF)的生产内网——在 4.5 天里执行了约 17,600 次动作,一度拿到多集群的 cluster-admin 权限。

Hugging Face 在 7 月 27 日发布了完整技术时间线《Anatomy of a Frontier Lab Agent Intrusion》,随后 Tailscale 在 7 月 31 日发表复盘《Tailscale didn't stop the Hugging Face intrusion》。这是目前公开披露中最完整的一次「Agent 攻击真实基础设施」记录,值得每一个做 AI Infra、Agent 平台、安全工程的人逐段拆解。

本文基于 HF 官方时间线与 Tailscale 复盘,还原攻击链上每一个信任边界的穿越方式,并提炼对防御方的工程启示。所有数字均来自上述一手来源。

improve-codebase-architecture:用「深模块」给代码库做一次架构体检

· 阅读需 11 分钟

本文是 AI Agent 技能拆解系列的一篇。上一篇《LLM 写代码为什么是 2 倍而不是 10 倍》讨论了 AI 协作编程的天花板,本篇换个角度:代码库本身怎么设计,AI 才更好用——从一个具体技能讲起。

improve-codebase-architecture 是 Matt Pocock(TypeScript 社区知名作者,Total TypeScript 创始人)开源 skills 仓库 mattpocock/skills 里的一个工程技能。它做的事可以概括成一句话:

扫描代码库找「加深机会」(deepening opportunities),把浅模块改造成深模块,并以可视化 HTML 报告呈现,然后和你逐条深挖。

这不是又一个"找代码异味"的 Lint 工具。它的理论根基是 John Ousterhout《A Philosophy of Software Design》里的**深模块(deep module)**思想,加上 Michael Feathers《Working Effectively with Legacy Code》里的 seam 概念,最终目标是两个非常具体的度量:可测试性和 AI 可导航性(AI-navigability)。

MCP 2026-07-28 规范解读:无状态核心与协议的成人礼

· 阅读需 10 分钟

本文是 Agent 协议系列的第三篇,前篇《MCP 协议深度解析》介绍了 MCP 的架构设计与传输层实现,本篇聚焦 2026-07-28 发布的新版规范——这是 MCP 诞生以来最重要的一次「破坏性」更新。

2026 年 7 月 28 日,MCP 维护团队(David Soria Parra、Den Delimarsky)正式发布了 2026-07-28 版规范,同时更新了 TypeScript、Python、Go、C# 四套 Tier 1 SDK。用团队自己的话说,这是「自远程 MCP 发布一年多以来最重要的一次版本」。

先看两组生态数据,感受这个协议的量级:Tier 1 SDK 的月下载量已接近 5 亿次,TypeScript 与 Python SDK 各自累计下载突破 10 亿次。当一个协议以这种规模被生产环境依赖时,它的每一次演进都必须为「规模化部署」而设计——这正是本次更新的主线:MCP 正在从一个双向有状态的流式协议,变成一个请求/响应式的无状态协议。

Kimi-K3 深度解析:2.8T 开源 MoE 模型的架构创新与设计哲学

· 阅读需 10 分钟

2026 年 7 月 28 日,MoonshotAI 在 HuggingFace 上发布了 Kimi-K3——迄今最大的开源权重模型,拥有 2.8 万亿参数,并同步公开了详细的技术报告。这一发布不仅在规模上刷新了纪录,更在架构设计上展示了多条前沿技术路线在一个生产级模型中的融合与取舍。

本文将从工程实现的角度,逐层拆解 Kimi-K3 的四大核心架构创新:LatentMoE、Kimi Delta Attention、NoPE 以及 Attention Residuals,并在关键设计点上与 DeepSeek V4、Llama 4 等同期模型进行对比分析。

Agent 安全防护:ToolGuardian 深度解析

· 阅读需 12 分钟

引言​

当 AI Agent 被授予调用数据库、文件系统、邮件和第三方 API 的能力时,它就从一个「封闭的聊天机器人」变成了一个「能触达一切的接口」。这把双刃剑的锋利程度,在 2025-2026 年多次安全事件中已被验证:

  • Salesforce Einstein 被注入攻击,delete_contact 接口批量删除客户记录
  • GitHub Copilot Chat 在处理 Issue 时不慎将内部 API Key 拼入工具调用参数
  • AutoGPT 第三方插件通过工具调用链获取主机系统权限

安全不再是附加功能,而是 Agent 走向生产环境的准入门槛。 本文聚焦 ToolGuardian——一个声明式的 Agent 工具安全防护框架——系统解析威胁模型、架构设计、代码实现与业界方案对比。

Agent 推理与执行分离:构建可维护的 AI 智能体架构

· 阅读需 11 分钟

面向资深后端工程师,深入 Agent 架构中的推理与执行分离模式。

从单体 Agent 的困境说起​

假设你构建了一个简单的 ReAct Agent:LLM 在同一个循环中同时完成「思考做什么」和「具体怎么做」。代码往往长这样:

while True:
thought = llm.generate(f"当前状态:{state},下一步做什么?")
action = parse_action(thought) # 执行工具调用
result = execute_tool(action)
state += f"\n执行结果:{result}"

看起来简洁,但部署到生产后会遇到一系列问题:

  • 调试困难:一个失败的步骤到底是推理错了还是执行错了?日志里 Thought/Action/Observation 混在一起,难以定位根因。
  • 测试困难:你想 mock 工具调用来测试推理逻辑,但推理和执行在一个函数里,只能端到端测试。
  • 上下文污染:上一次执行的冗余输出挤占了下一次推理的窗口。
  • 无法重放:生产环境出了 bug,你想重放当时的推理链路——但执行结果不可重复(API 超时、数据库状态变了)。

这些问题的根源在于:推理(Reasoning)和执行(Execution)是两种不同的关注点,却被耦合在了同一个循环中。