<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>AI Agents on On My Way</title>
    <link>https://tuanzi-wow.cn/tags/ai-agents/</link>
    <description>Recent content in AI Agents on On My Way</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <atom:link href="https://tuanzi-wow.cn/tags/ai-agents/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Agent的概念与生态</title>
      <link>https://tuanzi-wow.cn/agent/%E5%B0%8F%E6%9E%97coding/agent/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/agent/%E5%B0%8F%E6%9E%97coding/agent/</guid>
      <description>1.只具有生产能力而不具有执行能力 2.没有记忆,局限于上下文窗口 3.不会用tools 4.不会规划 LLM在循环中自主使用工具的系统(有点太浅了) 针对上面四个问题: 1.function call 2.记忆系统 3.MCP等协议 4.任务规划和拆解能力 1.核心:LLM:理解意图,判断推理 2.规划模块:把复杂任务拆解为可执行...</description>
      <content:encoded><![CDATA[<h1 id="agent的概念与生态">Agent的概念与生态</h1>
<h2 id="llm的弊端">LLM的弊端:</h2>
<p>1.只具有生产能力而不具有执行能力
2.没有记忆,局限于上下文窗口
3.不会用tools
4.不会规划</p>
<h2 id="agent">Agent:</h2>
<p>LLM在循环中自主使用工具的系统(有点太浅了)</p>
<p>针对上面四个问题:
1.function call
2.记忆系统
3.MCP等协议
4.任务规划和拆解能力</p>
<h3 id="组成">组成:</h3>
<p>1.核心:LLM:理解意图,判断推理
2.规划模块:把复杂任务拆解为可执行的步骤
3.记忆模块:负责存储和检索信息
4.工具模块:与外部世界互动</p>
<h2 id="agent和workflow的区别">Agent和Workflow的区别</h2>
<p>Workflow:指LLM和工具通过预定义的代码路径进行编排的系统
Agent:指LLM动态主导自身流程与工具调用的系统,由LLM自主决定如何完成任务</p>
<p>Workflow是预先定义好的,按照固定的顺序执行;agent是由LLM自主动态规划的,且是循环的</p>
<h3 id="什么时候用agent什么时候用workflow">什么时候用Agent,什么时候用Workflow</h3>
<p><strong>从最简单的方案开始，只在明确需要时才增加复杂度</strong></p>
<p>如果任务步骤是固定的、可以提前规划好的，或者对可靠性要求很高（比如金融交易、医疗系统），那就用 Workflow。如果任务是开放式的、无法预知所有步骤，或者需要灵活应对各种意外情况，那就用 Agent</p>
<p>在实际过程中,更常见的是混合架构</p>
<h3 id="agent有哪些工作模式">Agent有哪些工作模式?</h3>
<h3 id="模式一react">模式一:React</h3>
<p>Thought -&gt; Action -&gt; Observation
循环工作</p>
<p>优点:透明可审计,灵活
缺点:token消耗量大且有时会陷入循环</p>
<h3 id="模式二plan-and-execute">模式二:Plan-and-Execute</h3>
<p>先规划后执行</p>
<p>优点:省钱
缺点:不够灵活</p>
<h3 id="模式三reflection做完再检查">模式三:Reflection(做完再检查)</h3>
<p>实现方式(完成任务后自我评审)
自我反思或者双agent对话 (一个生成一个评审)</p>
<h3 id="模式四multi-agent">模式四:Multi-Agent</h3>
<p>目前主流的多 Agent 框架包括 LangGraph、CrewAI、OpenAI Agents SDK 和微软的 AutoGen 等</p>
<p>不要过早的引入多agent框架,有时候强大的单agent就够用了</p>
<p>这几一个多 Agent 系统中，每个 Agent 内部可能用的是 ReAct 模式，整体协作用的是 Multi-Agent 模式，最后还有一个 Reflection 环节来检查质量。模式不是互斥的,往往是组合使用</p>
<h2 id="function-call是什么">Function Call是什么</h2>
<p>函数(工具)调用</p>
<h3 id="流程">流程</h3>
<ol>
<li>定义函数:name,description,parameters</li>
<li>LLM自主判断,并生成结构化响应</li>
<li>执行函数</li>
<li>生成回答</li>
</ol>
<h2 id="mcpmodel-context-protocol">MCP(Model Context Protocol)</h2>
<p>上下文协议,解决了工具的集成问题</p>
<p>提供了统一的标准来连接外部工具或者数据源</p>
<h3 id="组成-1">组成</h3>
<p>MCP host:应用
MCP Client:与MCP Server通信
MCP Server:负责对外暴露具体的工具能力和数据资源</p>
<p>MCP解决了什么问题?
集成和动态发现新能力</p>
<h2 id="skills">Skills</h2>
<p>经验和方法论
<strong>自然语言指令文件</strong>,指导agent在什么场景下,遵照什么方法,遵循什么规范来完成特定任务
通常以SKILL.md形似存在</p>
<p><strong>Skills 的本质是&quot;知识 + 行为指令&quot;，它通过加载到上下文中来改变 Agent 的思考和行为方式，同时可以驱动 Agent 去调用 Function Call、MCP 工具、执行代码等外部操作</strong></p>
<h3 id="skills的价值">Skills的价值:</h3>
<p>Skills 的核心价值在于<strong>将专业知识和最佳实践编码成可复用的模块</strong></p>
<h2 id="三者的区别">三者的区别</h2>
<h3 id="本质区别">本质区别:</h3>
<p>从解决问题上看:从<strong>解决的问题</strong>来看，Function Call 解决的是&quot;LLM 怎么跟外部函数交互&quot;这个最基础的问题。MCP 解决的是&quot;怎么用统一标准管理大量工具&quot;的集成问题。Skills 解决的是&quot;Agent 怎么获得领域专业知识&quot;的知识问题。</p>
<p>从<strong>运行位置</strong>来看，Function Call 的函数在你的应用程序中执行。MCP 的工具在外部的 MCP Server 中执行。Skills 完全在 Agent 的上下文窗口内生效，不涉及任何外部调用。</p>
<p>从<strong>技术本质</strong>来看，Function Call 是一种 API 协议，LLM 输出结构化的调用请求，应用程序执行后返回结果。MCP 是一种通信标准，定义了 Client 和 Server 之间如何发现和调用工具。Skills 是一种提示词扩展，用自然语言编写的行为指令，加载到 Agent 的上下文中。</p>
<p>从<strong>标准化程度</strong>来看，Function Call 在各 LLM 厂商之间格式不统一（OpenAI 和 Anthropic 的格式就不一样）。MCP 是统一的开放标准，跨厂商通用。Skills 目前还没有统一标准，各个 Agent 平台有自己的 Skill 格式。</p>
<h2 id="什么是a2aagent-to-agent协议">什么是A2A(agent to agent)协议:</h2>
<p>涉及多个agent通话</p>
<p>第一个是 <strong>Agent Card（智能体名片）</strong>。每个支持 A2A 的 Agent 都会发布一个 JSON 格式的&quot;名片&quot;，描述自己的身份、能力、擅长的领域、支持的交互方式、认证要求等信息。其他 Agent 通过读取这个名片来了解&quot;这个 Agent 会什么，我能请它帮什么忙&quot;。这就像你在 LinkedIn 上看到一个人的简历，知道他的技能和经验后，才决定要不要跟他合作。</p>
<p>第二个是<strong>任务（Task）</strong>。A2A 中的所有协作都围绕&quot;任务&quot;展开。一个 Client Agent（发起方）创建一个任务，发送给一个 Remote Agent（执行方）。任务有完整的生命周期，从创建、处理中、到完成或失败，每个状态变化都有明确的定义。这让双方能清楚地跟踪任务进展。</p>
<p>第三个是<strong>消息和制品（Message &amp; Artifact）</strong>。Agent 之间通过消息来沟通过程中的信息，通过制品来传递最终结果。比如一个研究 Agent 完成分析后，会把分析报告作为制品返回给请求方。</p>
]]></content:encoded>
    </item>
    <item>
      <title>ClaudeCode</title>
      <link>https://tuanzi-wow.cn/agent/%E5%B0%8F%E6%9E%97coding/claudecode/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/agent/%E5%B0%8F%E6%9E%97coding/claudecode/</guid>
      <description>ClaudeCode相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<h1 id="一架构设计">一.架构设计</h1>
