<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Agent on 方糖猫Blog</title>
    <link>https://ftmao.com/blog/tags/agent/</link>
    <description>AI 视频、AI Agent 与工程实践笔记</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Wed, 02 Sep 2026 10:00:00 +0800</lastBuildDate><atom:link href="https://ftmao.com/blog/tags/agent/index.xml" rel="self" type="application/rss+xml" /><item>
      <title>本体数据（Ontology Data）核心概念与组成要素：从本体构建到智能体落地的实施路径</title>
      <link>https://ftmao.com/blog/posts/ontology-data-agent-implementation-path/</link>
      <pubDate>Wed, 02 Sep 2026 10:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/ontology-data-agent-implementation-path/</guid>
      <description>&lt;h1 id=&#34;本体数据ontology-data核心概念与组成要素从本体构建到智能体落地的实施路径&#34;&gt;本体数据（Ontology Data）核心概念与组成要素：从本体构建到智能体落地的实施路径&lt;/h1&gt;
&lt;p&gt;过去两年，一个&amp;quot;老词&amp;quot;重新热了起来：&lt;strong&gt;本体（Ontology）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它上一次被大规模讨论还是二十年前语义网（Semantic Web）的年代。这一次把它重新推上舞台中央的，是大模型和智能体（Agent）。原因很朴素：当 AI 从&amp;quot;聊天&amp;quot;走向&amp;quot;办事&amp;quot;，它需要的不再只是文本语料，而是&lt;strong&gt;对企业业务的结构化理解&lt;/strong&gt;——客户是什么、订单是什么、什么状态能退款、哪个字段对应哪个口径。这些东西散落在各个系统的表结构、接口文档和老员工的脑子里，LLM 猜不到，RAG 检索回来的也只是只言片语。&lt;/p&gt;
&lt;p&gt;Palantir 把 Ontology 做成了 AIP 的基石并在资本市场讲出了漂亮的故事；微软在 2025 年底 Ignite 大会发布 Fabric IQ、把 Ontology 塞进自家数据平台；中国信通院在 2026 年 7 月发布了《本体智能研究报告（1.0）》。本体，正从学术概念变成智能体落地的&amp;quot;语义底座&amp;quot;。&lt;/p&gt;
&lt;p&gt;这篇文章做两件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;把本体数据的核心概念与组成要素一次梳理清楚；&lt;/li&gt;
&lt;li&gt;给出一条从本体构建到智能体落地的、可操作的实施路径，并配上实战事例。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一什么是本体数据概念演化与边界&#34;&gt;一、什么是本体数据：概念演化与边界&lt;/h2&gt;
&lt;h3 id=&#34;11-从哲学到工程本体的四次演化&#34;&gt;1.1 从哲学到工程：本体的四次演化&lt;/h3&gt;
&lt;p&gt;&amp;ldquo;本体&amp;quot;这个词的履历相当丰富，理解它的演化路径，有助于我们明白今天工程语境下它到底指什么：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;timeline
    title 本体概念的演化路径
    古希腊~近代哲学 : 哲学本体论（Ontology）
                      : 研究&amp;#34;存在&amp;#34;本身——世界由什么构成
    1990s 人工智能 : 形式化本体
                   : Gruber 定义——&amp;#34;对概念化的显式规范&amp;#34;
                   : 让机器能共享和复用领域知识
    2000s 语义网 : OWL / RDF / SPARQL 标准体系
                 : W3C 语义网技术栈成型
                 : 本体语言具备形式化推理能力
    2012~ 知识图谱 : Google Knowledge Graph 引爆
                   : 本体作为图谱的 Schema 层
                   : 大规模实例数据 + 图存储
    2024~ 本体智能 : 大模型 + Agent 时代
                   : 本体成为智能体的语义基座
                   : 从&amp;#34;查询与推理&amp;#34;走向&amp;#34;决策与行动&amp;#34;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;工程界最常被引用的定义来自 Tom Gruber（1993）：&lt;strong&gt;&amp;ldquo;本体是对概念化的显式规范&amp;rdquo;（An ontology is an explicit specification of a conceptualization）&lt;/strong&gt;。翻译成大白话：把一群人脑子里对某个业务领域的共识，用机器可读的、形式化的方式写下来——有哪些概念、概念之间什么关系、遵守什么规则。&lt;/p&gt;
&lt;p&gt;中国信通院在《本体智能研究报告（1.0）》中追溯了&amp;quot;哲学本体论 → 形式化本体 → 知识图谱 → 本体智能&amp;quot;的完整脉络，并将&lt;strong&gt;本体智能&lt;/strong&gt;界定为：以形式化本体为语义基座，融合语义推理与知识计算，实现信息系统深层理解、逻辑推理与自动化执行的新范式（详见&lt;a href=&#34;https://www.secrss.com/articles/92201&#34;&gt;安全内参报道&lt;/a&gt;）。这个&amp;quot;从理解到执行&amp;quot;的落脚点变化，正是本轮本体复兴与二十年前语义网运动的本质区别。&lt;/p&gt;
&lt;h3 id=&#34;12-本体-vs-知识图谱-vs-语义层-vs-数据模型&#34;&gt;1.2 本体 vs 知识图谱 vs 语义层 vs 数据模型&lt;/h3&gt;
&lt;p&gt;这几个概念经常被混用，但它们的职责边界其实很清晰：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;概念&lt;/th&gt;
					&lt;th&gt;回答的问题&lt;/th&gt;
					&lt;th&gt;类比&lt;/th&gt;
					&lt;th&gt;典型载体&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;数据模型（Schema）&lt;/td&gt;
					&lt;td&gt;数据&lt;strong&gt;怎么存&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;仓库的货架设计图&lt;/td&gt;
					&lt;td&gt;ER 图、DDL、数据表&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;语义层（Semantic Layer）&lt;/td&gt;
					&lt;td&gt;指标和业务术语&lt;strong&gt;怎么算、怎么叫&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;全公司统一的度量衡手册&lt;/td&gt;
					&lt;td&gt;指标平台、Cube、dbt metrics&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;本体（Ontology）&lt;/td&gt;
					&lt;td&gt;业务世界里&lt;strong&gt;有什么、什么关系、什么规则&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;业务的&amp;quot;词典 + 语法书 + 法规汇编&amp;rdquo;&lt;/td&gt;
					&lt;td&gt;OWL、RDF Schema、Palantir Ontology&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;知识图谱（Knowledge Graph）&lt;/td&gt;
					&lt;td&gt;具体的人和事&lt;strong&gt;是什么样&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;装满货物、贴了统一标签的仓库&lt;/td&gt;
					&lt;td&gt;Neo4j、图数据库中的实例数据&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;用 Jessica Talisman 的一句广为流传的话概括：&amp;quot;&lt;strong&gt;语义层用于查找，本体用于上下文和推理。&lt;/strong&gt;&amp;quot;（参考&lt;a href=&#34;https://www.hubwiz.com/blog/ontology-vs-semantic-layer/&#34;&gt;OceanBase 团队的对比分析&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;一个直观的例子：你问&amp;quot;上个月哪个渠道贡献了最高 GMV&amp;quot;，语义层能给你一个口径统一的精确数字；但你接着问&amp;quot;为什么这个渠道掉了、该不该追加预算&amp;quot;，语义层就哑火了——它不知道&amp;quot;渠道&amp;quot;和&amp;quot;预算策略&amp;quot;、&amp;ldquo;市场活动&amp;rdquo;、&amp;ldquo;竞品动作&amp;quot;之间的关系与规则。而这正是本体的领地。&lt;/p&gt;
&lt;p&gt;再说本体和知识图谱的关系，一句话：&lt;strong&gt;本体是知识图谱的 Schema，知识图谱是本体的实例化。&lt;/strong&gt; 就像面向对象里&amp;quot;类&amp;quot;与&amp;quot;对象&amp;quot;的关系——本体定义了&amp;quot;设备&amp;quot;&amp;ldquo;工单&amp;quot;这些类以及它们的属性和关系，知识图谱里则躺着三万条具体的设备记录和十万条工单。&lt;/p&gt;
&lt;h3 id=&#34;13-为什么-agent-时代需要本体&#34;&gt;1.3 为什么 Agent 时代需要本体&lt;/h3&gt;
&lt;p&gt;不妨先看一个真实行业中反复上演的窘境（&lt;a href=&#34;https://www.hubwiz.com/blog/ontology-vs-semantic-layer/&#34;&gt;OceanBase DataPilot 团队观察&lt;/a&gt;）：同一个&amp;quot;收入&amp;quot;指标，财务说是 1020 万，市场说是 1040 万，Slack 里的 AI 助手说是 980 万。三个数字，没有共识。&lt;/p&gt;
&lt;p&gt;以前这是人的问题，开个十分钟的会就能对齐。但&lt;strong&gt;Agent 不会发消息问同事&amp;quot;这个指标怎么算&amp;rdquo;&lt;/strong&gt;。当它面对一个叫 &lt;code&gt;rev_ttm_adj_v2&lt;/code&gt; 的列名时，要么编造答案，要么随手捡起它找到的第一个定义。行业实践证明，把建模过的领域知识注入检索路径，幻觉率可以降低约 40%——前提是这些知识确实被结构化地沉淀下来了。&lt;/p&gt;
&lt;p&gt;大模型时代本体的价值，可以归纳为三点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;对齐语义&lt;/strong&gt;：给 LLM 一份&amp;quot;业务词典&amp;rdquo;，消除同名异义、异名同义，让 Agent 说&amp;quot;行话&amp;quot;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;约束行为&lt;/strong&gt;：用公理和规则圈出 Agent 能做什么、不能做什么（什么订单能退款、谁能审批），把&amp;quot;幻觉&amp;quot;关进笼子；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支撑推理与行动&lt;/strong&gt;：让 Agent 不只检索片段文本，而是沿关系推理（设备→部件→供应商→库存），最终落到可执行的动作（创建工单、锁定库存）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二本体数据的核心组成要素&#34;&gt;二、本体数据的核心组成要素&lt;/h2&gt;
&lt;h3 id=&#34;21-六大基本要素&#34;&gt;2.1 六大基本要素&lt;/h3&gt;
&lt;p&gt;一个完整的本体，通常由以下要素组成。这里用制造业&amp;quot;设备运维&amp;quot;域来举例说明：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;要素&lt;/th&gt;
					&lt;th&gt;英文&lt;/th&gt;
					&lt;th&gt;含义&lt;/th&gt;
					&lt;th&gt;设备运维域的例子&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;类 / 概念&lt;/td&gt;
					&lt;td&gt;Class / Concept&lt;/td&gt;
					&lt;td&gt;领域内事物的类型，可继承&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;设备&lt;/code&gt;，其子类：&lt;code&gt;泵&lt;/code&gt;、&lt;code&gt;电机&lt;/code&gt;、&lt;code&gt;压缩机&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;实例 / 个体&lt;/td&gt;
					&lt;td&gt;Instance / Individual&lt;/td&gt;
					&lt;td&gt;类的具体对象&lt;/td&gt;
					&lt;td&gt;&amp;ldquo;3 号车间的 P-102 号离心泵&amp;rdquo;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;属性&lt;/td&gt;
					&lt;td&gt;Property&lt;/td&gt;
					&lt;td&gt;实例的特征（数据属性）或实例间的关系（对象属性）&lt;/td&gt;
					&lt;td&gt;数据属性：&lt;code&gt;额定功率=75kW&lt;/code&gt;；对象属性：&lt;code&gt;P-102 安装在 3号车间&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;关系&lt;/td&gt;
					&lt;td&gt;Relation&lt;/td&gt;
					&lt;td&gt;类与类之间的语义关联&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;设备 包含 部件&lt;/code&gt;、&lt;code&gt;工单 处理 故障&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;公理 / 约束&lt;/td&gt;
					&lt;td&gt;Axiom / Constraint&lt;/td&gt;
					&lt;td&gt;永远为真的规则，用于推理和校验&lt;/td&gt;
					&lt;td&gt;&amp;ldquo;额定功率 &amp;gt; 100kW 的设备必须每季度点检&amp;rdquo;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;动作 / 函数&lt;/td&gt;
					&lt;td&gt;Action / Function&lt;/td&gt;
					&lt;td&gt;本体驱动的可执行操作（Palantir 风格的本体扩展）&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;创建维修工单(设备, 故障类型)&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;classDiagram
    class 设备 {
        +设备编号: string
        +额定功率: float
        +投运日期: date
    }
    class 泵
    class 电机
    class 部件 {
        +部件编号: string
        +材质: string
    }
    class 故障 {
        +故障码: string
        +发生时间: datetime
        +严重等级: int
    }
    class 维修工单 {
        +工单号: string
        +状态: enum
    }
    class 供应商 {
        +名称: string
        +备件库存: int
    }

    设备 &amp;lt;|-- 泵 : 继承(is-a)
    设备 &amp;lt;|-- 电机 : 继承(is-a)
    设备 &amp;#34;1&amp;#34; *-- &amp;#34;多&amp;#34; 部件 : 包含(has-part)
    设备 &amp;#34;1&amp;#34; --&amp;gt; &amp;#34;多&amp;#34; 故障 : 发生(has-fault)
    故障 &amp;#34;1&amp;#34; --&amp;gt; &amp;#34;0..1&amp;#34; 维修工单 : 触发(triggers)
    部件 &amp;#34;多&amp;#34; --&amp;gt; &amp;#34;1&amp;#34; 供应商 : 采购自(supplied-by)

    note for 设备 &amp;#34;公理：额定功率&amp;gt;100kW ⇒ 强制季度点检\n动作：创建维修工单(设备, 故障)&amp;#34;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;22-属性的两种类型与语义三元组&#34;&gt;2.2 属性的两种类型与语义三元组&lt;/h3&gt;
&lt;p&gt;在传统本体语言（RDF/OWL）里，所有知识最终都会落到**三元组（Triple）**上：&lt;code&gt;(主语, 谓语, 宾语)&lt;/code&gt;。谓语分两类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数据属性（Data Property）&lt;/strong&gt;：宾语是字面量，如 &lt;code&gt;(P-102, 额定功率, 75)&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对象属性（Object Property）&lt;/strong&gt;：宾语是另一个实例，如 &lt;code&gt;(P-102, 位于, 三号车间)&lt;/code&gt;——这是&amp;quot;图&amp;quot;的边。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对象属性还可以带语义特征，这些特征是自动推理的燃料：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;属性特征&lt;/th&gt;
					&lt;th&gt;含义&lt;/th&gt;
					&lt;th&gt;例子&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;传递性（Transitive）&lt;/td&gt;
					&lt;td&gt;A→B 且 B→C 则 A→C&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;部件属于部件&lt;/code&gt;：轴承属于转子，转子属于泵 ⇒ 轴承属于泵&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;对称性（Symmetric）&lt;/td&gt;
					&lt;td&gt;A→B 则 B→A&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;与……同轴安装&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;互逆性（Inverse）&lt;/td&gt;
					&lt;td&gt;A→B 等价于 B→A⁻¹&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;包含部件&lt;/code&gt; 与 &lt;code&gt;属于设备&lt;/code&gt; 互逆&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;函数性（Functional）&lt;/td&gt;
					&lt;td&gt;一个主语最多一个宾语&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;设备拥有唯一资产编号&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;23-用-owlturtle-写一个最小本体&#34;&gt;2.3 用 OWL/Turtle 写一个最小本体&lt;/h3&gt;
&lt;p&gt;让概念落地，下面是一段真实可用的 Turtle 语法（OWL 的文本序列化格式），描述上面设备域的一个切片：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-turtle&#34; data-lang=&#34;turtle&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;@prefix&lt;/span&gt; : &amp;lt;http://example.com/factory#&amp;gt; .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;@prefix&lt;/span&gt; owl: &amp;lt;http://www.w3.org/2002/07/owl#&amp;gt; .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;@prefix&lt;/span&gt; xsd: &amp;lt;http://www.w3.org/2001/XMLSchema#&amp;gt; .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 类与继承&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;设备&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;a&lt;/span&gt; owl:&lt;span style=&#34;color:#f92672&#34;&gt;Class&lt;/span&gt; .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;泵&lt;/span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;a&lt;/span&gt; owl:&lt;span style=&#34;color:#f92672&#34;&gt;Class&lt;/span&gt; ; owl:&lt;span style=&#34;color:#f92672&#34;&gt;subClassOf&lt;/span&gt; :&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;设备&lt;/span&gt; .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;部件&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;a&lt;/span&gt; owl:&lt;span style=&#34;color:#f92672&#34;&gt;Class&lt;/span&gt; .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;故障&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;a&lt;/span&gt; owl:&lt;span style=&#34;color:#f92672&#34;&gt;Class&lt;/span&gt; .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 对象属性（带传递性）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;包含部件&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;a&lt;/span&gt; owl:&lt;span style=&#34;color:#f92672&#34;&gt;ObjectProperty&lt;/span&gt; , owl:&lt;span style=&#34;color:#f92672&#34;&gt;TransitiveProperty&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           owl:&lt;span style=&#34;color:#f92672&#34;&gt;domain&lt;/span&gt; :&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;设备&lt;/span&gt; ; owl:&lt;span style=&#34;color:#f92672&#34;&gt;range&lt;/span&gt; :&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;部件&lt;/span&gt; .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;发生故障&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;a&lt;/span&gt; owl:&lt;span style=&#34;color:#f92672&#34;&gt;ObjectProperty&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           owl:&lt;span style=&#34;color:#f92672&#34;&gt;domain&lt;/span&gt; :&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;设备&lt;/span&gt; ; owl:&lt;span style=&#34;color:#f92672&#34;&gt;range&lt;/span&gt; :&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;故障&lt;/span&gt; .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 数据属性（带函数性约束）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;额定功率&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;a&lt;/span&gt; owl:&lt;span style=&#34;color:#f92672&#34;&gt;DatatypeProperty&lt;/span&gt; , owl:&lt;span style=&#34;color:#f92672&#34;&gt;FunctionalProperty&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           owl:&lt;span style=&#34;color:#f92672&#34;&gt;domain&lt;/span&gt; :&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;设备&lt;/span&gt; ; owl:&lt;span style=&#34;color:#f92672&#34;&gt;range&lt;/span&gt; xsd:&lt;span style=&#34;color:#f92672&#34;&gt;float&lt;/span&gt; .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 实例&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;P-102&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;a&lt;/span&gt; :&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;泵&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        :&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;额定功率&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;75.0&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        :&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;包含部件&lt;/span&gt; :&lt;span style=&#34;color:#f92672&#34;&gt;P-102-转子&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        :&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;发生故障&lt;/span&gt; :&lt;span style=&#34;color:#f92672&#34;&gt;F-2026-0817&lt;/span&gt; .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;有了这段形式化描述，推理机（Reasoner）就能自动回答：&amp;ldquo;P-102 属于设备吗？&amp;quot;（是，因为 &lt;code&gt;泵&lt;/code&gt; 是 &lt;code&gt;设备&lt;/code&gt; 的子类）、&amp;ldquo;它有哪些部件？&amp;quot;（沿传递关系展开）——&lt;strong&gt;这些答案不是你写进去的，是推出来的&lt;/strong&gt;。这正是本体区别于普通数据库视图的硬核能力。&lt;/p&gt;
&lt;h3 id=&#34;24-工程扩展从静态知识到可行动的本体&#34;&gt;2.4 工程扩展：从&amp;quot;静态知识&amp;quot;到&amp;quot;可行动的本体&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;传统本体止步于&amp;quot;描述世界&amp;rdquo;。而 Palantir 开创并影响了整个行业的工程实践是：&lt;strong&gt;把动作（Action）、权限（Security）、业务逻辑（Function）也装进本体&lt;/strong&gt;。于是本体不再只是&amp;quot;业务的词典&amp;quot;，还是&amp;quot;业务的操作界面&amp;quot;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Agent 查&amp;quot;哪些设备高风险&amp;quot;——沿本体关系和公理推理；&lt;/li&gt;
&lt;li&gt;Agent 决定&amp;quot;该停机检修&amp;quot;——调用本体上注册的 &lt;code&gt;创建维修工单&lt;/code&gt; Action；&lt;/li&gt;
&lt;li&gt;谁能调用这个 Action、能操作哪些车间的数据——由本体层统一做行级/列级权限控制。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就是&amp;quot;本体是智能体的语义底座&amp;quot;这句话的完整含义：&lt;strong&gt;知识、规则、行动、权限，四位一体。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三本体构建方法论&#34;&gt;三、本体构建方法论&lt;/h2&gt;
&lt;h3 id=&#34;31-三种构建路线&#34;&gt;3.1 三种构建路线&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;路线&lt;/th&gt;
					&lt;th&gt;做法&lt;/th&gt;
					&lt;th&gt;优点&lt;/th&gt;
					&lt;th&gt;缺点&lt;/th&gt;
					&lt;th&gt;适用场景&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;自顶向下&lt;/td&gt;
					&lt;td&gt;先由领域专家定义概念体系，再填充实例&lt;/td&gt;
					&lt;td&gt;体系严谨、语义一致&lt;/td&gt;
					&lt;td&gt;周期长、依赖稀缺专家&lt;/td&gt;
					&lt;td&gt;强监管、高严谨场景（医疗、金融合规）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;自底向上&lt;/td&gt;
					&lt;td&gt;从现有数据（表结构、文档）抽取概念，归纳出本体&lt;/td&gt;
					&lt;td&gt;起步快、贴地气&lt;/td&gt;
					&lt;td&gt;容易变成&amp;quot;表结构的镜像&amp;quot;，缺乏业务抽象&lt;/td&gt;
					&lt;td&gt;数据基础好、快速验证场景&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;混合式（推荐）&lt;/td&gt;
					&lt;td&gt;专家定骨架 + LLM 辅助从数据/文档中抽取血肉&lt;/td&gt;
					&lt;td&gt;兼顾质量与效率&lt;/td&gt;
					&lt;td&gt;需要人机协同流程设计&lt;/td&gt;
					&lt;td&gt;绝大多数企业落地场景&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;值得强调的是 LLM 给本体构建带来的范式变化：过去本体工程最大的瓶颈是&lt;strong&gt;人工成本&lt;/strong&gt;（专家访谈、概念梳理动辄数月），现在可以让 LLM 从制度文档、接口文档、表注释里抽取候选概念和关系，专家只做审核和裁决。信通院报告也指出，当前本体工程化最成熟的起点仍是&lt;strong&gt;结构化数据&lt;/strong&gt;；面对文本、表格等非结构化信息，可以结合大模型完成语义抽取与对齐后，再进入统一的本体语义体系（参考&lt;a href=&#34;https://www.eefocus.com/article/2076399.html&#34;&gt;与非网对本体产业的解读&lt;/a&gt;）。&lt;/p&gt;
&lt;h3 id=&#34;32-stanford-七步法经典构建流程&#34;&gt;3.2 Stanford 七步法：经典构建流程&lt;/h3&gt;
&lt;p&gt;本体工程领域最经典的方法论是斯坦福大学提出的&amp;quot;七步法&amp;quot;（Ontology Development 101）。结合 LLM 辅助，完整的构建流程如下：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[1. 确定范围与目的&amp;lt;br/&amp;gt;本体服务哪个业务域？回答什么问题？] --&amp;gt; B[2. 调研复用&amp;lt;br/&amp;gt;是否有现成上位本体/行业标准可继承？]
    B --&amp;gt; C[3. 枚举核心术语&amp;lt;br/&amp;gt;领域专家 + LLM 从文档/表结构抽取候选概念]
    C --&amp;gt; D[4. 定义类与层级&amp;lt;br/&amp;gt;确定 is-a 继承树，区分上位/下位概念]
    D --&amp;gt; E[5. 定义属性与关系&amp;lt;br/&amp;gt;数据属性、对象属性、属性特征]
    E --&amp;gt; F[6. 定义约束与公理&amp;lt;br/&amp;gt;基数约束、值域约束、业务规则]
    F --&amp;gt; G[7. 填充实例并验证&amp;lt;br/&amp;gt;推理机一致性检查 + 胜任问题测试]
    G --&amp;gt;|发现缺口/冲突| C
    G --&amp;gt; H[发布上线，进入版本化治理]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;两个容易被忽视但极其关键的环节：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;胜任问题（Competency Questions）&lt;/strong&gt;：在建模之前，先写下&amp;quot;这个本体必须能回答的 20 个问题&amp;quot;（如&amp;quot;某供应商断供时，影响哪些在产设备？&amp;quot;）。它是本体范围的验收标准，能有效防止建模发散。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复用优于自建&lt;/strong&gt;：医疗有 SNOMED CT、金融有 FIBO、通用领域有 Schema.org。直接继承成熟上位本体，比从零造轮子靠谱得多。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;33-工具链速览&#34;&gt;3.3 工具链速览&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;层级&lt;/th&gt;
					&lt;th&gt;开源工具&lt;/th&gt;
					&lt;th&gt;商业产品&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;本体建模&lt;/td&gt;
					&lt;td&gt;Protégé、TopBraid Composer（社区版）&lt;/td&gt;
					&lt;td&gt;Palantir Foundry Ontology、PoolParty&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;存储与查询&lt;/td&gt;
					&lt;td&gt;Apache Jena（RDF/SPARQL）、Neo4j（属性图/Cypher）、RDFLib&lt;/td&gt;
					&lt;td&gt;Stardog、GraphDB、Amazon Neptune&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;推理机&lt;/td&gt;
					&lt;td&gt;HermiT、Pellet、Openllet&lt;/td&gt;
					&lt;td&gt;Stardog 推理引擎&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;LLM 抽取/对齐&lt;/td&gt;
					&lt;td&gt;LangChain + Pydantic 结构化抽取、GraphRAG 管道&lt;/td&gt;
					&lt;td&gt;Palantir AIP、微软 Fabric IQ&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Agent 接入&lt;/td&gt;
					&lt;td&gt;MCP Server 自研、LangGraph 工具封装&lt;/td&gt;
					&lt;td&gt;Palantir AIP Logic、Salesforce Agentforce&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四实施路径从本体构建到智能体落地&#34;&gt;四、实施路径：从本体构建到智能体落地&lt;/h2&gt;