<p>分为四层架构</p>
<h3 id="引擎层负责调度和思考">引擎层:负责调度和思考</h3>
<p>关键设计原则:不包含任何的业务逻辑</p>
<ol>
<li>协调:把用户输入,系统提示词,历史对话拼接在一起</li>
<li>分发:LLM需要调用工具时,找到对应的工具并执行</li>
<li>决策:根据LLM的返回决定时继续循环还是结束对话</li>
</ol>
<p>该设计的好处是:新增能力只需要新增一个工具,引擎层完全不用改</p>
<h3 id="工具层能力">工具层:能力</h3>
<p>工具遵循统一的规范,这个规范强制定义了三个安全属性:
1.工具是只读的还是会改东西的
2.它是否具有破坏性,需要额外确认?
3.能不能和其他工具同时执行</p>
<h3 id="服务层">服务层:</h3>
<p>所有层共享的基础设施:
调大模型的API,上下文压缩,MCP协议</p>
<h3 id="安全和治理层">安全和治理层:</h3>
<p>权限系统决定哪些操作需要用户确认,哪些操作可以自动执行;
Hook系统允许工具在执行前后插入自定义行为
Bash安全模块会对shell命令做语法级别的分析,检测命令注入,路径逃逸等危险模式</p>
<h1 id="二agent工作模式">二.Agent工作模式</h1>
<h2 id="首先回顾react">首先回顾React</h2>
<p>Thought-&gt;Action-&gt;Observation(Loop)
存在的问题:Token太浪费;应用层代码太复杂了;为弱模型设计的(当时的模型推理能力不够,但是现在的模型推理能力已经足够强了)</p>
<h2 id="claude-code-tool-use-loop">Claude Code: Tool-Use Loop</h2>
<p><img alt="img" loading="lazy" src="https://cdn.xiaolincoding.com//picgo/1775113773385-76a9359b-1c69-42e1-93c2-c1b8a352e540.png"></p>
<p>没有推理步骤(这是因为Opus自己具有推理能力,这是通过Extended Thinking)
该设计的核心哲学是:信任模型的推理能力,保持应用层框架尽可能简单</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">async</span> <span class="n">function</span><span class="o">*</span> <span class="n">queryLoop</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="n">params</span><span class="p">:</span> <span class="n">QueryParams</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">consumedCommandUuids</span><span class="p">:</span> <span class="n">string</span><span class="p">[],</span>
</span></span><span class="line"><span class="cl"><span class="p">):</span> <span class="n">AsyncGenerator</span><span class="o">&lt;</span><span class="n">StreamEvent</span> <span class="o">|</span> <span class="n">Message</span><span class="p">,</span> <span class="n">Terminal</span><span class="o">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">let</span> <span class="n">state</span><span class="p">:</span> <span class="n">State</span> <span class="o">=</span> <span class="p">{</span> <span class="n">messages</span><span class="p">,</span> <span class="n">toolUseContext</span><span class="p">,</span> <span class="n">turnCount</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="o">...</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">while</span> <span class="p">(</span><span class="bp">true</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="o">//</span> <span class="err">步骤</span> <span class="mi">1</span><span class="err">：压缩上下文（五步从轻到重）</span>
</span></span><span class="line"><span class="cl">    <span class="o">//</span> <span class="err">步骤</span> <span class="mi">2</span><span class="err">：调用大模型</span> <span class="n">API</span><span class="err">，流式接收</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">await</span> <span class="p">(</span><span class="k">const</span> <span class="n">event</span> <span class="n">of</span> <span class="n">streamAPI</span><span class="p">(</span><span class="n">params</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nb">yield</span> <span class="n">event</span>  <span class="o">//</span> <span class="err">流式输出每个</span> <span class="n">token</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="o">//</span> <span class="err">步骤</span> <span class="mi">3</span><span class="err">：分析模型返回</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">stopReason</span> <span class="o">===</span> <span class="s1">&#39;end_turn&#39;</span><span class="p">)</span> <span class="k">break</span>  <span class="o">//</span> <span class="err">完成了，跳出循环</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="o">//</span> <span class="err">步骤</span> <span class="mi">4</span><span class="err">：执行工具调用（并发</span><span class="o">/</span><span class="err">串行编排）</span>
</span></span><span class="line"><span class="cl">    <span class="k">const</span> <span class="n">toolResults</span> <span class="o">=</span> <span class="n">await</span> <span class="n">executeToolCalls</span><span class="p">(</span><span class="n">toolUseMessages</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="o">//</span> <span class="err">步骤</span> <span class="mi">5</span><span class="err">：更新</span> <span class="n">state</span><span class="err">，继续循环</span>
</span></span><span class="line"><span class="cl">    <span class="n">state</span> <span class="o">=</span> <span class="p">{</span> <span class="o">...</span><span class="n">state</span><span class="p">,</span> <span class="n">messages</span><span class="p">:</span> <span class="n">updatedMessages</span><span class="p">,</span> <span class="n">turnCount</span><span class="p">:</span> <span class="n">turnCount</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">continue</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="优点">优点</h3>
<p>1.Extended Thinking让推理在模型内部完成
2.API原生支持tool_use:不需要通过正则表达式从文本中提取[Action].消除了React的格式解析问题
3.end_turn作为天然的终止信号:语义清晰,不需要额外解析</p>
<table>
	<thead>
			<tr>
					<th><strong>维度</strong></th>
					<th><strong>ReAct</strong></th>
					<th><strong>Tool-Use Loop</strong></th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>推理方式</td>
					<td>显式 Thought 文本</td>
					<td>模型内部 Extended Thinking</td>
			</tr>
			<tr>
					<td>工具调用</td>
					<td>解析文本提取 Action</td>
					<td>API 原生 tool_use</td>
			</tr>
			<tr>
					<td>终止判断</td>
					<td>检测 「Final Answer」</td>
					<td>API 原生 end_turn</td>
			</tr>
			<tr>
					<td>Token 开销</td>
					<td>每轮要输出 Thought</td>
					<td>无额外开销</td>
			</tr>
			<tr>
					<td>编排复杂度</td>
					<td>高（需要解析 Thought/Action）</td>
					<td>低（只需要 if/else）</td>
			</tr>
			<tr>
					<td>适合场景</td>
					<td>弱模型 + 简单工具</td>
					<td>强模型 + 复杂工具集</td>
			</tr>
	</tbody>
</table>
<h2 id="plan-mode">Plan Mode</h2>
<p>先规划,后执行
并不是一个独立得框架,而是在Tool-Use Loop中通过EnterPlanMode和ExitPlanMode两个工具实现的
分为三步:
第一步:模型自主进入或客户手动触发
模型判断为复杂任务,调用EnterPlanMode工具;或用户自己手动触发</p>
<p>第二步:只读探索+设计方法:
权限将为只读,使用只读工具探索代码库,将生成的plans写入.claude/plans/目录
每5轮对话,模型会warning模型,提示他还在Plan Mode</p>
<p>第三步:用户审批后实施
模型调用ExitPlanMode,此时需要用户确认,批准后,权限恢复</p>
<p>核心设计:工具即能力</p>
<p>PlanMode不是一种特殊的模式切换,而是调用了EnterPlanMode和ExitPlanMode这两个工具</p>
<h1 id="三system-prompt的构造">三.System Prompt的构造</h1>
<p>非静态文件,由十几个section拼接,且拼接过程做了缓存优化
源码翻译为了中文,保留了关键术语</p>
<h2 id="角色定义与安全红线">角色定义与安全红线</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">你是一个交互式代理（interactive agent），帮助用户完成软件工程任务。
</span></span><span class="line"><span class="cl">请使用下面的指令和可用的工具来协助用户。
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">重要：你绝对不能为用户生成或猜测 URL，除非你确信这些 URL
</span></span><span class="line"><span class="cl">是为了帮助用户完成编程任务。你可以使用用户在消息或本地文件中
</span></span><span class="line"><span class="cl">提供的 URL。
</span></span></code></pre></td></tr></table>
</div>
</div><p>安全约束指令</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">重要：允许协助已授权的安全测试、防御性安全研究、CTF 挑战赛
</span></span><span class="line"><span class="cl">和教育场景。拒绝涉及破坏性技术、DoS 攻击、大规模目标扫描、
</span></span><span class="line"><span class="cl">供应链攻击或用于恶意目的的检测规避请求。
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="行为准则">行为准则</h2>
<p>挑选:</p>
<p>write before read</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">一般来说，不要对你没有阅读过的代码提出修改建议。如果用户
</span></span><span class="line"><span class="cl">要求你查看或修改某个文件，先读一遍它。在提出修改建议之前，
</span></span><span class="line"><span class="cl">先理解现有代码。
</span></span></code></pre></td></tr></table>
</div>
</div><p>关于代码风格:less is more</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">不要在用户要求之外添加功能、重构代码或进行&#34;改进&#34;。修一个 bug
</span></span><span class="line"><span class="cl">不需要顺手清理周围的代码。一个简单功能不需要额外的可配置性。
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">不要为一次性操作创建辅助函数、工具类或抽象层。
</span></span><span class="line"><span class="cl">三行相似的代码比一个过早的抽象更好。
</span></span></code></pre></td></tr></table>
</div>
</div><p>关于失败处理:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">如果某个方案失败了，先诊断原因再决定是否换方案——读报错信息、
</span></span><span class="line"><span class="cl">检查你的假设、尝试有针对性的修复。不要盲目重试完全相同的操作，
</span></span><span class="line"><span class="cl">但也不要因为一次失败就放弃一个可行的方案。
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="操作安全">操作安全:</h2>
<p>从可逆性和影响范围两个维度来判断风险</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">仔细考虑操作的可逆性（reversibility）和影响范围（blast radius）。
</span></span><span class="line"><span class="cl">一般来说，你可以自由执行本地的、可逆的操作，比如编辑文件或
</span></span><span class="line"><span class="cl">运行测试。但对于难以撤销、影响共享系统或有风险的操作，
</span></span><span class="line"><span class="cl">请先和用户确认后再执行。
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">需要用户确认的高风险操作示例：
</span></span><span class="line"><span class="cl">- 破坏性操作：删除文件/分支、删表、rm -rf
</span></span><span class="line"><span class="cl">- 难以逆转的操作：force-push、git reset --hard、修改已发布的 commit
</span></span><span class="line"><span class="cl">- 对他人可见的操作：推送代码、创建/关闭 PR、发送消息
</span></span><span class="line"><span class="cl">- 上传到第三方工具：内容可能被缓存或索引，即使删除也无法撤回
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">用户批准了某个操作（比如 git push）一次，并不意味着他在所有
</span></span><span class="line"><span class="cl">场景下都批准这个操作。授权仅对指定的范围有效，不能超出范围。
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="工具使用指南">工具使用指南:</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">当有专用工具可用时，不要用 Bash 来执行命令。使用专用工具可以
</span></span><span class="line"><span class="cl">让用户更好地理解和审查你的工作。这一点至关重要：
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">- 读取文件用 Read 工具，而不是 cat、head、tail 或 sed
</span></span><span class="line"><span class="cl">- 编辑文件用 Edit 工具，而不是 sed 或 awk
</span></span><span class="line"><span class="cl">- 创建文件用 Write 工具，而不是 echo 重定向
</span></span><span class="line"><span class="cl">- 搜索文件用 Glob 工具，而不是 find 或 ls
</span></span><span class="line"><span class="cl">- 搜索内容用 Grep 工具，而不是 grep 或 rg
</span></span></code></pre></td></tr></table>
</div>
</div><p>可审查性:
当模型调用 <code>Read</code> 工具读文件时，UI 会清晰地展示「Agent 正在读取 src/index.ts」。但如果模型执行 <code>cat src/index.ts</code>，用户看到的只是一条 Bash 命令和一大坨输出，完全不知道 Agent 在干什么。</p>
<h2 id="git安全协议">Git安全协议:</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Git 安全协议：
</span></span><span class="line"><span class="cl">- 绝不修改 git config
</span></span><span class="line"><span class="cl">- 绝不执行破坏性 git 命令（push --force、reset --hard、
</span></span><span class="line"><span class="cl">  checkout .、clean -f），除非用户明确要求
</span></span><span class="line"><span class="cl">- 绝不跳过 hooks（--no-verify），除非用户明确要求
</span></span><span class="line"><span class="cl">- 绝不 force push 到 main/master 分支，如果用户要求则发出警告
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">关键：始终创建新的 commit（NEW commit），而不是用 --amend 修改。
</span></span><span class="line"><span class="cl">当 pre-commit hook 失败时，commit 实际上并没有发生——所以
</span></span><span class="line"><span class="cl">--amend 会修改上一个（不相关的）commit，可能导致代码丢失。
</span></span><span class="line"><span class="cl">正确做法是：修复问题后创建一个新的 commit。
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="输出风格约束">输出风格约束:</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># 输出效率
</span></span><span class="line"><span class="cl">直奔重点。先尝试最简单的方案。要极度简洁。
</span></span><span class="line"><span class="cl">工具调用之间的文字不超过 25 个词。最终回复不超过 100 个词。
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">先给出答案或行动，而不是推理过程。跳过填充词、开场白和
</span></span><span class="line"><span class="cl">不必要的过渡句。不要复述用户说过的话——直接做就行。
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="环境信息注入">环境信息注入</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># 环境信息
</span></span><span class="line"><span class="cl">- 主工作目录：/Users/you/my-project
</span></span><span class="line"><span class="cl">- 是否为 Git 仓库：是
</span></span><span class="line"><span class="cl">- 操作系统平台：darwin (macOS)
</span></span><span class="line"><span class="cl">- Shell 类型：zsh
</span></span><span class="line"><span class="cl">- 当前模型：Claude Opus 4.6 (1M context)
</span></span><span class="line"><span class="cl">- 知识截止日期：2025 年 5 月
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="分割线和三级缓存">分割线和三级缓存</h2>
<p><strong>SYSTEM_PROMPT_DYNAMIC_BOUNDARY</strong>
三级缓存:
全局缓存(分割线之上,跨组织跨用户共享)-&gt;组织缓存(同一组织内跨会话共享)-&gt;会话缓存(同一个section在一次会话内只计算一次)</p>
<h1 id="四记忆系统">四.记忆系统</h1>
<p>记忆分类:
user:用户画像
feedback:行为反馈:
rules,why,how to apply
project:项目动态
必须把相对日期转化为绝对日期</p>
<p>reference:外部指针</p>
<p>排除清单:不会被写入记忆系统的内容
<strong>可以从当前代码推导出来的信息，一律不存</strong></p>
<h3 id="存储的方式索引独立文件">存储的方式:索引+独立文件</h3>
<p>MEMORY.md文件作为索引被加载到System Prompt中,但是独立记忆文件按需加载
不超过200行(25KB)的轻量目录:通过行数和字节数限制</p>
<h3 id="召回方式通过sonnet做记忆检索">召回方式:通过sonnet做记忆检索</h3>
<p>流程</p>
<ol>
<li>扫描记忆文件的头部信息</li>
<li>拼成清单+用户当前输入,发给Sonnet做选择,Sonnet返回选中文件列表</li>
<li>加载选中的记忆文件,注入上下文</li>
</ol>
<p>记忆召回的执行时机:
在用户提交信息之后就立刻开始了(并行召回)</p>
<h1 id="五上下文窗口管理">五.上下文窗口管理</h1>
<p>压缩策略:分为五种程度
核心理念:压缩必定有信息的损失,进行层级的压缩策略</p>
<h3 id="一huge-tool-result存入磁盘">一.huge tool result存入磁盘</h3>
<p>进入message之前,超过50KB的tool result存磁盘,返回预览;
或一条message的总tool result&lt; 200kb,如果超过,选择最大的几个tool result存磁盘</p>
<h3 id="二砍掉远古消息">二.砍掉远古消息</h3>
<p>移除对话开头的老消息,并插入边界标记显式告知模型</p>
<h3 id="三裁剪老的tool-result">三.裁剪老的tool result</h3>
<p>Micro-Compact
核心思想:随时间衰减,可重新获取的
subagent的tool result永远不会被clear</p>
<p>被裁剪的tool result会被占位文本替代</p>
<h3 id="四读时投影read-time-projection">四.读时投影(Read-Time Projection)</h3>
<p>在调用API的那一刻,动态计算压缩视图给LLM</p>
<h3 id="五全量摘要">五.全量摘要</h3>
<p>trigger:设置的阈值
1.生成摘要
2.替换旧消息
3.<strong>Post-Compact Restoration（压缩后恢复</strong>)</p>
<p>从文件状态缓存（<code>fileStateCache</code>）中找出最近访问过的文件，按最后访问时间排序，挑选最多 5 个、总共不超过 50K Token 的文件内容重新注入。同时恢复活跃的 Skill（不超过 25K Token），如果有进行中的 Plan 也会恢复 Plan 文件</p>
<table>
	<thead>
			<tr>
					<th><strong>层级</strong></th>
					<th><strong>手段</strong></th>
					<th><strong>信息损失</strong></th>
					<th><strong>API 开销</strong></th>
					<th><strong>触发条件</strong></th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>第 1 层</td>
					<td>大结果存磁盘</td>
					<td>几乎为零</td>
					<td>零</td>
					<td>工具结果超 50KB</td>
			</tr>
			<tr>
					<td>第 2 层</td>
					<td>砍掉远古消息</td>
					<td>低</td>
					<td>零</td>
					<td>消息过时</td>
			</tr>
			<tr>
					<td>第 3 层</td>
					<td>清理老工具输出</td>
					<td>中低</td>
					<td>零</td>
					<td>缓存过期/数量超限</td>
			</tr>
			<tr>
					<td>第 4 层</td>
					<td>读时投影压缩</td>
					<td>中</td>
					<td>低</td>
					<td>上下文达 90%</td>
			</tr>
			<tr>
					<td>第 5 层</td>
					<td>全量摘要</td>
					<td>高</td>
					<td>高（一次 API 调用）</td>
					<td>上下文达 ~93%</td>
			</tr>
	</tbody>
</table>
]]></content:encoded>
    </item>
    <item>
      <title>Graph Engineering</title>
      <link>https://tuanzi-wow.cn/agent/%E5%B0%8F%E6%9E%97coding/graph-engineering/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/agent/%E5%B0%8F%E6%9E%97coding/graph-engineering/</guid>
      <description>Graph Engineering相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<p>按照任务之间的依赖关系,用graph来编排整个流程
而loop可以理解为一个节点的循环图</p>
<p><img alt="img" loading="lazy" src="https://cdn.xiaolincoding.com//picgo/adfd1df4_loop-as-smallest-graph.png"></p>
<h1 id="工作原理">工作原理</h1>
<p>组成:
节点,边,状态</p>
<p>节点:agent或代码或一次简单操作</p>
<p>边:
负责决定下一步执行哪个节点
确定性边:由提前写进代码的固定规则决定
模型决策边:交给模型判断</p>
<p>状态:
字段固定的任务状态表</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;backend&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;status&#34;</span><span class="p">:</span> <span class="s2">&#34;done&#34;</span><span class="p">,</span> <span class="s2">&#34;artifact&#34;</span><span class="p">:</span> <span class="s2">&#34;api/export.js&#34;</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;frontend&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;status&#34;</span><span class="p">:</span> <span class="s2">&#34;running&#34;</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;tests&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;status&#34;</span><span class="p">:</span> <span class="s2">&#34;pending&#34;</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;tokens_used&#34;</span><span class="p">:</span> <span class="mi">12000</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded>
    </item>
    <item>
      <title>GraphRAG And LightRAG</title>
      <link>https://tuanzi-wow.cn/agent/%E5%B0%8F%E6%9E%97coding/graphrag-and-lightrag/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/agent/%E5%B0%8F%E6%9E%97coding/graphrag-and-lightrag/</guid>
      <description>GraphRAG And LightRAG相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<h1 id="1传统的rag的缺陷">1.传统的RAG的缺陷:</h1>