&lt;p&gt;这是本文的重点。把前面所有概念串成一条可执行的路径，共六个阶段：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph 一[&amp;#34;阶段一：业务域盘点（1~2 周）&amp;#34;]
        A1[选定高价值场景] --&amp;gt; A2[盘点数据源与利益方] --&amp;gt; A3[写下胜任问题清单]
    end
    subgraph 二[&amp;#34;阶段二：本体建模（2~4 周）&amp;#34;]
        B1[专家定概念骨架] --&amp;gt; B2[LLM 辅助抽取候选概念/关系] --&amp;gt; B3[定义公理与动作]
    end
    subgraph 三[&amp;#34;阶段三：数据映射与实例化（2~4 周）&amp;#34;]
        C1[表/接口 → 本体映射] --&amp;gt; C2[ETL 实例化] --&amp;gt; C3[质量校验与消歧]
    end
    subgraph 四[&amp;#34;阶段四：语义服务化（1~2 周）&amp;#34;]
        D1[封装查询 API/SPARQL/Cypher] --&amp;gt; D2[封装 Action 接口] --&amp;gt; D3[权限与审计]
    end
    subgraph 五[&amp;#34;阶段五：Agent 接入（2~3 周）&amp;#34;]
        E1[工具注册 / MCP Server] --&amp;gt; E2[Prompt 注入领域语义] --&amp;gt; E3[编排推理与行动链]
    end
    subgraph 六[&amp;#34;阶段六：评估与治理迭代（持续）&amp;#34;]
        F1[胜任问题回归测试] --&amp;gt; F2[幻觉率/准确率评估] --&amp;gt; F3[本体版本演进]
    end
    一 --&amp;gt; 二 --&amp;gt; 三 --&amp;gt; 四 --&amp;gt; 五 --&amp;gt; 六
    六 -.反馈.-&amp;gt; 二&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;41-阶段一业务域盘点别上来就建模&#34;&gt;4.1 阶段一：业务域盘点——别上来就建模&lt;/h3&gt;
&lt;p&gt;最常见的失败模式是：IT 团队热血沸腾地建了一个覆盖全公司的&amp;quot;企业级本体&amp;quot;，半年后无人问津。正确的姿势是&lt;strong&gt;场景驱动&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;选一个痛且高频的场景&lt;/strong&gt;：比如&amp;quot;设备故障诊断与维修调度&amp;quot;——每天发生、跨系统（MES + ERP + 库存）、出错代价高；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;盘点数据源&lt;/strong&gt;：这个场景涉及哪些系统的哪些表、哪些文档（SOP、维修手册）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;写胜任问题清单&lt;/strong&gt;：和业务方一起写下 Agent 必须能回答/执行的事，作为本体的验收标准。&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;感悟：&lt;strong&gt;本体不是数据架构的目标，而是业务问题的副产品。&lt;/strong&gt; 没有胜任问题清单的本体项目，九成活不过一年。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;42-阶段二本体建模人机协同&#34;&gt;4.2 阶段二：本体建模——人机协同&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;领域专家定义概念骨架（设备、部件、故障、工单、供应商五大类及继承关系）；&lt;/li&gt;
&lt;li&gt;LLM 从维修手册、点检 SOP、表注释中抽取候选属性与关系，专家审核入库；&lt;/li&gt;
&lt;li&gt;定义公理（&amp;ldquo;功率&amp;gt;100kW 必须季度点检&amp;rdquo;）和动作（&lt;code&gt;创建工单&lt;/code&gt;、&lt;code&gt;锁定备件&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;反模式提醒&lt;/strong&gt;：不要照搬数据库表结构。表是&amp;quot;怎么存&amp;quot;，本体是&amp;quot;怎么理解&amp;quot;。比如 ERP 里 &lt;code&gt;MATERIAL&lt;/code&gt;、&lt;code&gt;BOM_ITEM&lt;/code&gt;、&lt;code&gt;SPARE_PART&lt;/code&gt; 三张表，在本体里可能统一为&lt;code&gt;部件&lt;/code&gt;一个概念加几个关系——本体建模的过程，本身就是一次业务概念对齐。&lt;/p&gt;
&lt;h3 id=&#34;43-阶段三数据映射与实例化&#34;&gt;4.3 阶段三：数据映射与实例化&lt;/h3&gt;
&lt;p&gt;把存量数据灌进图谱，技术上是 ETL，难点在&lt;strong&gt;实体消歧与对齐&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同一个供应商，ERP 里叫&amp;quot;上海精工机电有限公司&amp;quot;，MES 里叫&amp;quot;精工机电&amp;quot;——需要基于规则 + LLM 的实体对齐；&lt;/li&gt;
&lt;li&gt;保留&lt;strong&gt;溯源信息&lt;/strong&gt;：每个实例记录它来自哪个系统的哪条记录，这是后续可信审计的根基。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;44-阶段四语义服务化&#34;&gt;4.4 阶段四：语义服务化&lt;/h3&gt;
&lt;p&gt;本体不能直接丢给 Agent 裸查，要封装成稳定的语义服务：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    subgraph 语义服务层
        Q[查询服务&amp;lt;br/&amp;gt;SPARQL / Cypher / REST] 
        Act[动作服务&amp;lt;br/&amp;gt;创建工单 / 锁库存 / 派工]
        S[权限与审计&amp;lt;br/&amp;gt;行级权限 + 操作留痕]
    end
    KG[(知识图谱&amp;lt;br/&amp;gt;Neo4j / RDF Store)]
    ERP[(ERP)] 
    MES[(MES)]
    WMS[(库存系统)]
    
    ERP --&amp;gt;|ETL 映射| KG
    MES --&amp;gt;|ETL 映射| KG
    WMS --&amp;gt;|ETL 映射| KG
    KG --&amp;gt; Q
    Q --&amp;gt; Act
    Act --&amp;gt;|回写| MES
    S -.管控.-&amp;gt; Q
    S -.管控.-&amp;gt; Act&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;这一层的意义：&lt;strong&gt;Agent 永远通过受控接口访问世界&lt;/strong&gt;，而不是直接操作数据库。权限收敛在一处，审计留痕在一处。&lt;/p&gt;
&lt;h3 id=&#34;45-阶段五agent-接入&#34;&gt;4.5 阶段五：Agent 接入&lt;/h3&gt;
&lt;p&gt;当前主流有两种接入方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;工具封装&lt;/strong&gt;：把语义服务包成 Agent 框架的 Tool（LangChain/LangGraph/AgentScope 都支持），在工具描述里写清楚本体语义；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP（Model Context Protocol）&lt;/strong&gt;：把语义服务做成 MCP Server，让任何兼容 Agent 即插即用——这是 2025 年后快速成为事实标准的路线。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一次典型的 Agent 调用时序如下：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;sequenceDiagram
    participant U as 值班工程师
    participant AG as 运维 Agent (LLM)
    participant MCP as 本体 MCP Server
    participant KG as 知识图谱
    participant MES as MES 系统

    U-&amp;gt;&amp;gt;AG: P-102 振动超标，怎么办？
    AG-&amp;gt;&amp;gt;MCP: query(设备 P-102 的档案/历史故障/部件清单)
    MCP-&amp;gt;&amp;gt;KG: Cypher 查询
    KG--&amp;gt;&amp;gt;MCP: 设备档案 + 3 次历史故障(均为轴承磨损) + 部件: 转子/轴承
    MCP--&amp;gt;&amp;gt;AG: 结构化结果
    AG-&amp;gt;&amp;gt;MCP: query(轴承备件库存与供应商)
    MCP-&amp;gt;&amp;gt;KG: 沿 部件→供应商 关系查询
    KG--&amp;gt;&amp;gt;MCP: 库存 2 件, 供应商交期 3 天
    MCP--&amp;gt;&amp;gt;AG: 结构化结果
    Note over AG: 推理：大概率轴承磨损&amp;lt;br/&amp;gt;备件充足，建议立即更换
    AG-&amp;gt;&amp;gt;MCP: action: 创建维修工单(P-102, 更换轴承)
    MCP-&amp;gt;&amp;gt;MES: 回写工单（含权限校验+审计）
    MES--&amp;gt;&amp;gt;MCP: 工单 WO-2026-3312
    MCP--&amp;gt;&amp;gt;AG: 成功
    AG--&amp;gt;&amp;gt;U: 建议立即停机更换轴承（备件在库），已创建工单 WO-2026-3312，依据：近半年 3 次同型故障…&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;注意最后一轮回复的形态：&lt;strong&gt;结论 + 已执行动作 + 推理依据&lt;/strong&gt;。这就是本体给 Agent 带来的质变——它不再&amp;quot;复述检索到的文档片段&amp;quot;，而是在一个结构化的业务世界里推理和行动，并且&lt;strong&gt;每一步都有据可查&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;46-阶段六评估与治理迭代&#34;&gt;4.6 阶段六：评估与治理迭代&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;回归测试&lt;/strong&gt;：每次本体变更后，用胜任问题清单跑回归——这 20 个问题还能答对吗？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;效果评估&lt;/strong&gt;：幻觉率、答案准确率、Action 执行成功率，对比接入本体前后的基线；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;版本治理&lt;/strong&gt;：本体是活资产，业务变了本体就要演进。建立变更评审机制，防止&amp;quot;语义漂移&amp;quot;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;47-三个落地案例速览&#34;&gt;4.7 三个落地案例速览&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;行业&lt;/th&gt;
					&lt;th&gt;本体核心概念&lt;/th&gt;
					&lt;th&gt;Agent 能力&lt;/th&gt;
					&lt;th&gt;价值点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;制造业&lt;/td&gt;
					&lt;td&gt;设备、部件、故障、工单、供应商&lt;/td&gt;
					&lt;td&gt;故障诊断 + 自动派单&lt;/td&gt;
					&lt;td&gt;平均故障响应时间从小时级降到分钟级&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;金融&lt;/td&gt;
					&lt;td&gt;客户、账户、交易、产品、监管规则&lt;/td&gt;
					&lt;td&gt;合规审查 Agent：沿&amp;quot;账户→交易→规则&amp;quot;推理风险敞口&lt;/td&gt;
					&lt;td&gt;审查口径统一，漏报率下降&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;医疗&lt;/td&gt;
					&lt;td&gt;疾病、症状、药品、检查、禁忌（复用 SNOMED CT）&lt;/td&gt;
					&lt;td&gt;辅助诊断 Agent：校验用药禁忌与检查互斥&lt;/td&gt;
					&lt;td&gt;用公理兜底 LLM 的危险建议&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五2026-年行业最新动态&#34;&gt;五、2026 年行业最新动态&lt;/h2&gt;
&lt;p&gt;本体赛道在过去一年明显升温，几条值得关注的线索：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Palantir：Ontology 成为 AIP 的灵魂&lt;/strong&gt;。Palantir 把 Ontology 从数据建模层升级为&amp;quot;企业操作系统&amp;quot;的概念核心——知识、动作、安全三合一，Agent 在 Ontology 之上编排业务操作。2026 年 4 月，Palantir 将 AIP Agent Studio 更名为 AIP Chatbot Studio，进一步明确对话式 Agent 产品定位；AIP Analyst 也于 2026 年 4 月 GA，支持对话式查询 Ontology 数据、生成可视化并执行动作（参考&lt;a href=&#34;https://releasefeed.net/palantir/palantir-2026-04-22-aip-chatbot-studio-rebrand/&#34;&gt;Palantir 发布解读&lt;/a&gt;与 &lt;a href=&#34;https://pub.towardsai.net/inside-palantir-aip-how-the-worlds-most-controversial-ai-platform-actually-works-9ec5b7a6c05a&#34;&gt;Towards AI 深度解析&lt;/a&gt;）。美国陆军 TITAN、Maven 等大额合同持续验证这套打法（&lt;a href=&#34;https://kalkine.com/news/premium/palantir-pltr-stock-analysis-2026-aip-momentum-valuation-reality-check-and-the-road-ahead&#34;&gt;Kalkine 分析&lt;/a&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;微软：Fabric IQ 把 Ontology 搬进数据平台&lt;/strong&gt;。Fabric IQ 于 2025 年 11 月 Ignite 大会发布、2026 年 6 月 Build 大会正式 GA，通过 Ontology 和 Power BI 语义模型把 OneLake 中的数据提升为&amp;quot;业务级语义&amp;quot;，与 Work IQ、Foundry IQ、Web IQ 共同构成微软的企业语义智能层（参考&lt;a href=&#34;https://blog.csdn.net/hyde_jiang/article/details/162932418&#34;&gt;语义工程系列分析&lt;/a&gt;）。数据平台厂商集体下场做本体，是本轮最重要的信号。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;中国信通院发布《本体智能研究报告（1.0）》&lt;/strong&gt;（2026 年 7 月，智能原生大会）：首次系统界定&amp;quot;本体智能&amp;quot;内涵，梳理从哲学本体论到本体智能的演化脉络，提出以形式化本体为智能体可信语义底座的产业范式（&lt;a href=&#34;https://www.secrss.com/articles/92201&#34;&gt;安全内参&lt;/a&gt;、&lt;a href=&#34;https://www.modb.pro/db/2076843769111584768&#34;&gt;墨天轮&lt;/a&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语义层与知识图谱全面复兴&lt;/strong&gt;。腾讯云的行业观察指出，2026 年 AI 模型对&amp;quot;正确数据&amp;quot;的需求推动语义层和知识图谱崛起，SAP、Salesforce 等应用巨头纷纷把语义层作为 Agent 战略的前置投入（&lt;a href=&#34;https://cloud.tencent.com/developer/article/2616559&#34;&gt;腾讯云开发者社区&lt;/a&gt;）。企业智能问数也已分化出 RAG 召回、NL2SQL、指标平台增强、本体语义四大技术路线（&lt;a href=&#34;https://tencentcloud.csdn.net/69eae14054b52172bc6f7a43.html&#34;&gt;路线对比分析&lt;/a&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GraphRAG 成为本体价值的最快验证点&lt;/strong&gt;。微软开源的 GraphRAG 路线（从文档抽取实体关系构建图谱，再做社区摘要与图增强检索）让&amp;quot;结构化知识增强生成&amp;quot;从理念变成 pip install 级的实践，很多企业正是从 GraphRAG 尝到甜头后，才开始认真考虑更完整的本体工程。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一句话总结行业共识：&lt;strong&gt;大模型的军备竞赛告一段落，竞争的下半场是&amp;quot;语义基建&amp;quot;——谁家的 Agent 更懂业务，谁就赢。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六思考与感悟&#34;&gt;六、思考与感悟&lt;/h2&gt;
&lt;p&gt;写完这条路径，分享几点踩坑后的真实感受：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 本体的价值不在&amp;quot;建&amp;quot;，在&amp;quot;对齐&amp;quot;。&lt;/strong&gt; 本体建模最有产出的时刻，往往不是画类图的时候，而是业务、数据、IT 三方为了&amp;quot;&amp;lsquo;客户&amp;rsquo;到底包不包括潜在客户&amp;quot;吵一下午的时候。那个争吵的过程，就是组织知识显式化的过程。建出来的图谱可能三年就换代了，但吵出来的共识会留在组织里。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 谨防&amp;quot;本体过度工程&amp;quot;。&lt;/strong&gt; 见过太多团队一上来追求形式化完美——全套 OWL 公理、严密的上位本体继承——结果六个月没见到一个能跑的 Agent。务实的顺序是：&lt;strong&gt;先让 Agent 用上粗糙的本体跑起来，再在使用中打磨语义&lt;/strong&gt;。胜任问题答得对，比逻辑上自洽重要。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 本体是 Agent 的&amp;quot;宪法&amp;quot;，不是&amp;quot;百科全书&amp;quot;。&lt;/strong&gt; 不要指望本体装下所有知识——非结构化的经验、文档、案例，交给 RAG；本体负责的是&lt;strong&gt;不容含糊的那部分&lt;/strong&gt;：核心概念、口径、规则、权限边界。一个好的心智模型是：RAG 给 Agent &amp;ldquo;见识&amp;rdquo;，本体给 Agent &amp;ldquo;常识与纪律&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. 行动能力（Action）是这轮本体复兴的灵魂。&lt;/strong&gt; 二十年前的语义网止步于&amp;quot;让机器理解数据&amp;quot;，失败了；今天的本体因为绑定了 Agent 的行动闭环而重生。如果你的本体里没有定义任何 Action，那它大概率只是一张漂亮但寂寞的图。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. 对个体工程师的启示。&lt;/strong&gt; 本体工程是少有的&amp;quot;越老越吃香&amp;quot;的 AI 技能——模型会迭代，框架会更替，但对一个行业业务概念体系的深刻理解，沉淀的是复利。选一个你熟悉的垂直领域，亲手建一个小本体、接一个 Agent 跑通闭环，是 2026 年性价比极高的技术投资。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.secrss.com/articles/92201&#34;&gt;中国信通院《本体智能研究报告（1.0）》发布解读 - 安全内参&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.hubwiz.com/blog/ontology-vs-semantic-layer/&#34;&gt;本体论 vs. 语义层 - OceanBase/Hubwiz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.eefocus.com/article/2076399.html&#34;&gt;本体产业深度解读：语义层重构智能体数据底座 - 与非网&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://cloud.tencent.com/developer/article/2616559&#34;&gt;AI 数据新纪元：语义层与知识图谱的崛起 - 腾讯云&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.csdn.net/hyde_jiang/article/details/162932418&#34;&gt;微软语义层：从 Schema 到本体的演进 - CSDN 语义工程系列&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pub.towardsai.net/inside-palantir-aip-how-the-worlds-most-controversial-ai-platform-actually-works-9ec5b7a6c05a&#34;&gt;Inside Palantir AIP: How the Platform Actually Works - Towards AI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jimo.studio/blog/enterprise-ontology-engineering-the-semantic-foundation-for-next-generation-ai/&#34;&gt;本体工程：从知识图谱到企业智能体的语义基石 - jimo.studio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Noy &amp;amp; McGuinness, &lt;em&gt;Ontology Development 101: A Guide to Creating Your First Ontology&lt;/em&gt;, Stanford University&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title>Agent-Chat：基于 AgentScope 2.0 &#43; Mem0 的多 Agent 群聊陪伴系统</title>
      <link>https://ftmao.com/blog/posts/agent-chat-multi-agent-companion/</link>
      <pubDate>Tue, 04 Aug 2026 12:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/agent-chat-multi-agent-companion/</guid>
      <description>&lt;h1 id=&#34;agent-chat基于-agentscope-20--mem0-的多-agent-群聊陪伴系统&#34;&gt;Agent-Chat：基于 AgentScope 2.0 + Mem0 的多 Agent 群聊陪伴系统&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;开源地址&lt;/strong&gt;：https://gitee.com/soulnew/agent-chat&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;你有没有想过，把一群性格各异的 AI 拉进同一个微信群，他们会怎么聊天？&lt;/p&gt;
&lt;p&gt;不是那种一问一答的客服机器人，而是会主动接梗、会吃醋、会安慰人、会记住你上周说过喜欢喝燕麦拿铁的“AI 朋友”。我开发的&lt;strong&gt;Agent-Chat&lt;/strong&gt; 就是想做这件事：一个支持多角色、多记忆、可配置人格的群聊多 Agent 陪伴系统。&lt;/p&gt;
&lt;p&gt;下图是一个实际运行中的群聊界面：用户 &lt;code&gt;@王姐&lt;/code&gt; 让她描述下自己，王姐和海公公两个 Agent 基于长期记忆给出了个性化的用户画像回应。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;http://ftmao.com/blog/images/ScreenShot_2026-08-04_202545_484.png&#34; alt=&#34;Agent-Chat 群聊界面：@王姐询问用户画像&#34;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一为什么需要这个工具&#34;&gt;一、为什么需要这个工具？&lt;/h2&gt;
&lt;h3 id=&#34;11-单-agent-聊天-vs-多-agent-群聊&#34;&gt;1.1 单 Agent 聊天 vs. 多 Agent 群聊&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;维度&lt;/th&gt;
					&lt;th&gt;单 Agent 聊天（如 ChatGPT 网页版）&lt;/th&gt;
					&lt;th&gt;多 Agent 群聊（Agent-Chat）&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;交互形态&lt;/td&gt;
					&lt;td&gt;1 对 1 问答&lt;/td&gt;
					&lt;td&gt;1 个用户 + N 个 Agent 同时在线&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;角色多样性&lt;/td&gt;
					&lt;td&gt;只有一个固定角色&lt;/td&gt;
					&lt;td&gt;可配置多个性格、职业、说话风格各异的角色&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;社交氛围&lt;/td&gt;
					&lt;td&gt;像咨询顾问&lt;/td&gt;
					&lt;td&gt;像朋友群，Agent 之间会互动、接话、调侃&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;记忆隔离&lt;/td&gt;
					&lt;td&gt;全局统一记忆&lt;/td&gt;
					&lt;td&gt;支持“Agent 对用户的私有记忆”+“公共记忆”&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;发言调度&lt;/td&gt;
					&lt;td&gt;用户问一句答一句&lt;/td&gt;
					&lt;td&gt;Agent 自主决定是否发言、@谁、说什么&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;单 Agent 适合办事，多 Agent 适合陪伴。当你只是想找人闲聊、吐槽、或者看几个“朋友”互相斗嘴时，一个群比私聊更自然。&lt;/p&gt;
&lt;h3 id=&#34;12-直接用-llm-api-vs-用-agent-chat&#34;&gt;1.2 直接用 LLM API vs. 用 Agent-Chat&lt;/h3&gt;
&lt;p&gt;很多开发者可能会想：我直接调 DeepSeek API，自己写个循环不就行了？理论上可以，但落到工程上会碰到一堆问题：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;问题&lt;/th&gt;
					&lt;th&gt;自己调 API&lt;/th&gt;
					&lt;th&gt;Agent-Chat 的做法&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;多 Agent 并发管理&lt;/td&gt;
					&lt;td&gt;自己维护 N 个对话上下文，容易串台&lt;/td&gt;
					&lt;td&gt;AgentScope 2.0 统一运行时 + Redis 短期记忆&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;谁该说话&lt;/td&gt;
					&lt;td&gt;每次用户发言都让所有 Agent 回复，刷屏严重&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Orchestrator&lt;/code&gt; 调度器：置信度排序、并发上限、冷却时间、@触发&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;长期记忆&lt;/td&gt;
					&lt;td&gt;自己拼 prompt，历史越长越贵&lt;/td&gt;
					&lt;td&gt;Mem0 自动事实提取、去重、语义检索&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;记忆隔离&lt;/td&gt;
					&lt;td&gt;所有 Agent 共享同一份历史&lt;/td&gt;
					&lt;td&gt;按 &lt;code&gt;user_id&lt;/code&gt; + &lt;code&gt;agent_id&lt;/code&gt; 分层作用域&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;人格配置&lt;/td&gt;
					&lt;td&gt;写死 prompt&lt;/td&gt;
					&lt;td&gt;运营后台可配置 Agent 人格、版本、关系、禁忌话题&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;实时通信&lt;/td&gt;
					&lt;td&gt;自己搭 WebSocket&lt;/td&gt;
					&lt;td&gt;FastAPI 原生 WebSocket + 简单 Web UI&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Agent-Chat 并不是为了替代 ChatGPT，而是把“多 Agent 群聊”这个场景的工程骨架搭好，让你能专注在角色设计、记忆策略和交互体验上。&lt;/p&gt;
&lt;h3 id=&#34;13-现有群聊机器人-vs-agent-chat&#34;&gt;1.3 现有群聊机器人 vs. Agent-Chat&lt;/h3&gt;
&lt;p&gt;市面上也有不少群聊机器人，但大多数是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;规则触发&lt;/strong&gt;：关键字回复，缺乏上下文理解；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;单轮回复&lt;/strong&gt;：不会主动参与话题；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;无记忆&lt;/strong&gt;：每次重启都是陌生人；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;人格单一&lt;/strong&gt;：无法运营多个差异化角色。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Agent-Chat 的核心差异是：&lt;strong&gt;把每个 Agent 当成有记忆、有情绪、有关系的虚拟人&lt;/strong&gt;，而不是一个只会响应命令的工具。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二技术栈&#34;&gt;二、技术栈&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;层级&lt;/th&gt;
					&lt;th&gt;选型&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;后端框架&lt;/td&gt;
					&lt;td&gt;FastAPI&lt;/td&gt;
					&lt;td&gt;高性能异步 Web 框架，原生支持 WebSocket&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;多 Agent 框架&lt;/td&gt;
					&lt;td&gt;AgentScope 2.0&lt;/td&gt;
					&lt;td&gt;支持 Agent 生命周期、消息总线、工具调用、ReAct、Middleware&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;主力 LLM&lt;/td&gt;
					&lt;td&gt;DeepSeek&lt;/td&gt;
					&lt;td&gt;OpenAI 兼容接口，通过 &lt;code&gt;DeepSeekChatModel&lt;/code&gt; 统一调用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;长期记忆&lt;/td&gt;
					&lt;td&gt;Mem0 (self-hosted)&lt;/td&gt;
					&lt;td&gt;自动事实提取、去重、合并，支持按用户/Agent 作用域隔离&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;向量数据库&lt;/td&gt;
					&lt;td&gt;Qdrant&lt;/td&gt;
					&lt;td&gt;Mem0 推荐的向量后端，轻量高性能&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;嵌入模型&lt;/td&gt;
					&lt;td&gt;BGE 系列（BGE-small-zh-v1.5 / BGE-M3 可配置）&lt;/td&gt;
					&lt;td&gt;本地加载，中文语义召回效果好&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;短期记忆&lt;/td&gt;
					&lt;td&gt;Redis&lt;/td&gt;
					&lt;td&gt;房间消息滑动窗口、会话摘要、在线状态&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;关系数据&lt;/td&gt;
					&lt;td&gt;MySQL 8.0+&lt;/td&gt;
					&lt;td&gt;用户、Agent、房间、消息、关系、事件&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;前端&lt;/td&gt;
					&lt;td&gt;简单 Web UI (HTML + JS)&lt;/td&gt;
					&lt;td&gt;第一阶段提供基础群聊界面&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;部署&lt;/td&gt;
					&lt;td&gt;Docker Compose&lt;/td&gt;
					&lt;td&gt;MySQL + Redis + Qdrant 一键拉起&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;注：项目中默认使用 &lt;code&gt;BGE-small-zh-v1.5&lt;/code&gt;（512 维），但架构上模型路径与维度均可通过环境变量配置，可平滑替换为 &lt;code&gt;BGE-M3&lt;/code&gt; 等更强的多语言嵌入模型。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三系统架构&#34;&gt;三、系统架构&lt;/h2&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph TB
    subgraph Client[&amp;#34;客户端&amp;#34;]
        UI[&amp;#34;简单 Web UI&amp;lt;br/&amp;gt;HTML + WebSocket&amp;#34;]
    end

    subgraph Backend[&amp;#34;后端服务&amp;#34;]
        FastAPI[&amp;#34;FastAPI Chat Service&amp;lt;br/&amp;gt;REST API + WebSocket&amp;#34;]
        RoomManager[&amp;#34;RoomManager / RoomRuntime&amp;#34;]
        Orchestrator[&amp;#34;Orchestrator 调度器&amp;#34;]
    end

    subgraph AgentRuntime[&amp;#34;AgentScope 2.0 运行时&amp;#34;]
        AgentInstance[&amp;#34;AgentInstance&amp;lt;br/&amp;gt;每个房间每个 Agent 一个实例&amp;#34;]
        Agent[&amp;#34;agentscope.agent.Agent&amp;#34;]
        Toolkit[&amp;#34;Toolkit + FunctionTool&amp;lt;br/&amp;gt;时间 / 天气 / 搜索 / 抓取&amp;#34;]
        Middleware[&amp;#34;GroupChatMem0Middleware&amp;lt;br/&amp;gt;per-user 记忆读写&amp;#34;]
    end

    subgraph Memory[&amp;#34;记忆层&amp;#34;]
        Redis[(Redis&amp;lt;br/&amp;gt;短期记忆 / 会话摘要 / 在线状态)]
        Mem0[Mem0 AsyncMemory&amp;lt;br/&amp;gt;长期记忆 / 事实提取 / 语义检索]
        Qdrant[(Qdrant&amp;lt;br/&amp;gt;向量存储)]
        BGE[&amp;#34;BGE Embedding&amp;lt;br/&amp;gt;bge-small-zh-v1.5 / BGE-M3&amp;#34;]
    end

    subgraph Data[&amp;#34;关系数据&amp;#34;]
        MySQL[(MySQL 8.0&amp;lt;br/&amp;gt;users / agents / rooms / messages / relationships / events)]
    end

    subgraph LLM[&amp;#34;大模型&amp;#34;]
        DeepSeek[&amp;#34;DeepSeek Chat API&amp;lt;br/&amp;gt;OpenAI 兼容&amp;#34;]
    end

    UI --&amp;gt;|WebSocket / HTTP| FastAPI
    FastAPI --&amp;gt; RoomManager
    RoomManager --&amp;gt; Orchestrator
    RoomManager --&amp;gt; AgentInstance
    AgentInstance --&amp;gt; Agent
    Agent --&amp;gt; Toolkit
    Agent --&amp;gt; Middleware
    Middleware --&amp;gt; Mem0
    Mem0 --&amp;gt; Qdrant
    Mem0 --&amp;gt; BGE
    Agent --&amp;gt; DeepSeek
    RoomManager --&amp;gt; Redis
    FastAPI --&amp;gt; MySQL
    Mem0 --&amp;gt; DeepSeek&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;四核心设计&#34;&gt;四、核心设计&lt;/h2&gt;
&lt;h3 id=&#34;41-agent-生命周期&#34;&gt;4.1 Agent 生命周期&lt;/h3&gt;
&lt;p&gt;Agent 不是临时对象，而是运营预先配置的“角色模板”。一个 Agent 可以被添加到多个房间，在每个房间内有独立的运行实例和记忆空间。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[运营后台创建 Agent] --&amp;gt; B[写入 agents 表]
    B --&amp;gt; C[生成 persona_summary&amp;lt;br/&amp;gt;可选 DeepSeek 质量检查]
    C --&amp;gt; D[Agent 状态 active]
    D --&amp;gt; E[将 Agent 加入房间]
    E --&amp;gt; F[RoomRuntime 实例化 AgentInstance]
    F --&amp;gt; G[注册到 MsgHub]
    G --&amp;gt; H[参与群聊]
    H --&amp;gt; I[用户退出或移除 Agent]
    I --&amp;gt; J[保留历史与记忆]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;每个 Agent 可配置：昵称、年龄、职业、性格标签、兴趣、说话风格、语气、回复概率、最大回复长度、禁忌话题等。&lt;/p&gt;
&lt;p&gt;Agent 人格的核心是 &lt;code&gt;system_prompt&lt;/code&gt;，但为了让模型稳定地“扮演”一个角色，系统会把这些字段组合成一段结构化的基础人设：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;你是 {name}，{age} 岁，职业是 {job}。性格：{traits}。说话风格：{speaking_style}。语气：{voice_tone}。
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{system_prompt}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;重要规则：
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;-&lt;/span&gt; 你只输出你要说的话，不要加自己的名字前缀。
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;-&lt;/span&gt; 保持自然、像真人一样，不要太长（不超过 {max_reply_length} 字）。
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- 你是 AI，不是真人。不要诱导用户泄露隐私或进行危险行为。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;为了让同一 Agent 能在不同房间里保持一致的“人格”，但又能感知到不同的房间成员和关系，系统把 prompt 拆成两部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;静态人设（&lt;code&gt;_base_system_prompt&lt;/code&gt;）&lt;/strong&gt;：在 &lt;code&gt;AgentInstance&lt;/code&gt; 初始化时构建，只与 Agent 自身属性有关；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动态上下文（&lt;code&gt;_full_system_prompt&lt;/code&gt;）&lt;/strong&gt;：每次生成回复前拼接，包含当前房间名、成员列表、关系、用户画像、近期摘要、检索记忆等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种“静态人格 + 动态上下文”的分离，让人格稳定、上下文新鲜，也便于缓存和版本管理。&lt;/p&gt;
&lt;h3 id=&#34;42-记忆分层&#34;&gt;4.2 记忆分层&lt;/h3&gt;
&lt;p&gt;记忆是陪伴系统的灵魂。Agent-Chat 把记忆分成三层：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;范围&lt;/th&gt;
					&lt;th&gt;存储&lt;/th&gt;
					&lt;th&gt;更新频率&lt;/th&gt;
					&lt;th&gt;用途&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;瞬时记忆&lt;/td&gt;
					&lt;td&gt;当前请求&lt;/td&gt;
					&lt;td&gt;Prompt 上下文&lt;/td&gt;
					&lt;td&gt;每次请求&lt;/td&gt;
					&lt;td&gt;保证即时上下文连贯&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;短期记忆&lt;/td&gt;
					&lt;td&gt;当前会话&lt;/td&gt;
					&lt;td&gt;Redis&lt;/td&gt;
					&lt;td&gt;实时&lt;/td&gt;
					&lt;td&gt;维护会话历史窗口与摘要&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;长期记忆&lt;/td&gt;
					&lt;td&gt;跨会话&lt;/td&gt;
					&lt;td&gt;Mem0 + Qdrant&lt;/td&gt;
					&lt;td&gt;实时/异步&lt;/td&gt;
					&lt;td&gt;用户画像、关系、事件、偏好&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TB
    subgraph Instant[&amp;#34;瞬时记忆&amp;#34;]
        P[Prompt 注入:&amp;lt;br/&amp;gt;当前消息 + 近期历史 + 检索记忆]
    end

    subgraph ShortTerm[&amp;#34;短期记忆 Redis&amp;#34;]
        R1[&amp;#34;room:{room_id}:messages&amp;#34;]
        R2[&amp;#34;room:{room_id}:summary&amp;#34;]
    end

    subgraph LongTerm[&amp;#34;长期记忆 Mem0 + Qdrant&amp;#34;]
        M1[&amp;#34;Agent ↔ 用户 私有记忆&amp;#34;]
        M2[&amp;#34;用户公共记忆&amp;#34;]
        M3[&amp;#34;Agent 公共记忆&amp;#34;]
        M4[&amp;#34;全局公共记忆&amp;#34;]
    end

    User[用户发言] --&amp;gt; FastAPI
    FastAPI --&amp;gt; R1
    FastAPI --&amp;gt;|异步| M2
    FastAPI --&amp;gt;|达到阈值| R2
    R1 --&amp;gt; P
    R2 --&amp;gt; P
    M1 --&amp;gt; P
    M2 --&amp;gt; P
    M3 --&amp;gt; P
    M4 --&amp;gt; P
    P --&amp;gt; DeepSeek[DeepSeek 生成回复]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h4 id=&#34;421-短期记忆redis-滑动窗口--增量摘要&#34;&gt;4.2.1 短期记忆：Redis 滑动窗口 + 增量摘要&lt;/h4&gt;
&lt;p&gt;短期记忆负责“当前这次聊天不冷场”。实现上，每个房间在 Redis 中有两个 key：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;room:{room_id}:messages  -&amp;gt;  List&amp;lt;Message JSON&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;room:{room_id}:summary   -&amp;gt;  String&amp;lt;Summary JSON&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;messages&lt;/code&gt; 保存最近 N 条消息（默认约 30 条）；&lt;/li&gt;
&lt;li&gt;超过窗口后，对早期消息做增量摘要，生成 &lt;code&gt;session_summary&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;请求 LLM 时，prompt 中注入：会话摘要 + 最近 K 条完整消息 + 当前用户消息。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;摘要策略：每新增 10 条消息触发一次增量摘要，由 DeepSeek 生成，保留关键事实、用户情绪、未决话题。摘要本身也作为长期记忆写入 Mem0。&lt;/p&gt;
&lt;h4 id=&#34;422-长期记忆mem0--qdrant--bge&#34;&gt;4.2.2 长期记忆：Mem0 + Qdrant + BGE&lt;/h4&gt;
&lt;p&gt;长期记忆解决“跨会话还记得你”的问题。我们选用 &lt;strong&gt;Mem0&lt;/strong&gt; 作为记忆层，原因有三：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;专为 LLM/Agent 设计&lt;/strong&gt;：自动完成事实提取、去重、合并，不用自己写召回逻辑；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持 &lt;code&gt;user_id&lt;/code&gt; 与 &lt;code&gt;agent_id&lt;/code&gt; 双重作用域&lt;/strong&gt;：天然适合“每个 Agent 对用户有独立记忆”的群聊场景；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可 self-hosted&lt;/strong&gt;：向量后端用 Qdrant，数据自主可控。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Mem0 的记忆作用域设计非常关键：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;user_id&lt;/th&gt;
					&lt;th&gt;agent_id&lt;/th&gt;
					&lt;th&gt;含义&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;有&lt;/td&gt;
					&lt;td&gt;有&lt;/td&gt;
					&lt;td&gt;该 Agent 对该用户的&lt;strong&gt;私有记忆&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;有&lt;/td&gt;
					&lt;td&gt;无&lt;/td&gt;
					&lt;td&gt;用户的&lt;strong&gt;公共记忆&lt;/strong&gt;，所有 Agent 可读&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;无&lt;/td&gt;
					&lt;td&gt;有&lt;/td&gt;
					&lt;td&gt;该 Agent 的&lt;strong&gt;公共记忆&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;无&lt;/td&gt;
					&lt;td&gt;无&lt;/td&gt;
					&lt;td&gt;全局公共记忆（房间摘要、事件）&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这意味着：所有 Agent 都知道“用户喜欢猫”，但只有 Agent A 记得“用户昨天跟 Agent A 吐槽了老板”。Agent B 可以假装不知道，让 Agent A 去安慰用户，更像真人社交。&lt;/p&gt;
&lt;h4 id=&#34;423-长期记忆写入流程&#34;&gt;4.2.3 长期记忆写入流程&lt;/h4&gt;
&lt;p&gt;每次群聊产生一条真实消息后，由 &lt;code&gt;Memory Service&lt;/code&gt; 统一写入 Mem0，写入是&lt;strong&gt;异步&lt;/strong&gt;的，不阻塞消息返回。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[用户/Agent 发言] --&amp;gt; B[保存到 MySQL messages]
    B --&amp;gt; C[写入 Redis 短期记忆]
    C --&amp;gt; D{发送者类型}
    D --&amp;gt;|user| E[user_id=用户ID&amp;lt;br/&amp;gt;agent_id=None&amp;lt;br/&amp;gt;公共记忆]
    D --&amp;gt;|agent 回复用户| F[user_id=用户ID&amp;lt;br/&amp;gt;agent_id=AgentID&amp;lt;br/&amp;gt;私有记忆]
    D --&amp;gt;|agent 主动发言| G[user_id=None&amp;lt;br/&amp;gt;agent_id=AgentID&amp;lt;br/&amp;gt;Agent 公共记忆]
    D --&amp;gt;|系统摘要| H[user_id=None&amp;lt;br/&amp;gt;agent_id=None&amp;lt;br/&amp;gt;run_id=房间ID]
    E --&amp;gt; I[Mem0.add 异步写入]
    F --&amp;gt; I
    G --&amp;gt; I
    H --&amp;gt; I
    I --&amp;gt; J[Mem0 自动事实提取 / 去重 / 合并]
    J --&amp;gt; K[Qdrant 向量存储]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;写入时根据场景选择作用域：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;场景&lt;/th&gt;
					&lt;th&gt;写入内容&lt;/th&gt;
					&lt;th&gt;user_id&lt;/th&gt;
					&lt;th&gt;agent_id&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;用户发言&lt;/td&gt;
					&lt;td&gt;用户说的话、情绪、偏好&lt;/td&gt;
					&lt;td&gt;用户 ID&lt;/td&gt;
					&lt;td&gt;为空（公共记忆）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Agent 回复用户&lt;/td&gt;
					&lt;td&gt;Agent 与用户的完整对话轮次&lt;/td&gt;
					&lt;td&gt;用户 ID&lt;/td&gt;
					&lt;td&gt;当前 Agent ID&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Agent 之间互动&lt;/td&gt;
					&lt;td&gt;Agent A 对 Agent B 的回复&lt;/td&gt;
					&lt;td&gt;为空&lt;/td&gt;
					&lt;td&gt;Agent A ID&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;会话摘要生成&lt;/td&gt;
					&lt;td&gt;摘要内容作为长期事实&lt;/td&gt;
					&lt;td&gt;为空&lt;/td&gt;
					&lt;td&gt;为空 / run_id=room_id&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&#34;424-长期记忆读取流程&#34;&gt;4.2.4 长期记忆读取流程&lt;/h4&gt;
&lt;p&gt;Agent 生成回复前，&lt;code&gt;Memory Service&lt;/code&gt; 会按优先级分层检索相关记忆：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TB
    A[当前消息] --&amp;gt; B[检索 Agent ↔ 当前用户 私有记忆]
    B --&amp;gt; C[检索 用户公共记忆]
    C --&amp;gt; D[检索 该 Agent 公共记忆]
    D --&amp;gt; E[检索 全局公共记忆]
    E --&amp;gt; F[按相关度 + 时间排序]
    F --&amp;gt; G[去重]
    G --&amp;gt; H[注入 Prompt]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;检索优先级：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Agent 对当前用户的私有记忆&lt;/strong&gt;（&lt;code&gt;user_id=user_id, agent_id=agent_id&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户的公共记忆&lt;/strong&gt;（&lt;code&gt;user_id=user_id, agent_id=None&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;该 Agent 的公共记忆&lt;/strong&gt;（&lt;code&gt;user_id=None, agent_id=agent_id&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全局公共记忆&lt;/strong&gt;（&lt;code&gt;user_id=None, agent_id=None&lt;/code&gt;，如房间摘要、重要事件）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;注入 Prompt 时，记忆会被格式化为：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;### 关于 {target_user_name} 的记忆
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;-&lt;/span&gt; 阿杰记得 {target_user_name} 上周说很喜欢吃火锅。
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;-&lt;/span&gt; {target_user_name} 提到过自己是程序员，工作压力比较大。
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;### 关于你自己的记忆
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;-&lt;/span&gt; 你之前答应过 {target_user_name} 要推荐科幻电影。
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;### 群聊公共记忆
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- 这个群经常深夜聊天，氛围比较轻松。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h4 id=&#34;425-记忆与结构化表的联动&#34;&gt;4.2.5 记忆与结构化表的联动&lt;/h4&gt;
&lt;p&gt;Mem0 负责“自动提取和检索事实”，但一些业务逻辑仍需要显式的关系型数据，因此会同步到 MySQL：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;关系变化&lt;/strong&gt;：当 Mem0 提取到“用户和 Agent 关系变好/变差”时，更新 &lt;code&gt;relationships&lt;/code&gt; 表的 &lt;code&gt;intimacy&lt;/code&gt; 字段；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重要事件&lt;/strong&gt;：当提取到“用户生日”“吵架”“约定”等事件时，写入 &lt;code&gt;events&lt;/code&gt; 表，便于按时间线展示；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户画像摘要&lt;/strong&gt;：定期从 Mem0 导出用户画像，更新 &lt;code&gt;user_profiles.summary&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实现方式：后台 Worker 定期扫描 Mem0 新增记忆，用 LLM 判断是否需要更新结构化表。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sync_structured_memory&lt;/span&gt;(user_id: str, agent_id: str):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    recent_memories &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; memory&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_all(user_id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;user_id, agent_id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;agent_id, limit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt;, after&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;timestamp_24h_ago)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;await&lt;/span&gt; llm&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;analyze_memory_changes(recent_memories)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; result[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;relationship_change&amp;#34;&lt;/span&gt;]:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;await&lt;/span&gt; update_relationship(&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; result[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;new_events&amp;#34;&lt;/span&gt;]:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;await&lt;/span&gt; create_events(&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; result[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;profile_update&amp;#34;&lt;/span&gt;]:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;await&lt;/span&gt; update_user_profile(&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;43-消息流与调度&#34;&gt;4.3 消息流与调度&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;sequenceDiagram
    autonumber
    participant U as 用户
    participant F as FastAPI / WebSocket
    participant R as Redis 短期记忆
    participant M as Mem0 长期记忆
    participant O as Orchestrator 调度器
    participant A as AgentInstance
    participant D as DeepSeek

    U-&amp;gt;&amp;gt;F: 发送消息
    F-&amp;gt;&amp;gt;MySQL: 保存消息
    F-&amp;gt;&amp;gt;U: 广播用户消息
    F-&amp;gt;&amp;gt;R: 写入短期记忆
    F-&amp;gt;&amp;gt;M: 异步写入长期记忆
    F-&amp;gt;&amp;gt;O: 触发 Agent 回复决策
    loop 对每个 Agent
        O-&amp;gt;&amp;gt;A: should_reply(query, recent, memories)
        A-&amp;gt;&amp;gt;M: 检索相关记忆
        A-&amp;gt;&amp;gt;D: 判断是否回复、回复对象、意图
        D--&amp;gt;&amp;gt;A: JSON 决策
    end
    O-&amp;gt;&amp;gt;O: 按置信度排序，限制并发数
    loop 被选中的 Agent
        O-&amp;gt;&amp;gt;A: generate_reply(...)
        A-&amp;gt;&amp;gt;R: 读取近期消息
        A-&amp;gt;&amp;gt;M: Middleware 注入记忆
        A-&amp;gt;&amp;gt;D: 生成回复
        D--&amp;gt;&amp;gt;A: 文本回复
        A--&amp;gt;&amp;gt;O: 回复内容
    end
    O-&amp;gt;&amp;gt;F: 逐个保存并广播 Agent 回复
    F-&amp;gt;&amp;gt;R: 更新短期记忆
    F-&amp;gt;&amp;gt;M: Middleware 写入对话记忆&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;调度策略包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;最大同时响应数&lt;/strong&gt;：默认限制并发 Agent 回复数，避免刷屏；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;冷却时间&lt;/strong&gt;：同一 Agent 两次发言间隔不少于 N 秒；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;相关性过滤&lt;/strong&gt;：消息与 Agent 兴趣/角色相关才参与；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@ 触发&lt;/strong&gt;：被 @ 的 Agent 优先响应；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;情绪/氛围&lt;/strong&gt;：根据聊天氛围调整不同类型 Agent 的发言权重。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;44-工具与-react&#34;&gt;4.4 工具与 ReAct&lt;/h3&gt;
&lt;p&gt;AgentScope 2.0 的 Agent 内置 ReAct 循环，可自动调用工具。当前支持的工具包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;time&lt;/code&gt;：获取当前时间；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;weather&lt;/code&gt;：查询天气；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;location_by_ip&lt;/code&gt;：IP 定位；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;web_search&lt;/code&gt;：网络搜索（DuckDuckGo 或 Serper）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fetch_url&lt;/code&gt;：抓取网页内容。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;工具通过 &lt;code&gt;FunctionTool&lt;/code&gt; 注册到 &lt;code&gt;Toolkit&lt;/code&gt;，Agent 自己决定什么时候调用。&lt;/p&gt;
&lt;h3 id=&#34;45-人格画像与关系设计&#34;&gt;4.5 人格画像与关系设计&lt;/h3&gt;
&lt;h4 id=&#34;451-agent-人格模型&#34;&gt;4.5.1 Agent 人格模型&lt;/h4&gt;
&lt;p&gt;Agent 的人格不仅是 prompt，而是一套可运营、可迭代的配置。核心表结构如下：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TABLE&lt;/span&gt; agents (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    id CHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;PRIMARY&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;KEY&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;DEFAULT&lt;/span&gt; (UUID()),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    name VARCHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;UNIQUE&lt;/span&gt;,       &lt;span style=&#34;color:#75715e&#34;&gt;-- 昵称，全局唯一
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    avatar_url VARCHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    age INT,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    job VARCHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    traits JSON,                            &lt;span style=&#34;color:#75715e&#34;&gt;-- 性格标签，如 [&amp;#34;乐观&amp;#34;, &amp;#34;毒舌&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    interests JSON,                         &lt;span style=&#34;color:#75715e&#34;&gt;-- 兴趣话题，如 [&amp;#34;电影&amp;#34;, &amp;#34;旅行&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    speaking_style TEXT &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,           &lt;span style=&#34;color:#75715e&#34;&gt;-- 说话风格描述
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    system_prompt TEXT &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,            &lt;span style=&#34;color:#75715e&#34;&gt;-- 核心系统提示词
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    voice_tone VARCHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;),                 &lt;span style=&#34;color:#75715e&#34;&gt;-- 语气基调
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    default_reply_probability DECIMAL(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;DEFAULT&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    max_reply_length INT &lt;span style=&#34;color:#66d9ef&#34;&gt;DEFAULT&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    forbidden_topics JSON,                  &lt;span style=&#34;color:#75715e&#34;&gt;-- 禁忌话题
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    persona_summary TEXT,                   &lt;span style=&#34;color:#75715e&#34;&gt;-- 一句话人设（可自动生成）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    status VARCHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;DEFAULT&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;active&amp;#39;&lt;/span&gt;,    &lt;span style=&#34;color:#75715e&#34;&gt;-- active | disabled | archived
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    current_version INT &lt;span style=&#34;color:#66d9ef&#34;&gt;DEFAULT&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    created_at DATETIME &lt;span style=&#34;color:#66d9ef&#34;&gt;DEFAULT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;CURRENT_TIMESTAMP&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    updated_at DATETIME &lt;span style=&#34;color:#66d9ef&#34;&gt;DEFAULT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;CURRENT_TIMESTAMP&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;UPDATE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;CURRENT_TIMESTAMP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;关键设计：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt; 全局唯一，作为 Agent 在群聊中的显示名；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;traits&lt;/code&gt; / &lt;code&gt;interests&lt;/code&gt; 用 JSON 数组，便于后续做相关性过滤和标签检索；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;persona_summary&lt;/code&gt; 由系统根据 &lt;code&gt;traits&lt;/code&gt; + &lt;code&gt;speaking_style&lt;/code&gt; + &lt;code&gt;interests&lt;/code&gt; 自动生成，用于 &lt;code&gt;should_reply&lt;/code&gt; 等轻量决策；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;status&lt;/code&gt; 支持 &lt;code&gt;active&lt;/code&gt; / &lt;code&gt;disabled&lt;/code&gt; / &lt;code&gt;archived&lt;/code&gt;，便于灰度和下线；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;current_version&lt;/code&gt; 指向 &lt;code&gt;agent_versions&lt;/code&gt; 表的最新版本，支持人格迭代。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Agent 配置示例&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;阿杰&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;age&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;28&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;job&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;程序员&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;traits&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;幽默&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;直率&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;有点宅&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;interests&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;游戏&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;科幻电影&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;电子产品&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;speaking_style&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;说话直接，喜欢用网络梗，偶尔会吐槽&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;voice_tone&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;轻松调侃&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;system_prompt&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;你是阿杰，28岁程序员。你性格幽默直率，说话喜欢用网络梗。你正在一个群聊里和朋友聊天。请记住：你是 AI，不是真人。不要诱导用户泄露隐私或进行危险行为。&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;default_reply_probability&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0.6&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;max_reply_length&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;150&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;forbidden_topics&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;政治&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;暴力&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;色情&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h4 id=&#34;452-用户画像模型&#34;&gt;4.5.2 用户画像模型&lt;/h4&gt;
&lt;p&gt;用户画像是 Agent“懂用户”的基础，与 Mem0 形成互补：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TABLE&lt;/span&gt; user_profiles (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    user_id CHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;PRIMARY&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;KEY&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    summary TEXT,                 &lt;span style=&#34;color:#75715e&#34;&gt;-- 一句话画像（可由 Mem0 导出）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    attributes JSON,              &lt;span style=&#34;color:#75715e&#34;&gt;-- 稳定属性，如 {&amp;#34;city&amp;#34;: &amp;#34;杭州&amp;#34;, &amp;#34;job&amp;#34;: &amp;#34;设计师&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    preferences JSON,             &lt;span style=&#34;color:#75715e&#34;&gt;-- 喜欢/讨厌的话题
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    updated_at DATETIME
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;summary&lt;/code&gt;：由 LLM 定期从 Mem0 记忆中提炼；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;attributes&lt;/code&gt;：用户明确告诉系统的稳定属性；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;preferences&lt;/code&gt;：喜欢/讨厌的话题，用于过滤和个性化推荐。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用户画像会作为动态上下文注入 Agent 的 system prompt：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;关于 {target_user_name} 的重要记忆：
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;-&lt;/span&gt; 他是程序员，工作压力大。
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;-&lt;/span&gt; 他喜欢猫，讨厌下雨天。
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- 他上周提到最近在追《三体》。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;实际效果如下图所示：用户问王姐“你对我的画像是什么”，王姐基于长期记忆中积累的事实，总结出了“好奇心强、有点迷糊、爱玩爱闹、可能搞技术”等画像特征，并用了符合其“王姐”人设的俏皮语气表达。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://ftmao.com/blog/images/ScreenShot_2026-08-04_202545_484.png&#34; alt=&#34;Agent-Chat 中 Agent 基于长期记忆生成用户画像&#34;&gt;&lt;/p&gt;
&lt;h4 id=&#34;453-关系模型&#34;&gt;4.5.3 关系模型&lt;/h4&gt;
&lt;p&gt;关系表维护 Agent-用户、Agent-Agent 之间的亲密度和关系类型：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TABLE&lt;/span&gt; relationships (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    id CHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;PRIMARY&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;KEY&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;DEFAULT&lt;/span&gt; (UUID()),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    room_id CHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    source_id CHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,         &lt;span style=&#34;color:#75715e&#34;&gt;-- Agent 或 User ID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    target_id CHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    relation_type VARCHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;),           &lt;span style=&#34;color:#75715e&#34;&gt;-- &amp;#39;friend&amp;#39; | &amp;#39;colleague&amp;#39; | &amp;#39;rival&amp;#39; | &amp;#39;intimate&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    intimacy INT &lt;span style=&#34;color:#66d9ef&#34;&gt;CHECK&lt;/span&gt; (intimacy &lt;span style=&#34;color:#66d9ef&#34;&gt;BETWEEN&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    notes TEXT,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    updated_at DATETIME &lt;span style=&#34;color:#66d9ef&#34;&gt;DEFAULT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;CURRENT_TIMESTAMP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;关系会影响：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;发言决策&lt;/strong&gt;：关系亲密的 Agent 更可能主动接话；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语气风格&lt;/strong&gt;：对亲密的人更随意，对陌生的人更礼貌；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;话题选择&lt;/strong&gt;：知道用户和 Agent A 吵过架，Agent B 可能会岔开话题。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关系文本会注入 prompt：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;你与其他人的关系：
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;-&lt;/span&gt; 与 阿杰：friend，亲密度 80/100。经常一起打游戏。
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- 与 小明：colleague，亲密度 50/100。普通朋友。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h4 id=&#34;454-事件模型&#34;&gt;4.5.4 事件模型&lt;/h4&gt;
&lt;p&gt;重要事件（生日、约定、吵架、里程碑）单独记录，便于按时间线回溯：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TABLE&lt;/span&gt; events (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    id CHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;PRIMARY&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;KEY&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;DEFAULT&lt;/span&gt; (UUID()),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    room_id CHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    user_id CHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    agent_id CHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    event_summary TEXT &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    emotion_tag VARCHAR(&lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;),             &lt;span style=&#34;color:#75715e&#34;&gt;-- happy | sad | angry | excited
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    happened_at DATETIME,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    created_at DATETIME &lt;span style=&#34;color:#66d9ef&#34;&gt;DEFAULT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;CURRENT_TIMESTAMP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;事件可以由 Mem0 自动提取后同步写入，也可以由运营/用户手动维护。Agent 在合适时机引用事件，会让陪伴感更强：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;群聊公共记忆：
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;-&lt;/span&gt; 上周大家一起为 {user} 庆祝了生日，氛围很开心。
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- {user} 和 阿杰 约定这周末一起联机《黑神话：悟空》。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;46-安全与治理&#34;&gt;4.6 安全与治理&lt;/h3&gt;
&lt;p&gt;陪伴类系统对安全和边界的要求很高，Agent-Chat 从几个层面做了约束：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;人格边界&lt;/strong&gt;：Agent 的 &lt;code&gt;system_prompt&lt;/code&gt; 必须包含“你是 AI，不是真人”的声明；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内容审核&lt;/strong&gt;：LLM 输出先经过敏感词/有害内容检测，必要时拦截并重写；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;频率限制&lt;/strong&gt;：单个用户/Agent 的消息频率限制，防止刷屏；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;隐私隔离&lt;/strong&gt;：长期记忆按房间/用户隔离，支持用户删除自己的记忆；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;审计日志&lt;/strong&gt;：所有 LLM 调用记录模型、Prompt、Token 消耗、耗时；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;禁忌话题&lt;/strong&gt;：每个 Agent 可配置 &lt;code&gt;forbidden_topics&lt;/code&gt;，遇到相关话题主动回避。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五快速上手&#34;&gt;五、快速上手&lt;/h2&gt;
&lt;h3 id=&#34;51-安装依赖&#34;&gt;5.1 安装依赖&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 使用 Poetry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;poetry install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 或使用 pip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install -r requirements.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;52-配置环境变量&#34;&gt;5.2 配置环境变量&lt;/h3&gt;
&lt;p&gt;复制 &lt;code&gt;.env.example&lt;/code&gt; 为 &lt;code&gt;.env&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp .env.example .env&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;关键配置：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DEEPSEEK_API_KEY&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;your_deepseek_key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DEEPSEEK_BASE_URL&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;https://api.deepseek.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DEEPSEEK_MODEL&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;deepseek-chat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;MYSQL_URL&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;mysql+aiomysql://root:password@localhost:3306/agentscope_chat?charset&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;utf8mb4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;REDIS_URL&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;redis://localhost:6379/0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;QDRANT_URL&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;http://localhost:6333
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EMBEDDING_MODEL_PATH&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/path/to/bge-small-zh-v1.5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EMBEDDING_MODEL_DIMS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;512&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;53-启动服务&#34;&gt;5.3 启动服务&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 一键启动依赖（MySQL + Redis + Qdrant）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker-compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 运行数据库迁移&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;poetry run alembic upgrade head
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 启动应用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;poetry run uvicorn app.main:app --reload --port &lt;span style=&#34;color:#ae81ff&#34;&gt;8020&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;54-访问&#34;&gt;5.4 访问&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Web UI：http://localhost:8020/chat&lt;/li&gt;
&lt;li&gt;Admin 后台：http://localhost:8020/admin&lt;/li&gt;
&lt;li&gt;API 文档：http://localhost:8020/docs&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六项目结构&#34;&gt;六、项目结构&lt;/h2&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── main.py              # FastAPI 入口
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── config.py            # 配置管理
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── api/                 # REST API 路由
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── websocket/           # WebSocket 处理
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── agents/              # AgentScope Agent 定义与管理
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   ├── instance.py      # AgentInstance 包装 AgentScope Agent
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   ├── runtime.py       # RoomRuntime / RoomManager
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   ├── scope_models.py  # DeepSeekChatModel 单例
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   ├── tools.py         # FunctionTool 工具集
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   └── group_chat_mem0_middleware.py  # 自定义记忆 Middleware
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── memory/              # 短期/长期记忆服务
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   ├── short_term.py    # Redis 短期记忆
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   └── long_term.py     # Mem0 长期记忆封装
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── models/              # SQLAlchemy 数据模型
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── schemas/             # Pydantic 模型
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── services/            # 业务服务
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└── static/              # Web UI 静态文件&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;七典型应用场景&#34;&gt;七、典型应用场景&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;AI 陪伴社群&lt;/strong&gt;：运营一批有固定人设的 Agent，让用户感觉像加了一个兴趣群；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;角色扮演游戏&lt;/strong&gt;：每个 Agent 扮演不同 NPC，用户参与剧情；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;情感支持/树洞&lt;/strong&gt;：Agent 记住用户情绪历史，提供持续性心理陪伴；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语言练习&lt;/strong&gt;：多个 Agent 分别扮演不同口音/性格的语伴；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;产品原型验证&lt;/strong&gt;：快速验证多 Agent 交互体验，再决定是否自研更底层框架。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;八写在最后&#34;&gt;八、写在最后&lt;/h2&gt;
&lt;p&gt;Agent-Chat 的初心不是做一个“更聪明的聊天机器人”，而是做一个&lt;strong&gt;有温度、有记忆、有社交感的多 Agent 群聊底座&lt;/strong&gt;。它把 FastAPI 的实时能力、AgentScope 2.0 的 Agent 运行时、DeepSeek 的对话能力、Mem0 的长期记忆能力拼在一起，让开发者可以用配置文件“捏”出一群性格各异的朋友。&lt;/p&gt;
&lt;p&gt;项目还在持续迭代中，欢迎试用、提 issue、一起完善。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;开源地址&lt;/strong&gt;：https://gitee.com/soulnew/agent-chat&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你也在做多 Agent 陪伴系统，欢迎在评论区交流：你觉得“记忆隔离”和“发言调度”哪个更难做好？&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Netflix 的因果推断 Agent 工作流：没有标准答案时，怎么审计一个 AI</title>
      <link>https://ftmao.com/blog/posts/netflix-agentic-workflow-causal-inference/</link>
      <pubDate>Mon, 08 Jun 2026 10:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/netflix-agentic-workflow-causal-inference/</guid>
      <description>&lt;h1 id=&#34;netflix-的因果推断-agent-工作流没有标准答案时怎么审计一个-ai&#34;&gt;Netflix 的因果推断 Agent 工作流：没有标准答案时，怎么审计一个 AI&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;原文：&lt;a href=&#34;https://netflixtechblog.com/a-human-augmenting-agentic-workflow-for-causal-inference-4623f0a9c5af&#34;&gt;A Human-Augmenting Agentic Workflow for Causal Inference&lt;/a&gt;
目标读者：在做 AI Agent 落地的工程师、数据科学家，以及所有想过「这个 agent 给的数到底能不能信」的人。
阅读目标：搞清楚 Netflix 怎么把一个「没有标准答案、错不自知」的分析任务工程化成 agent 工作流，以及这套思路对普通后端和 AI 工程的迁移价值。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;先拆一个直觉agent-给了答案你敢用吗&#34;&gt;〇、先拆一个直觉：agent 给了答案，你敢用吗&lt;/h2&gt;
&lt;p&gt;先想一个场景：你让一个数据分析 agent 回答「看某部爆款剧对会员长期留存有没有因果效应」。它查了数、跑了回归、自信满满地返回一个数。你该信多少？它有没有处理掉那些隐蔽的偏差——比如把狂热粉丝当成普通观众？没有深厚的方法论功底，你甚至看不出它错没错。&lt;/p&gt;
&lt;p&gt;这就是观测性因果推断（Observational Causal Inference，OCI）的特殊处境。一般的 agent 评估套路是拿输出和 ground truth 程序化对比——但&lt;strong&gt;观测数据里根本没有 ground truth&lt;/strong&gt;。不是数据不够，是这个问题在本质上没有标准答案可比对。Netflix 这篇文章的核心贡献，就是正面回答了「评估对象不存在时怎么办」：&lt;strong&gt;评估不了结果，就审计过程。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;整个工作流立在他们 AI 时代之前就建好的 OCI 工具箱上，指导思想是「目标试验模拟」（target trial emulation）：拿到一个时点型因果问题，先问「回答这个问题的理想 A/B 实验长什么样？」这个实验可能太贵、太慢甚至不可行，但这个思想实验能逼你把假设钉死。&lt;/p&gt;
&lt;h2 id=&#34;一四个设计诊断工具箱里真正的硬货&#34;&gt;一、四个设计诊断：工具箱里真正的硬货&lt;/h2&gt;
&lt;p&gt;为了让「目标试验」这个类比可操作，工具箱内置了四个设计诊断，专门检查处理组和对照组的比较是否公平：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;协变量平衡&lt;/strong&gt;：加权之后，处理组和对照组在处理前协变量上的标准化均差应小于 0.2。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重叠性（overlap）&lt;/strong&gt;：接受处理的概率（倾向得分）应该落在 0.1 到 0.9 之间——太接近 0 或 1 的样本，处理与否基本是注定的，不存在「可比的对照」。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安慰剂结局&lt;/strong&gt;：在处理发生之前测量的变量上，「处理效应」应该和零没有显著差异。处理还没发生就有效应，说明两组人本来就不同。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对隐藏混杂的敏感性&lt;/strong&gt;：结论要放在「假设存在一个同时影响处理和结局的遗漏变量」的语境下重新考量。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这四条没有什么 AI 含量，全是统计学的老手艺。但这正是文章的潜台词：&lt;strong&gt;agent 工作流的可靠性不来自模型更聪明，来自把纪律焊死在流程里。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;二三个角色principalactorcritic&#34;&gt;二、三个角色：Principal、Actor、Critic&lt;/h2&gt;
&lt;p&gt;工作流有三个角色，后两个由软件扮演，跑成一个 actor-critic 循环：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    P[&amp;#34;Principal 人类&amp;lt;br/&amp;gt;写初始分析计划&amp;lt;br/&amp;gt;交代混杂因素与业务背景&amp;lt;br/&amp;gt;指定可用工具和数据集&amp;#34;] --&amp;gt; A[&amp;#34;Actor 软件&amp;lt;br/&amp;gt;把计划细化为分析 spec&amp;lt;br/&amp;gt;只用被允许的工具执行&amp;lt;br/&amp;gt;跑核心分析和四个设计诊断&amp;#34;]
    A --&amp;gt; ART[&amp;#34;工件&amp;lt;br/&amp;gt;plan 和 spec&amp;lt;br/&amp;gt;图表 报告 可复现 notebook&amp;#34;]
    A --&amp;gt; C[&amp;#34;Critic 软件&amp;lt;br/&amp;gt;找计划盲区 查计划与执行的一致性&amp;lt;br/&amp;gt;给结果定可信度等级&amp;lt;br/&amp;gt;对照理想 RCT 找差距&amp;#34;]
    C --&amp;gt;|&amp;#34;诊断失败或发现盲区&amp;lt;br/&amp;gt;触发补救或下一轮迭代&amp;#34;| A
    ART --&amp;gt;|&amp;#34;过程审计&amp;lt;br/&amp;gt;人类可下载重跑&amp;#34;| P
    style P fill:#fff3cd
    style ART fill:#e8f5e9&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;Critic 的职责清单值得细看，它不只是「再看看对不对」：检查 Principal 计划里没提到的混杂因素；核对计划、spec、实际执行三者是否对齐；看完诊断后给结果定可信度等级；明确说明估计量是否偏离了 ATE（比如因为倾向得分裁剪）；把实际分析和理想 RCT 做对照；还要至少给出一种替代测量方案（比如激励式 RCT）。&lt;/p&gt;
&lt;p&gt;人类这边的配套是一个模板化 notebook，底层用经过验证的（非 agent 的）OCI 工具箱，效应估计用 doubly robust learning。agent 产出的报告有版本控制，执行过的 notebook 上传到文件存储，Principal 可以下载下来亲自重跑。&lt;strong&gt;人不用亲自干苦活，但每一步都留了可以让人验算的凭据&lt;/strong&gt;——这就是标题里 &amp;ldquo;human-augmenting&amp;rdquo; 的实际含义：不是替代人，是把人的精力从重复劳动（反复检查协变量平衡、跑敏感性分析、管理迭代版本）挪到只有人能做的事上（框定问题、审视假设、判断结果）。&lt;/p&gt;
&lt;h2 id=&#34;三案例新娱乐类型的留存影响估计值缩水到四分之一&#34;&gt;三、案例：新娱乐类型的留存影响，估计值缩水到四分之一&lt;/h2&gt;
&lt;p&gt;Netflix 近年加了不少视频之外的新娱乐类型，自然要问：这些东西对会员满意度和续订有什么影响？他们拿其中一个类型（文中叫 Type X）做了对照实验：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;处理&lt;/strong&gt;：Type X 的使用天数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结局&lt;/strong&gt;：两个月留存&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;潜在混杂&lt;/strong&gt;：包括处理前的 Type X 使用天数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;基线&lt;/strong&gt;：把这份分析计划不加任何脚手架直接喂给 Claude Sonnet 4.6。模型选了一个说得过去的策略——用留存对使用天数加控制变量做线性回归——输出干净漂亮。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;paved path（铺好的路）&lt;/strong&gt;：同一份计划、同一个模型，走他们的工具箱加 agentic 工作流，产出的估计值&lt;strong&gt;只有基线的 25%&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;差异的根源是&lt;strong&gt;早期采用者偏差&lt;/strong&gt;（early adopter bias）：新功能的第一批用户和一般人群系统性不同——他们可能是 Netflix 重度用户，或者是相关 IP 的死忠粉。这个偏差在数据里表现为重叠性崩塌：绝大多数观测的 Type X 参与概率估值都极小（功能还太新）。critic 在报告里抓住了这个问题，还标记了安慰剂检验失败：早期采用者在&lt;strong&gt;处理发生之前&lt;/strong&gt;测量的重要协变量上就和非采用者有显著差异——两组人本来就不是一路人。&lt;/p&gt;
&lt;p&gt;补救手段来自工作流内置的 playbook：重叠性差就用 Crump 式裁剪，估计因果效应前先把倾向得分落在 0.1 到 0.9 之外的样本裁掉。代价是结论的适用范围缩水——估计的 ATE 只适用于「参与与否不是注定」的那部分人群，critic 必须在报告里把这个注意事项写明。但换来的是可信度的质变：裁剪后的估计只依赖「处理近似随机」的子人群，和目标试验的精神一致；而基线那个数靠的是对低概率人群的外推，外推出来的数字没有扎实数据支撑，还很可能被早期采用者偏差污染。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    PLAN[&amp;#34;同一份分析计划&amp;lt;br/&amp;gt;同一个 Sonnet 4.6&amp;#34;] --&amp;gt; BASE[&amp;#34;裸调 one-shot&amp;lt;br/&amp;gt;线性回归 不加诊断&amp;#34;]
    PLAN --&amp;gt; PP[&amp;#34;paved path&amp;lt;br/&amp;gt;脚手架加诊断加 critic&amp;#34;]
    BASE --&amp;gt; B1[&amp;#34;结果干净漂亮&amp;lt;br/&amp;gt;但依赖外推&amp;lt;br/&amp;gt;被早期采用者偏差污染&amp;#34;]
    PP --&amp;gt; D1[&amp;#34;重叠性诊断失败&amp;lt;br/&amp;gt;安慰剂检验失败&amp;#34;]
    D1 --&amp;gt; D2[&amp;#34;Crump 裁剪&amp;lt;br/&amp;gt;只保留倾向得分 0.1 到 0.9 的人群&amp;#34;]
    D2 --&amp;gt; B2[&amp;#34;估计值只有基线的 25%&amp;lt;br/&amp;gt;适用范围缩水但可信&amp;#34;]
    style B1 fill:#ffcccc
    style B2 fill:#e8f5e9&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;这个案例最扎心的地方在于：&lt;strong&gt;基线的产出是「defensible」的&lt;/strong&gt;——策略挑不出大毛病，呈现也很专业。如果你不是 OCI 从业者，你大概率就收下了。&lt;/p&gt;
&lt;h2 id=&#34;四编排后续分析agent-真正省力的部分&#34;&gt;四、编排后续分析：agent 真正省力的部分&lt;/h2&gt;
&lt;p&gt;分析做完还有两类自然后续，都是「同一分析跑 N 个变体」的脏活：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;敏感性分析&lt;/strong&gt;：换不同的裁剪阈值重做分析。他们让 agent 把裁剪界从 0 到 1（不裁剪）一路变到 0.15 到 0.85，结论是重叠人群上的 ATE 估计在 0.005 到 0.995 的界内对阈值选择稳健。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;时间序列&lt;/strong&gt;：把同一分析在十个不同的日期分区上重跑，看效应随时间的演变。这里有个微妙的坑：跨时间比较必须协调各次分析的人群——如果某次为了可信度裁掉了一批用户，其他几次也得裁同一批。跑出来的结果显示季节性：冬季日期的处理效应强于夏季。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这两类活的技术含量为零，出错概率不低（参数改一个忘一个、人群没对齐），正是 agent 该吃的苦。&lt;/p&gt;
&lt;h2 id=&#34;五开源与评测critic-真的能区分好坏估计&#34;&gt;五、开源与评测：critic 真的能区分好坏估计&lt;/h2&gt;
&lt;p&gt;Netflix 开源了一个独立版 &lt;code&gt;oci-agent&lt;/code&gt;，附带两个基于 ACIC 2016（大西洋因果推断会议竞赛）公开数据集的评测，以及一个只用开源软件（EconML）的轻量因果机器学习 notebook。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;评测一&lt;/strong&gt;：对 77 个数据生成过程（DGP）各随机抽 3 个数据集，共 231 个估计，让 critic 依据诊断把它们分成 satisfactory 和 unsatisfactory。结果：192 个 satisfactory、39 个 unsatisfactory。对照竞赛里 44 个参赛方法，他们的统计方法本身就有竞争力——RMSE 足够低，95% 置信区间的覆盖率约 95%（校准良好）。但重点在这：&lt;strong&gt;satisfactory 那组的 RMSE 显著更低、区间校准更好，unsatisfactory 那组明显更差&lt;/strong&gt;——诊断套件加 critic 确实能把可信的估计和不可信的估计分开。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;评测二&lt;/strong&gt;：同一份分析计划，带脚手架 vs 裸调（one-shot prompting）。随机抽十个 ACIC 数据集，带脚手架的 LLM 复原了九个的真值，且估计与真值高度相关；裸调 Sonnet 4.6 则一致地错，和真值基本不相关。&lt;/p&gt;
&lt;p&gt;作者也坦白了局限：合成数据集压测不了 agent 对真实业务场景的语义理解。但仓库演示了两条核心原则——&lt;strong&gt;用足量脚手架让 agent 按设计遵守最佳实践；要求可检查的工件，让人类能审计 agent 的过程而不只是结果。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;工程实践联想&#34;&gt;工程实践联想&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;没有 ground truth 的领域，把 eval 拆成「结果评估」和「过程审计」两层。&lt;/strong&gt; 推荐、增长、风控策略、A/B 之外的分析场景，大量任务都没有可比对的标准答案。Netflix 的答案是：结果层用代理指标（ACIC 合成数据上的 RMSE），过程层靠工件留痕（plan、spec、notebook、版本化报告）让人审。我们写 agent 时也该问一句：这个 agent 的产出，三个月后另一个工程师能不能重建它的推理链？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;脚手架比模型重要。&lt;/strong&gt; 同一个 Sonnet 4.6，裸调和走 paved path 的估计差了 4 倍——而且错的是看起来更漂亮的那个。「换更强的模型」解决的是能力问题，「模板、诊断、playbook、强制的 critic 环节」解决的是纪律问题。分析类任务里，纪律缺口比能力缺口大得多。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;actor-critic 结构的关键是 critic 有独立的、可操作的责任清单。&lt;/strong&gt; Netflix 的 critic 不是泛泛地「你再检查一遍」，而是有具体义务：找计划盲区、核对三层一致性、定可信度等级、对照理想 RCT、给替代方案。critic 的职责越具体，漏检越少。这和 code review 清单化是同一个道理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;诊断失败要有 playbook，而不是一句「请注意」。&lt;/strong&gt; 重叠性差对应 Crump 裁剪，裁剪导致估计量偏离 ATE 就要求 critic 在报告里标注适用范围。诊断、补救、注意事项三条线绑在一起，流程才是闭环的。我们系统里的告警如果只报不处理，和人肉运维没区别。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;把人放在「审」的位置，而不是「干」的位置。&lt;/strong&gt; 人的精力留给框定问题、审视假设、判断结果；重复执行、版本管理、批量变体交给 agent。这个分工原则对任何「专业判断密集 + 重复劳动密集」的工作流都成立，不止因果推断。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;本篇小结&#34;&gt;本篇小结&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;问题&lt;/strong&gt;：观测性因果推断没有 ground truth，agent 给的因果答案无法拿结果对错来评估，错了也很难被发现。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解法&lt;/strong&gt;：Principal-Actor-Critic 三角色工作流。人类写计划和背景，actor 按模板执行分析并跑四个设计诊断（协变量平衡 SMD ＜ 0.2、倾向得分落在 0.1 到 0.9、安慰剂结局、敏感性分析），critic 有明确清单地挑毛病并定可信度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;人的位置&lt;/strong&gt;：human-augmenting 的落点是工件——版本化报告、可下载重跑的 notebook——用过程审计代替结果评估。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;案例&lt;/strong&gt;：新娱乐类型的留存效应，裸调 Sonnet 4.6 给出漂亮但依赖外推的回归结果；走工作流后诊断抓住早期采用者偏差，Crump 裁剪后估计值只有基线的 25%。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;评测&lt;/strong&gt;：ACIC 2016 上 231 个估计，critic 判定的 192 个 satisfactory 估计质量显著优于 39 个 unsatisfactory；带脚手架 10 个数据集复原 9 个真值，裸调全军覆没。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;私货&lt;/strong&gt;：这篇文章真正的主题不是因果推断，是「如何工程化地使用一个你信不过的聪明组件」——脚手架定纪律、critic 做对抗、工件留凭据、人类审过程。这套四件套放在任何高风险 agent 场景都成立。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;原文：Winston Chou 等，&lt;a href=&#34;https://netflixtechblog.com/a-human-augmenting-agentic-workflow-for-causal-inference-4623f0a9c5af&#34;&gt;A Human-Augmenting Agentic Workflow for Causal Inference&lt;/a&gt;，Netflix Technology Blog，2026-06-08。&lt;/li&gt;
&lt;li&gt;开源仓库：Netflix 的独立版 &lt;code&gt;oci-agent&lt;/code&gt;（原文有链接，基于 EconML）。&lt;/li&gt;
&lt;li&gt;2016 Atlantic Causal Inference Conference（ACIC）数据分析竞赛数据集（评测所用的 77 个 DGP 来源）。&lt;/li&gt;
&lt;li&gt;Crump 等人的倾向得分裁剪方法（重叠性诊断失败的补救手段，原文引用的 playbook 条目）。&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title>LLM 输出 JSON 不稳定：Schema &#43; 重试的实战方案</title>
      <link>https://ftmao.com/blog/posts/goodjson/</link>
      <pubDate>Thu, 02 Apr 2026 15:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/goodjson/</guid>
      <description>&lt;h1 id=&#34;llm-输出-json-不稳定schema--重试的实战方案&#34;&gt;LLM 输出 JSON 不稳定：Schema + 重试的实战方案&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;做 AI Agent 或 LLM 应用时，一个高频需求是让模型输出结构化数据。比如 Agent 需要 LLM 决定调用哪个 Tool、视觉规划需要输出 JSON 数组、代码生成需要返回固定格式的片段。但 LLM 输出 JSON 很容易出问题：格式错乱、字段缺失、类型不对、多了句废话。这篇文章分享我们是如何把结构化输出成功率从 75% 左右提升到 98% 以上的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一问题的普遍性&#34;&gt;一、问题的普遍性&lt;/h2&gt;
&lt;p&gt;我们先看几个真实遇到的 LLM 输出：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;场景 1：Agent 决定调用 Tool&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;期望输出：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;tool&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;RetrieveMaterials&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;params&amp;#34;&lt;/span&gt;: {&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;query&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;海边日落&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;实际输出：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;我决定调用 RetrieveMaterials 工具，参数是 {&amp;#34;query&amp;#34;: &amp;#34;海边日落&amp;#34;}。&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;场景 2：视觉规划输出 JSON 数组&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;期望输出：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;element_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TitleCard&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;AI 剪辑实战&amp;#34;&lt;/span&gt;}]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;实际输出：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;result&amp;#34;&lt;/span&gt;: [{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;element_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TitleCard&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;AI 剪辑实战&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;场景 3：字段类型错误&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;duration&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;30秒&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;期望是数字：&lt;code&gt;30&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这些输出人都看得懂，但程序解析不了。不解决的话，LLM 应用根本跑不稳。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二常见的四层解决方案&#34;&gt;二、常见的四层解决方案&lt;/h2&gt;
&lt;p&gt;我们实践下来，可靠的方案是四层防护：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[&amp;#34;第一层：Prompt 设计（明确格式 + Few-shot）&amp;#34;] --&amp;gt; B[&amp;#34;第二层：JSON Schema / Function Calling 约束&amp;#34;]
    B --&amp;gt; C[&amp;#34;第三层：后端 Pydantic 校验&amp;#34;]
    C --&amp;gt; D[&amp;#34;第四层：自动重试 + 降级&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;单层都不够，必须组合使用。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三第一层prompt-设计&#34;&gt;三、第一层：Prompt 设计&lt;/h2&gt;
&lt;h3 id=&#34;31-明确输出格式&#34;&gt;3.1 明确输出格式&lt;/h3&gt;
&lt;p&gt;Prompt 里必须清楚说明输出格式，不要含糊：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;请直接输出 JSON，不要包含任何解释性文字。
JSON 格式如下：
{
  &amp;#34;tool&amp;#34;: &amp;#34;工具名称&amp;#34;,
  &amp;#34;params&amp;#34;: {
    &amp;#34;参数名&amp;#34;: &amp;#34;参数值&amp;#34;
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;32-few-shot-示例&#34;&gt;3.2 Few-shot 示例&lt;/h3&gt;
&lt;p&gt;在 Prompt 里给 2-3 个正确示例，效果提升明显：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;示例 1：
输入：用户想要一个海边日落视频
输出：{&amp;#34;tool&amp;#34;: &amp;#34;RetrieveMaterials&amp;#34;, &amp;#34;params&amp;#34;: {&amp;#34;query&amp;#34;: &amp;#34;海边日落&amp;#34;}}

示例 2：
输入：用户想要删除视频中的语气词
输出：{&amp;#34;tool&amp;#34;: &amp;#34;RemoveFillers&amp;#34;, &amp;#34;params&amp;#34;: {&amp;#34;aggressive&amp;#34;: false}}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;33-限制输出长度&#34;&gt;3.3 限制输出长度&lt;/h3&gt;
&lt;p&gt;对于简单任务，明确要求 LLM 不要展开：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;输出必须严格符合上述 JSON 格式，总长度不超过 200 个字符。&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;四第二层json-schema-约束&#34;&gt;四、第二层：JSON Schema 约束&lt;/h2&gt;
&lt;h3 id=&#34;41-什么是-json-schema&#34;&gt;4.1 什么是 JSON Schema&lt;/h3&gt;
&lt;p&gt;JSON Schema 是一种描述 JSON 数据结构的规范。你可以把它传给 LLM，让模型按这个结构输出。&lt;/p&gt;
&lt;p&gt;DeepSeek、GPT-4、Claude 3 都支持 JSON Schema 或 Function Calling。&lt;/p&gt;
&lt;h3 id=&#34;42-我们的-schema-示例&#34;&gt;4.2 我们的 Schema 示例&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;visual_plan_schema &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;array&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;items&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;object&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;properties&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sentence_index&amp;#34;&lt;/span&gt;: {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;integer&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;element_type&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;enum&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TitleCard&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BRoll&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;QuoteCard&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CodeBlock&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ListCard&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TalkingHead&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;reason&amp;#34;&lt;/span&gt;: {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;string&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;suggested_content&amp;#34;&lt;/span&gt;: {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;string&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;required&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sentence_index&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;element_type&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;reason&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;43-deepseek-调用示例&#34;&gt;4.3 DeepSeek 调用示例&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; openai
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;client &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; openai&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;OpenAI(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    api_key&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;your-api-key&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    base_url&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://api.deepseek.com/v1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;response &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; client&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;chat&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;completions&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;create(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    model&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deepseek-chat&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    messages&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;system&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;你是一个专业的视频剪辑规划助手。&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: prompt}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    response_format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;json_schema&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;json_schema&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;visual_plan&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;schema&amp;#34;&lt;/span&gt;: visual_plan_schema
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    temperature&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0.2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;loads(response&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;choices[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;message&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;content)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;44-function-calling&#34;&gt;4.4 Function Calling&lt;/h3&gt;
&lt;p&gt;Function Calling 本质上也是让 LLM 输出结构化的函数调用参数：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;response &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; client&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;chat&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;completions&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;create(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    model&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deepseek-chat&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    messages&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;[{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: prompt}],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    tools&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;function&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;function&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;plan_visual_elements&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;为口播视频规划视觉元素&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;parameters&amp;#34;&lt;/span&gt;: visual_plan_schema
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    tool_choice&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;function&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;function&amp;#34;&lt;/span&gt;: {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;plan_visual_elements&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tool_call &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; response&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;choices[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;message&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;tool_calls[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;loads(tool_call&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;function&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;arguments)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;Function Calling 的好处是模型更清楚自己在做什么，输出稳定性通常更好。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五第三层pydantic-后端校验&#34;&gt;五、第三层：Pydantic 后端校验&lt;/h2&gt;
&lt;p&gt;即使 LLM 支持 Schema，也不能 100% 保证输出合法。后端必须用 Pydantic 做严格校验。&lt;/p&gt;
&lt;h3 id=&#34;51-模型定义&#34;&gt;5.1 模型定义&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; pydantic &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; BaseModel, Field, field_validator
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; typing &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; Literal
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;VisualElement&lt;/span&gt;(BaseModel):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sentence_index: int &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Field(ge&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    element_type: Literal[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TitleCard&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BRoll&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;QuoteCard&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CodeBlock&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ListCard&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TalkingHead&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    reason: str &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Field(min_length&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, max_length&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    suggested_content: str &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@field_validator&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;suggested_content&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@classmethod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;validate_content&lt;/span&gt;(cls, v, info):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        element_type &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; info&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;element_type&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; element_type &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TitleCard&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; len(v) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;raise&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ValueError&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TitleCard 必须有标题内容&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; v
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;VisualPlan&lt;/span&gt;(BaseModel):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    elements: list[VisualElement]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;52-校验与错误收集&#34;&gt;5.2 校验与错误收集&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;parse_visual_plan&lt;/span&gt;(raw_output: str) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; VisualPlan:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        data &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;loads(raw_output)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;except&lt;/span&gt; json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;JSONDecodeError &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; e:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;raise&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ValueError&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JSON 解析失败: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;e&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 兼容 LLM 外层多套一层 result 的情况&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; isinstance(data, dict) &lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;result&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; data &lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; isinstance(data[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;result&amp;#34;&lt;/span&gt;], list):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        data &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; data[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;result&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; VisualPlan(elements&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;data)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;53-常见兼容处理&#34;&gt;5.3 常见兼容处理&lt;/h3&gt;
&lt;p&gt;实际生产中会见到各种「不标准」的输出，我们做了几个兼容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;去掉 Markdown 代码块标记 &lt;code&gt;json ... &lt;/code&gt;&lt;/li&gt;
&lt;li&gt;去掉多余的前缀说明文字&lt;/li&gt;
&lt;li&gt;兼容外层多套一层 &lt;code&gt;{&amp;quot;result&amp;quot;: [...]}&lt;/code&gt; 的情况&lt;/li&gt;
&lt;li&gt;兼容中文字段名（如果 Prompt 不小心用了中文）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六第四层自动重试--降级&#34;&gt;六、第四层：自动重试 + 降级&lt;/h2&gt;
&lt;h3 id=&#34;61-重试策略&#34;&gt;6.1 重试策略&lt;/h3&gt;
&lt;p&gt;当校验失败时，不要直接报错，而是把错误信息回传给 LLM，让它重新生成。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; tenacity &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; retry, stop_after_attempt, wait_exponential
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@retry&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    stop&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;stop_after_attempt(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    wait&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;wait_exponential(multiplier&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, min&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, max&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    retry&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;retry_if_exception_type(&lt;span style=&#34;color:#a6e22e&#34;&gt;ValueError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;generate_with_retry&lt;/span&gt;(prompt: str, schema: dict) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; dict:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    raw &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; llm&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;generate(prompt, response_format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;schema)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; parse_visual_plan(raw)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;except&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ValueError&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; e:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# 把错误信息加入 Prompt，重新生成&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        prompt &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;注意：你之前的输出校验失败，错误是：&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;e&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;请严格按照 JSON Schema 输出。&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;raise&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;62-温度参数调整&#34;&gt;6.2 温度参数调整&lt;/h3&gt;
&lt;p&gt;重试时降低 temperature，让输出更稳定：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;temperature_schedule &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;0.2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0.1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0.0&lt;/span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;63-降级方案&#34;&gt;6.3 降级方案&lt;/h3&gt;
&lt;p&gt;如果 3 次重试都失败，不能卡住，要有降级：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;safe_generate_visual_plan&lt;/span&gt;(script: str) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; VisualPlan:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; generate_with_retry(script)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;except&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Exception&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# 降级：所有句子保持 TalkingHead&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; VisualPlan(elements&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            VisualElement(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                sentence_index&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;i,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                element_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TalkingHead&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                reason&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;LLM 规划失败，降级为默认方案&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(len(script&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;split(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;。&amp;#39;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;这样至少能保证系统不崩，用户可以拿到一个基础版本的视频。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七完整代码示例&#34;&gt;七、完整代码示例&lt;/h2&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; json
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; pydantic &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; BaseModel, Field
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; typing &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; Literal
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;VisualElement&lt;/span&gt;(BaseModel):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sentence_index: int &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Field(ge&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    element_type: Literal[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TitleCard&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BRoll&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;QuoteCard&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CodeBlock&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ListCard&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TalkingHead&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    reason: str &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Field(min_length&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, max_length&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    suggested_content: str &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clean_llm_output&lt;/span&gt;(raw: str) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; str:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;清理 LLM 可能产生的多余格式&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    raw &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; raw&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;strip()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; raw&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;startswith(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;```&amp;#34;&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        raw &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; raw&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;strip(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;`&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; raw&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;startswith(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;json&amp;#34;&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            raw &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; raw[&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;:]&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;strip()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; raw
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;robust_parse&lt;/span&gt;(raw: str) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; list[VisualElement]:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    raw &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; clean_llm_output(raw)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        data &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;loads(raw)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;except&lt;/span&gt; json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;JSONDecodeError:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# 尝试找到第一个 [ 和最后一个 ]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        start &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; raw&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;find(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        end &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; raw&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rfind(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; start &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; end &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            data &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;loads(raw[start:end&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;raise&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 兼容外层嵌套&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; isinstance(data, dict):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; key &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;result&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;elements&amp;#34;&lt;/span&gt;]:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; key &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; data &lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; isinstance(data[key], list):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                data &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; data[key]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; isinstance(data, list):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;raise&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ValueError&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;期望数组，实际得到 &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;type(data)&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; [VisualElement(&lt;span style=&#34;color:#f92672&#34;&gt;**&lt;/span&gt;item) &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; item &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; data]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;八效果数据&#34;&gt;八、效果数据&lt;/h2&gt;
&lt;p&gt;在我们实际使用中，这套四层方案的效果如下：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;方案&lt;/th&gt;
					&lt;th&gt;解析成功率&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;纯 Prompt 约束&lt;/td&gt;
					&lt;td&gt;约 75%&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;+ JSON Schema&lt;/td&gt;
					&lt;td&gt;约 90%&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;+ Pydantic 校验 + 重试&lt;/td&gt;
					&lt;td&gt;约 98%&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;+ 降级方案&lt;/td&gt;
					&lt;td&gt;系统可用性 99.9%+&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;（待补充真实数据）&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;九踩过的坑&#34;&gt;九、踩过的坑&lt;/h2&gt;
&lt;h3 id=&#34;91-schema-太复杂导致模型懵&#34;&gt;9.1 Schema 太复杂导致模型懵&lt;/h3&gt;
&lt;p&gt;早期的 Schema 有 20 多个字段，模型输出经常漏字段。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：Schema 只保留必要字段，非必要字段放 &lt;code&gt;metadata&lt;/code&gt; 或后续步骤再补。&lt;/p&gt;
&lt;h3 id=&#34;92-中文标点导致-json-解析失败&#34;&gt;9.2 中文标点导致 JSON 解析失败&lt;/h3&gt;
&lt;p&gt;LLM 输出中文引号或中文逗号，导致 JSON 解析失败。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：在 Prompt 里明确说明用英文标点，后端做字符替换兼容。&lt;/p&gt;
&lt;h3 id=&#34;93-模型输出超长&#34;&gt;9.3 模型输出超长&lt;/h3&gt;
&lt;p&gt;复杂任务下，LLM 输出解释性文字 + JSON，超出 Schema 控制。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;明确要求「只输出 JSON，不要解释」&lt;/li&gt;
&lt;li&gt;设置 &lt;code&gt;max_tokens&lt;/code&gt; 上限&lt;/li&gt;
&lt;li&gt;后端做截断和清洗&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;94-不同模型-schema-支持不一致&#34;&gt;9.4 不同模型 Schema 支持不一致&lt;/h3&gt;
&lt;p&gt;DeepSeek、GPT、Claude 对 JSON Schema 的支持细节不同。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;统一封装 LLM 调用层&lt;/li&gt;
&lt;li&gt;对不同模型做适配&lt;/li&gt;
&lt;li&gt;尽量使用 Function Calling，兼容性更好&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十总结&#34;&gt;十、总结&lt;/h2&gt;
&lt;p&gt;LLM 输出结构化数据不稳定，不是模型不行，而是&lt;strong&gt;提示、约束、校验、重试&lt;/strong&gt;四个环节必须闭环。我们的经验是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Prompt 要明确要求格式&lt;/strong&gt;，别指望模型自己猜&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JSON Schema / Function Calling 是第二层保险&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;后端 Pydantic 校验必不可少&lt;/strong&gt;，不要信任模型输出&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重试 + 降级保证系统可用性&lt;/strong&gt;，而不是一失败就抛异常&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对模型差异做抽象封装&lt;/strong&gt;，方便切换和升级&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这套方案不只适用于视频生成，几乎所有 LLM Agent 应用都需要。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;如果你在 LLM 结构化输出方面也踩过坑，欢迎在评论区分享。&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Claude Code 是怎么运行的？给新手的 AI 编程代理入门指南</title>
      <link>https://ftmao.com/blog/posts/claude-code-principles-for-beginners/</link>
      <pubDate>Fri, 09 Jan 2026 10:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/claude-code-principles-for-beginners/</guid>
      <description>&lt;h1 id=&#34;claude-code-是怎么运行的给新手的-ai-编程代理入门指南&#34;&gt;Claude Code 是怎么运行的？给新手的 AI 编程代理入门指南&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;参考：&lt;a href=&#34;https://github.com/shareAI-lab/learn-claude-code&#34;&gt;shareAI-lab/learn-claude-code&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;你有没有想过，为什么你跟 Claude Code 说“帮我改一下这个网页”，它就能自己打开文件、修改代码、运行测试，然后告诉你结果？&lt;/p&gt;
&lt;p&gt;它看起来好聪明，像人一样会“动手”。但其实，它背后的原理并不神秘，甚至可以用几十行简单的代码讲清楚。&lt;/p&gt;
&lt;p&gt;这篇文章是给新手的。不管你有没有学过编程，我都会尽量用生活中的例子来解释。读完之后，你会明白：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Claude Code 最核心的部分是什么；&lt;/li&gt;
&lt;li&gt;它是怎么“看懂”文件、“动手”改代码的；&lt;/li&gt;
&lt;li&gt;它为什么能记住很多事情、做错事能重来；&lt;/li&gt;
&lt;li&gt;以及如果你想自己做一个类似的 AI 助手，应该从哪里开始。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一一句话讲清楚-claude-code&#34;&gt;一、一句话讲清楚 Claude Code&lt;/h2&gt;
&lt;p&gt;如果把 Claude Code 拆开，你会发现它只有三个东西：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;一个循环 + 一张工具表 + 一个会说话的 AI&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;部件&lt;/th&gt;
					&lt;th&gt;作用&lt;/th&gt;
					&lt;th&gt;生活里的比喻&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;会说话的 AI（大语言模型）&lt;/td&gt;
					&lt;td&gt;思考、理解你说的话、决定下一步做什么&lt;/td&gt;
					&lt;td&gt;一个超级聪明的大脑&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;工具表&lt;/td&gt;
					&lt;td&gt;让 AI 能读写文件、运行命令、搜索代码&lt;/td&gt;
					&lt;td&gt;给大脑装上双手和眼睛&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;循环&lt;/td&gt;
					&lt;td&gt;不断重复“思考 → 行动 → 看结果 → 再思考”&lt;/td&gt;
					&lt;td&gt;机器人一直干活，直到做完&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这个“循环”非常重要。没有它，AI 就只能说一次话，没法连续做很多事。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph 工具箱[&amp;#34;🧰 工具箱（Harness）&amp;#34;]
        读文件[&amp;#34;读文件&amp;#34;]
        写文件[&amp;#34;写文件&amp;#34;]
        执行命令[&amp;#34;执行命令&amp;#34;]
        搜索[&amp;#34;搜索代码&amp;#34;]
        权限[&amp;#34;权限检查&amp;#34;]
    end

    大脑[&amp;#34;🧠 AI 大脑&amp;lt;br/&amp;gt;会思考、会推理&amp;#34;]
    电脑[&amp;#34;💻 你的电脑&amp;#34;]

    大脑 --&amp;gt;|我想读文件| 读文件
    读文件 --&amp;gt;|文件内容| 大脑
    大脑 --&amp;gt;|我想运行测试| 执行命令
    执行命令 --&amp;gt; 电脑
    电脑 --&amp;gt;|测试结果| 大脑
    权限 --&amp;gt;|这个能做吗？| 执行命令&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;二最核心的-30-行代码&#34;&gt;二、最核心的 30 行代码&lt;/h2&gt;
&lt;p&gt;Claude Code 的心脏，是一段很简单的代码。你可以把它理解成“机器人干活的主流程”：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;agent_loop&lt;/span&gt;(query):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 1. 先把用户的问题记下来&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    messages &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: query}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# 2. 把对话历史发给 AI，告诉它有哪些工具可以用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        response &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; client&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;messages&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;create(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            model&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;MODEL,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            system&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;SYSTEM,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            messages&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;messages,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            tools&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;TOOLS,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            max_tokens&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;8000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# 3. 把 AI 的回复存进历史&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        messages&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;append({&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;assistant&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: response&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;content})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# 4. 如果 AI 不再调用工具，就说明它说完了，结束循环&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; response&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;stop_reason &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tool_use&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# 5. 执行 AI 要求的工具，并把结果告诉它&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        results &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; block &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; response&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;content:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; block&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;type &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tool_use&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                output &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; run_tool(block&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;name, block&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;input)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                results&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;append({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tool_result&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tool_use_id&amp;#34;&lt;/span&gt;: block&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;id,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: output,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        messages&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;append({&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: results})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;人话解释&#34;&gt;人话解释&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;你问了一个问题&lt;/strong&gt; → 比如“帮我修一下这个 bug”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI 看历史和工具表&lt;/strong&gt; → 它想：“我需要先读一下代码文件。”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI 说“我要用读文件工具”&lt;/strong&gt; → 程序真的去打开文件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;把文件内容还给 AI&lt;/strong&gt; → AI 再看，决定下一步。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;一直重复，直到 AI 说“我搞定了”&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    开始([你输入任务]) --&amp;gt; 发给AI[把任务+历史发给 AI]
    发给AI --&amp;gt; AI思考[AI 思考]
    AI思考 --&amp;gt; 判断{AI 想调用工具吗？}
    判断 --&amp;gt;|想| 执行工具[程序执行工具]
    判断 --&amp;gt;|不想| 输出答案[输出最终答案]
    执行工具 --&amp;gt; 返回结果[把结果返回给 AI]
    返回结果 --&amp;gt; 发给AI
    输出答案 --&amp;gt; 结束([结束])&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;三20-节课都在讲什么一张总图看懂&#34;&gt;三、20 节课都在讲什么？一张总图看懂&lt;/h2&gt;
&lt;p&gt;Claude Code 的学习资料里有 &lt;strong&gt;20 节课&lt;/strong&gt;，每节课加一个新能力。它们不是乱排的，而是像打游戏升级一样，一步一步变强。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph 第一阶段[&amp;#34;🌱 第一阶段：让 AI 动起来&amp;#34;]
        s01[&amp;#34;s01 循环&amp;#34;]
        s02[&amp;#34;s02 工具&amp;#34;]
        s03[&amp;#34;s03 权限&amp;#34;]
        s04[&amp;#34;s04 钩子&amp;#34;]
    end

    subgraph 第二阶段[&amp;#34;🛠️ 第二阶段：做复杂任务&amp;#34;]
        s05[&amp;#34;s05 计划&amp;#34;]
        s06[&amp;#34;s06 子代理&amp;#34;]
        s07[&amp;#34;s07 技能&amp;#34;]
        s08[&amp;#34;s08 压缩记忆&amp;#34;]
    end

    subgraph 第三阶段[&amp;#34;🧠 第三阶段：记得住、错得了&amp;#34;]
        s09[&amp;#34;s09 记忆&amp;#34;]
        s10[&amp;#34;s10 系统提示&amp;#34;]
        s11[&amp;#34;s11 错误恢复&amp;#34;]
    end

    subgraph 第四阶段[&amp;#34;⏳ 第四阶段：长时间运行&amp;#34;]
        s12[&amp;#34;s12 任务图&amp;#34;]
        s13[&amp;#34;s13 后台任务&amp;#34;]
        s14[&amp;#34;s14 定时任务&amp;#34;]
    end

    subgraph 第五阶段[&amp;#34;👥 第五阶段：团队协作&amp;#34;]
        s15[&amp;#34;s15 队友&amp;#34;]
        s16[&amp;#34;s16 团队协议&amp;#34;]
        s17[&amp;#34;s17 自治&amp;#34;]
        s18[&amp;#34;s18 目录隔离&amp;#34;]
    end

    subgraph 第六阶段[&amp;#34;🔌 第六阶段：扩展组装&amp;#34;]
        s19[&amp;#34;s19 MCP 插件&amp;#34;]
        s20[&amp;#34;s20 完整系统&amp;#34;]
    end

    第一阶段 --&amp;gt; 第二阶段 --&amp;gt; 第三阶段 --&amp;gt; 第四阶段 --&amp;gt; 第五阶段 --&amp;gt; 第六阶段&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;下面拆解核心部分。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四第一阶段让-ai-动起来&#34;&gt;四、第一阶段：让 AI 动起来&lt;/h2&gt;
&lt;h3 id=&#34;s01-agent-loop一个循环就够了&#34;&gt;s01 Agent Loop：一个循环就够了&lt;/h3&gt;
&lt;p&gt;这是所有东西的基础。就像你骑自行车，核心是“踩踏板 → 车轮转 → 车前进”这个循环。Claude Code 的核心就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI 思考 → 调用工具 → 看结果 → 再思考 → 再调用工具 → …… → 完成&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;没有循环，AI 只能说一句话。有了循环，它就能连续做很多步。&lt;/p&gt;
&lt;h3 id=&#34;s02-tool-use从一把螺丝刀到整套工具箱&#34;&gt;s02 Tool Use：从一把螺丝刀到整套工具箱&lt;/h3&gt;
&lt;p&gt;最早的 AI 只有一个工具：执行终端命令（bash）。但这样很不方便，就像你修自行车只能用一个螺丝刀。&lt;/p&gt;
&lt;p&gt;后来 Claude Code 给 AI 配了一整套工具：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;read_file&lt;/code&gt;：读文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;write_file&lt;/code&gt;：写文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;edit_file&lt;/code&gt;：改文件中的一部分&lt;/li&gt;
&lt;li&gt;&lt;code&gt;glob&lt;/code&gt;：按名字找文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grep&lt;/code&gt;：在文件里搜索文字&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些工具是“分发表”管理的。程序不用写一堆 if/else，而是查一个字典：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TOOL_HANDLERS &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;read_file&amp;#34;&lt;/span&gt;:  read_file_function,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;write_file&amp;#34;&lt;/span&gt;: write_file_function,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;edit_file&amp;#34;&lt;/span&gt;:  edit_file_function,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# AI 说想用 read_file，就找到对应的函数执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;handler &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; TOOL_HANDLERS[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;read_file&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; handler(path&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;main.py&amp;#34;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;好处&lt;/strong&gt;：加新工具就像往工具箱里多放一把扳手，不用改主流程。&lt;/p&gt;
&lt;h3 id=&#34;s03-permission先问能不能做再让它做&#34;&gt;s03 Permission：先问能不能做，再让它做&lt;/h3&gt;
&lt;p&gt;这是 Claude Code 很重要的一课：&lt;strong&gt;自由要有边界&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;AI 能力很强，但它不能想删啥就删啥、想改啥就改啥。权限系统就像家长给孩子定规矩：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;读文件可以；&lt;/li&gt;
&lt;li&gt;修改重要文件要问一下；&lt;/li&gt;
&lt;li&gt;删除整个文件夹？不行。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    AI想做事[AI 想执行命令] --&amp;gt; 查权限{权限系统检查}
    查权限 --&amp;gt;|允许| 直接执行
    查权限 --&amp;gt;|需要确认| 问用户[弹窗问用户]
    查权限 --&amp;gt;|禁止| 拒绝[拒绝执行]
    问用户 --&amp;gt;|同意| 直接执行
    问用户 --&amp;gt;|不同意| 拒绝&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;这教会我们一个工程原则：&lt;strong&gt;先设边界，再给自由。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&#34;s04-hooks在循环边上挂挂钩&#34;&gt;s04 Hooks：在循环边上挂“挂钩”&lt;/h3&gt;
&lt;p&gt;Hook 中文叫“钩子”。想象你在书包上挂很多小挂件：钥匙扣、饭卡、耳机。主书包不变，但你可以加东西。&lt;/p&gt;
&lt;p&gt;Claude Code 的 Hook 系统也是这样：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;工具执行前，可以检查一下（PreToolUse）；&lt;/li&gt;
&lt;li&gt;工具执行后，可以记录日志（PostToolUse）；&lt;/li&gt;
&lt;li&gt;会话开始/结束时，可以做初始化或清理。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    AI决定[AI 决定调用工具] --&amp;gt; 前钩子[&amp;#34;PreToolUse 钩子&amp;lt;br/&amp;gt;检查/拦截&amp;#34;]
    前钩子 --&amp;gt; 执行工具
    执行工具 --&amp;gt; 后钩子[&amp;#34;PostToolUse 钩子&amp;lt;br/&amp;gt;记录/通知&amp;#34;]
    后钩子 --&amp;gt; 返回AI&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;核心思想&lt;/strong&gt;：主循环不要改来改去，把扩展功能挂到钩子上。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五第二阶段做复杂任务&#34;&gt;五、第二阶段：做复杂任务&lt;/h2&gt;
&lt;h3 id=&#34;s05-todowrite先做计划再动手&#34;&gt;s05 TodoWrite：先做计划，再动手&lt;/h3&gt;
&lt;p&gt;如果你要写一篇大作文，你会先列提纲，对吧？Claude Code 也是这样。&lt;/p&gt;
&lt;p&gt;做复杂任务前，AI 会先写一个待办清单（Todo）：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;1. 读 README 了解项目      [待做]
2. 找到 bug 所在的文件     [进行中]
3. 修改代码                [待做]
4. 运行测试确认修好        [待做]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;每完成一步，就更新状态。如果 AI 太久没更新，系统还会“唠叨”它：“喂，你忘了更新待办清单啦！”&lt;/p&gt;
&lt;p&gt;这个机制让 AI 不容易“跑偏”。&lt;/p&gt;
&lt;h3 id=&#34;s06-subagent雇一个小助手&#34;&gt;s06 Subagent：雇一个小助手&lt;/h3&gt;
&lt;p&gt;有时候一个任务需要查很多东西。比如“这个项目的测试框架是什么？”AI 可能要读 10 个文件才能确定答案是 &lt;code&gt;pytest&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;如果让主 AI 自己读 10 个文件，它的“脑子”会塞满东西，又慢又贵。&lt;/p&gt;
&lt;p&gt;解决办法是：&lt;strong&gt;雇一个临时小助手（子代理）&lt;/strong&gt;。小助手用全新的对话去读那 10 个文件，最后只把答案“pytest”告诉主 AI。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    主AI[&amp;#34;主 AI&amp;#34;] --&amp;gt;|派任务| 子AI[&amp;#34;子 AI&amp;lt;br/&amp;gt;新开一个对话&amp;#34;]
    子AI --&amp;gt;|读10个文件| 文件[&amp;#34;项目文件&amp;#34;]
    文件 --&amp;gt;|内容| 子AI
    子AI --&amp;gt;|只返回结论：pytest| 主AI&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;主 AI 的脑子很干净，只记住了最重要的结论。&lt;/p&gt;
&lt;h3 id=&#34;s07-skill-loading需要哪本字典就翻哪本&#34;&gt;s07 Skill Loading：需要哪本字典，就翻哪本&lt;/h3&gt;
&lt;p&gt;想象你要学数学、物理、化学三科。你不会每次上课都把三本书全背上，而是上什么课带什么书。&lt;/p&gt;
&lt;p&gt;Claude Code 也是这样。它有很多“技能书”（比如 git 用法、测试规范、API 文档），但不会一次性全塞给 AI。&lt;/p&gt;
&lt;p&gt;它是两层加载：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;先给目录&lt;/strong&gt;：告诉 AI 有哪些技能书；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需要时再翻开&lt;/strong&gt;：AI 说“我要查 git 那本书”，系统才把完整内容给它。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这样就省了很多“脑容量”。&lt;/p&gt;
&lt;h3 id=&#34;s08-context-compact脑子塞不下时怎么办&#34;&gt;s08 Context Compact：脑子塞不下时怎么办？&lt;/h3&gt;
&lt;p&gt;AI 一次能看的文字是有限的，就像你的作业本只有那么多页。如果写得太多，就要翻页或者撕掉旧的。&lt;/p&gt;
&lt;p&gt;Claude Code 有三种“翻页”方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;micro_compact&lt;/strong&gt;：把很久以前的工具结果换成一句话摘要，比如“之前用过 read_file”；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;auto_compact&lt;/strong&gt;：当文字太多时，自动让 AI 写个总结，用总结替换原来的长对话；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;compact 工具&lt;/strong&gt;：AI 自己决定什么时候该“翻页”。&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    subgraph 第一层[&amp;#34;第一层：micro_compact&amp;#34;]
        旧结果[&amp;#34;旧工具结果&amp;#34;] --&amp;gt; 占位符[&amp;#34;换成占位符&amp;lt;br/&amp;gt;[之前读过 main.py]&amp;#34;]
    end

    subgraph 第二层[&amp;#34;第二层：auto_compact&amp;#34;]
        太多文字[&amp;#34;对话太长&amp;#34;] --&amp;gt; 写总结[&amp;#34;AI 写摘要&amp;#34;] --&amp;gt; 替换历史[&amp;#34;用摘要替换历史&amp;#34;]
    end

    subgraph 第三层[&amp;#34;第三层：compact 工具&amp;#34;]
        AI判断[&amp;#34;AI 觉得该压缩了&amp;#34;] --&amp;gt; 手动触发[&amp;#34;调用 compact 工具&amp;#34;]
    end

    第一层 --&amp;gt; 第二层 --&amp;gt; 第三层&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;六第三阶段记得住错得了&#34;&gt;六、第三阶段：记得住、错得了&lt;/h2&gt;
&lt;h3 id=&#34;s09-memoryai-也要记笔记&#34;&gt;s09 Memory：AI 也要记笔记&lt;/h3&gt;
&lt;p&gt;AI 没有真正的记忆。每次对话结束，它就忘了。如果想让它长期记住东西（比如你喜欢什么代码风格、项目有什么规矩），就需要一个“记忆系统”。&lt;/p&gt;
&lt;p&gt;记忆系统通常分三步：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;选择&lt;/strong&gt;：哪些东西值得记住？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提取&lt;/strong&gt;：把重要信息摘出来；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;固化&lt;/strong&gt;：存到文件或数据库里，下次对话再读出来。&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    对话[&amp;#34;一段对话&amp;#34;] --&amp;gt; 选择[&amp;#34;选择重要信息&amp;#34;]
    选择 --&amp;gt; 提取[&amp;#34;提取关键事实&amp;#34;]
    提取 --&amp;gt; 存储[&amp;#34;存到记忆文件&amp;#34;]
    存储 --&amp;gt; 下次对话[&amp;#34;下次启动时读取&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;比如 AI 记住了：“这个用户喜欢用 2 个空格缩进。”下次写代码时它就会自动用 2 个空格。&lt;/p&gt;
&lt;h3 id=&#34;s10-system-prompt提示词不是写死的&#34;&gt;s10 System Prompt：提示词不是写死的&lt;/h3&gt;
&lt;p&gt;System Prompt 就是告诉 AI“你是谁、该怎么做事”的那段话。&lt;/p&gt;
&lt;p&gt;Claude Code 的 System Prompt 不是一次性写死的，而是&lt;strong&gt;运行时拼接&lt;/strong&gt;的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基础身份部分；&lt;/li&gt;
&lt;li&gt;当前项目规则；&lt;/li&gt;
&lt;li&gt;加载的技能书；&lt;/li&gt;
&lt;li&gt;用户的偏好记忆。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;就像你写作文时，老师给的题目要求 + 你自己的提纲 + 参考资料，组合在一起。&lt;/p&gt;
&lt;h3 id=&#34;s11-error-recovery做错事能重来&#34;&gt;s11 Error Recovery：做错事能重来&lt;/h3&gt;
&lt;p&gt;AI 也会犯错。比如它调用了一个不存在的文件，或者写的代码运行报错。这时候怎么办？&lt;/p&gt;
&lt;p&gt;Claude Code 有几种“重来”策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;重试&lt;/strong&gt;：可能是网络抖动，再试一次就好了；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;换条路&lt;/strong&gt;：这个方法不行，换另一个工具试试；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;清理空间&lt;/strong&gt;：上下文太满导致看不清，先压缩一下再试；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;换个小模型/大模型&lt;/strong&gt;：简单任务用小模型省钱，复杂任务换大模型。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    出错[工具执行出错] --&amp;gt; 重试{重试有用吗？}
    重试 --&amp;gt;|有用| 再试一次
    重试 --&amp;gt;|没用| 换方法[换工具/换思路]
    换方法 --&amp;gt;|还不行| 清空间[压缩上下文]
    清空间 --&amp;gt;|再试| 再试一次&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;重要道理&lt;/strong&gt;：错误不是终点，而是调整的起点。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七第四阶段长时间运行&#34;&gt;七、第四阶段：长时间运行&lt;/h2&gt;
&lt;h3 id=&#34;s12-task-system把大目标拆成小任务&#34;&gt;s12 Task System：把大目标拆成小任务&lt;/h3&gt;
&lt;p&gt;复杂项目不能靠一个简单的 Todo 清单。任务之间有依赖关系：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A 做完了，B 才能开始；&lt;/li&gt;
&lt;li&gt;C 和 D 可以同时进行；&lt;/li&gt;
&lt;li&gt;E 要等 C 和 D 都做完。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Claude Code 用&lt;strong&gt;任务图&lt;/strong&gt;来管理。每个任务存成一个文件，记录自己的状态、依赖谁、被谁依赖。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[&amp;#34;设计登录页面&amp;#34;] --&amp;gt; B[&amp;#34;写前端代码&amp;#34;]
    A --&amp;gt; C[&amp;#34;写后端接口&amp;#34;]
    B --&amp;gt; D[&amp;#34;联调测试&amp;#34;]
    C --&amp;gt; D&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;s13-background-tasks慢活放后台&#34;&gt;s13 Background Tasks：慢活放后台&lt;/h3&gt;
&lt;p&gt;有些命令要跑很久，比如 &lt;code&gt;npm install&lt;/code&gt; 可能要几分钟。如果 AI 停下来等，就太浪费了。&lt;/p&gt;
&lt;p&gt;Claude Code 会开一个新的后台线程去跑这些慢命令，主 AI 继续思考别的事。等后台跑完了，再通知 AI。&lt;/p&gt;
&lt;h3 id=&#34;s14-cron-scheduler定时任务&#34;&gt;s14 Cron Scheduler：定时任务&lt;/h3&gt;
&lt;p&gt;Cron 就是“定时器”。比如你可以让 AI 每天早上 8 点检查一遍代码仓库，看看有没有需要更新的依赖。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“到点了就干活，不用人喊。”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    时间到[时间到了] --&amp;gt; Cron[Cron 触发器]
    Cron --&amp;gt; 任务[执行预设任务]
    任务 --&amp;gt; 结果[把结果发给 AI]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;八第五阶段团队协作&#34;&gt;八、第五阶段：团队协作&lt;/h2&gt;
&lt;h3 id=&#34;s15-agent-teams多个-ai-一起干活&#34;&gt;s15 Agent Teams：多个 AI 一起干活&lt;/h3&gt;
&lt;p&gt;一个 AI 干不完的大项目，可以叫一群 AI 一起干。每个 AI 有自己的身份和“收件箱”（mailbox）。&lt;/p&gt;
&lt;p&gt;它们通过 JSONL 文件收发消息：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;from&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;leader&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;to&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;alice&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;你去写登录页面&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;from&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;alice&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;to&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;leader&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;我做好了&amp;#34;&lt;/span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;每行一条消息，追加写入，像写日记一样简单。&lt;/p&gt;
&lt;h3 id=&#34;s16-team-protocols队友之间要讲规矩&#34;&gt;s16 Team Protocols：队友之间要讲规矩&lt;/h3&gt;
&lt;p&gt;多人协作不能乱说话。Claude Code 的团队协议规定：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个重要请求都要带一个 &lt;code&gt;request_id&lt;/code&gt;（像快递单号）；&lt;/li&gt;
&lt;li&gt;回复时要引用同一个 &lt;code&gt;request_id&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;请求状态是 pending（等待中）、approved（同意）或 rejected（拒绝）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样就不会搞混谁同意了什么。&lt;/p&gt;
&lt;h3 id=&#34;s17-autonomous-agentsai-自己会找活干&#34;&gt;s17 Autonomous Agents：AI 自己会找活干&lt;/h3&gt;
&lt;p&gt;更高级的团队里，AI 不需要等领导分配任务。它会自己去看任务板，认领还没人做的、并且前置条件满足的任务。&lt;/p&gt;
&lt;p&gt;如果 60 秒没活干，它就自动“下班关机”。&lt;/p&gt;
&lt;h3 id=&#34;s18-worktree-isolation各干各的不打架&#34;&gt;s18 Worktree Isolation：各干各的，不打架&lt;/h3&gt;
&lt;p&gt;两个 AI 同时改同一个文件，会互相覆盖。Claude Code 用 &lt;strong&gt;git worktree&lt;/strong&gt; 给每个任务一个独立目录和独立分支：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;任务 A → 目录 auth-refactor/ → 分支 wt/auth-refactor
任务 B → 目录 ui-login/     → 分支 wt/ui-login&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;大家互不干扰，最后再把代码合并。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;九第六阶段扩展组装&#34;&gt;九、第六阶段：扩展组装&lt;/h2&gt;
&lt;h3 id=&#34;s19-mcp-plugin不够用时插更多工具&#34;&gt;s19 MCP Plugin：不够用时，插更多工具&lt;/h3&gt;
&lt;p&gt;MCP 是“模型上下文协议”。你可以把它理解成“USB 接口”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Claude Code 本身带了一些工具；&lt;/li&gt;
&lt;li&gt;如果你需要连数据库、查浏览器、操作 Slack，可以通过 MCP 插进来；&lt;/li&gt;
&lt;li&gt;这些外部工具和自带工具一样，AI 都能调用。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    Claude[&amp;#34;Claude Code&amp;#34;] --&amp;gt; MCP[&amp;#34;MCP 接口&amp;#34;]
    MCP --&amp;gt; 数据库[&amp;#34;数据库工具&amp;#34;]
    MCP --&amp;gt; 浏览器[&amp;#34;浏览器工具&amp;#34;]
    MCP --&amp;gt; Slack[&amp;#34;Slack 工具&amp;#34;]
    数据库 --&amp;gt;|结果| Claude
    浏览器 --&amp;gt;|结果| Claude
    Slack --&amp;gt;|结果| Claude&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;s20-comprehensive-agent把所有东西拼起来&#34;&gt;s20 Comprehensive Agent：把所有东西拼起来&lt;/h3&gt;
&lt;p&gt;最后一节课，就是把前面 19 节课的所有机制都装进同一个循环里：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;一个循环 + 工具 + 权限 + 钩子 + 计划 + 子代理 + 技能 + 记忆 + 压缩 + 任务图 + 后台任务 + Cron + 团队 + 自治 + Worktree + MCP = 完整的 Claude Code&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;听起来很多，但你已经一个个看过了。它们都是围绕最初那个简单循环加上的“配件”。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十给新手的-5-个开发小技巧&#34;&gt;十、给新手的 5 个开发小技巧&lt;/h2&gt;
&lt;p&gt;这些技巧来自 Claude Code 的源码，平时写程序也能用到。&lt;/p&gt;
&lt;h3 id=&#34;1-用查表代替一堆-ifelse&#34;&gt;1. 用“查表”代替一堆 if/else&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 不推荐&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; name &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;read&amp;#34;&lt;/span&gt;: read_file()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;elif&lt;/span&gt; name &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;write&amp;#34;&lt;/span&gt;: write_file()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 推荐&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HANDLERS &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;read&amp;#34;&lt;/span&gt;: read_file, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;write&amp;#34;&lt;/span&gt;: write_file}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HANDLERS[name]()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;加新功能只要加一行。&lt;/p&gt;
&lt;h3 id=&#34;2-修改列表要小心&#34;&gt;2. 修改列表要小心&lt;/h3&gt;
&lt;p&gt;如果你想在一个函数里修改外面的列表，要用切片赋值：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;messages[:] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; new_list  &lt;span style=&#34;color:#75715e&#34;&gt;# 正确：改原来的列表&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# messages = new_list   # 错误：只是让局部变量指向新列表&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;3-用-kwargs-接受任意参数&#34;&gt;3. 用 &lt;code&gt;**kwargs&lt;/code&gt; 接受任意参数&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;**&lt;/span&gt;kw):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(kw[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;path&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;handler(path&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;main.py&amp;#34;&lt;/span&gt;, limit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;&lt;code&gt;(**kw)&lt;/code&gt; 表示“不管什么参数名，都装进字典 kw 里”。&lt;/p&gt;
&lt;h3 id=&#34;4-守护线程做后台任务&#34;&gt;4. 守护线程做后台任务&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; threading
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;t &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; threading&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Thread(target&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;download_file, daemon&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;t&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;start()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;主程序退出时，守护线程会自动结束，不会卡住。&lt;/p&gt;
&lt;h3 id=&#34;5-jsonl-比-json-更适合追加写入&#34;&gt;5. JSONL 比 JSON 更适合追加写入&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 写：每行一条&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt; open(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;inbox.jsonl&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    f&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;write(json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;dumps(msg) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 读：逐行解析&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; line &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; open(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;inbox.jsonl&amp;#34;&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    msg &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;loads(line)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;追加写入很安全，不会因为同时写入而损坏文件。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十一总结&#34;&gt;十一、总结&lt;/h2&gt;
&lt;p&gt;Claude Code 看起来很厉害，但它的核心其实非常朴素：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;一个 while 循环 + 一张工具表 + 一个会说话的 AI。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;真正让它变强的，是围绕这个循环一层层加上的“配件”：权限、计划、子代理、技能、记忆、压缩、任务图、后台任务、团队、自治、目录隔离、MCP……&lt;/p&gt;
&lt;p&gt;这些配件都是为了解决一个核心问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;怎么让一个只会说话的 AI，真正能在现实世界里连续、安全、高效地干活。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;理解了这个骨架之后，你再回头看 Claude Code，就不会觉得它是黑魔法了。它就是一个被精心设计的“机器人工作台”，而我们看到的聪明，来自那个会思考的大脑，加上一套会执行的 harness。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;大脑负责想，工作台负责做。把工作台造好，大脑就能发挥全部实力。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;本文是学习 &lt;a href=&#34;https://github.com/shareAI-lab/learn-claude-code&#34;&gt;shareAI-lab/learn-claude-code&lt;/a&gt; 的笔记整理。如果你想动手，可以从 &lt;code&gt;s01_agent_loop/code.py&lt;/code&gt; 开始，一课一课跟着做。&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    <item>
      <title>《AI 工程》学习笔记（下）：RAG、Agent、微调、推理优化与应用架构</title>
      <link>https://ftmao.com/blog/posts/ai-engineering-book-notes-part2/</link>
      <pubDate>Sat, 13 Dec 2025 14:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/ai-engineering-book-notes-part2/</guid>
      <description>&lt;h1 id=&#34;ai-工程学习笔记下ragagent微调推理优化与应用架构&#34;&gt;《AI 工程》学习笔记（下）：RAG、Agent、微调、推理优化与应用架构&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;这是 Chip Huyen《AI 工程》读书笔记的下篇，覆盖第 6-10 章。上篇讲了基础模型、评估和提示工程（见 &lt;a href=&#34;https://ftmao.com/blog/blog/posts/ai-engineering-book-notes-part1/&#34;&gt;《AI 工程》学习笔记（上）&lt;/a&gt;），这篇进入&amp;quot;重型&amp;quot;话题：RAG、Agent、微调、数据工程、推理优化，最后收拢到完整的应用架构。&lt;/p&gt;
&lt;p&gt;如果说上篇的主题是&amp;quot;怎么知道模型干得好不好&amp;quot;，下篇的主题就是&amp;quot;怎么让它在真实世界里又快又稳地干活&amp;quot;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一rag先检索后生成&#34;&gt;一、RAG：先检索，后生成&lt;/h2&gt;
&lt;h3 id=&#34;11-为什么-rag-是第一个要掌握的模式&#34;&gt;1.1 为什么 RAG 是第一个要掌握的模式&lt;/h3&gt;
&lt;p&gt;模型的知识有两个硬限制：&lt;strong&gt;上下文窗口装不下&lt;/strong&gt;（整个代码库、几百本书），以及&lt;strong&gt;训练截止后的事情不知道&lt;/strong&gt;。RAG（检索增强生成）用&amp;quot;开卷考试&amp;quot;的思路同时解决两个问题：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph 离线[&amp;#34;离线索引（写路径）&amp;#34;]
        DOC[文档库] --&amp;gt; CHUNK[切分 Chunking]
        CHUNK --&amp;gt; EMB[Embedding 向量化]
        EMB --&amp;gt; VDB[(向量数据库&amp;lt;br/&amp;gt;+ BM25 倒排索引)]
    end
    subgraph 在线[&amp;#34;在线查询（读路径）&amp;#34;]
        Q[用户问题] --&amp;gt; QE[查询向量化]
        QE --&amp;gt; RET[检索&amp;lt;br/&amp;gt;top-k 相关片段]
        RET --&amp;gt; RER[可选: 重排序 Rerank]
        RER --&amp;gt; GEN[&amp;#34;LLM 生成&amp;lt;br/&amp;gt;问题 + 检索片段 → 回答&amp;#34;]
    end
    VDB --&amp;gt; RET&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;作者的一个重要判断：&lt;strong&gt;RAG 系统的成败在检索器，不在生成器&lt;/strong&gt;。检索不到正确材料，生成模型只能&amp;quot;基于错误的证据一本正经地编&amp;quot;。上篇那个合同审查案例就是活例子。&lt;/p&gt;
&lt;h3 id=&#34;12-两派检索算法&#34;&gt;1.2 两派检索算法&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;词项检索（BM25/Elasticsearch）&lt;/th&gt;
					&lt;th&gt;向量检索（Embedding）&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;原理&lt;/td&gt;
					&lt;td&gt;词面匹配 + 词频统计&lt;/td&gt;
					&lt;td&gt;语义相似度&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;强项&lt;/td&gt;
					&lt;td&gt;精确词命中（型号、ID、专有名词）、轻量、可解释&lt;/td&gt;
					&lt;td&gt;同义改写、跨语言、模糊查询&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;弱项&lt;/td&gt;
					&lt;td&gt;&amp;ldquo;汽车&amp;quot;搜不到&amp;quot;轿车&amp;rdquo;&lt;/td&gt;
					&lt;td&gt;精确 ID 反而可能搜偏&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;成本&lt;/td&gt;
					&lt;td&gt;极低&lt;/td&gt;
					&lt;td&gt;索引/查询都要算 embedding&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;实战结论是混合检索（hybrid search）&lt;/strong&gt;：BM25 和向量检索各跑一遍，按 RRF（Reciprocal Rank Fusion）之类的方法融合排序。词项检索是非常强的 baseline，书里的建议是&lt;strong&gt;先用 BM25 起步，验证检索确实是瓶颈后再上向量检索，而不是反过来&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;13-踩坑记录&#34;&gt;1.3 踩坑记录&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;踩坑 1：chunk 一刀切。&lt;/strong&gt; 按固定 500 token 切分，把表格拦腰切断、把&amp;quot;问题&amp;quot;和&amp;quot;答案&amp;quot;切进不同 chunk，检索回来全是语义残缺的碎片。改法：按文档结构切（标题层级、段落边界），代码按函数/类边界切，表格整存。chunk 之间留 10%-20% 重叠（overlap），缓解边界处上下文丢失。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;踩坑 2：只评估端到端，不看召回率。&lt;/strong&gt; RAG 至少要分开盯两个指标：检索的 top-k 召回率（正确片段在不在结果里）和生成的忠实度（回答有没有超出检索内容瞎编）。前者低改检索，后者低改 prompt 或模型——混为一谈就会像无头苍蝇。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;踩坑 3：元数据过滤用晚了。&lt;/strong&gt; 知识库里混着 2020 年和 2025 年的制度文档，用户问&amp;quot;年假几天&amp;quot;，检索回来旧制度。给 chunk 打上时间、部门、文档类型等元数据，检索时先过滤再排序，比换更大的 embedding 模型有效得多。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;成功案例&lt;/strong&gt;：我们给一个内部知识库做问答，初期纯向量检索，员工搜报销系统名称&amp;quot;易快报&amp;quot;时召回很差（专有名词语义模糊）。加上 BM25 混合检索后这类 query 的召回率从 61% 提到 93%，整体满意度显著提升。&lt;strong&gt;教训：语义检索不是万能升级，词面匹配在专有名词场景不可替代。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二agent让模型当规划者&#34;&gt;二、Agent：让模型当规划者&lt;/h2&gt;
&lt;h3 id=&#34;21-从-rag-到-agent一脉相承&#34;&gt;2.1 从 RAG 到 Agent：一脉相承&lt;/h3&gt;
&lt;p&gt;书里有个很妙的视角：&lt;strong&gt;RAG 是 Agent 的特例&lt;/strong&gt;——检索器只是模型可用的一件工具。推而广之，给模型配上更多工具（搜索、计算器、数据库、代码执行、API），让它自己规划&amp;quot;先做什么、再做什么&amp;quot;，就成了 Agent。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TB
    GOAL[任务目标] --&amp;gt; PLAN[&amp;#34;规划 Planning&amp;lt;br/&amp;gt;模型分解任务、生成步骤&amp;#34;]
    PLAN --&amp;gt; ACT[&amp;#34;执行 Action&amp;lt;br/&amp;gt;调用工具&amp;#34;]
    ACT --&amp;gt; OBS[&amp;#34;观察 Observation&amp;lt;br/&amp;gt;读取工具返回&amp;#34;]
    OBS --&amp;gt; REFLECT{&amp;#34;反思 Reflection&amp;lt;br/&amp;gt;结果对吗？目标达成了吗？&amp;#34;}
    REFLECT -- 继续 --&amp;gt; PLAN
    REFLECT -- 完成 --&amp;gt; OUT[最终输出]
    subgraph MEM[&amp;#34;记忆系统 Memory&amp;#34;]
        M1[短期: 对话/执行历史]
        M2[长期: 向量库/知识库]
    end
    PLAN -.读取/写入.-&amp;gt; MEM&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;Agent 由三要素定义：&lt;strong&gt;环境&lt;/strong&gt;（它感知和操作的世界）、&lt;strong&gt;工具&lt;/strong&gt;（它能调用的动作集）、&lt;strong&gt;规划能力&lt;/strong&gt;（模型分析任务、选路径的脑力）。规划是瓶颈——复杂任务需要多步推理，模型的规划能力决定了 Agent 的上限，所以 Agent 类应用对模型能力最敏感。&lt;/p&gt;
&lt;h3 id=&#34;22-失败模式与工程约束&#34;&gt;2.2 失败模式与工程约束&lt;/h3&gt;
&lt;p&gt;书里对 Agent 的警告很直接：&lt;strong&gt;自动化程度越高，失败越灾难性&lt;/strong&gt;。典型失败模式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;规划错误：任务分解就错了，后面越努力越离谱；&lt;/li&gt;
&lt;li&gt;工具调用错误：参数编错、调错工具、幻觉出不存在的 API；&lt;/li&gt;
&lt;li&gt;循环失控：反复重试同一个失败动作，token 烧光任务没进展；&lt;/li&gt;
&lt;li&gt;复合错误：单步准确率 95% 看着不错，10 步下来整体成功率只有 0.95¹⁰ ≈ 60%。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对应的工程约束（都是血泪换来的常识）：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 1. 硬性步数上限，防止失控循环&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;MAX_STEPS &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 2. 每次循环检查预算（步数/token/钱）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; step &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(MAX_STEPS):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; budget&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;exceeded():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; fallback_answer(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;任务超出预算，转人工处理&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    action &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; plan_next(state)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; execute(action)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    state&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;update(action, result)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 3. 不可逆操作（发邮件、删数据、支付）必须人工确认&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; action&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;risk_level &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;high&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    require_human_approval(action)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;失败案例&lt;/strong&gt;：某团队的客服 Agent 有&amp;quot;查询订单&amp;quot;和&amp;quot;退款&amp;quot;两个工具。一次上游 LLM 提供商抖动了几次超时，Agent 把超时误判为&amp;quot;查询失败&amp;quot;，触发了它的兜底逻辑——居然直接走了&amp;quot;退款&amp;quot;流程安抚用户。一晚上误退几十单。教训有三：&lt;strong&gt;工具的失败语义要精确&lt;/strong&gt;（超时 ≠ 业务失败）、&lt;strong&gt;写操作必须和读操作分级管理&lt;/strong&gt;、&lt;strong&gt;Agent 的所有写操作要留可审计日志&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;感悟&lt;/strong&gt;：Agent 的工程本质是&amp;quot;给概率系统装刹车&amp;quot;。演示 Demo 里 Agent 行云流水，是因为 Demo 只跑了成功路径。生产化的工作量 80% 在失败路径上。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三微调什么时候才轮到你上场&#34;&gt;三、微调：什么时候才轮到你上场&lt;/h2&gt;
&lt;h3 id=&#34;31-微调-vs-rag决策树&#34;&gt;3.1 微调 vs RAG：决策树&lt;/h3&gt;
&lt;p&gt;这是被问得最多的问题，书里给的思路可以画成决策树：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TB
    Q1{&amp;#34;模型缺的是&amp;lt;br/&amp;gt;知识还是行为？&amp;#34;}
    Q1 -- &amp;#34;缺知识&amp;lt;br/&amp;gt;（不知道你公司的产品、最新政策）&amp;#34; --&amp;gt; RAG[&amp;#34;选 RAG&amp;lt;br/&amp;gt;知识更新快、可溯源&amp;#34;]
    Q1 -- &amp;#34;缺行为&amp;lt;br/&amp;gt;（知识够，但格式/风格/领域表达不对）&amp;#34; --&amp;gt; Q2{&amp;#34;提示工程 + few-shot&amp;lt;br/&amp;gt;能教会吗？&amp;#34;}
    Q2 -- 能 --&amp;gt; PE[&amp;#34;停在提示工程&amp;lt;br/&amp;gt;最便宜、迭代最快&amp;#34;]
    Q2 -- 不能 --&amp;gt; FT[&amp;#34;微调 Finetuning&amp;#34;]
    Q1 -- &amp;#34;都缺&amp;#34; --&amp;gt; BOTH[&amp;#34;RAG + 微调组合&amp;lt;br/&amp;gt;常见的企业方案&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;一句话记忆：&lt;strong&gt;RAG 给模型&amp;quot;资料&amp;quot;，微调教模型&amp;quot;习惯&amp;quot;&lt;/strong&gt;。需要频繁更新的知识走 RAG（改数据库就行）；稳定的领域行为（医疗报告的书写规范、固定输出格式）走微调。&lt;/p&gt;
&lt;p&gt;不微调的理由同样重要：微调需要高质量标注数据（最难的部分）、引入模型管理复杂度、基础模型升级后可能要重训、还可能损害模型的通用能力（灾难性遗忘）。&lt;/p&gt;
&lt;h3 id=&#34;32-peft-与-lora微调的平民化&#34;&gt;3.2 PEFT 与 LoRA：微调的平民化&lt;/h3&gt;
&lt;p&gt;全参数微调动辄几百 GB 显存，普通团队玩不起。于是有了一类叫 &lt;strong&gt;PEFT（Parameter-Efficient Fine-Tuning，参数高效微调）&lt;/strong&gt; 的技术：共同思路是&lt;strong&gt;冻结绝大部分原模型权重，只训练一小撮新增或挑选出来的参数&lt;/strong&gt;。家族成员包括 Adapter（在层间插小模块）、Prefix/Prompt Tuning（只学一段可训练的&amp;quot;软提示&amp;quot;向量）等，其中目前最主流、事实标准的是 &lt;strong&gt;LoRA&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;LoRA（Low-Rank Adaptation）的思路是：&lt;strong&gt;冻结原模型权重，只训练一对低秩矩阵&lt;/strong&gt;来近似权重的变化量 ΔW ≈ A·B：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    X[输入 x] --&amp;gt; W[&amp;#34;原始权重 W&amp;lt;br/&amp;gt;（冻结，不训练）&amp;#34;]
    X --&amp;gt; A[&amp;#34;低秩矩阵 A&amp;lt;br/&amp;gt;（可训练）&amp;#34;]
    A --&amp;gt; B[&amp;#34;低秩矩阵 B&amp;lt;br/&amp;gt;（可训练）&amp;#34;]
    W --&amp;gt; SUM((+))
    B --&amp;gt; SUM
    SUM --&amp;gt; Y[输出 y = Wx + BAx]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;好处实打实：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可训练参数量降到 0.1%-1%，显存需求砍掉一个数量级；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模块化&lt;/strong&gt;：一个基础模型可以挂多个 LoRA&amp;quot;插件&amp;quot;——客服一个、营销一个，推理时按需加载，不用每个场景部署一份完整模型；&lt;/li&gt;
&lt;li&gt;推理时可以把 LoRA 权重合并回主干，零额外延迟。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;踩坑 4：LoRA rank 不是越大越好。&lt;/strong&gt; 新手直觉是 rank 越大容量越大，但数据量撑不住时，大 rank 只会过拟合得更快。常见起点是 rank=8-16，配合几百到几千条高质量数据，往往比 rank=128 + 脏数据强。&lt;strong&gt;微调的效果上限在数据质量，不在参数量&lt;/strong&gt;——这直接引出了下一章。&lt;/p&gt;
&lt;h3 id=&#34;33-lora-的数学原理手算一遍就懂了&#34;&gt;3.3 LoRA 的数学原理：手算一遍就懂了&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;① 前向传播的公式。&lt;/strong&gt; 设原始权重 $W \in \mathbb{R}^{d \times d}$（冻结），LoRA 用一对小矩阵乘积来近似权重的变化量：&lt;/p&gt;
&lt;p&gt;$$
\Delta W = BA, \quad B \in \mathbb{R}^{d \times r},\ A \in \mathbb{R}^{r \times d},\ r \ll d
$$&lt;/p&gt;
&lt;p&gt;前向计算变成：&lt;/p&gt;
&lt;p&gt;$$
y = Wx + BAx = (W + BA)x
$$&lt;/p&gt;
&lt;p&gt;参数量对比一目了然：全参数微调要学 $d^2$ 个数（$d=4096$ 时约 1677 万）；LoRA 只学 $2dr$ 个（$d=4096, r=16$ 时约 13.1 万，占 0.8%）。省显存的真正大头其实不在参数本身，而在&lt;strong&gt;优化器状态&lt;/strong&gt;：冻结的 $W$ 没有梯度，Adam 也就不必为它存两份和权重一样大的动量张量——全参数微调时那才是真正吃显存的部分。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;② 为什么&amp;quot;低秩&amp;quot;够用。&lt;/strong&gt; 直觉是：预训练已经把模型放在了一个很好的解附近，微调只需要在少数几个方向上做修正，而不是对 $d^2$ 维空间做任意改动。LoRA 论文的实验支持这一点——权重增量的&lt;strong&gt;内在秩（intrinsic rank）很低&lt;/strong&gt;，rank 取 1、2 在很多任务上就能接近全参数微调的效果。$r$ 就是&amp;quot;允许修改的子空间维数&amp;quot;：$r=1$ 时 $\Delta W$ 的所有列都是 $B$ 的倍数，只能表达&amp;quot;沿一个方向拉伸&amp;quot;；$r$ 越大，能表达的修正模式越丰富。&lt;/p&gt;
&lt;p&gt;两个工程细节：&lt;strong&gt;初始化&lt;/strong&gt;时 $A$ 用随机高斯、$B$ 全零，这样训练起点 $BA=0$，模型行为和原模型完全一致；实际实现里增量还会乘缩放系数 $\alpha/r$（$\alpha$ 是超参），让换 rank 时不用重调学习率。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;③ 手算：一个 $2 \times 2$ 的完整训练步。&lt;/strong&gt; 取 $d=2, r=1$，冻结权重设为单位阵，输入 $x = [1, 2]^T$，目标输出 $y^* = [0, 0]^T$。假设 $A = [1, 1]$（$1 \times 2$）、$B = [1, 1]^T$（$2 \times 1$），都只有 2 个可训练参数：&lt;/p&gt;
&lt;p&gt;$$
W = \begin{bmatrix} 1 &amp;amp; 0 \\ 0 &amp;amp; 1 \end{bmatrix}, \quad
A = \begin{bmatrix} 1 &amp;amp; 1 \end{bmatrix}, \quad
B = \begin{bmatrix} 1 \\ 1 \end{bmatrix}
$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前向&lt;/strong&gt;：先算 $A$ 再算 $B$（注意顺序，别先乘出 $\Delta W$，那是 $d \times d$ 的大矩阵，先算 $Ax$ 只需 $O(dr)$）：&lt;/p&gt;
&lt;p&gt;$$
Ax = 1 \times 1 + 1 \times 2 = 3, \quad
BAx = B \cdot 3 = \begin{bmatrix} 3 \\ 3 \end{bmatrix}, \quad
y = Wx + BAx = \begin{bmatrix} 1 \\ 2 \end{bmatrix} + \begin{bmatrix} 3 \\ 3 \end{bmatrix} = \begin{bmatrix} 4 \\ 5 \end{bmatrix}
$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;损失&lt;/strong&gt;：$L = \frac{1}{2} |y - y^*|^2 = \frac{1}{2}(4^2 + 5^2) = 20.5$。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;反向&lt;/strong&gt;：令 $g = y - y^* = [4, 5]^T$，即 $\partial L / \partial y$。梯度沿链路只流向 $A$ 和 $B$，$W$ 不参与：&lt;/p&gt;
&lt;p&gt;$$
\frac{\partial L}{\partial A} = B^T g \cdot x^T = \big([1,1] \cdot [4,5]^T\big) \cdot [1,2] = 9 \times [1, 2] = \begin{bmatrix} 9 &amp;amp; 18 \end{bmatrix}
$$&lt;/p&gt;
&lt;p&gt;$$
\frac{\partial L}{\partial B} = g \cdot (Ax) = \begin{bmatrix} 4 \\ 5 \end{bmatrix} \times 3 = \begin{bmatrix} 12 \\ 15 \end{bmatrix}
$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;更新&lt;/strong&gt;（学习率 $\eta = 0.1$）：&lt;/p&gt;
&lt;p&gt;$$
A_{\text{new}} = \begin{bmatrix} 1 &amp;amp; 1 \end{bmatrix} - 0.1 \begin{bmatrix} 9 &amp;amp; 18 \end{bmatrix} = \begin{bmatrix} 0.1 &amp;amp; -0.8 \end{bmatrix}, \quad
B_{\text{new}} = \begin{bmatrix} 1 \\ 1 \end{bmatrix} - 0.1 \begin{bmatrix} 12 \\ 15 \end{bmatrix} = \begin{bmatrix} -0.2 \\ -0.5 \end{bmatrix}
$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;再走一遍前向验证&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;$$
A_{\text{new}}x = 0.1 \times 1 + (-0.8) \times 2 = -1.5, \quad
B_{\text{new}}A_{\text{new}}x = \begin{bmatrix} -0.2 \\ -0.5 \end{bmatrix} \times (-1.5) = \begin{bmatrix} 0.3 \\ 0.75 \end{bmatrix}, \quad
y_{\text{new}} = \begin{bmatrix} 1.3 \\ 2.75 \end{bmatrix}
$$&lt;/p&gt;
&lt;p&gt;新损失 $L_{\text{new}} = \frac{1}{2}(1.3^2 + 2.75^2) \approx 4.63$。&lt;strong&gt;一步梯度下降，损失从 20.5 降到 4.63，全程没碰过 $W$ 的一个元素&lt;/strong&gt;——这就是 LoRA 训练的全部。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;④ 推理时合并。&lt;/strong&gt; 部署时把增量并回主干：&lt;/p&gt;
&lt;p&gt;$$
\Delta W = B_{\text{new}}A_{\text{new}} = \begin{bmatrix} -0.2 \\ -0.5 \end{bmatrix} \begin{bmatrix} 0.1 &amp;amp; -0.8 \end{bmatrix} = \begin{bmatrix} -0.02 &amp;amp; 0.16 \\ -0.05 &amp;amp; 0.4 \end{bmatrix}, \quad
W_{\text{merged}} = W + \Delta W = \begin{bmatrix} 0.98 &amp;amp; 0.16 \\ -0.05 &amp;amp; 1.4 \end{bmatrix}
$$&lt;/p&gt;
&lt;p&gt;验证：$W_{\text{merged}} x = [0.98 + 0.32,\ -0.05 + 2.8]^T = [1.3,\ 2.75]^T$，和上面分开算的结果完全一致。合并后就是一个普通矩阵乘法，&lt;strong&gt;零额外推理延迟&lt;/strong&gt;就是这么来的。&lt;/p&gt;
&lt;p&gt;（这个玩具例子里 LoRA 是 4 个参数、全参数也是 4 个，省不了——节省只在 $r \ll d$ 的大矩阵上出现。）&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四数据工程质量覆盖数量&#34;&gt;四、数据工程：质量、覆盖、数量&lt;/h2&gt;
&lt;p&gt;第 8 章是全书最&amp;quot;脏活累活&amp;quot;的一章，也是我最推荐反复读的一章。数据集设计三准则：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TB
    D[数据集三准则] --&amp;gt; Q[&amp;#34;质量 Quality&amp;lt;br/&amp;gt;标注准确、格式一致、无噪声&amp;#34;]
    D --&amp;gt; C[&amp;#34;覆盖 Coverage&amp;lt;br/&amp;gt;覆盖真实场景的多样性&amp;lt;br/&amp;gt;含边界情况和失败样例&amp;#34;]
    D --&amp;gt; N[&amp;#34;数量 Quantity&amp;lt;br/&amp;gt;够用即可，边际收益递减&amp;#34;]
    Q -.-&amp;gt;|&amp;#34;少量高质量 &amp;gt; 大量噪声&amp;#34;| LESSON[&amp;#34;核心教训&amp;#34;]
    C -.-&amp;gt; LESSON
    N -.-&amp;gt; LESSON&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;几个反直觉的要点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;少量高质量数据胜过大量噪声数据&lt;/strong&gt;。LIMA 等研究表明，1000 条精心策划的指令数据可以让模型行为对齐得相当好；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;合成数据是主力补给，但必须评估&lt;/strong&gt;。用大模型生成训练数据已经是标准操作（比如用 GPT-4 造指令数据微调小模型，即蒸馏），但&amp;quot;AI 生成的数据&amp;quot;和&amp;quot;AI 生成的内容&amp;quot;一样需要评估把关。人们更倾向于使用自己能可靠评估的合成数据；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;最难的不是标注，是写标注规范&lt;/strong&gt;。&amp;ldquo;什么叫好答案&amp;quot;没想清楚的团队，标注出来的数据就是标注员个人偏好的大杂烩。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;踩坑 5：合成数据近亲繁殖。&lt;/strong&gt; 用模型 A 生成数据训练模型 B，再用 B 生成数据训练 C…… 几轮下来多样性塌陷，模型只会说&amp;quot;AI 腔&amp;rdquo;。书外研究（model collapse）也印证了这点。对策：合成数据里持续掺真实数据、定期用多样性指标（如 n-gram 去重率）体检。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;成功案例&lt;/strong&gt;：一个做 SQL 生成的朋友团队，微调数据从&amp;quot;网上爬的 5 万条 SQL 问答&amp;quot;换成&amp;quot;自己业务库表结构 + 人工审核的 3000 条&amp;quot;，效果反而大幅提升。爬虫数据里大量通用示例和他们的业务 schema 无关甚至冲突。&lt;strong&gt;覆盖你的真实分布，比堆量重要得多。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五推理优化先懂指标再谈优化&#34;&gt;五、推理优化：先懂指标，再谈优化&lt;/h2&gt;
&lt;h3 id=&#34;51-延迟的两段式结构&#34;&gt;5.1 延迟的两段式结构&lt;/h3&gt;
&lt;p&gt;自回归生成决定了延迟不是单一数字：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;sequenceDiagram
    participant U as 用户
    participant S as 推理服务
    U-&amp;gt;&amp;gt;S: 发送 prompt
    S-&amp;gt;&amp;gt;S: Prefill 预填充阶段&amp;lt;br/&amp;gt;并行处理全部输入 token
    S--&amp;gt;&amp;gt;U: 第一个 token (TTFT)
    loop Decode 解码阶段（逐 token 串行）
        S--&amp;gt;&amp;gt;U: 第 2, 3, ... N 个 token (间隔 = TPOT)
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TTFT（Time To First Token）&lt;/strong&gt;：首 token 延迟，由 prefill 阶段决定。长 prompt 的应用（塞了一大段检索内容的 RAG）TTFT 高；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TPOT（Time Per Output Token）&lt;/strong&gt;：每个输出 token 的间隔，由 decode 阶段决定。长输出的应用（写报告）对 TPOT 敏感；&lt;/li&gt;
&lt;li&gt;吞吐量和延迟存在权衡：batch 开大吞吐高、单价低，但单请求延迟上升。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;实战含义&lt;/strong&gt;：流式输出（streaming）是最便宜的&amp;quot;延迟优化&amp;quot;——总时长没变，但用户感知延迟从&amp;quot;整个生成时间&amp;quot;变成了 TTFT。聊天场景不流式输出基本不可接受。&lt;/p&gt;
&lt;h3 id=&#34;52-优化手段地图&#34;&gt;5.2 优化手段地图&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TB
    OPT[推理优化] --&amp;gt; MO[&amp;#34;模型级优化&amp;lt;br/&amp;gt;（会改变模型本身）&amp;#34;]
    OPT --&amp;gt; SO[&amp;#34;服务级优化&amp;lt;br/&amp;gt;（模型不动，改服务方式）&amp;#34;]
    MO --&amp;gt; Q[量化 Quantization&amp;lt;br/&amp;gt;FP16→INT8/INT4，省显存提速]
    MO --&amp;gt; D[蒸馏 Distillation&amp;lt;br/&amp;gt;大模型教小模型]
    MO --&amp;gt; KV[KV Cache 管理&amp;lt;br/&amp;gt;注意力机制优化]
    SO --&amp;gt; B[连续批处理&amp;lt;br/&amp;gt;Continuous Batching]
    SO --&amp;gt; PC[Prompt 缓存&amp;lt;br/&amp;gt;相同前缀不重算]
    SO --&amp;gt; P[并行策略&amp;lt;br/&amp;gt;张量并行 / 副本并行]
    SO --&amp;gt; PD[Prefill/Decode 分离部署]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;对应用开发者（主要用 API 的人）最相关的两条：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;① Prompt 缓存（prompt caching）&lt;/strong&gt;。多轮对话或固定长 system prompt 的场景，重复的前缀不用重复算，省钱省延迟。Anthropic/OpenAI 的 API 都已支持，但要注意&lt;strong&gt;缓存按前缀匹配&lt;/strong&gt;——把变化的内容（时间戳、用户问题）放在 prompt 尾部，稳定内容放头部，否则缓存命中率是零。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;踩坑 6&lt;/strong&gt;：我们就犯过这个错——system prompt 开头嵌了当前时间，每请求都变，prompt cache 从没命中过。把动态部分挪到末尾后，长 system prompt 场景的成本降了约 40%。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;② 量化是性价比之王&lt;/strong&gt;。书里总结&amp;quot;跨场景最有效的技术通常是量化&amp;quot;——INT8 几乎无损，INT4 轻微掉点但显存减半以上。自托管时先用上量化再谈别的。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六收拢完整的-ai-应用架构&#34;&gt;六、收拢：完整的 AI 应用架构&lt;/h2&gt;
&lt;p&gt;第 10 章把前面所有技术拼成一张图。一个生产级生成式 AI 应用的典型架构：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TB
    U[用户] --&amp;gt; GW[&amp;#34;模型网关 Model Gateway&amp;lt;br/&amp;gt;认证 / 限流 / 路由 / 审计&amp;#34;]
    GW --&amp;gt; GR1[&amp;#34;输入护栏&amp;lt;br/&amp;gt;注入检测 / 敏感词 / PII 脱敏&amp;#34;]
    GR1 --&amp;gt; CTX[&amp;#34;上下文增强&amp;lt;br/&amp;gt;RAG 检索 / 记忆 / 用户画像&amp;#34;]
    CTX --&amp;gt; CACHE{&amp;#34;缓存命中？&amp;#34;}
    CACHE -- 是 --&amp;gt; RESP
    CACHE -- 否 --&amp;gt; ROUTER[&amp;#34;模型路由&amp;lt;br/&amp;gt;简单问题→小模型&amp;lt;br/&amp;gt;复杂问题→大模型&amp;#34;]
    ROUTER --&amp;gt; LLM[基础模型&amp;lt;br/&amp;gt;+ LoRA 插件]
    LLM --&amp;gt; GR2[&amp;#34;输出护栏&amp;lt;br/&amp;gt;事实核查 / 格式校验 / 安全过滤&amp;#34;]
    GR2 --&amp;gt; RESP[响应]
    RESP --&amp;gt; FB[&amp;#34;用户反馈采集&amp;lt;br/&amp;gt;点赞/点踩/会话信号&amp;#34;]
    FB --&amp;gt; OBS[&amp;#34;可观测平台&amp;lt;br/&amp;gt;指标 / 告警 / 追溯&amp;#34;]
    OBS -.数据飞轮.-&amp;gt; CTX&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;这张图是按&amp;quot;增量搭建&amp;quot;的顺序理解的——作者的 step-by-step 思路非常实用：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;先增强上下文&lt;/strong&gt;（RAG/记忆），解决&amp;quot;模型不知道&amp;quot;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;加护栏&lt;/strong&gt;，解决&amp;quot;模型乱说&amp;quot;，护栏可以在输入侧、输出侧，或独立服务；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;加网关和路由&lt;/strong&gt;，解决&amp;quot;多模型管理&amp;quot;：简单 query 走便宜小模型，复杂的走大模型，省钱；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;加缓存&lt;/strong&gt;降延迟降成本；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;最后才加 Agent 模式&lt;/strong&gt;，解决&amp;quot;模型不会做&amp;quot;——这是复杂度最高的一步，放最后。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;61-可观测性与用户反馈&#34;&gt;6.1 可观测性与用户反馈&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;可观测性&lt;/strong&gt;的核心问题是&amp;quot;理解系统怎么失败的&amp;quot;。LLM 应用的新失败模式（幻觉、注入、格式漂移）要求新指标：除了传统的延迟/错误率，还要跟踪忠实度评分、护栏拦截率、judge 分数趋势、token 成本曲线。日志里要存完整的 prompt 和上下文，否则 bad case 根本无法复盘。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;用户反馈&lt;/strong&gt;是被工程师系统性低估的金矿。点赞点踩、追问、复制回答、重新生成……这些会话信号是迭代评估集和微调数据的免费来源——这就是&lt;strong&gt;数据飞轮&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    P[产品上线] --&amp;gt; U[用户使用]
    U --&amp;gt; F[反馈信号采集]
    F --&amp;gt; E[回流评估集&amp;lt;br/&amp;gt;发现 bad case]
    E --&amp;gt; I[迭代 prompt/检索/模型]
    I --&amp;gt; P&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;作者因此说&amp;quot;AI 工程比 ML 工程离产品更近&amp;quot;——反馈机制设计传统上是产品的事，但它是模型改进的数据源头，工程师必须介入。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;感悟&lt;/strong&gt;：这张图最值得记住的不是组件本身，而是&lt;strong&gt;搭建顺序&lt;/strong&gt;。见过太多项目第一天就上 Agent + 多模型路由，结果复杂度爆炸、没人知道错误来自哪一层。每加一个组件，系统能力 +1，但失败模式 +N。够用就好，是 AI 架构的第一美德。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七思考与感悟下篇&#34;&gt;七、思考与感悟（下篇）&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;检索、工具、微调，本质都是&amp;quot;上下文管理&amp;quot;。&lt;/strong&gt; RAG 是把外部知识塞进上下文，工具是把能力塞进上下文，微调是把行为烙进权重。选哪种取决于：变化的频率（天天变→RAG，稳定→微调）、成本（上下文 token 费 vs 训练费）、可靠性要求。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;复杂度是敌人，按失败模式的&amp;quot;价格&amp;quot;出牌。&lt;/strong&gt; 每章读完都有一个共同感受：作者永远在问&amp;quot;这个技术的失败模式是什么&amp;quot;。RAG 的失败在检索，Agent 的失败在规划复合错误，微调的失败在数据，judge 的失败在漂移。工程技术选型 = 选择你承受得起的那种失败。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;数据飞轮是唯一持久的护城河。&lt;/strong&gt; 模型会商品化，框架会趋同，但&amp;quot;真实用户反馈 → 评估集 → 迭代&amp;quot;这个循环积累下来的数据和评估体系，别人抄不走。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;先把指标立住，再谈优化。&lt;/strong&gt; TTFT/TPOT/召回率/忠实度这些指标的意义在于：它们把&amp;quot;感觉变慢了&amp;quot;&amp;ldquo;感觉变笨了&amp;quot;变成可以定位、可以回归的数字。没有指标体系的优化都是玄学。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;八面试高频题下篇&#34;&gt;八、面试高频题（下篇）&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Q1：RAG 和微调怎么选？&lt;/strong&gt;
看缺什么：缺知识选 RAG（更新快、可溯源、成本低）；缺行为/格式/风格选微调；都缺就组合。实践顺序：先提示工程，再 RAG，最后微调——按投入产出排序。补充：微调需要高质量标注数据，且可能损害通用能力。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q2：RAG 效果差，你的排查顺序是什么？&lt;/strong&gt;
组件级评估：① 单独测检索召回率——正确片段在不在 top-k；不在则查 chunking、混合检索、元数据过滤、查询改写；② 召回没问题再测生成忠实度——回答是否忠于检索内容；不忠实则改 prompt、加引用约束或换模型。③ 全程保留 bad case 进评估集。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q3：词项检索和向量检索各自的适用场景？&lt;/strong&gt;
词项检索（BM25）：精确匹配强（ID、型号、专有名词）、轻量可解释，但不理解语义；向量检索：同义改写、模糊查询强，但精确词可能搜偏、成本高。生产上常用混合检索 + 融合排序。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q4：Agent 的单步准确率 95%，为什么 20 步任务成功率不到 40%？怎么改进？&lt;/strong&gt;
错误复合：0.95²⁰ ≈ 36%。改进：缩短链路（任务分解更粗粒度）、加反思与自我纠错、关键步骤验证后再继续、步数/预算上限、高风险动作人工确认、提升单步可靠性（更好的工具描述与参数校验）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q5：LoRA 的原理是什么？为什么受欢迎？&lt;/strong&gt;
冻结原权重，用低秩分解 ΔW≈A·B 学习权重增量，可训练参数降到 1% 量级。优点：显存省一个数量级；数据效率高；模块化——一个基座挂多个 LoRA 插件按需加载；可合并回主干零额外推理开销。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q6：TTFT 和 TPOT 的区别？各自受什么影响？怎么优化？&lt;/strong&gt;
TTFT 由 prefill 决定，受 prompt 长度影响——优化：prompt 缓存、压缩上下文、流式输出改善感知；TPOT 由 decode 决定，逐 token 串行——优化：连续批处理、量化、投机解码、更好的硬件利用率。两者存在吞吐-延迟权衡。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q7：怎么设计一个 AI 应用的护栏体系？&lt;/strong&gt;
分层：输入护栏（注入检测、PII 脱敏、话题边界）、生成约束（结构化输出、引用检索内容）、输出护栏（事实核查、安全过滤、格式校验）、动作护栏（工具最小权限、高危操作人工确认）。护栏可放在网关、推理服务或独立组件，关键指标是拦截率和误杀率。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q8：模型网关（Model Gateway）解决什么问题？&lt;/strong&gt;
统一入口做认证、限流、审计、多模型路由（简单问题走小模型省钱）、故障转移（provider 挂了就切换）、缓存。类比微服务里的 API Gateway——当系统里有多个模型、多个 provider 时，它把横切关注点从业务代码里收走。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;全书写在最后&#34;&gt;全书写在最后&lt;/h2&gt;
&lt;p&gt;把两篇笔记浓缩成一句话：&lt;strong&gt;AI 工程 = 用评估驾驭概率，用上下文注入知识，用架构吸收失败&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这本书值得放在手边反复翻。技术细节会过时（明年 Agent 框架肯定又换了一轮），但书里那些思维框架——组件级评估、失败模式分析、先简单后复杂的搭建顺序、数据飞轮——是长期有效的工程直觉。&lt;/p&gt;
</description>
    </item>
    <item>
      <title>LangChain 入门笔记：AI 视频生成实战</title>
      <link>https://ftmao.com/blog/posts/langchain-intro-notes/</link>
      <pubDate>Fri, 28 Nov 2025 11:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/langchain-intro-notes/</guid>
      <description>&lt;h1 id=&#34;langchain-入门笔记ai-视频生成实战&#34;&gt;LangChain 入门笔记：AI 视频生成实战&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;最近重新刷了吴恩达和 Harrison Chase 主讲的《LangChain for LLM Application Development》。这门课不长，但把 LangChain 的&amp;quot;为什么存在&amp;quot;讲得很透：它不是让你写更多胶水代码，而是把 LLM 调用、提示工程、上下文管理、工具调用这些重复模式抽象成可组合的组件。这篇文章整理课程里的核心原理，并落到我们最熟悉的 AI 视频生成场景，给出可直接跑的 Demo。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一langchain-解决什么问题&#34;&gt;一、LangChain 解决什么问题？&lt;/h2&gt;
&lt;p&gt;在直接调用 OpenAI / Claude / 国产大模型 API 时，我们通常会写出这样的代码：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; openai
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;messages &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;system&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;你是一位短视频脚本专家。&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;主题是&amp;#39;如何用 LangChain 生成视频脚本&amp;#39;，风格轻松，30 秒左右。&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;resp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; openai&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;chat&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;completions&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;create(model&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gpt-4o&amp;#34;&lt;/span&gt;, messages&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;messages)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;script &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; resp&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;choices[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;message&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;content&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;这段代码能跑，但问题很明显：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提示词散落在各处，难以复用和版本管理；&lt;/li&gt;
&lt;li&gt;输出是字符串，需要手写解析逻辑；&lt;/li&gt;
&lt;li&gt;多轮对话、上下文记忆要自己拼 messages；&lt;/li&gt;
&lt;li&gt;一旦涉及&amp;quot;检索素材 → 生成脚本 → 检查合规 → 输出结构化数据&amp;quot;，代码就会迅速膨胀成面条。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;LangChain 的核心思想&lt;/strong&gt;：把 LLM 应用里的常见模式抽象成标准组件，让你像搭积木一样拼装工作流。&lt;/p&gt;
&lt;p&gt;可以把它理解成：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;LangChain = 模型接口统一层 + 提示模板 + 输出解析 + 记忆 + 链式调用 + 工具/Agent 编排&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;二课程核心内容回顾&#34;&gt;二、课程核心内容回顾&lt;/h2&gt;
&lt;p&gt;吴恩达这门课围绕 6 个模块展开，也是 LangChain 最基础的 6 个能力：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;模块&lt;/th&gt;
					&lt;th&gt;作用&lt;/th&gt;
					&lt;th&gt;视频生成场景映射&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Models&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;统一不同 LLM 的调用接口&lt;/td&gt;
					&lt;td&gt;切换 GPT-4o / Claude / 国产模型时无需改业务代码&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Prompts&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;模板化管理提示词&lt;/td&gt;
					&lt;td&gt;脚本生成、分镜描述、标题优化的模板复用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Output Parsers&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;把自然语言输出转成结构化数据&lt;/td&gt;
					&lt;td&gt;解析 JSON 分镜、时间轴、素材清单&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Memory&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;维护多轮对话状态&lt;/td&gt;
					&lt;td&gt;用户反复修改脚本时保留上下文&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Chains&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;把多个 LLM/工具步骤串成链&lt;/td&gt;
					&lt;td&gt;&amp;ldquo;主题 → 大纲 → 脚本 → 分镜 → 渲染参数&amp;quot;流水线&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Agents&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;让 LLM 决定调用哪些工具&lt;/td&gt;
					&lt;td&gt;Agent 自主判断需要检索素材还是生成画面描述&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;下面逐一看原理和代码。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三核心组件原理与示例&#34;&gt;三、核心组件原理与示例&lt;/h2&gt;
&lt;h3 id=&#34;31-models--prompts统一接口与模板复用&#34;&gt;3.1 Models &amp;amp; Prompts：统一接口与模板复用&lt;/h3&gt;
&lt;p&gt;LangChain 用 &lt;code&gt;ChatOpenAI&lt;/code&gt;、&lt;code&gt;ChatAnthropic&lt;/code&gt; 等类封装模型，并用 &lt;code&gt;ChatPromptTemplate&lt;/code&gt; 管理提示词模板。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain_openai &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; ChatOpenAI
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain_core.prompts &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; ChatPromptTemplate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;llm &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ChatOpenAI(model&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gpt-4o&amp;#34;&lt;/span&gt;, temperature&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0.7&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prompt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ChatPromptTemplate&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;from_messages([
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;system&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;你是一位短视频脚本专家，擅长把技术概念写成&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{style}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;风格的口播脚本。&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;human&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;主题是：&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{topic}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;，时长控制在&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{duration}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;秒，需要&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{scene_count}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;个分镜。&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;messages &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; prompt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;invoke({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;style&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;轻松幽默&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topic&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;LangChain 如何自动生成视频脚本&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;duration&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;scene_count&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;response &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; llm&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;invoke(messages)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(response&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;content)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;好处&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提示词与业务数据解耦，模板可复用、可版本化；&lt;/li&gt;
&lt;li&gt;切换模型只需改一行 &lt;code&gt;ChatOpenAI&lt;/code&gt; → &lt;code&gt;ChatAnthropic&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;支持批量 &lt;code&gt;batch&lt;/code&gt;、流式 &lt;code&gt;stream&lt;/code&gt;、异步 &lt;code&gt;ainvoke&lt;/code&gt; 等高级调用方式。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&#34;32-output-parsers从文本到结构化数据&#34;&gt;3.2 Output Parsers：从文本到结构化数据&lt;/h3&gt;
&lt;p&gt;视频生成流程需要结构化输出，例如：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;scenes&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0-10s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;narration&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;visual&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;bgm&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;tags&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;LangChain 提供 &lt;code&gt;PydanticOutputParser&lt;/code&gt;，让模型按指定 Schema 输出。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; pydantic &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; BaseModel, Field
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain_core.output_parsers &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; PydanticOutputParser
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain_core.prompts &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; PromptTemplate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Scene&lt;/span&gt;(BaseModel):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    time_range: str &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Field(description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;时间区间，如 0-10s&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    narration: str &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Field(description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;口播文案&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    visual: str &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Field(description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;画面描述，用于后续生成图片/视频&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bgm_mood: str &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Field(description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;背景音乐情绪&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;VideoScript&lt;/span&gt;(BaseModel):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    title: str
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    scenes: list[Scene]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    tags: list[str]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;parser &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; PydanticOutputParser(pydantic_object&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;VideoScript)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prompt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; PromptTemplate(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    template&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;根据主题生成短视频脚本。&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{format_instructions}&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;主题：&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{topic}&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;时长：&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{duration}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;秒&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    input_variables&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topic&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;duration&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    partial_variables&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;format_instructions&amp;#34;&lt;/span&gt;: parser&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_format_instructions()},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chain &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; prompt &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; llm &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; parser
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; chain&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;invoke({&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topic&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;LangChain 自动生成短视频&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;duration&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(result&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;model_dump_json(indent&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：LLM 不一定 100% 返回合法 JSON，生产环境建议加 &lt;code&gt;RetryOutputParser&lt;/code&gt; 或兜底解析。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;33-memory多轮修改不再失忆&#34;&gt;3.3 Memory：多轮修改不再&amp;quot;失忆&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;做视频脚本时，用户常会说：&amp;ldquo;前面不错，但把第二段改得更口语化一点&amp;rdquo;。没有记忆，LLM 会从头生成，丢失已确认的片段。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain.memory &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; ConversationBufferMemory
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain.chains &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; ConversationChain
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;memory &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ConversationBufferMemory()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;conversation &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ConversationChain(llm&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;llm, memory&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;memory)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;conversation&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;predict(input&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;帮我写一个 30 秒的 LangChain 短视频脚本&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;conversation&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;predict(input&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;第二段太正式了，改成口语化一些&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(memory&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;load_memory_variables({}))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;LangChain 还提供 &lt;code&gt;ConversationBufferWindowMemory&lt;/code&gt;（只保留最近 N 轮）、&lt;code&gt;ConversationSummaryMemory&lt;/code&gt;（摘要历史）等，适用于长会话场景。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;34-chains把多个步骤串成流水线&#34;&gt;3.4 Chains：把多个步骤串成流水线&lt;/h3&gt;
&lt;p&gt;视频生成的一个典型链：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;主题 → 生成标题 → 生成脚本 → 生成分镜 → 输出结构化渲染参数&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;用 LCEL（LangChain Expression Language）可以非常直观地表达：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain_core.runnables &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; RunnablePassthrough
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain_core.output_parsers &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; StrOutputParser
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 子链 1：生成标题&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;title_prompt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ChatPromptTemplate&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;from_template(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;为&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{topic}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;写一个 20 字以内的爆款标题&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;title_chain &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; title_prompt &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; llm &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; StrOutputParser()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 子链 2：根据标题和主题生成脚本&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;script_prompt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ChatPromptTemplate&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;from_template(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;标题：&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{title}&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;主题：&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{topic}&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;时长：&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{duration}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;秒&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;请生成 3 个分镜的脚本。&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;script_chain &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; script_prompt &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; llm &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; StrOutputParser()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 组合&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;full_chain &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topic&amp;#34;&lt;/span&gt;: RunnablePassthrough(), &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;duration&amp;#34;&lt;/span&gt;: RunnablePassthrough()}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; RunnablePassthrough&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;assign(title&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;title_chain)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; RunnablePassthrough&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;assign(script&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;script_chain)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; full_chain&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;invoke({&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topic&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;LangChain 视频生成&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;duration&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(result)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;LCEL 的 &lt;code&gt;|&lt;/code&gt; 运算符让数据流像 Unix 管道一样清晰，这也是 LangChain 从 0.1 到 0.2/0.3 版本最重要的设计演进。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;35-rag用本地素材库增强脚本生成&#34;&gt;3.5 RAG：用本地素材库增强脚本生成&lt;/h3&gt;
&lt;p&gt;做批量短视频时，通常有沉淀的素材库（文案库、分镜库、音乐库）。LangChain 的 RAG 组件可以让模型先检索再生成：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain_community.vectorstores &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; FAISS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain_openai &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; OpenAIEmbeddings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain_core.prompts &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; ChatPromptTemplate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain.chains.combine_documents &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; create_stuff_documents_chain
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 1. 构建向量库&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;embeddings &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; OpenAIEmbeddings()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vectorstore &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; FAISS&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;from_texts(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;分镜案例 1：开头用悬念钩子...&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;爆款标题公式：数字+痛点+解决方案...&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    embedding&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;embeddings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;retriever &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; vectorstore&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;as_retriever(search_kwargs&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;k&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 2. 构建 RAG Chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prompt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ChatPromptTemplate&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;from_messages([
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;system&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;参考以下素材生成脚本：&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{context}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;human&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;主题：&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{topic}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;，时长：&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{duration}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;秒&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rag_chain &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; create_stuff_documents_chain(llm, prompt) &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topic&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;lambda&lt;/span&gt; x: x[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topic&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;context&amp;#34;&lt;/span&gt;: retriever
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 实际调用时先检索文档，再塞入 prompt&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;在方糖猫 AI 短视频平台的工程实现中，我们会把 RAG 检索结果和 LangGraph 状态机结合，实现&amp;quot;检索 → 生成 → 人工审核 → 渲染&amp;quot;的完整闭环。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;36-agents让-llm-自己决定下一步&#34;&gt;3.6 Agents：让 LLM 自己决定下一步&lt;/h3&gt;
&lt;p&gt;当流程不是固定流水线，而是需要动态决策时，Agent 更有优势。例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;判断用户输入是否需要检索素材库；&lt;/li&gt;
&lt;li&gt;根据脚本内容决定调用文生图还是文生视频工具；&lt;/li&gt;
&lt;li&gt;调用外部 API 查询热点话题。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain.agents &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; AgentExecutor, create_openai_tools_agent
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain_core.tools &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; tool
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;generate_image&lt;/span&gt;(description: str) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; str:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;根据画面描述生成一张图片，返回图片 URL。&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 实际接入 DALL·E / Midjourney / Stable Diffusion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://fake-img.example.com?prompt=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;description&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;generate_video_clip&lt;/span&gt;(description: str, duration: int) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; str:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;根据画面描述生成一段视频片段，返回视频 URL。&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://fake-video.example.com?prompt=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;description&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;amp;duration=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;duration&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tools &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [generate_image, generate_video_clip]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;agent_prompt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ChatPromptTemplate&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;from_messages([
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;system&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;你是一位 AI 视频导演，能调用工具生成图片或视频。&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;human&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{input}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;placeholder&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{agent_scratchpad}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;agent &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; create_openai_tools_agent(llm, tools, agent_prompt)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;agent_executor &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; AgentExecutor(agent&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;agent, tools&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;tools, verbose&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;agent_executor&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;invoke({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;input&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;我要一个 30 秒关于 LangChain 的短视频，先出 3 张分镜图，再合成视频。&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;四demo一个可扩展的ai-视频脚本生成器&#34;&gt;四、Demo：一个可扩展的&amp;quot;AI 视频脚本生成器&amp;quot;&lt;/h2&gt;
&lt;p&gt;下面把上面所有组件串起来，做一个最小的可运行 Demo。它的输出是一份结构化脚本，后续可以无缝接到 Remotion、FFmpeg 或视频生成 API。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; os
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain_openai &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; ChatOpenAI
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain_core.prompts &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; ChatPromptTemplate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain_core.output_parsers &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; PydanticOutputParser
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langchain_core.runnables &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; RunnablePassthrough
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; pydantic &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; BaseModel, Field
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;os&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;environ[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;OPENAI_API_KEY&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;your-api-key&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;llm &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ChatOpenAI(model&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gpt-4o-mini&amp;#34;&lt;/span&gt;, temperature&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0.7&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Scene&lt;/span&gt;(BaseModel):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    time_range: str
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    narration: str
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    visual: str
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    tool: str &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Field(description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;生成该分镜所需工具：image 或 video&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;VideoProject&lt;/span&gt;(BaseModel):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    title: str
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    target_platform: str
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    scenes: list[Scene]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;parser &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; PydanticOutputParser(pydantic_object&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;VideoProject)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;title_chain &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ChatPromptTemplate&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;from_template(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;为&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{topic}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;写一个适合&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{platform}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;的爆款标题&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; llm
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; StrOutputParser()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;script_prompt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ChatPromptTemplate&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;from_template(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;为平台&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{target_platform}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;生成短视频脚本。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{format_instructions}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;标题：&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{title}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;主题：&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{topic}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;时长：&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{duration}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;秒
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;要求：每个分镜标注用 image（图片）还是 video（视频片段）生成。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;script_chain &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    RunnablePassthrough&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;assign(title&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;title_chain)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; script_prompt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;partial(format_instructions&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;parser&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_format_instructions())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; llm
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; parser
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;project &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; script_chain&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;invoke({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topic&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;LangChain 如何帮助 AI 视频创作&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;platform&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;抖音&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;target_platform&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;抖音&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;duration&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(project&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;model_dump_json(indent&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, ensure_ascii&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;False&lt;/span&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;下一步可以扩展的方向&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;把 &lt;code&gt;Scene.visual&lt;/code&gt; 传给 DALL·E / Stable Diffusion / 可灵 / Pika 生成画面；&lt;/li&gt;
&lt;li&gt;用 &lt;code&gt;pydub&lt;/code&gt; + &lt;code&gt;gTTS&lt;/code&gt; 合成配音，或用 CosyVoice 克隆音色；&lt;/li&gt;
&lt;li&gt;用 Remotion 或 MoviePy 把图片、视频、字幕、BGM 合成为成片；&lt;/li&gt;
&lt;li&gt;接入 LangGraph 做状态持久化和人工审核节点（参考我之前写的 &lt;a href=&#34;https://ftmao.com/blog/blog/posts/langgraph-agent-guide/&#34;&gt;LangGraph 入门笔记&lt;/a&gt;）。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五分布式场景下的运行方案&#34;&gt;五、分布式场景下的运行方案&lt;/h2&gt;
&lt;p&gt;当 LangChain 应用从本地脚本走向生产环境，单进程运行肯定不够。AI 视频生成是典型的长链路任务：脚本生成、素材检索、文生图、文生视频、配音、渲染，每一步都可能耗时数秒到数分钟。分布式架构的关键是：&lt;strong&gt;让 LangChain 推理层保持无状态，把状态交给任务队列和持久化存储。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&#34;推荐架构&#34;&gt;推荐架构&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[&amp;#34;用户请求&amp;#34;] --&amp;gt; B[&amp;#34;FastAPI 网关&amp;#34;]
    B --&amp;gt; C[&amp;#34;Redis/RocketMQ&amp;lt;br/&amp;gt;（任务队列）&amp;#34;]
    C --&amp;gt; D[&amp;#34;Worker 集群（LangChain 链/Agent 执行）&amp;lt;br/&amp;gt;- Python&amp;lt;br/&amp;gt;- LangChain&amp;lt;br/&amp;gt;- GPU 节点&amp;#34;]
    D --&amp;gt; E[&amp;#34;结果存储&amp;lt;br/&amp;gt;（MySQL/PostgreSQL + OSS/S3）&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;关键设计点&#34;&gt;关键设计点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;LangChain 服务无状态化&lt;/strong&gt;
不保存用户会话到本地内存，所有上下文通过 &lt;code&gt;state&lt;/code&gt; 参数或 Redis 传入。这样任意 Worker 都可以处理任意任务，方便水平扩展。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;任务队列解耦&lt;/strong&gt;
用 Celery、RQ 或自研 Worker 消费 RocketMQ/Redis Stream。一个任务对应一次视频生成链路，失败可以重试，不会阻塞 API 网关。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;持久化中间状态&lt;/strong&gt;
把每个阶段的结果（脚本 JSON、分镜图 URL、视频片段 URL）写入数据库。如果 Worker 崩溃，可以从上一个阶段恢复，而不是从头执行。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;LangGraph 的分布式友好性&lt;/strong&gt;
LangGraph 的 &lt;code&gt;State&lt;/code&gt; 天然适合持久化。可以配置 &lt;code&gt;checkpointer&lt;/code&gt; 把状态快照到 Redis/Postgres，实现断点续跑：&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langgraph.checkpoint.memory &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; MemorySaver
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langgraph.graph &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; StateGraph
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builder &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; StateGraph(VideoGenState)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ... 添加节点和边 ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;graph &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; builder&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;compile(checkpointer&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;MemorySaver())&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;生产环境建议把 &lt;code&gt;MemorySaver&lt;/code&gt; 替换为 &lt;code&gt;PostgresSaver&lt;/code&gt; 或 &lt;code&gt;RedisSaver&lt;/code&gt;，让不同 Worker 共享状态。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六服务器异常恢复方案&#34;&gt;六、服务器异常恢复方案&lt;/h2&gt;
&lt;p&gt;AI 视频生成链路长、依赖多（LLM API、素材库、视频生成服务、对象存储），任何一环抖动都会导致失败。异常恢复不是简单 try/except，而是要从架构层面保证&lt;strong&gt;可观测、可重试、可续跑&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;1-分级重试策略&#34;&gt;1. 分级重试策略&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;异常类型&lt;/th&gt;
					&lt;th&gt;处理方式&lt;/th&gt;
					&lt;th&gt;示例&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;LLM API 限流 / 超时&lt;/td&gt;
					&lt;td&gt;指数退避重试 3 次&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;tenacity&lt;/code&gt; 或 LangChain 内置 &lt;code&gt;max_retries&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;第三方服务不可用&lt;/td&gt;
					&lt;td&gt;降级或转人工审核&lt;/td&gt;
					&lt;td&gt;视频生成失败时返回占位图 + 提示&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Worker 进程崩溃&lt;/td&gt;
					&lt;td&gt;队列自动重发，幂等消费&lt;/td&gt;
					&lt;td&gt;Celery &lt;code&gt;acks_late=True&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;数据格式错误&lt;/td&gt;
					&lt;td&gt;进入死信队列，人工处理&lt;/td&gt;
					&lt;td&gt;JSON 解析失败&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;LangChain 调用模型时建议统一封装：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; tenacity &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; retry, stop_after_attempt, wait_exponential
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@retry&lt;/span&gt;(stop&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;stop_after_attempt(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;), wait&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;wait_exponential(multiplier&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, min&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, max&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;invoke_with_retry&lt;/span&gt;(chain, inputs):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; chain&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;invoke(inputs)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;2-幂等性设计&#34;&gt;2. 幂等性设计&lt;/h3&gt;
&lt;p&gt;同一个视频生成任务可能因为网络超时被重复投递。给每个任务分配唯一 &lt;code&gt;task_id&lt;/code&gt;，在数据库里记录 &lt;code&gt;PENDING → PROCESSING → SUCCESS/FAILURE&lt;/code&gt; 状态。Worker 消费前先看状态，避免重复执行。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;process_video_task&lt;/span&gt;(task_id: str, inputs: dict):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; db&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_status(task_id) &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SUCCESS&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PROCESSING&amp;#34;&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; db&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_result(task_id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    db&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;set_status(task_id, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PROCESSING&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; video_chain&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;invoke(inputs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        db&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;set_status(task_id, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SUCCESS&amp;#34;&lt;/span&gt;, result&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;result)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; result
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;except&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Exception&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; e:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        db&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;set_status(task_id, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;FAILURE&amp;#34;&lt;/span&gt;, error&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;str(e))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;raise&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;3-死信队列dlq&#34;&gt;3. 死信队列（DLQ）&lt;/h3&gt;
&lt;p&gt;重试仍然失败的任务进入死信队列，由告警系统通知运维或产品人员处理。DLQ 里的任务可以手动重跑、补数据或退款。&lt;/p&gt;
&lt;h3 id=&#34;4-状态快照与断点续跑&#34;&gt;4. 状态快照与断点续跑&lt;/h3&gt;
&lt;p&gt;结合 LangGraph 的 &lt;code&gt;checkpointer&lt;/code&gt;，每个节点执行完后自动保存状态。Worker 重启后，可以根据 &lt;code&gt;thread_id&lt;/code&gt; 恢复到最近的 checkpoint：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;config &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;configurable&amp;#34;&lt;/span&gt;: {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;thread_id&amp;#34;&lt;/span&gt;: task_id}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 首次执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;graph&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;invoke(initial_state, config&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;config)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Worker 重启后继续执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;state &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; graph&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_state(config)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;graph&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;invoke(&lt;span style=&#34;color:#66d9ef&#34;&gt;None&lt;/span&gt;, config&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;config)  &lt;span style=&#34;color:#75715e&#34;&gt;# 从 checkpoint 继续&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;七如何实现高并发&#34;&gt;七、如何实现高并发&lt;/h2&gt;
&lt;p&gt;AI 视频生成场景的高并发，核心矛盾是：&lt;strong&gt;LLM API 调用有速率限制，但用户请求可能突增&lt;/strong&gt;。不能简单堆机器，需要把 IO 等待和计算分离。&lt;/p&gt;
&lt;h3 id=&#34;1-异步调用释放线程&#34;&gt;1. 异步调用释放线程&lt;/h3&gt;
&lt;p&gt;LangChain 支持 &lt;code&gt;ainvoke&lt;/code&gt;、&lt;code&gt;abatch&lt;/code&gt;、&lt;code&gt;astream&lt;/code&gt;，配合 &lt;code&gt;asyncio&lt;/code&gt; 可以大幅提升吞吐：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; asyncio
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;batch_generate&lt;/span&gt;(tasks):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    results &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;await&lt;/span&gt; script_chain&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;abatch(tasks)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; results
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 并发处理 20 个脚本生成请求&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tasks &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topic&amp;#34;&lt;/span&gt;: t, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;duration&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; t &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; topic_list]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;results &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; asyncio&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;run(batch_generate(tasks))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;注意：底层 HTTP 客户端（如 &lt;code&gt;httpx&lt;/code&gt;）需要配置连接池，避免每次请求新建连接。&lt;/p&gt;
&lt;h3 id=&#34;2-流式响应降低首字节延迟&#34;&gt;2. 流式响应降低首字节延迟&lt;/h3&gt;
&lt;p&gt;对于长文本生成，使用 &lt;code&gt;astream&lt;/code&gt; 把结果逐步返回给用户，避免长时间阻塞：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; chunk &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; chain&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;astream({&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topic&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;LangChain 高并发&amp;#34;&lt;/span&gt;}):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(chunk, end&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, flush&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;3-限流与背压&#34;&gt;3. 限流与背压&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;模型侧限流&lt;/strong&gt;：根据 OpenAI/Claude 的 RPM/TPM 限制，用令牌桶算法控制请求速率。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;队列侧背压&lt;/strong&gt;：当队列堆积超过阈值时，API 网关返回 &lt;code&gt;429 Too Many Requests&lt;/code&gt;，保护下游 Worker。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; asyncio
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; asyncio &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; Semaphore
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sem &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Semaphore(&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;)  &lt;span style=&#34;color:#75715e&#34;&gt;# 同时最多 10 个 LLM 调用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;limited_invoke&lt;/span&gt;(inputs):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt; sem:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;await&lt;/span&gt; chain&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ainvoke(inputs)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;4-缓存常用结果&#34;&gt;4. 缓存常用结果&lt;/h3&gt;
&lt;p&gt;很多提示词是重复的（比如热门模板、常见分镜描述）。可以用 Redis 缓存 &lt;code&gt;prompt_hash → result&lt;/code&gt;，命中时直接返回，不走 LLM：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; hashlib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;get_cache_key&lt;/span&gt;(inputs: dict) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; str:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; hashlib&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;sha256(json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;dumps(inputs, sort_keys&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;encode())&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;hexdigest()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;key &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; get_cache_key(inputs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; cached &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; redis&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(key):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;loads(cached)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; chain&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;invoke(inputs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;redis&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;setex(key, &lt;span style=&#34;color:#ae81ff&#34;&gt;3600&lt;/span&gt;, json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;dumps(result))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;5-水平扩展与资源隔离&#34;&gt;5. 水平扩展与资源隔离&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CPU 密集型步骤&lt;/strong&gt;（如 FFmpeg 渲染、图片后处理）放到独立 Worker 池，避免阻塞 LLM 推理线程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPU 密集型步骤&lt;/strong&gt;（如文生视频）单独部署 GPU 节点，通过队列按需调度。&lt;/li&gt;
&lt;li&gt;API 网关层用 Nginx/Envoy 做负载均衡，无状态 LangChain 服务可以快速扩容。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;八学完这门课的几点体会&#34;&gt;八、学完这门课的几点体会&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;不要神化 LangChain&lt;/strong&gt;：它本质是高阶胶水，帮你少写重复代码，但不会让模型变得更聪明。复杂的业务逻辑仍然需要自己设计。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优先用 LCEL&lt;/strong&gt;：新项目中尽量用 &lt;code&gt;Runnable&lt;/code&gt; + &lt;code&gt;|&lt;/code&gt; 组合链，比旧的 &lt;code&gt;LLMChain&lt;/code&gt;、&lt;code&gt;SequentialChain&lt;/code&gt; 更灵活、更易调试。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结构化输出是工程关键&lt;/strong&gt;：视频、电商、客服等场景都需要把 LLM 输出转成 JSON，PydanticOutputParser 是必备技能。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent 不是银弹&lt;/strong&gt;：固定流程用 Chain，动态决策才用 Agent。Agent 调试成本高，要配合观察日志和工具描述优化。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;九参考资源&#34;&gt;九、参考资源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;吴恩达 &amp;amp; Harrison Chase 官方课程：&lt;a href=&#34;https://learn.deeplearning.ai/langchain&#34;&gt;LangChain for LLM Application Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;中文笔记与代码：&lt;a href=&#34;https://github.com/MING-ZCH/awesome-LangChain-for-LLM-Application-Development&#34;&gt;awesome-LangChain-for-LLM-Application-Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;我之前的相关笔记：&lt;a href=&#34;https://ftmao.com/blog/blog/posts/langgraph-agent-guide/&#34;&gt;LangGraph 入门：给传统工程师的 Agent 状态与编排指南&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;这篇文章把吴恩达课程的核心内容和我自己在 AI 视频生成项目里的经验做了结合。如果你也在用 LangChain 做视频、口播剪辑或 Agent 工作流，欢迎留言交流。&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    <item>
      <title>生成式AI原理与实战（Part 2）学习笔记：提示工程、Agent 与 RAG 的通俗理解</title>
      <link>https://ftmao.com/blog/posts/llm-interview-notes-part2/</link>
      <pubDate>Sat, 08 Nov 2025 15:24:25 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/llm-interview-notes-part2/</guid>
      <description>&lt;h1 id=&#34;生成式ai原理与实战part-2学习笔记提示工程agent-与-rag-的通俗理解&#34;&gt;生成式AI原理与实战（Part 2）学习笔记：提示工程、Agent 与 RAG 的通俗理解&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;这是《生成式AI原理与实战》学习笔记的第二篇。Part 1 聊了 Transformer、Token、Embedding、Attention、KV Cache 这些“底层零件”；Part 2 则进入“怎么用”的层面：怎么写提示词、怎么让模型完成复杂任务、怎么给模型外挂知识库。目标读者仍然是&lt;strong&gt;刚接触 AI 的初中级开发者&lt;/strong&gt;——读完之后，你不需要会训模型，但应该能清楚地说出提示工程、Agent、RAG 这几个热门词到底在解决什么问题。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;写在前面从调用-api到搭一个系统&#34;&gt;写在前面：从“调用 API”到“搭一个系统”&lt;/h2&gt;
&lt;p&gt;如果你只调过 ChatGPT API，可能会觉得大模型就是一个“输入问题、返回答案”的黑盒。但实际做项目时，很快会遇到这些问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同样的 prompt，为什么每次回答不一样？&lt;/li&gt;
&lt;li&gt;模型怎么老是“一本正经地胡说八道”？&lt;/li&gt;
&lt;li&gt;想让模型输出 JSON，它却总带多余解释。&lt;/li&gt;
&lt;li&gt;对话轮数多了，模型就忘了用户是谁。&lt;/li&gt;
&lt;li&gt;公司私有文档模型不知道，怎么办？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Part 2 的内容，本质上就是回答这些问题。我会把它们分成三块：&lt;strong&gt;提示工程&lt;/strong&gt;（怎么写好 prompt）、&lt;strong&gt;Agent&lt;/strong&gt;（怎么让模型动起来）、&lt;strong&gt;RAG&lt;/strong&gt;（怎么给模型外挂知识）。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一提示工程不是写文案而是设计接口&#34;&gt;一、提示工程：不是写文案，而是设计接口&lt;/h2&gt;
&lt;p&gt;很多人把提示工程当成“怎么哄 AI 开心”。其实对开发者来说，prompt 更像一个&lt;strong&gt;函数签名&lt;/strong&gt;：输入清楚、输出可控、边界明确。&lt;/p&gt;
&lt;h3 id=&#34;11-两个旋钮temperature-与-top_p&#34;&gt;1.1 两个旋钮：temperature 与 top_p&lt;/h3&gt;
&lt;p&gt;大模型生成下一个词时，不是“选择概率最高的词”就完事了。它有两个常用的“随机性旋钮”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;temperature&lt;/strong&gt;：控制采样的“大胆程度”。值越低越保守，接近“只选概率最高的词”；值越高越有创意，容易跳出常规。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;top_p（nucleus sampling）&lt;/strong&gt;：只从累计概率达到一定比例的候选词里挑。比如 top_p=0.9，就只在概率最高的那一小撮词里采样。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[模型输出概率分布] --&amp;gt; B{采样策略}
    B --&amp;gt;|temperature 低| C[集中在高概率词&amp;lt;br/&amp;gt;输出稳定]
    B --&amp;gt;|temperature 高| D[概率被拉平&amp;lt;br/&amp;gt;输出更多样]
    B --&amp;gt;|top_p 小| E[候选池小&amp;lt;br/&amp;gt;更聚焦]
    B --&amp;gt;|top_p 大| F[候选池大&amp;lt;br/&amp;gt;更发散]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;不同任务推荐参数如下：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;任务类型&lt;/th&gt;
					&lt;th&gt;temperature&lt;/th&gt;
					&lt;th&gt;top_p&lt;/th&gt;
					&lt;th&gt;原因&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;翻译、摘要、代码&lt;/td&gt;
					&lt;td&gt;0.2 - 0.5&lt;/td&gt;
					&lt;td&gt;0.8 - 1.0&lt;/td&gt;
					&lt;td&gt;需要准确、可重复&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;创意写作&lt;/td&gt;
					&lt;td&gt;0.7 - 1.0&lt;/td&gt;
					&lt;td&gt;0.9 - 1.0&lt;/td&gt;
					&lt;td&gt;需要多样性和想象力&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;头脑风暴&lt;/td&gt;
					&lt;td&gt;0.8 - 1.2&lt;/td&gt;
					&lt;td&gt;0.9 - 1.0&lt;/td&gt;
					&lt;td&gt;越跳出常规越好&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;验证参数好坏的方法&lt;/strong&gt;：人工看多轮输出是否稳定/有趣；对翻译用 BLEU/ROUGE；对创意任务用 distinct-n 看词汇多样性。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;小知识：有些模型 temperature=0 时输出仍不稳定，可能是因为用了**推测解码（Speculative Decoding）**等加速技术，候选生成阶段仍带随机性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;12-一个专业提示词长什么样&#34;&gt;1.2 一个专业提示词长什么样？&lt;/h3&gt;
&lt;p&gt;把 prompt 当成接口文档来设计，通常包含以下模块：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[角色定义] --&amp;gt; B[任务目标]
    B --&amp;gt; C[输入信息/上下文]
    C --&amp;gt; D[输出格式]
    D --&amp;gt; E[约束条件]
    E --&amp;gt; F[示例]
    F --&amp;gt; G[模型输出]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;模块&lt;/th&gt;
					&lt;th&gt;作用&lt;/th&gt;
					&lt;th&gt;例子&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;角色定义&lt;/td&gt;
					&lt;td&gt;限定语气、专业范围&lt;/td&gt;
					&lt;td&gt;“你是一位严谨的学术助手。”&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;任务目标&lt;/td&gt;
					&lt;td&gt;消除歧义&lt;/td&gt;
					&lt;td&gt;“请把下面这段话翻译成英文。”&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;输入信息&lt;/td&gt;
					&lt;td&gt;限制回答依据&lt;/td&gt;
					&lt;td&gt;“仅根据以下材料回答。”&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;输出格式&lt;/td&gt;
					&lt;td&gt;便于解析&lt;/td&gt;
					&lt;td&gt;“输出 JSON，包含结论和依据。”&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;约束条件&lt;/td&gt;
					&lt;td&gt;降低风险&lt;/td&gt;
					&lt;td&gt;“不要编造，不知道就说不知道。”&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;示例&lt;/td&gt;
					&lt;td&gt;快速对齐预期&lt;/td&gt;
					&lt;td&gt;给 1-2 个输入输出样例&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;为什么角色定义很重要？&lt;/strong&gt; 大模型在训练时见过无数种文体和身份。明确角色，相当于激活了模型内部对应的知识路径和语气风格，也能让它更谨慎，减少胡说八道的概率。&lt;/p&gt;
&lt;h3 id=&#34;13-怎么减少模型幻觉&#34;&gt;1.3 怎么减少模型“幻觉”？&lt;/h3&gt;
&lt;p&gt;幻觉（Hallucination）就是模型一本正经地编造不存在的信息。常用防御手段：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;限定信息源&lt;/strong&gt;：只根据给定材料回答。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;强化真实性要求&lt;/strong&gt;：明确说“不知道就说不知道”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;要求引用依据&lt;/strong&gt;：让模型说明答案出处。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限制输出格式&lt;/strong&gt;：用 JSON、表格等结构化输出，减少自由发挥。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;低 temperature&lt;/strong&gt;：减少随机编造。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;14-怎么防止提示词注入攻击&#34;&gt;1.4 怎么防止提示词注入攻击？&lt;/h3&gt;
&lt;p&gt;提示词注入是指：用户输入里夹带“忽略前面指令、现在执行我的命令”这类内容，试图绕过系统限制。防御思路：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[用户输入] --&amp;gt; B[结构化隔离&amp;lt;br/&amp;gt;JSON/YAML/字段分离]
    B --&amp;gt; C[系统层过滤&amp;lt;br/&amp;gt;正则/规则/小模型守门]
    C --&amp;gt; D[明确指令优先级&amp;lt;br/&amp;gt;禁止修改角色与规则]
    D --&amp;gt; E[函数调用输出&amp;lt;br/&amp;gt;固定 schema]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;结构化输入&lt;/strong&gt;：不要把用户输入直接拼进自然语言 prompt，用 JSON 等格式隔离。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;明确边界&lt;/strong&gt;：系统提示里写明“不可改变角色”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数调用&lt;/strong&gt;：让模型按固定 schema 输出，减少被操控空间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;系统层检测&lt;/strong&gt;：用规则或小模型识别异常输入（如突然要求“忽略之前指令”）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;15-让模型先思考再回答cotself-consistencytot&#34;&gt;1.5 让模型“先思考再回答”：CoT、Self-Consistency、ToT&lt;/h3&gt;
&lt;p&gt;复杂任务（数学、逻辑、规划）直接要答案，模型容易错。可以先让它把推理过程写出来。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    subgraph 思维链 CoT
        Q1[问题] --&amp;gt; R1[一步一步推理] --&amp;gt; A1[答案]
    end

    subgraph 自洽性 Self-Consistency
        Q2[问题] --&amp;gt; R2a[采样推理 1]
        Q2 --&amp;gt; R2b[采样推理 2]
        Q2 --&amp;gt; R2c[采样推理 N]
        R2a --&amp;gt; V[投票/多数共识]
        R2b --&amp;gt; V
        R2c --&amp;gt; V
        V --&amp;gt; A2[最终答案]
    end

    subgraph 思维树 ToT
        Q3[问题] --&amp;gt; B1[分支 1]
        Q3 --&amp;gt; B2[分支 2]
        Q3 --&amp;gt; B3[分支 3]
        B1 --&amp;gt; E[评估/回溯]
        B2 --&amp;gt; E
        B3 --&amp;gt; E
        E --&amp;gt; A3[最优答案]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;方法&lt;/th&gt;
					&lt;th&gt;优点&lt;/th&gt;
					&lt;th&gt;缺点&lt;/th&gt;
					&lt;th&gt;适用场景&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;CoT&lt;/td&gt;
					&lt;td&gt;简单有效，兼容多数模型&lt;/td&gt;
					&lt;td&gt;可能产生幻觉推理步骤&lt;/td&gt;
					&lt;td&gt;数学、逻辑题&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Self-Consistency&lt;/td&gt;
					&lt;td&gt;稳定，减少随机波动&lt;/td&gt;
					&lt;td&gt;计算开销大&lt;/td&gt;
					&lt;td&gt;精度要求高&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;ToT&lt;/td&gt;
					&lt;td&gt;多路径探索，适合长规划&lt;/td&gt;
					&lt;td&gt;实现复杂&lt;/td&gt;
					&lt;td&gt;解谜、策略任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;反思 Reflection&lt;/td&gt;
					&lt;td&gt;可自我纠错&lt;/td&gt;
					&lt;td&gt;依赖初始回答质量&lt;/td&gt;
					&lt;td&gt;代码调试、文本润色&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;16-怎么保证输出格式&#34;&gt;1.6 怎么保证输出格式？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;明确格式要求&lt;/strong&gt;：在 prompt 里清楚说明想要的结构。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;给 few-shot 示例&lt;/strong&gt;：1-2 个例子比千言万语管用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限制随机性&lt;/strong&gt;：JSON 输出常用 temperature=0。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用 API 的 JSON Mode / Function Calling&lt;/strong&gt;：从接口层面约束输出。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;后处理校验&lt;/strong&gt;：用 &lt;code&gt;json.loads()&lt;/code&gt; 等工具兜底。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;17-分类任务怎么保证只输出指定类别&#34;&gt;1.7 分类任务怎么保证只输出指定类别？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;提示词里写明“只能输出以下类别之一”。&lt;/li&gt;
&lt;li&gt;用 API 的 &lt;code&gt;logit_bias&lt;/code&gt; 强行禁止非法 token。&lt;/li&gt;
&lt;li&gt;Function Calling 限定返回枚举值。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二agent让大模型从回答问题到完成任务&#34;&gt;二、Agent：让大模型从“回答问题”到“完成任务”&lt;/h2&gt;
&lt;p&gt;提示工程解决的是“单次问答怎么做好”；Agent 解决的是“怎么让模型自主完成一个多步骤任务”。&lt;/p&gt;
&lt;h3 id=&#34;21-agent-的工作循环&#34;&gt;2.1 Agent 的工作循环&lt;/h3&gt;
&lt;p&gt;一个典型的 Agent 长这样：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[用户任务] --&amp;gt; B[思考 Thought]
    B --&amp;gt; C[行动 Action]
    C --&amp;gt; D[调用工具/搜索/查库]
    D --&amp;gt; E[观察 Observation]
    E --&amp;gt; F{任务完成了吗？}
    F --&amp;gt;|否| B
    F --&amp;gt;|是| G[输出最终答案]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;这就是 ReAct 模式的核心：&lt;strong&gt;想一步、做一步、看结果、再决定下一步&lt;/strong&gt;。比如你要做一个“调研 GPT-5 最新消息”的 Agent，它的循环可能是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;分析目标 → 提取关键词。&lt;/li&gt;
&lt;li&gt;生成搜索关键词。&lt;/li&gt;
&lt;li&gt;调用搜索引擎。&lt;/li&gt;
&lt;li&gt;浏览网页，抽取信息。&lt;/li&gt;
&lt;li&gt;更新记忆，避免重复搜索。&lt;/li&gt;
&lt;li&gt;判断是否需要继续，直到满意。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;22-多-agent-协作一个复杂任务拆给多个专员&#34;&gt;2.2 多 Agent 协作：一个复杂任务拆给多个“专员”&lt;/h3&gt;
&lt;p&gt;当任务复杂、提示词过长时，可以把一个 Agent 拆成多个子 Agent：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    U[用户请求] --&amp;gt; R[Router Agent&amp;lt;br/&amp;gt;识别意图]
    R --&amp;gt; F[航班 Agent]
    R --&amp;gt; H[酒店 Agent]
    R --&amp;gt; I[行程 Agent]
    F --&amp;gt; P[Planner Agent&amp;lt;br/&amp;gt;整合结果]
    H --&amp;gt; P
    I --&amp;gt; P
    P --&amp;gt; O[返回用户]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Router Agent&lt;/strong&gt;：根据用户意图决定调用谁。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;子 Agent&lt;/strong&gt;：各自处理专业领域。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Planner Agent&lt;/strong&gt;：汇总输出，生成统一回复。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;子 Agent 之间通过共享上下文对象、向量数据库等方式传递信息。&lt;/p&gt;
&lt;h3 id=&#34;23-记忆模型不会自动记住你&#34;&gt;2.3 记忆：模型不会自动记住你&lt;/h3&gt;
&lt;p&gt;大模型本身没有长期记忆。对话轮数多了，它会“忘”掉 earlier 的关键信息。解决办法：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[历史对话] --&amp;gt; B[滑动窗口&amp;lt;br/&amp;gt;保留最近 N 轮]
    B --&amp;gt; C[摘要压缩&amp;lt;br/&amp;gt;生成关键状态]
    C --&amp;gt; D[外部记忆存储&amp;lt;br/&amp;gt;Redis/向量库]
    D --&amp;gt; E[需要时检索注入 Prompt]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;显式重复&lt;/strong&gt;：把关键信息重新塞进 prompt。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;摘要压缩&lt;/strong&gt;：每 N 轮生成一次对话摘要。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;外部存储&lt;/strong&gt;：用 Redis、向量数据库保存用户画像和历史事件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KV 缓存持久化&lt;/strong&gt;：把历史对话的 Key-Value 缓存存起来，下一轮直接复用，减少重复计算和延迟。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;24-异步工具调用别让一个慢工具卡住整个对话&#34;&gt;2.4 异步工具调用：别让一个慢工具卡住整个对话&lt;/h3&gt;
&lt;p&gt;如果某个工具（比如查航班 API）要几秒才返回，Agent 不应该傻等。可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把工具调用做成异步任务。&lt;/li&gt;
&lt;li&gt;给用户一个中间状态回复：“正在查询，请稍等。”&lt;/li&gt;
&lt;li&gt;同时处理其他事情，工具返回后再继续。&lt;/li&gt;
&lt;li&gt;用请求 ID 追踪每个调用，确保结果能匹配回上下文。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三rag给大模型外接一个知识库&#34;&gt;三、RAG：给大模型外接一个“知识库”&lt;/h2&gt;
&lt;p&gt;大模型训练数据有截止日期，也不会包含你的私有文档。RAG（Retrieval-Augmented Generation，检索增强生成）的思路是：&lt;strong&gt;在生成答案前，先从外部知识库检索相关内容，把检索结果作为上下文喂给模型&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;31-rag-的基本流程&#34;&gt;3.1 RAG 的基本流程&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    Q[用户问题] --&amp;gt; R[检索模块]
    D[文档库] --&amp;gt; C[文档分块]
    C --&amp;gt; V[向量数据库]
    V --&amp;gt; R
    R --&amp;gt; M[Top-k 相关片段]
    M --&amp;gt; L[大模型]
    Q --&amp;gt; L
    L --&amp;gt; A[带依据的答案]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;32-为什么要把文档切成块&#34;&gt;3.2 为什么要把文档切成块？&lt;/h3&gt;
&lt;p&gt;直接拿整篇文档做向量，效果不好，原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;检索精度低&lt;/strong&gt;：用户只关心其中一两段，整篇文档的向量会被不相关部分稀释。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;嵌入模型有长度限制&lt;/strong&gt;：BERT、MiniLM 等通常只能处理 512 token 左右。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;细粒度匹配更好&lt;/strong&gt;：小片段更容易和查询语义对齐。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但切块也会带来&lt;strong&gt;上下文缺失&lt;/strong&gt;的问题。常用补救方法：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;方法&lt;/th&gt;
					&lt;th&gt;思路&lt;/th&gt;
					&lt;th&gt;优点&lt;/th&gt;
					&lt;th&gt;缺点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;滑动窗口 + 重叠&lt;/td&gt;
					&lt;td&gt;相邻块有重叠区域&lt;/td&gt;
					&lt;td&gt;保留局部上下文&lt;/td&gt;
					&lt;td&gt;存储冗余&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;带标题分块&lt;/td&gt;
					&lt;td&gt;每个块附带章节标题&lt;/td&gt;
					&lt;td&gt;增强结构感&lt;/td&gt;
					&lt;td&gt;对无结构文档效果有限&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;检索时扩展&lt;/td&gt;
					&lt;td&gt;召回相邻块一起送给模型&lt;/td&gt;
					&lt;td&gt;上下文完整&lt;/td&gt;
					&lt;td&gt;需要系统支持&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;多粒度索引&lt;/td&gt;
					&lt;td&gt;同时建“摘要级”和“原文级”索引&lt;/td&gt;
					&lt;td&gt;兼顾梗概与细节&lt;/td&gt;
					&lt;td&gt;实现复杂&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;33-向量检索不够还要混合检索和重排序&#34;&gt;3.3 向量检索不够，还要混合检索和重排序&lt;/h3&gt;
&lt;p&gt;向量检索擅长“语义相似”，但不擅长“精确关键词匹配”；传统关键词检索（如 BM25）正好反过来。所以生产环境常用&lt;strong&gt;混合检索&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    Q[用户查询] --&amp;gt; A[向量检索&amp;lt;br/&amp;gt;Dense Retrieval]
    Q --&amp;gt; B[关键词检索&amp;lt;br/&amp;gt;BM25/TF-IDF]
    A --&amp;gt; F[候选结果]
    B --&amp;gt; F
    F --&amp;gt; R[Rerank&amp;lt;br/&amp;gt;Cross-Encoder]
    R --&amp;gt; K[Top-k 最相关片段]
    K --&amp;gt; L[大模型生成]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;向量检索&lt;/strong&gt;：找语义相近的文档。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;关键词检索&lt;/strong&gt;：补全精确匹配能力。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rerank（重排序）&lt;/strong&gt;：用更强的 Cross-Encoder 模型对召回结果精排。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;34-为什么查询要改写&#34;&gt;3.4 为什么查询要改写？&lt;/h3&gt;
&lt;p&gt;用户提问往往口语化、不完整，直接拿去检索效果差。Query Rewriting 的目标是把问题改写成“更适合嵌入模型的语义表达”。&lt;/p&gt;
&lt;p&gt;比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;原问题：“他出生在哪？”&lt;/li&gt;
&lt;li&gt;改写后：“Barack Obama was born in ?”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;方法包括：LLM 改写、同义词扩展、模板化改写、指令式嵌入（如 E5 模型的 &lt;code&gt;query:&lt;/code&gt; 前缀）。&lt;/p&gt;
&lt;h3 id=&#34;35-检索到冲突或过时的信息怎么办&#34;&gt;3.5 检索到冲突或过时的信息怎么办？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;检索前&lt;/strong&gt;：做数据源筛选、时效性过滤。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;检索中&lt;/strong&gt;：多阶段 reranking，提升相关性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成前&lt;/strong&gt;：在 prompt 里加防御性约束，比如“如果来源冲突，请说明”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成时&lt;/strong&gt;：要求模型标注来源，输出可信度分数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成后&lt;/strong&gt;：用一致性校验或外部验证器判断答案是否忠实于来源。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;36-rag-的可解释性&#34;&gt;3.6 RAG 的可解释性&lt;/h3&gt;
&lt;p&gt;想让用户信任答案，最好告诉它“这个答案来自哪”。做法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;保留文档 ID、URL、时间戳。&lt;/li&gt;
&lt;li&gt;做生成-来源对齐（Attribution），把生成内容逐句回溯到文档片段。&lt;/li&gt;
&lt;li&gt;输出置信度分数：检索相似度、生成概率、验证器分数等。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;37-多模态-rag-与长期记忆&#34;&gt;3.7 多模态 RAG 与长期记忆&lt;/h3&gt;
&lt;p&gt;RAG 不限于文本。可以扩展到图像、视频：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用 CLIP 等模型把图像、文本映射到统一向量空间。&lt;/li&gt;
&lt;li&gt;文档里的图表提取为图像块，保留位置信息。&lt;/li&gt;
&lt;li&gt;视频按时间分段，提取关键帧 + ASR 文本。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI 伴侣、企业知识库这类长期记忆场景，则需要：每日摘要、事件图谱、多层次召回、时间感知检索、经验版本控制（避免新经验覆盖旧经验）。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四从面试题到工程实践给初级开发者的建议&#34;&gt;四、从面试题到工程实践：给初级开发者的建议&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;先跑通端到端，再优化局部&lt;/strong&gt;。不要一上来就追求最先进的 reranker 或 Agent 框架，先用最简单的方式验证需求是否成立。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;把 prompt 当代码管&lt;/strong&gt;。纳入 Git，做版本控制，写回归测试。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;评估比调参更重要&lt;/strong&gt;。没有指标，就不知道改进是否有效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上下文质量 &amp;gt; 上下文长度&lt;/strong&gt;。塞太多无关信息，反而让模型抓不到重点。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;有结构地失败&lt;/strong&gt;。模型总会出错，关键是在出错时有兜底、有日志、能回滚。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;结语&#34;&gt;结语&lt;/h2&gt;
&lt;p&gt;Part 2 的内容从“怎么写 prompt”一路延伸到“怎么搭 Agent、做 RAG”。对初级开发者来说，最重要的不是记住每个参数的具体数值，而是理解这些技术背后的&lt;strong&gt;工程思想&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提示工程 = 设计人与模型的接口协议；&lt;/li&gt;
&lt;li&gt;Agent = 把单次调用扩展成有状态、有工具、有记忆的循环；&lt;/li&gt;
&lt;li&gt;RAG = 用外部知识库补齐模型能力的缺口。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;掌握这三块，你就已经能从“会调 API”进阶到“能搭 AI 应用”了。&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;参考：《生成式AI原理与实战 —— Part 2》&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
  </channel>
</rss>