<h2 id="11跨文档的多跳推理">1.1跨文档的多跳推理</h2>
<h3 id="什么叫多跳推理multi-hop-reasoning">什么叫多跳推理(Multi-hop Reasoning)</h3>
<p>一个形象化地解释就是:需要从A关联到B,再从B关联到C,然后由A推到C地问题
或者还有一种比较具体的表现:链式推理</p>
<h2 id="12全局性问题">1.2全局性问题</h2>
<p>举例:
这本小说的主题思想是什么?
Query-Focused Summarization问题,本质上不是检索任务,而是归纳任务</p>
<h2 id="13切块带来的语义断裂">1.3.切块带来的语义断裂</h2>
<ul>
<li>语言切断</li>
<li>实体关系丢失</li>
<li>检索噪声:这个有个比较有意思的点:[苹果的营收]检索到一堆水果</li>
</ul>
<h2 id="14-根本原因">1.4 根本原因:</h2>
<p>传统的RAG只理解语义,但是忽略了关系</p>
<h2 id="15-解决方法">1.5 解决方法:</h2>
<p>引入知识图谱,这也就是GraphRAG的核心思路</p>
<h1 id="2什么是graphrag为什么会有graphrag">2.什么是GraphRAG?为什么会有GraphRAG?</h1>
<p>基于知识图谱做RAG的方法,基于微软发布的开源项目
定义:GraphRAG就是用LLM把文档读成一张知识图谱,然后基于这张图谱来做检索和回答</p>
<h2 id="传统rag和graphrag的核心差异">传统RAG和GraphRAG的核心差异</h2>
<p>知识的存储形式:</p>
<p>传统RAG:离散的文本块
GraphRAG:以图的形式存储,文档中的实体和他们的关系被显式提取出来,形成一张结构化的关系网络</p>
<h2 id="图的优点">图的优点:</h2>
<ol>
<li>多跳推理可行</li>
<li>全局性
将整个知识图谱通过社区检测算法划分为若干个社区(图中关系密切的节点),然后再用LLM为各个社区生成一份摘要</li>
<li>实体和关系显式化,切断语义迎刃而解</li>
</ol>
<h1 id="3graphrag的工作流程">3.GraphRAG的工作流程</h1>
<p>分为两大阶段:索引阶段和查询阶段</p>
<h2 id="索引阶段">索引阶段</h2>
<h3 id="1文档切块text-chunking">1.文档切块(Text Chunking):</h3>
<p>毕竟上下文窗口有限</p>
<h3 id="2实体与关系提取">2.实体与关系提取</h3>
<p>将文本块发送给LLM,让他提取出其中的实体(Entity)和关系(Relationship)</p>
<p>专用的prompt,大致格式:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">你是一个实体关系抽取助手。请从下面的文本中：
</span></span><span class="line"><span class="cl">1. 识别所有的实体，每个实体给出：
</span></span><span class="line"><span class="cl">   - entity_name：实体名（大写）
</span></span><span class="line"><span class="cl">   - entity_type：类型（比如 [人物, 组织, 地点, 事件]）
</span></span><span class="line"><span class="cl">   - entity_description：实体的综合描述
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2. 识别所有实体之间的关系，每对关系给出：
</span></span><span class="line"><span class="cl">   - source_entity：源实体
</span></span><span class="line"><span class="cl">   - target_entity：目标实体
</span></span><span class="line"><span class="cl">   - relationship_description：关系的描述
</span></span><span class="line"><span class="cl">   - relationship_strength：关系强度（1-10 的数字）
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">文本内容：
</span></span><span class="line"><span class="cl">{input_text}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">请按以下格式输出：
</span></span><span class="line"><span class="cl">(&#34;entity&#34;|实体名|类型|描述)
</span></span><span class="line"><span class="cl">(&#34;relationship&#34;|源|目标|描述|强度)
</span></span></code></pre></td></tr></table>
</div>
</div><p>此处有一个缺陷:重复和歧义
同一个实体可能有不同的身份,不如刘备,玄德都是同一个人,都是LLM提取时不会合并</p>
<h3 id="3生成实体关系摘要">3.生成实体/关系摘要</h3>
<p>把同一个实体在所有文本块里的描述汇总起来，让 LLM 合成一段更完整的实体描述,关系也是如此</p>
<h3 id="4社区检测">4.社区检测</h3>
<p>社区检测算法:Leiden算法,是一种层次化社区检测办法
他会把图谱划分为多个层级的社区
这种层次化的划分,时Graph能够处理不同粒度全局问题的基础:不同程度的问题,使用对应层级的社区</p>
<h3 id="5生成社区摘要">5.生成社区摘要</h3>
<p>为每个社区单独生成一份摘要报告</p>
<p>最终产物:
实体节点-关系边-层次化社区-社区报告</p>
<p>在这个过程中,token的成本非常大</p>
<h2 id="查询阶段两种搜索方法各司其职">查询阶段:两种搜索方法各司其职</h2>
<h3 id="模式一local-search本地搜索">模式一:Local Search(本地搜索)</h3>
<p>适用场景:询问某个具体实体</p>
<p><strong>工作流程</strong>：</p>
<ol>
<li><strong>定位入口实体</strong>：先用问题的向量，在所有实体节点的向量索引里做相似度搜索，找到最相关的几个实体。比如问诸葛亮，就先定位到「诸葛亮」这个节点</li>
<li><strong>顺藤摸瓜扩展</strong>：从入口实体出发，沿着图的边扩展，找到相关的<strong>邻居实体、关系、原始文本块、所属社区报告</strong></li>
<li><strong>组装上下文</strong>：把找到的这些信息整合成一段上下文（Context）</li>
<li><strong>交给 LLM 生成答案</strong></li>
</ol>
<h3 id="模式二global-search全局搜索">模式二:Global Search(全局搜索)</h3>
<p>适用场景:全局性,宏观性</p>
<p>工作流程:Map-Reduce策略</p>
<ul>
<li><strong>Map 阶段</strong>：把某个层级（比如 Level 1）的所有社区报告都拿出来，分成好多批，对每一批都让 LLM 生成一个「中间答案」，并给每个观点打一个「重要性评分」</li>
<li><strong>Reduce 阶段</strong>：把所有中间答案里的观点汇总，按评分排序，保留最重要的那些，最后让 LLM 合并成一个完整的最终答案:</li>
</ul>
<p>本质:将某个问题拆分成多个社区内部的子问题并行解答,再汇总
很烧钱</p>
<p><img alt="img" loading="lazy" src="https://cdn.xiaolincoding.com//picgo/1776760836761-e1a407ff-df74-4bd6-b4b1-eb01c2f34ae8.png"></p>
<p><img alt="img" loading="lazy" src="https://cdn.xiaolincoding.com//picgo/1776760509060-f60311a7-308c-4f6b-988f-7f39d62a9513.png"></p>
<p><img alt="img" loading="lazy" src="https://cdn.xiaolincoding.com//picgo/1776760661776-4b9b6354-dbc1-43c9-aa26-9190291d6ea2.png"></p>
<p>我觉得这个图做的真心不错</p>
<h1 id="4graph的缺陷">4.Graph的缺陷</h1>
<h2 id="1索引成本">1.索引成本</h2>
<p>过程中多次调用LLM,token成本非常高</p>
<h2 id="2实体消歧">2.实体消歧</h2>
<p>LLM做实体抽取,对于现实的统一实体的不同名称会抽取为几个独立的实体</p>
<p>导致问题:图谱被近重复节点塞满;关系碎片化;错误指数级放大</p>
<h2 id="3查询延迟">3.查询延迟</h2>
<p>特别是Global Search
虽然后续提出了动态社区选择的这样的优化,都是延迟依然比ANN低一个数量级</p>
<h2 id="4增量更新很麻烦">4.增量更新很麻烦</h2>
<h3 id="业界应对增量问题的几种思路有点懒得看"><a href="https://xiaolinnote.com/agent/rag/graphrag-lightrag.html#%E4%B8%9A%E7%95%8C%E5%BA%94%E5%AF%B9%E5%A2%9E%E9%87%8F%E9%97%AE%E9%A2%98%E7%9A%84%E5%87%A0%E7%A7%8D%E6%80%9D%E8%B7%AF">业界应对增量问题的几种思路</a>(有点懒得看)</h3>
<p>这个问题这么难，业界有没有办法？有，但每种办法都是<strong>有代价的妥协</strong>。下面几种主流思路，你可以根据自己的业务场景挑。</p>
<p><strong>思路一：简单粗暴，定期全量重建</strong></p>
<p>最土但最省心的办法：每天、每周、或者每月定时把所有文档重新跑一遍 GraphRAG 索引。</p>
<p><strong>优点</strong>：实现简单，一致性好，图谱永远是新鲜的。</p>
<p><strong>缺点</strong>：贵。<strong>非常贵</strong>。假设你有 1000 万 token 的语料，每天重建一次，一年就是 300 多次全量索引，光 LLM 调用费可能就要几万美元。而且重建过程中服务还要切换到「旧索引」上，运维复杂度也不低。</p>
<p>适合什么场景？<strong>文档更新频率低 + 数据量不大 + 对实时性不敏感</strong>的场景，比如公司年度法规库、历史档案库。</p>
<p><strong>思路二：增量索引（Incremental Indexing）</strong></p>
<p>微软 GraphRAG 的后续版本（以及 Fast GraphRAG 这类改良方案）都支持了<strong>增量索引</strong>，只处理新增的文档，把新抽出的实体和关系追加到已有图上。</p>
<p><img alt="img" loading="lazy" src="https://cdn.xiaolincoding.com//picgo/1776761362958-ac6702f5-46fa-48e1-870b-2cc367835694.png">img</p>
<p><strong>核心流程是这样的</strong>：先对新文档做一次实体和关系抽取（注意，只处理新的，老文档完全不碰），然后把抽出来的新实体和图里的老实体做消歧合并（这一步也叫 upsert，实现上一般会用字符串编辑距离加上向量相似度组合判断），合并完之后把新关系追加到图上。这时候关键的一步来了：<strong>系统要判断哪些社区受到了这次更新的影响</strong>（通常是通过图算法识别受影响的子图），然后<strong>只对这些受影响的社区重新做一次检测和摘要</strong>，没受影响的部分保持原样不动。</p>
<p><strong>优点</strong>：不用全量重建，成本低很多。Fast GraphRAG 这种方案跑 430 个文档的增量，用本地 14B 模型大概 8.5 小时就能搞定。</p>
<p><strong>缺点</strong>：<strong>精度会有损失</strong>。因为社区划分本质是一个全局优化问题，你只重做局部社区，全局的社区划分就不一定是最优的。时间长了，图谱的质量会慢慢「漂移」，需要阶段性做一次全量重建来「校准」。</p>
<p><strong>思路三：混合策略，小增量 + 周期性全量</strong></p>
<p>这是目前<strong>生产环境最常见的做法</strong>，就是把前面两个思路结合起来用。日常有新文档进来，就跑一次增量索引，又快又便宜；但每隔一段时间（比如每个月一次），再做一次全量重建，把之前累积漂移掉的精度拉回来。</p>
<p>这种方式的优点就是<strong>成本和质量的平衡最好</strong>，缺点嘛，就是你得同时维护两套流程。</p>
<p><strong>思路四：时间分区（Temporal Partitioning）</strong></p>
<p>如果你的数据有明显的时间属性（比如新闻、月度报告、季度财报），还有一种做法是<strong>按时间段分开建图</strong>：2025 Q1 一张图，Q2 一张图，Q3 又是一张图。</p>
<p>查询的时候，要么指定时间段查对应的图，要么跨图联邦查询再聚合。</p>
<p><strong>优点</strong>：每张图相对小、更新隔离性好、老数据不受新数据影响。</p>
<p><strong>缺点</strong>：跨时间段的查询要专门做联邦策略，图和图之间的实体也需要做全局对齐。</p>
<p><strong>思路五：延迟实体合并 + 最终一致性</strong></p>
<p>有些团队的做法更激进：<strong>索引时不做消歧</strong>，只把所有实体直接加进去，哪怕同一个 IBM 有四个节点也无所谓。然后<strong>查询时再做合并</strong>，或者<strong>异步离线跑消歧任务</strong>。</p>
<p><strong>优点</strong>：索引极快，增量几乎零成本。</p>
<p><strong>缺点</strong>：查询时可能要做更多的聚合和去重，查询延迟会变高。而且在没来得及异步合并之前，查询结果可能会漏召回。</p>
<h1 id="5什么是-lightrag为什么会有-lightrag">5.<a href="https://xiaolinnote.com/agent/rag/graphrag-lightrag.html#_6%E3%80%81%E4%BB%80%E4%B9%88%E6%98%AF-lightrag-%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BC%9A%E6%9C%89-lightrag">什么是 LightRAG？为什么会有 LightRAG？</a></h1>
<p>在保留图结构带来的关系理解能力的前提下,把成本,速度,增量三件事做到了极致</p>
<h2 id="lightrag的三个核心创新">LightRAG的三个核心创新</h2>
<h3 id="一图增强的文本索引graph-enhanced-text-indexing">一.图增强的文本索引**（Graph-Enhanced Text Indexing）**</h3>
<p>保留实体节点+关系边,省略社区检测和社区摘要</p>
<h3 id="二双层检索范式">二.双层检索范式</h3>
<p>对于全局问题的解法:
<strong>不用提前做全局聚合,而是在查询时把查询本身拆成两层关键词,分别做检索</strong></p>
<p>底层关键词关注具体的实体和细节
高层关键词关心抽象的主题和概念</p>
<p>对于两种关键词</p>
<ul>
<li>用低级关键词去向量库里面检索实体</li>
<li>用高级关键词去向量库找相关的关系</li>
</ul>
<p>优点:每次查询只调取一次LLM做关键词抽取,然后几次向量检索,降低了成本和查询延迟</p>
<h3 id="三增量更新算法">三.增量更新算法</h3>
<p>LightRAG 的增量更新，<strong>本质上就是「追加」两个字</strong>。新文档来了，跑一下实体和关系抽取，然后把抽出来的新实体、新关系直接 upsert 到图和向量库里就行了。如果新实体和老实体有重合（比如都叫 IBM），那就合并节点的描述；要是完全是新实体，那就加个新节点。<strong>整个过程完全不需要重新做社区检测、不需要重新生成摘要、更不需要全量重建索引</strong>
(抽取实体和关系,然后去重,追加新节点和建立新关系)</p>
<p>LightRAG的代价是什么?
主要牺牲了一定的<strong>全局深度洞察</strong>
LightRAG的本质还是<strong>基于查询去拼凑全局视角</strong></p>
<h1 id="6lightrag的工作原理">6.LightRAG的工作原理</h1>
<p>同样的分为索引阶段和查询阶段</p>
<h2 id="索引阶段轻量化的图构建">索引阶段:轻量化的图构建</h2>
<ol>
<li>文档切块(chunking)</li>
<li>实体和关系提取
此处有一个小巧思:关系关键词:描述的是这条关系所代表的主题或概念</li>
<li>键对值生成+去重
对于每个实体和关系,生成一个键对值:方便关键词检索时复杂的Embedding和chunk遍历
去重:同名实体和重复关系合并
但是LightRAG的去重比较朴素,主要基于名称朴素,不会处理同人不同名的情况,例如AI和Artificial Intelligence,但是little problem,在查询时所有相似实体都会被查询然后多路召回合并</li>
</ol>
<p>最终的存储结构
两种形式:
知识图谱
向量数据库:实体描述的向量,关系描述的向量,关系关键词的向量</p>
<h2 id="查询阶段双层检索">查询阶段:双层检索</h2>
<ol>
<li>关键词抽取:调用LLM抽取处低层关键词和高层关键词</li>
</ol>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">查询：&#34;国际贸易如何影响全球经济稳定？&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">LLM 输出：
</span></span><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">  &#34;high_level_keywords&#34;: [&#34;国际贸易&#34;, &#34;全球经济稳定&#34;, &#34;经济影响&#34;],
</span></span><span class="line"><span class="cl">  &#34;low_level_keywords&#34;: [&#34;贸易协定&#34;, &#34;关税&#34;, &#34;货币汇率&#34;, &#34;进口&#34;, &#34;出口&#34;]
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></td></tr></table>
</div>
</div><p>WOC有点夸张</p>
<p><img alt="img" loading="lazy" src="https://cdn.xiaolincoding.com//picgo/1776762213807-f26f01d3-e037-4498-bb11-7e3809005f9b.png"></p>
<p>​	2.双层检索</p>
<p><strong>Low-level 检索</strong>：用低层关键词去向量库里搜<strong>实体节点</strong>。比如用「贸易协定」「关税」这些关键词，找到相关的实体节点（可能是某个具体的贸易协定、某种税种等）。然后从这些入口实体出发，在图上扩展到它们的<strong>一跳邻居</strong>，收集相关的关系和描述。</p>
<p><strong>High-level 检索</strong>：用高层关键词去向量库里搜<strong>关系边</strong>。比如用「国际贸易」「经济影响」这些关键词，找到相关的关系边（可能是「贸易协定 → 影响 → 国家经济」这类关系）。然后从这些关系出发，聚合它们涉及的实体和更高层的语义。</p>
<p>​	3.上下文组装(Context Building)
​	把 Low-level 检索到的实体 + 邻居 + 相关文本块，和 High-level 检索到的关系 	+ 涉及实体 + 相关文本块<strong>拼在一起</strong>，组装成一段完整的上下文。</p>
<p>​	这里有个细节：LightRAG 会控制上下文的总 token 数（比如默认 4000 		token），优先保留相关性最高的内容，避免上下文超过 LLM 窗口。</p>
<p>​	4.LLM生成答案</p>
<h3 id="四种查询模式灵活应对不同场景"><a href="https://xiaolinnote.com/agent/rag/graphrag-lightrag.html#%E5%9B%9B%E7%A7%8D%E6%9F%A5%E8%AF%A2%E6%A8%A1%E5%BC%8F-%E7%81%B5%E6%B4%BB%E5%BA%94%E5%AF%B9%E4%B8%8D%E5%90%8C%E5%9C%BA%E6%99%AF">四种查询模式：灵活应对不同场景</a></h3>
<p>除了上面描述的「双层检索」默认模式（也叫 Hybrid 模式），LightRAG 实际上提供了<strong>四种查询模式</strong>，满足不同场景需求：</p>
<table>
	<thead>
			<tr>
					<th>模式</th>
					<th>用什么检索</th>
					<th>适用场景</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Naive（朴素）</td>
					<td>纯向量检索文本块（就是传统 RAG）</td>
					<td>简单事实问答，不需要关系推理</td>
			</tr>
			<tr>
					<td>Local（本地）</td>
					<td>只用 Low-level 检索（找具体实体）</td>
					<td>具体实体类问题，比如「这个 API 怎么用」</td>
			</tr>
			<tr>
					<td>Global（全局）</td>
					<td>只用 High-level 检索（找关系主题）</td>
					<td>抽象概念、主题归纳类问题</td>
			</tr>
			<tr>
					<td>Hybrid（混合）</td>
					<td>Low-level + High-level 同时用</td>
					<td>复杂综合问题，默认推荐</td>
			</tr>
	</tbody>
</table>
<p><strong>多数场景用 Hybrid 就够了，它是 LightRAG 推荐的默认模式</strong>。</p>
<h2 id="增量更新">增量更新</h2>
<p>流程:</p>
<ol>
<li>切块</li>
<li>抽取实体和关系(针对新文档</li>
<li>增量更新:已有实体节点-&gt;追加描述或合并
全新的实习:增加一个新的节点,再处理逻辑关系</li>
<li>将新的实习和关系描述做向量化</li>
</ol>
<p>一个小细节:LightRAG的增量更新对语义冲突不敏感,对于冲突的关系会同时保留,需要自己在上层加逻辑处理(如果有需要)</p>
<h3 id="总结-lightrag-的完整工作原理"><a href="https://xiaolinnote.com/agent/rag/graphrag-lightrag.html#%E4%B8%80%E5%BC%A0%E5%9B%BE%E6%80%BB%E7%BB%93-lightrag-%E7%9A%84%E5%AE%8C%E6%95%B4%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86">总结 LightRAG 的完整工作原理</a></h3>
<p><img alt="img" loading="lazy" src="https://cdn.xiaolincoding.com//picgo/1776762795099-cd3d6f76-b414-403a-87de-61aa7e62cedc.png">img</p>
<p><strong>索引阶段</strong>：</p>
<p><img alt="img" loading="lazy" src="https://cdn.xiaolincoding.com//picgo/1776762487496-40a57b8e-0483-4229-af1f-38117357af61.png">img</p>
<p><strong>查询阶段（Hybrid 模式）</strong>：</p>
<p><img alt="img" loading="lazy" src="https://cdn.xiaolincoding.com//picgo/1776762578083-12a9c7f7-2715-4933-820a-2a44f7264a2e.png">img</p>
<p><strong>增量阶段</strong>：</p>
<p><img alt="img" loading="lazy" src="https://cdn.xiaolincoding.com//picgo/1776762670457-d9be8568-9ccd-4669-af2c-4479a6a02f62.png"></p>
<h1 id="这图做的真不错吧">这图做的真不错吧!!!!</h1>
]]></content:encoded>
    </item>
    <item>
      <title>Harness Engineering</title>
      <link>https://tuanzi-wow.cn/agent/%E5%B0%8F%E6%9E%97coding/harness-engineering/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/agent/%E5%B0%8F%E6%9E%97coding/harness-engineering/</guid>
      <description>Harness Engineering相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<h1 id="从prompt-engineering到harness-engineering">从Prompt Engineering到Harness Engineering</h1>
<h2 id="prompt-engineering">Prompt Engineering</h2>
<p>首先要明白LMM的原理:
本质上是:根据你输入的内容,预测下一个字,即生成式语言模型</p>
<p>因此,准确的提示词能够让AI更好地预测你的想法
写提示词的本质,不是在命令模型,而是在塑造它的概率空间</p>
<h2 id="context-engineering">Context Engineering</h2>
<p>Context Window:LLM能够看到的信息
Agent Skill的思路:渐进式披露</p>
<h2 id="harness-engineering">Harness Engineering</h2>
<p>Harness Engineering的出发点:<strong>当模型从「回答问题」走向「执行任务」，系统就不能只负责喂信息，还要能「驾驭」整个执行过程</strong></p>
<h1 id="harness的组成和结构">Harness的组成和结构</h1>
<p>分为六层,可以按照功能分为下面的三组</p>
<p>输入侧:
上下文精细化管理+记忆与状态管理</p>
<p>动作侧:
工具系统+任务执行编排</p>
<p>校验侧:
评估观测+约束恢复</p>
<p>六层为:
上下文精细化,记忆与状态,工具系统,执行编排,评估与观测,约束与恢复</p>
<h3 id="第一层上下文精细化">第一层:上下文精细化</h3>
<ul>
<li>确定角色和目标</li>
<li>按需给予相关信息</li>
<li>结构化组织</li>
</ul>
<h3 id="第二层工具系统的可控调用">第二层:工具系统的可控调用</h3>
<ul>
<li>给予tools列表</li>
<li>when to use</li>
<li>return tool result to LLM</li>
</ul>
<h3 id="第三层任务执行的全局编排">第三层:任务执行的全局编排</h3>
<p>给予模型一条精确的workflow</p>
<h3 id="第四层记忆与状态的分层管理">第四层:记忆与状态的分层管理</h3>
<p>Agent的状态不应该在上下文中,而是应该外化到文件系统中
AI没有记忆</p>
<h3 id="第五层独立的评估和观测系统">第五层:独立的评估和观测系统</h3>
<p>Eval集:
典型任务+标注好的标准答案;在Harness被更改的时候,把这些任务跑一次</p>
<p>Trace+日志+指标</p>
<h3 id="第六层约束校验和失败恢复机制">第六层:约束校验和失败恢复机制</h3>
<ul>
<li>
<p>约束:定义&quot;什么事不能做&quot;</p>
<p>最好能硬编码到代码或者linter规则中</p>
</li>
<li>
<p>校验:子啊每一步输出前后都做自动检查</p>
</li>
<li>
<p>恢复:失败后有预案</p>
</li>
</ul>
<h1 id="落地">落地:</h1>
<p>更诡异的是，Cognition（就是做 Devin 那家公司）在用 Claude Sonnet 4.5 重做 Devin 的时候，观察到一个特别有意思的现象，他们把它叫做「<strong>上下文焦虑</strong>」（Context Anxiety）。</p>
<p>什么意思呢？就是模型自己好像也能感觉到「我快撑不住了」。当它觉得上下文窗口快用完的时候，模型不仅开始丢细节，还会出现一种奇怪的行为：它开始着急地想收尾。它会突然简化方案、跳过验证步骤、急匆匆地宣布「任务完成」。</p>
<p><strong>原则一：重启胜过修补，状态沉到文件里，Agent 随时可以在一个干净的上下文窗口里接力继续</strong>。</p>
<h3 id="二自我反思总是偏向乐观的">二:自我反思总是偏向乐观的</h3>
<p>三角分工:</p>
<ul>
<li><strong>Planner（规划者）</strong>：负责把模糊的需求扩展成完整的规格说明</li>
<li><strong>Generator（生成者）</strong>：负责一步一步去实现</li>
<li><strong>Evaluator（验收者）</strong>：负责像 QA 一样真实地测试</li>
</ul>
<p><strong>原则二：生产和验收必须分离，而且验收方必须能摸到真实世界</strong></p>
<h3 id="三agent失败后工程师应该做什么">三:Agent失败后,工程师应该做什么?</h3>
<p><strong>原则三：Agent 反复失败的时候，别问模型能不能更努力，要问环境还缺什么</strong></p>
<h3 id="四规范文件越写越长为什么agent反而越来越糊涂">四:规范文件越写越长,为什么Agent反而越来越糊涂</h3>
<p>核心思路:渐进式披露</p>
<ul>
<li><strong>主文件只保留 100 行左右的核心索引</strong>。你没看错，OpenAI 原文博客里特地写明了这个数字：整个 <a href="http://agents.md/">AGENTS.md</a> 控制在大约 100 行，它不告诉 Agent 每条细节规则，只告诉 Agent「你想看什么，去哪儿看」</li>
<li>详细的内容拆到具体的子文档里：架构文档一份、设计原则一份、产品规格一份、执行计划一份、质量评分一份，每份都有清晰的主题</li>
<li>Agent 平时只看目录，只有真的需要某一部分的时候，才钻进对应的子文档</li>
</ul>
<p><strong>原则四：规则文件宁缺毋滥，给模型看的东西少即是多</strong></p>
<p>五:AL slop: AI代码泔水</p>
<ul>
<li><strong>把人类工程师关于&quot;什么是好代码&quot;的经验，写成一套「Golden Principles」（黄金原则）沉进仓库</strong></li>
<li><strong>让一批后台 Agent 按固定节奏自动跑</strong></li>
</ul>
<p><strong>原则五：技术债不是攒一堆集中还，而是每天让后台 Agent 自动偿还一点</strong></p>
]]></content:encoded>
    </item>
    <item>
      <title>Loop Engineering</title>
      <link>https://tuanzi-wow.cn/agent/%E5%B0%8F%E6%9E%97coding/loop-engineering/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/agent/%E5%B0%8F%E6%9E%97coding/loop-engineering/</guid>
      <description>Loop Engineering相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<h1 id="loop-engineering">Loop Engineering</h1>
<p>递归式的目标</p>
<h2 id="loop的组成">Loop的组成</h2>
<h3 id="一自动化">一.自动化</h3>
<p>定时或者事件触发</p>
<h3 id="二worktree">二.worktree</h3>
<p>允许并发进行
git的worktree机制:给每个agent一个独立的工作目录和独立分支,共享同一份仓库历史,但是物理上互不干扰,各干各的,最后各开各的PR</p>
<h3 id="三skill">三.Skill</h3>
<h3 id="四connector">四.Connector</h3>
<p>基于MCP协议的连接器</p>
<h3 id="五sub-agent">五.Sub-agent</h3>
<p>将产出和评估解耦</p>
<h3 id="六记忆">六.记忆</h3>
<p>持久化到磁盘中而不是上下文中</p>
<table>
	<thead>
			<tr>
					<th>部件</th>
					<th>在 loop 里的职责</th>
					<th>Codex</th>
					<th>Claude Code</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>自动化</td>
					<td>定时发现和分诊</td>
					<td>Automations 面板 + 分诊收件箱</td>
					<td>计划任务、<code>/loop</code>、hooks</td>
			</tr>
			<tr>
					<td>worktree</td>
					<td>隔离并行任务</td>
					<td>每个线程内置 worktree</td>
					<td><code>git worktree</code>、隔离配置</td>
			</tr>
			<tr>
					<td>skill</td>
					<td>固化项目知识</td>
					<td>Agent Skills</td>
					<td>Agent Skills</td>
			</tr>
			<tr>
					<td>connector</td>
					<td>连接外部工具</td>
					<td>基于 MCP 的 Connectors</td>
					<td>MCP servers</td>
			</tr>
			<tr>
					<td>sub-agent</td>
					<td>分头干活、写查分离</td>
					<td>配置文件定义子 agent</td>
					<td>子 agent、agent teams</td>
			</tr>
			<tr>
					<td>记忆</td>
					<td>追踪进度</td>
					<td>markdown 或接工单系统</td>
					<td>markdown 或接工单系统</td>
			</tr>
	</tbody>
</table>
<h3 id="验证仍然归你"><a href="https://xiaolinnote.com/agent/engineering/loop-engineering.html#%E7%AC%AC%E4%B8%80%E7%9B%86-%E9%AA%8C%E8%AF%81%E4%BB%8D%E7%84%B6%E5%BD%92%E4%BD%A0">验证仍然归你</a></h3>
<p>loop 无人值守地运行，听起来很美。但换个角度念这句话：<strong>一个无人值守运行的 loop，也是一个无人值守犯错的 loop</strong>。</p>
<p>你睡觉时它在干活，也意味着你睡觉时它在犯错。</p>
<p>就算你按规矩配了负责检查的 sub-agent，也别高兴太早：<strong>检查 agent 嘴里的「done」，只是一个声明，不是一个证明</strong>。它说没问题，和真的没问题，中间还隔着你的眼睛。</p>
<h3 id="理解债越顺滑涨得越快"><a href="https://xiaolinnote.com/agent/engineering/loop-engineering.html#%E7%AC%AC%E4%BA%8C%E7%9B%86-%E7%90%86%E8%A7%A3%E5%80%BA-%E8%B6%8A%E9%A1%BA%E6%BB%91%E6%B6%A8%E5%BE%97%E8%B6%8A%E5%BF%AB">理解债，越顺滑涨得越快</a></h3>
<p>第二个问题更隐蔽。loop 交付你没写过的代码越快，「仓库里实际存在的东西」和「你脑子里真正理解的东西」之间的鸿沟就越大。</p>
<p>这有个专门的名字，叫<strong>理解债（Comprehension Debt）</strong>。</p>
<p>它和技术债不一样：技术债是代码烂，理解债是代码可能不烂，<strong>但你不知道它为什么是对的</strong>。出问题的那天，你面对的是一片自己「拥有」但不「理解」的代码。一个顺滑的 loop 不会帮你还这笔债，只会让它涨得更快，除非你坚持去读 loop 产出的东西。</p>
<p>第三个问题最扎心。loop 自己转起来之后，你会发现一个特别舒服的姿势：不再对产出有自己的观点，它给什么就收什么。</p>
<p>这个状态有个专门的名字，叫<strong>认知投降（Cognitive Surrender）</strong>。Osmani 的博客里有一段关于它的原话，非常锋利：</p>
<p>「带着判断力去设计 loop，它是解药；为了逃避思考去设计 loop，它是助燃剂。同一个动作，相反的结果。」</p>
<p>最后还有一笔很现实的账：token 成本。loop 是按循环烧 token 的，sub-agent 每多一个，就多一份模型和工具的开销。比较务实的花法，是把 sub-agent 用在「值得买第二意见」的地方，而不是处处双保险。token 富裕和精打细算这两种人，会设计出两种完全不同的 loop。</p>
]]></content:encoded>
    </item>
    <item>
      <title>RAG</title>
      <link>https://tuanzi-wow.cn/agent/%E5%B0%8F%E6%9E%97coding/rag/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/agent/%E5%B0%8F%E6%9E%97coding/rag/</guid>
      <description>RAG相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<h1 id="rag">RAG</h1>
<h3 id="llm的局限性">LLM的局限性</h3>
<ul>
<li>知识库有截至时间</li>
<li>大模型没有外部的私有数据</li>
<li>会出现幻觉</li>
</ul>
<h3 id="核心思路">核心思路</h3>
<ol>
<li>先从外部知识库中<strong>检索（Retrieval）</strong> 出和用户问题相关的资料</li>
<li>把检索到的资料作为<strong>增强（Augmented）</strong> 上下文，和用户的问题一起给到大模型</li>
<li>大模型基于这些真实的资料来<strong>生成（Generation）</strong> 回答</li>
</ol>
<p>两大阶段:
索引阶段(离线)和查询阶段(在线)</p>
<h2 id="索引阶段">索引阶段</h2>
<ol>
<li>文档加载:将各种格式的文档转化为纯文本</li>
<li>文档切割(Chunking)(分块):
不同的分块策略</li>
<li>向量化(嵌入:Embedding):将分好块的文本块转化为一个向量表示</li>
<li>存入向量数据库</li>
</ol>
<h2 id="查询阶段">查询阶段</h2>
<ol>
<li>输入向量化</li>
<li>相似度检索(+重排序)</li>
<li>构造增强prompt</li>
<li>LLM生成回答</li>
</ol>
<p>上面为最基础的RAG流程,也成为Naive RAG</p>
<h3 id="微调和rag区别是什么">微调和RAG区别是什么?</h3>
<p>微调(Fine_tuning):针对的是训练,针对下游任务进行</p>
<p>分为:</p>
<ul>
<li>全量微调</li>
<li>参数高效微调:如LoRA</li>
<li>指令微调:用(指令+回答)格式数据的微调</li>
</ul>
<h3 id="rag的chunking策略">RAG的Chunking策略</h3>
<h4 id="策略一固定大小切割">策略一:固定大小切割:</h4>
<p>容易破坏语义-&gt;引入重叠(但是不能解决问题)</p>
<h4 id="策略二递归字符切割">策略二:递归字符切割</h4>
<p>这是目前<strong>最常用的切割策略</strong>，也是 LangChain 框架中 <code>RecursiveCharacterTextSplitter</code> 的实现方式。</p>
<p>核心思想:按照文本的自然边界切割
维护一个分隔符的优先级列表,进行递归切割,如果使用a字符切割块太大,就使用下一个优先级的字符在块内切割,递归进行</p>
<h4 id="策略三基于文档结构的切割">策略三:基于文档结构的切割</h4>
<p>比如MD文件,使用标题层级
比如代码文件.根据函数,类
HTML,根据标签</p>
<h4 id="策略四语义切割">策略四:语义切割</h4>
<p>基于内容的语义相似度进行切割</p>
<p>核心思想是：<strong>把语义相似的句子放在一起，语义发生转折的地方就是切割点。</strong></p>
<p>实现方法:
先把文档按句子切分，然后计算相邻句子之间的语义相似度（用 Embedding 模型把句子转成向量，然后计算余弦相似度）。如果相邻句子的相似度很高，说明它们在讨论同一个话题，应该放在同一个块里；如果相似度突然下降，说明话题发生了转变，这里就是一个切割点</p>
<p>优点:切割质量最高 缺点:计算成本最高</p>
<p>策略五:Agent驱动的智能切割</p>
<p>先用上述方法生成初始的文本块，然后用 LLM 来审视每个块，判断这个块的内容是否完整、是否需要和相邻的块合并或拆分。LLM 充当一个「智能编辑」的角色，根据对内容的理解来做出切割决策</p>
<p>不缺钱的可以这么玩,效果理论上最好</p>
<h2 id="re-rank">Re-rank</h2>
<p>问题:向量检索只检索语义相似度,缺乏对于整体的理解</p>
<p>Bi-Encoder(双编码器).是RAG的Embedding模型,方法:
将查询和文档编码为向量并计算余弦相似度</p>
<p>Bi-Encoder的两个缺陷:
1.信息压缩损失
2.缺乏查询意图感知</p>
<h4 id="cross--encoder">Cross -Encoder:</h4>
<p>Re-rank使用的是Cross-Encoder(交叉编码器)
去Bi-coder的根本区别在于:<strong>它把查询和文档拼在一起,让模型同时看到两者,进行深度的交互分析</strong></p>
<p>Cross-Encoder把查询和文档拼成如下格式的输出:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">[CLS] 用户的问题 [SEP] 检索到的文档内容 [SEP]
</span></span></code></pre></td></tr></table>
</div>
</div><h5 id="缺陷">缺陷:</h5>
<p>太慢了,需要将查询和候选文档拼在一起做一次计算</p>
<h4 id="实际应用">实际应用</h4>
<p>两阶段检索
第一阶段:Bi-Encoder快速召回候选文档,追求速度和召回率
第二阶段:Cross-Encoder做精细化重排序</p>
<h4 id="主流的re-rank模型自己看">主流的Re-rank模型(自己看)</h4>
<p>目前市面上的 Re-rank 模型选择还挺多的，我聊聊几个主流的。</p>
<p><strong>Cohere Rerank</strong> 是目前用得最多的商业方案之一，它是一个 SaaS API 服务，效果好、接入简单，基本上几行代码就能用起来。如果你的项目预算充足，不想自己部署模型，Cohere 是最省心的选择。</p>
<p>如果你更倾向开源方案，<strong>BGE-Reranker</strong> 是目前开源模型里的标杆，由智源研究院出品，有 base 和 large 两个版本。它在中文场景下表现特别好，而且可以本地部署，数据安全有保障。很多国内企业在生产环境中用的就是它。</p>
<p><strong>ms-marco-MiniLM</strong> 是微软基于 MiniLM 训练的一个轻量级 Cross-Encoder，模型体积很小，推理速度快，适合资源有限的场景。比如你的服务器 GPU 不多，或者对延迟要求很高，这个模型就很合适。</p>
<p>另外还有 <strong>Jina Reranker</strong>，Jina AI 出品的，支持多语言，如果你有英文之外的检索需求可以关注一下；以及 <strong>bce-reranker</strong>，网易有道开源的双语重排序模型，中英文混合场景下效果不错。</p>
<h4 id="实际效果">实际效果</h4>
<p>在复杂效果中提升效果巨大,准确率上升幻觉降低</p>
<h2 id="embedding">Embedding</h2>
<p>将文字转化为计算机能够理解的文字,也就是向量
而在高维空间中,语义相近的文本在向量空间中的距离也相近</p>
<h4 id="第一代静态词向量">第一代:静态词向量</h4>
<p>Word2Vec:两种训练方式</p>
<ul>
<li>CBOW</li>
<li>Skip-gram</li>
</ul>
<h4 id="第二代上下文嵌入时代">第二代:上下文嵌入时代</h4>
<p>BERT:
自注意力机制,双向上下文理解</p>
<p>预训练方式:MLM和NSP</p>
<h4 id="第三代融合和优化时代">第三代:融合和优化时代</h4>
<p><strong>BGE-M3</strong> 是 2023 年发布的一个里程碑模型，它的「M3」代表三个多：</p>
<ul>
<li><strong>Multi-Granularity（多粒度）</strong>：能处理句子、段落、篇章、文档等不同粒度的输入，最大支持 8192 tokens。</li>
<li><strong>Multi-Functionality（多功能）</strong>：一站式集成稠密检索、稀疏检索和多向量检索三种能力，一次推理就能得到三种输出。</li>
<li><strong>Multi-Language（多语言）</strong>：支持 100 多种语言</li>
</ul>
<h4 id="第四代基于大模型的embedding">第四代:基于大模型的Embedding</h4>
<p>大模型有远超传统编码器模型的语义理解能力，如果能把这种能力迁移到 Embedding 生成上，</p>
<h3 id="怎么选-embedding-模型"><a href="https://xiaolinnote.com/agent/rag/rag.html#%E6%80%8E%E4%B9%88%E9%80%89-embedding-%E6%A8%A1%E5%9E%8B">怎么选 Embedding 模型？</a></h3>
<p>面对这么多选择，实际项目中怎么选？给几个实用的建议：</p>
<ol>
<li><strong>看榜单</strong>：参考 MTEB 排行榜，这是目前最权威的 Embedding 模型评测榜单。</li>
<li><strong>中文场景优先选国产模型</strong>：BGE 系列、M3E 系列、ACGE 系列在中文场景下表现通常优于 OpenAI 的模型。</li>
<li><strong>关注上下文窗口</strong>：如果你的文档很长（比如法律合同、学术论文），一定要选支持长上下文的模型（如 BGE-M3 的 8192 tokens）。</li>
<li><strong>考虑部署方式</strong>：如果对数据安全有要求，需要私有化部署，就选开源模型（BGE、M3E）；如果追求简单省事，就用 API 服务。</li>
</ol>
<h2 id="向量数据库">向量数据库</h2>
<p>使用特殊的索引结构,能够在海量向量中实现毫秒级的<strong>近似最近邻搜索</strong>(ANN)</p>
<h3 id="核心原理">核心原理</h3>
<p>用空间换时间,通过提前建立索引结构,让检索时不需要遍历所有向量
目前最主流的三种</p>
<h5 id="最常见的hnsw">最常见的HNSW</h5>
<p>给所有向量建立了一个多层导航图,几次跳级就可以定位到目标,查询速度快(ms),且召回率高</p>
<h5 id="ivf">IVF</h5>
<p>核心思想:先分区域再搜索
将所有向量先按照相似度聚合成若干个桶,查询先判断在哪几个桶,再在这几个桶里面查询
好处:内存效率高,适合超大规模数据,会损失一点召回率</p>
<p>PQ:
核心:压缩存储
把每个向量切成几段,每段嘴一个简化版的表示
适合内存优先的场景下特别使用</p>
<h3 id="主流向量数据库对比">主流向量数据库对比</h3>
<p>先说 <strong>Milvus</strong>。这个应该是目前开源向量数据库里最有名的一个了，由 Zilliz 公司开发维护，GitHub 上有 2 万多 Star。它最大的优势就是「能扛」，支持十亿级甚至百亿级的向量规模，索引类型也很丰富，HNSW、IVF、PQ 都支持，还有 GPU 加速选项。如果你的项目是那种企业级的、数据量特别大的场景，Milvus 基本上是首选。它的生态也很完善，Python、Java、Go 的 SDK 都有。但说实话，Milvus 的部署和维护有一定门槛，通常需要 Kubernetes 来编排，如果你团队没有 DevOps 经验，上手会有点吃力。</p>
<p>然后是 <strong>Pinecone</strong>。如果你不想折腾基础设施，Pinecone 可能是最省心的选择。它是一个全托管的 SaaS 服务，你不需要自己部署任何东西，注册个账号、几行代码就能开始用。自动扩缩容、零运维，对开发团队特别友好。但它的缺点也很明显：一是付费的，而且费用不算便宜；二是数据存在第三方服务器上，如果你的数据有合规要求（比如不能出境），就不太合适了。</p>
<p>再来说 <strong>Weaviate</strong>。这个是我个人比较喜欢的一个，因为它原生支持混合检索，也就是向量检索和 BM25 关键词检索可以一起做，不用你自己去拼接两套系统。它还内置了多种 Embedding 模型的集成，可以直接在 Weaviate 内部完成文本到向量的转换，省了一个步骤。如果你要做混合检索的 RAG 系统，Weaviate 是开箱即用的，体验很好。不过在大规模数据场景下，它的性能会比 Milvus 弱一些，适合中小规模的应用。</p>
<p><strong>Chroma</strong> 则是另外一个极端。它主打的就是「轻量」和「简单」，Python 原生支持，装个 pip 包就能用，API 设计得非常简洁。如果你是在做原型验证、个人项目、或者教学演示，Chroma 是最方便的。但它的功能和性能都比较有限，不支持分布式，也没有安全机制（没有加密、没有权限控制），所以不太适合用在生产环境里。</p>
<p>最后是 <strong>Qdrant</strong>。这个是后起之秀，用 Rust 语言写的，所以单机性能非常强。在 2025 年的一些基准测试中，Qdrant 的 QPS 和延迟表现都是同类产品里最好的。它也支持丰富的过滤条件和混合检索。如果你的场景对响应速度有很高要求，或者想自建但不想用那么重的 Milvus，Qdrant 是一个很好的折中选择。不过它的分布式方案相对来说还比较新，如果你需要多节点的集群部署，可能需要多测试一下稳定性。</p>
<h2 id="多路召回">多路召回</h2>
<p>向量检索只关注语义相似度,在精确匹配方面存在弊端</p>
<h3 id="核心思想">核心思想</h3>
<p>将多种召回方式的结果合并
常见的召回通道有</p>
<h4 id="1向量检索dense-retrieval">1.向量检索(Dense Retrieval)</h4>
<p>语义相似度,主力通道</p>
<h4 id="2关键词检索">2.关键词检索</h4>
<p>BM25,基于词频和文档频率</p>
<h4 id="3知识图谱检索">3.知识图谱检索</h4>
<p>关键:融合
多路召回的结果需要合并去重,并按照相关性排序
融合的方法</p>
<p>1.RRF(倒数排名融合,Reciprocal Rank Fusion)
核心思想:不看每个文档的绝对分数,只看他在各路召回中的排名</p>
<h3 id="混合检索的具体实现">混合检索的具体实现</h3>
<p>目前 RAG 实践中，<strong>向量检索 + BM25 关键词检索的混合检索</strong>已经成为标配方案。</p>
<ol>
<li>用户提问后，同时发起两路检索：
<ul>
<li>向量检索：把问题转成向量，在向量数据库中搜索 Top-K 个相似文档</li>
<li>BM25 检索：把问题分词后，在倒排索引中搜索 Top-K 个相关文档</li>
</ul>
</li>
<li>用 RRF 算法合并两路结果，得到综合排序</li>
<li>（可选）对合并后的结果做 Re-rank 精排</li>
<li>取最终 Top-N 个文档送入大模型</li>
</ol>
<h3 id="除了向量查询和关键词查询之外的其他的高级召回策略">除了向量查询和关键词查询之外的其他的高级召回策略:</h3>
<ul>
<li><strong>查询改写（Query Rewriting）</strong>：在检索之前，先用 LLM 把用户的原始问题改写成更适合检索的形式。比如用户问「你们公司加班多吗」，可以改写成「公司加班制度」「加班时间规定」「加班补贴政策」等多个查询，分别检索后再合并结果。</li>
<li><strong>HyDE（Hypothetical Document Embedding）</strong>：先让 LLM 根据用户问题生成一个「假设性的答案文档」，然后用这个假设文档的向量去检索。因为假设文档在表述上更接近真实的答案文档，所以检索效果通常更好。</li>
<li><strong>多查询扩展（Multi-Query）</strong>：把用户的一个问题，用 LLM 改写成多个不同角度的子问题，分别检索后合并结果。</li>
</ul>
<h2 id="量化rag的效果">量化RAG的效果</h2>
<p>分为两步部分进行,检索质量和生成质量</p>
<h3 id="检索质量的评估指标">检索质量的评估指标</h3>
<p><strong>召回率（Recall@K）：找全了没有？</strong></p>
<p>在检索返回的 Top-K 个结果中，有多少真正相关的文档被找到了。比如知识库中有 10 个和问题相关的文档，检索返回了 5 个，那召回率就是 50%。召回率关注的是「有没有遗漏」，找得全不全。</p>
<p><strong>精确率（Precision@K）：找对了没有？</strong></p>
<p>在检索返回的 Top-K 个结果中，有多少是真正相关的。比如检索返回了 10 个文档，其中 6 个是相关的，那精确率就是 60%。精确率关注的是「有没有乱凑」，找得准不准。</p>
<p>这两个是一对好搭档，一个关注「全」，一个关注「准」，通常需要平衡着看。除了这两个，还有一个更综合的指标叫 <strong>NDCG</strong>，它不仅看你找得全不全、准不准，还看「排得对不对」，也就是高度相关的文档是不是排在了前面，部分相关的文档是不是排在了后面。NDCG 是信息检索领域最常用的综合评估指标。</p>
<p>此外，还有一些辅助指标，比如 MRR 关注的是「第一个相关文档排在了第几位」，MAP 关注的是「所有相关文档的整体排序质量」。了解一下就行，核心记住 Recall、Precision 和 NDCG 这三个就够了。</p>
<h3 id="生成质量的评估指标">生成质量的评估指标</h3>
<p>需要判断回答是否准确,是否相关,是否忠实于检索到的文档</p>
<h4 id="faithfulness忠实度">Faithfulness(忠实度)</h4>
<p>最重要的指标,衡量LLM生成的回答是否忠实于检索到的文档,有没有编造检索文档中不存在的信息</p>
<p>RAGAS 框架（后面会介绍）的评估方式是：先把生成的回答拆分成一个个独立的陈述，然后检查每个陈述是否能从检索到的文档中找到支撑。如果有 10 个陈述，8 个能找到支撑，2 个是编造的，那忠实度就是 0.8。</p>
<h4 id="answer-relevance答案相关性">Answer Relevance(答案相关性)</h4>
<h4 id="context-relevance上下文相关性">Context Relevance(上下文相关性)</h4>
<h2 id="ragasrag评估的事实标准">RAGAS:RAG评估的事实标准</h2>
<p>目前RAG评估领域最流行的开源框架
核心思路:利用一个更强大的LLM作为裁判,来自动化评估RAG系统的输出质量
你只需要提供测试数据集(包含问题、标准答案、检索到的文档、模型生成的回答)
RAGAS就能自动计算上面提到的指标</p>
<p>RAGAS 的使用方式也很简单。你准备一个包含 <code>question</code>（问题）、<code>contexts</code>（检索到的文档）、<code>answer</code>（模型生成的回答）、<code>ground_truth</code>（标准答案）的数据集，然后调用 RAGAS 的 <code>evaluate</code> 函数就行了。</p>
<p>除了 RAGAS，还有一些其他的 RAG 评估工具：</p>
<ul>
<li><strong>DeepEval</strong>：把 RAG 评估融入单元测试框架，适合工程化团队</li>
<li><strong>TruLens</strong>：提供 RAG 应用的深度可观测性和诊断能力</li>
<li><strong>ARES</strong>：用 LLM 生成合成评估数据，解决人工标注数据不足的问题</li>
</ul>
<h2 id="幻觉hallucination">幻觉（Hallucination）</h2>
<p>大模型自行编造的内容
幻觉不等于错误,而是不知道而假装指导</p>
<h3 id="幻觉的类型">幻觉的类型</h3>
<h4 id="事实性幻觉factuality-hallucination">事实性幻觉（Factuality Hallucination）</h4>
<p>生成的内容与客观事实不符
又分为两类:内在幻觉和外在幻觉
内在幻觉:与上下文信息矛盾
外在幻觉:生成内容无法从输入上下文和任何已知知识中验证,是凭空捏造的</p>
<h3 id="幻觉的产生的原因">幻觉的产生的原因</h3>
<h4 id="数据层面">数据层面</h4>
<p>训练数据包含错误信息,偏见或过时的知识</p>
<h4 id="训练层面">训练层面</h4>
<p>LLM追求生成[看起来合理]的内容而非[事实上正确]的内容</p>
<h4 id="推理层面">推理层面</h4>
<p>提示词诱导幻觉:比如提示词包含错误信息</p>
<h3 id="rag是怎么降低幻觉的">RAG是怎么降低幻觉的</h3>
<ul>
<li>注入真实知识</li>
<li>注意力机制偏向</li>
<li>可追溯可验证</li>
</ul>
<p>但是不能消除幻觉</p>
<h3 id="除了rag还有哪些可以降低幻觉的方法">除了RAG还有哪些可以降低幻觉的方法?</h3>
<ol>
<li>prompt engineering</li>
<li>输出验证(独立校验)</li>
<li>领域微调(SFT[有监督微调]和RLHF[人类反馈强化学习])</li>
<li>不确定性量化</li>
<li>GraphRAG和lightRAG</li>
</ol>
]]></content:encoded>
    </item>
  </channel>
</rss>
