<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>工程实践 on 扎塔-Zata</title><link>https://www.zata.cc/categories/%E5%B7%A5%E7%A8%8B%E5%AE%9E%E8%B7%B5/</link><description>Recent content in 工程实践 on 扎塔-Zata</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>Example Person</copyright><lastBuildDate>Thu, 24 Sep 2026 17:09:06 +0800</lastBuildDate><atom:link href="https://www.zata.cc/categories/%E5%B7%A5%E7%A8%8B%E5%AE%9E%E8%B7%B5/index.xml" rel="self" type="application/rss+xml"/><item><title>LogQL 查询语言详解：先选流，再过滤，最后才解析</title><link>https://www.zata.cc/p/logql-%E6%9F%A5%E8%AF%A2%E8%AF%AD%E8%A8%80%E8%AF%A6%E8%A7%A3%E5%85%88%E9%80%89%E6%B5%81%E5%86%8D%E8%BF%87%E6%BB%A4%E6%9C%80%E5%90%8E%E6%89%8D%E8%A7%A3%E6%9E%90/</link><pubDate>Wed, 09 Sep 2026 09:00:00 +0800</pubDate><guid>https://www.zata.cc/p/logql-%E6%9F%A5%E8%AF%A2%E8%AF%AD%E8%A8%80%E8%AF%A6%E8%A7%A3%E5%85%88%E9%80%89%E6%B5%81%E5%86%8D%E8%BF%87%E6%BB%A4%E6%9C%80%E5%90%8E%E6%89%8D%E8%A7%A3%E6%9E%90/</guid><description>&lt;img src="https://www.zata.cc/p/logql-%E6%9F%A5%E8%AF%A2%E8%AF%AD%E8%A8%80%E8%AF%A6%E8%A7%A3%E5%85%88%E9%80%89%E6%B5%81%E5%86%8D%E8%BF%87%E6%BB%A4%E6%9C%80%E5%90%8E%E6%89%8D%E8%A7%A3%E6%9E%90/images/index/index.svg" alt="Featured image of post LogQL 查询语言详解：先选流，再过滤，最后才解析" />&lt;p>2026 年 9 月 9 日上午，我在给自己部署的 AI 应用排查&amp;quot;生成失败&amp;quot;问题时，顺手打开了 Grafana 上的日志面板，结果先被日志面板气到了：所有服务器的日志混在一起，每条日志外面包着一层 Docker 元数据的 JSON，最新的在最上面，长行还不自动换行。想找一段报错，体验还不如直接 SSH 上去 &lt;code>grep&lt;/code> 一个 &lt;code>log.txt&lt;/code>。&lt;/p>
&lt;p>问题最后出在查询语句上。面板用的查询是 &lt;code>{node=~&amp;quot;.+&amp;quot;}&lt;/code>——选中所有节点的所有日志，其余什么都没做。而把它救回来的，是一条三段式的 LogQL：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">{compose_project=&amp;#34;freshai&amp;#34;, compose_service=&amp;#34;freshai-backend&amp;#34;}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> | json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> | line_format &amp;#34;{{.message}}&amp;#34;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>执行这条查询后，日志恢复了本来的样子：&lt;code>INFO: 127.0.0.1:35822 - &amp;quot;GET /health HTTP/1.1&amp;quot; 200 OK&lt;/code>，一行就是一条，干净可读。&lt;/p>
&lt;p>这条查询的写法背后其实是一套完整的心智模型：&lt;strong>先选流，再过滤，最后才解析&lt;/strong>。这个顺序不只是语法结构，也直接决定了查询的性能。这篇文章就把 LogQL 讲透：它为什么长这样、每一段在做什么、怎么写快、卡住时怎么自己定位，以及什么时候你根本不该用它。&lt;/p>
&lt;h2 id="一前提loki-为什么不索引日志正文">一、前提：Loki 为什么不索引日志正文
&lt;/h2>&lt;p>要理解 LogQL 的语法设计，得先理解 Loki 这个存储引擎做的一个关键取舍。&lt;/p>
&lt;p>传统日志方案（比如 Elasticsearch）会在写入时对日志正文建全文索引：写入成本高、存储膨胀，但查询时随便搜。Loki 反过来——官方文档的表述是，它&amp;quot;不为日志内容建索引，只为每条日志流的元数据（标签）建索引&amp;quot;，日志正文被&amp;quot;压缩后以 chunk 的形式存进对象存储（比如 S3）&amp;quot;。&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/logql-%E6%9F%A5%E8%AF%A2%E8%AF%AD%E8%A8%80%E8%AF%A6%E8%A7%A3%E5%85%88%E9%80%89%E6%B5%81%E5%86%8D%E8%BF%87%E6%BB%A4%E6%9C%80%E5%90%8E%E6%89%8D%E8%A7%A3%E6%9E%90/images/chunks_diagram.png"
width="859"
height="531"
srcset="https://www.zata.cc/p/logql-%E6%9F%A5%E8%AF%A2%E8%AF%AD%E8%A8%80%E8%AF%A6%E8%A7%A3%E5%85%88%E9%80%89%E6%B5%81%E5%86%8D%E8%BF%87%E6%BB%A4%E6%9C%80%E5%90%8E%E6%89%8D%E8%A7%A3%E6%9E%90/images/chunks_diagram_hu15377815961181565913.png 480w, https://www.zata.cc/p/logql-%E6%9F%A5%E8%AF%A2%E8%AF%AD%E8%A8%80%E8%AF%A6%E8%A7%A3%E5%85%88%E9%80%89%E6%B5%81%E5%86%8D%E8%BF%87%E6%BB%A4%E6%9C%80%E5%90%8E%E6%89%8D%E8%A7%A3%E6%9E%90/images/chunks_diagram_hu8086332810726464954.png 1024w"
loading="lazy"
alt="Loki 的存储模型"
class="gallery-image"
data-flex-grow="161"
data-flex-basis="388px"
>&lt;/p>
&lt;p>&lt;em>▲ Loki 的存储模型：标签组合哈希成一个流 ID，同流的日志行聚成 chunk 压缩存储，索引只记录&amp;quot;去哪个 chunk 找&amp;quot;。图：Grafana Loki 官方文档（Apache-2.0）&lt;/em>&lt;/p>
&lt;p>上面这张官方图把模型讲得很清楚：&lt;code>{component=&amp;quot;printer&amp;quot;, location=&amp;quot;f2c16&amp;quot;, level=&amp;quot;error&amp;quot;}&lt;/code> 这组标签哈希出一个流 ID，后续相同标签的日志都追加进同一个 chunk，攒满后压缩落盘；另有一个很小的索引负责&amp;quot;根据标签找到 chunk&amp;quot;。换个标签值，就是另一条流、另一个 chunk。&lt;/p>
&lt;p>这个设计的直接后果是：&lt;strong>写入便宜，查询时付成本&lt;/strong>。查询时 Loki 要根据标签圈定一批流，再把 chunk 解压出来逐行扫描。所以 LogQL 的第一原则就是让&amp;quot;圈定&amp;quot;这一步尽量窄——这也解释了为什么语法把流选择器放在最前面，而且它是唯一必填的部分。&lt;/p>
&lt;h2 id="二一条查询的解剖选择器与流水线">二、一条查询的解剖：选择器与流水线
&lt;/h2>&lt;p>LogQL 的一条日志查询由两部分组成：&lt;strong>流选择器&lt;/strong>（必填）和&lt;strong>日志流水线&lt;/strong>（可选）。&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/logql-%E6%9F%A5%E8%AF%A2%E8%AF%AD%E8%A8%80%E8%AF%A6%E8%A7%A3%E5%85%88%E9%80%89%E6%B5%81%E5%86%8D%E8%BF%87%E6%BB%A4%E6%9C%80%E5%90%8E%E6%89%8D%E8%A7%A3%E6%9E%90/images/query_components.png"
width="582"
height="527"
srcset="https://www.zata.cc/p/logql-%E6%9F%A5%E8%AF%A2%E8%AF%AD%E8%A8%80%E8%AF%A6%E8%A7%A3%E5%85%88%E9%80%89%E6%B5%81%E5%86%8D%E8%BF%87%E6%BB%A4%E6%9C%80%E5%90%8E%E6%89%8D%E8%A7%A3%E6%9E%90/images/query_components_hu18322935102319258683.png 480w, https://www.zata.cc/p/logql-%E6%9F%A5%E8%AF%A2%E8%AF%AD%E8%A8%80%E8%AF%A6%E8%A7%A3%E5%85%88%E9%80%89%E6%B5%81%E5%86%8D%E8%BF%87%E6%BB%A4%E6%9C%80%E5%90%8E%E6%89%8D%E8%A7%A3%E6%9E%90/images/query_components_hu10477383659937809971.png 1024w"
loading="lazy"
alt="LogQL 查询结构"
class="gallery-image"
data-flex-grow="110"
data-flex-basis="265px"
>&lt;/p>
&lt;p>&lt;em>▲ 一条 LogQL 查询的完整结构：&lt;code>{流选择器}&lt;/code> 后接可选流水线——行过滤、标签过滤、解析器与格式化表达式。图：Grafana Loki 官方文档（Apache-2.0）&lt;/em>&lt;/p>
&lt;h3 id="流选择器唯一的索引入口">流选择器：唯一的索引入口
&lt;/h3>&lt;p>流选择器就是花括号里的标签匹配器，写法与 Prometheus 完全一致：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">{container=&amp;#34;query-frontend&amp;#34;, namespace=&amp;#34;loki-dev&amp;#34;}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>四个匹配操作符：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>操作符&lt;/th>
&lt;th>含义&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>=&lt;/code>&lt;/td>
&lt;td>等于&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>!=&lt;/code>&lt;/td>
&lt;td>不等于&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>=~&lt;/code>&lt;/td>
&lt;td>正则匹配&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>!~&lt;/code>&lt;/td>
&lt;td>正则不匹配&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>两个容易忽略的规则：第一，Loki 明确声明选择器沿用 &lt;a class="link" href="https://prometheus.io/docs/prometheus/latest/querying/basics/#instant-vector-selectors" target="_blank" rel="noopener"
>Prometheus 标签选择器的规则&lt;/a>——至少要有一个&lt;strong>不能匹配空字符串&lt;/strong>的匹配器，否则查询会命中所有流；第二，&lt;code>=~&lt;/code> 和 &lt;code>!~&lt;/code> 的正则是&lt;strong>完全锚定&lt;/strong>的，&lt;code>level=~&amp;quot;info&amp;quot;&lt;/code> 只匹配恰好等于 &lt;code>info&lt;/code> 的值，想匹配前缀要写 &lt;code>level=~&amp;quot;info.*&amp;quot;&lt;/code>。&lt;/p>
&lt;p>标签体系是采集端定的。我部署的采集链路是 Vector 读取 Docker 容器日志，把 &lt;code>compose_project&lt;/code>、&lt;code>compose_service&lt;/code>、&lt;code>level&lt;/code> 挂成 Loki 标签，所以我的选择器可以直接写 &lt;code>{compose_project=&amp;quot;freshai&amp;quot;, compose_service=&amp;quot;freshai-backend&amp;quot;}&lt;/code>。&lt;strong>选择器能写多窄，取决于采集端把标签设计多合理&lt;/strong>——这是用 Loki 时唯一需要在写入侧认真规划的事。&lt;/p>
&lt;h3 id="行过滤分布式-grep">行过滤：分布式 grep
&lt;/h3>&lt;p>流水线里最常用的是行过滤表达式。官方对它的定位很直白：&amp;ldquo;对选中日志流做一次分布式 &lt;code>grep&lt;/code>&amp;quot;。四个操作符：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>操作符&lt;/th>
&lt;th>含义&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>|=&lt;/code>&lt;/td>
&lt;td>行包含该字符串&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>!=&lt;/code>&lt;/td>
&lt;td>行不包含该字符串&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>|~&lt;/code>&lt;/td>
&lt;td>行匹配该正则&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>!~&lt;/code>&lt;/td>
&lt;td>行不匹配该正则&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">{job=&amp;#34;mysql&amp;#34;} |= &amp;#34;error&amp;#34; != &amp;#34;timeout&amp;#34;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>注意这些匹配是&lt;strong>大小写敏感&lt;/strong>的，且是纯子串匹配——不解析、不提取，就是逐行看内容，所以非常快。正则走 RE2 风格，&lt;code>(?i)&lt;/code> 前缀可以做大小写不敏感匹配。&lt;/p>
&lt;p>这里埋着 LogQL 最著名的坑，官方文档专门加了警告：&lt;strong>行过滤的 &lt;code>|~&lt;/code> 和 &lt;code>!~&lt;/code> 正则不做完全锚定，&lt;code>.&lt;/code> 会匹配包括换行在内的所有字符&lt;/strong>。这和标签匹配器的正则行为不一致，写复杂正则时要特别留意。&lt;/p>
&lt;h2 id="三流水线深潜过滤解析格式化">三、流水线深潜：过滤、解析、格式化
&lt;/h2>&lt;p>流水线可以串联多个表达式，官方文档对执行顺序的描述是：&lt;strong>每个表达式按从左到右的顺序逐行执行；一旦某个表达式把一行日志过滤掉，流水线立即停止处理这行，跳去处理下一行&lt;/strong>。&lt;/p>
&lt;p>这个机制直接推出了最重要的性能规则：行过滤要放在解析器前面。官方文档给了一组对比例子，两条查询结果完全相同，但前者始终快于后者：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl"># 快：先过滤，命中的行才解析
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{job=&amp;#34;mysql&amp;#34;} |= &amp;#34;error&amp;#34; | json | line_format &amp;#34;{{.err}}&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># 慢：每行都解析完才过滤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{job=&amp;#34;mysql&amp;#34;} | json | line_format &amp;#34;{{.message}}&amp;#34; |= &amp;#34;error&amp;#34;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原因很直观：前者只对包含 &lt;code>error&lt;/code> 的行付出解析成本，后者对每一行都解析。&lt;strong>&amp;ldquo;先选流，再过滤，最后才解析&amp;quot;不只是阅读顺序，就是执行顺序。&lt;/strong>&lt;/p>
&lt;h3 id="解析器把日志行变成可引用的字段">解析器：把日志行变成可引用的字段
&lt;/h3>&lt;p>解析器负责把非结构化的日志行拆成字段，拆出来的字段可以在后续的标签过滤、格式化和指标聚合里引用：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>解析器&lt;/th>
&lt;th>适用格式&lt;/th>
&lt;th>备注&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>json&lt;/code>&lt;/td>
&lt;td>JSON 行&lt;/td>
&lt;td>官方建议优先使用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>logfmt&lt;/code>&lt;/td>
&lt;td>&lt;code>key=value&lt;/code> 行&lt;/td>
&lt;td>官方建议优先使用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>pattern&lt;/code>&lt;/td>
&lt;td>固定结构的行&lt;/td>
&lt;td>官方明说比 regexp 好写且更快&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>regexp&lt;/code>&lt;/td>
&lt;td>任意行&lt;/td>
&lt;td>用正则捕获组提取&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>unpack&lt;/code>&lt;/td>
&lt;td>JSON 打包的二进制等&lt;/td>
&lt;td>特殊场景&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;code>pattern&lt;/code> 解析器值得单独一说。它用一个&amp;quot;模板&amp;quot;描述行结构，尖括号是捕获，&lt;code>&amp;lt;_&amp;gt;&lt;/code> 是跳过不捕获。官方文档用一条 NGINX 日志做演示：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">| pattern &amp;#34;&amp;lt;ip&amp;gt; - - &amp;lt;_&amp;gt; \&amp;#34;&amp;lt;method&amp;gt; &amp;lt;uri&amp;gt; &amp;lt;_&amp;gt;\&amp;#34; &amp;lt;status&amp;gt; &amp;lt;size&amp;gt; &amp;lt;_&amp;gt; \&amp;#34;&amp;lt;agent&amp;gt;\&amp;#34; &amp;lt;_&amp;gt;&amp;#34;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>就能把 &lt;code>ip&lt;/code>、&lt;code>method&lt;/code>、&lt;code>uri&lt;/code>、&lt;code>status&lt;/code> 全部提出来。&lt;/p>
&lt;p>三个和解析器相关的重要行为：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>解析失败不丢行&lt;/strong>。一行日志格式不对时，Loki 不会把它过滤掉，而是给它打上 &lt;code>__error__&lt;/code> 标签继续走。所以想只看解析成功的行，显式加一个 &lt;code>| __error__=&amp;quot;&amp;quot;&lt;/code>。&lt;/li>
&lt;li>&lt;strong>字段名会被清洗&lt;/strong>。JSON 里的 &lt;code>a.b&lt;/code> 会被改写成 &lt;code>a_b&lt;/code>，以符合 Prometheus 命名规范。&lt;/li>
&lt;li>&lt;strong>字段名冲突加后缀&lt;/strong>。解析出的字段和已有标签重名时，会得到 &lt;code>_extracted&lt;/code> 后缀的新标签，比如 &lt;code>level&lt;/code> 已存在时解析结果叫 &lt;code>level_extracted&lt;/code>。&lt;/li>
&lt;/ul>
&lt;h3 id="解析之后标签过滤与格式化">解析之后：标签过滤与格式化
&lt;/h3>&lt;p>字段提取出来之后，可以做结构化的标签过滤，支持字符串、时长、字节数的比较运算：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">| duration &amp;gt;= 20ms or size == 20KB
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>最后是两个格式化表达式，都基于 Go 的 &lt;a class="link" href="https://pkg.go.dev/text/template" target="_blank" rel="noopener"
>text/template&lt;/a> 语法：&lt;/p>
&lt;ul>
&lt;li>&lt;code>line_format&lt;/code>：重写整行的显示内容，&lt;code>{{.message}}&lt;/code> 引用字段；&lt;/li>
&lt;li>&lt;code>label_format&lt;/code>：重命名或改写字段，右边也可以是模板，如 &lt;code>dst=&amp;quot;{{.status}} {{.query}}&amp;quot;&lt;/code>。&lt;/li>
&lt;/ul>
&lt;p>我在 Grafana 面板里用的 &lt;code>| line_format &amp;quot;{{.message}}&amp;quot;&lt;/code>，作用就是把日志显示从&amp;quot;整包 JSON&amp;quot;还原成正文本身。&lt;/p>
&lt;h2 id="四回到我的面板一次真实修复">四、回到我的面板：一次真实修复
&lt;/h2>&lt;p>把语法讲完，回头看开头那个难读的面板。我的监控栈是 Vector 采集 Docker 容器日志、写入 Loki（写作时我服务器上跑的是 3.7.7），Grafana（13.2.1）负责查询展示。Vector 落到 Loki 的每一行日志，正文其实是一个 JSON：应用日志嵌在其中的 &lt;code>message&lt;/code> 字段里，外面还包着 Docker 的容器名、标签等元数据。&lt;/p>
&lt;p>旧面板的查询 &lt;code>{node=~&amp;quot;.+&amp;quot;}&lt;/code> 有三个问题：选择器宽到等于没有选择器；没解析 JSON，读者看到的是整包元数据；再配上&amp;quot;倒序 + 不换行&amp;quot;的显示设置，彻底没法读。&lt;/p>
&lt;p>修复后的查询逐段拆开看：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">{compose_project=&amp;#34;freshai&amp;#34;, compose_service=&amp;#34;freshai-backend&amp;#34;} # ① 用标签把范围收到一个容器
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> | json # ② 解析 JSON 包装
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> | line_format &amp;#34;{{.message}}&amp;#34; # ③ 只显示正文
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>①把搜索范围从&amp;quot;全部服务器全部容器&amp;quot;缩到单个服务；②③把行内容还原成应用自己打的日志。这段查询我在 Loki 的 HTTP API 上实测过，返回的就是干净的 &lt;code>INFO: ... &amp;quot;GET /health HTTP/1.1&amp;quot; 200 OK&lt;/code>。&lt;/p>
&lt;p>在 Grafana 的 Explore 里写这些查询时，可以用 Builder 模式通过下拉框拼，也可以切到 Code 模式手写 LogQL：&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/logql-%E6%9F%A5%E8%AF%A2%E8%AF%AD%E8%A8%80%E8%AF%A6%E8%A7%A3%E5%85%88%E9%80%89%E6%B5%81%E5%86%8D%E8%BF%87%E6%BB%A4%E6%9C%80%E5%90%8E%E6%89%8D%E8%A7%A3%E6%9E%90/images/grafana-query-builder.png"
width="1411"
height="515"
srcset="https://www.zata.cc/p/logql-%E6%9F%A5%E8%AF%A2%E8%AF%AD%E8%A8%80%E8%AF%A6%E8%A7%A3%E5%85%88%E9%80%89%E6%B5%81%E5%86%8D%E8%BF%87%E6%BB%A4%E6%9C%80%E5%90%8E%E6%89%8D%E8%A7%A3%E6%9E%90/images/grafana-query-builder_hu649640754460675118.png 480w, https://www.zata.cc/p/logql-%E6%9F%A5%E8%AF%A2%E8%AF%AD%E8%A8%80%E8%AF%A6%E8%A7%A3%E5%85%88%E9%80%89%E6%B5%81%E5%86%8D%E8%BF%87%E6%BB%A4%E6%9C%80%E5%90%8E%E6%89%8D%E8%A7%A3%E6%9E%90/images/grafana-query-builder_hu10430957227711538694.png 1024w"
loading="lazy"
alt="Grafana Explore 的 Loki 查询界面"
class="gallery-image"
data-flex-grow="273"
data-flex-basis="657px"
>&lt;/p>
&lt;p>&lt;em>▲ Grafana Explore 的 Loki 查询界面：Builder 模式用&amp;quot;Label filters + Line contains&amp;quot;拼查询，右上角可切换到 Code 模式手写 LogQL。图：Grafana Loki 官方文档（Apache-2.0）&lt;/em>&lt;/p>
&lt;p>我日常最常用的几个查询模式：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl"># 只看错误和异常（大小写不敏感）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{compose_service=&amp;#34;freshai-backend&amp;#34;}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> |~ &amp;#34;(?i)error|exception|timeout&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> | json | line_format &amp;#34;{{.message}}&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># 隐藏健康检查噪音
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{compose_service=&amp;#34;freshai-backend&amp;#34;}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> | json | line_format &amp;#34;{{.message}}&amp;#34; != &amp;#34;GET /health&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># 用 request_id 串联一次请求的全部日志
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{compose_project=&amp;#34;freshai&amp;#34;} |= &amp;#34;req_abc123&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># 错误行数曲线：5 分钟窗口按 level 聚合
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sum by (level) (
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> count_over_time({compose_service=&amp;#34;freshai-backend&amp;#34;} | json [5m])
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>最后一条是 LogQL 的另一面：&lt;strong>指标查询&lt;/strong>。日志查询返回日志行，指标查询把同一段流水线包在 &lt;code>count_over_time&lt;/code>、&lt;code>rate&lt;/code> 等函数里，返回的是时间序列——语法和 PromQL 几乎一样，还有 &lt;code>unwrap&lt;/code> 可以从日志行里提取数值做聚合。这意味着告警规则可以直接建在日志内容上，比如&amp;quot;5 分钟内 ERROR 超过 N 条就告警&amp;rdquo;，不需要额外的指标埋点。&lt;/p>
&lt;h2 id="五把查询写快的四条原则">五、把查询写快的四条原则
&lt;/h2>&lt;p>Loki 把成本从写入挪到了查询，查询习惯就决定了这套系统的体验。结合官方建议和我自己踩过的坑，总结成四条：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>选择器先窄，宽了等于全表扫描。&lt;/strong> Loki 只索引标签，选择器是唯一走索引的环节。至少一个不能匹配空串的匹配器是语法底线，而实践中目标是把范围收到个位数的流。&lt;/li>
&lt;li>&lt;strong>行过滤永远放在解析器前面。&lt;/strong> 前面官方的那组对比查询就是证据：先 &lt;code>|=&lt;/code> 再 &lt;code>| json&lt;/code>，解析成本只花在命中的行上。&lt;/li>
&lt;li>&lt;strong>解析器能简则简。&lt;/strong> 官方原话是 &lt;code>json&lt;/code> 和 &lt;code>logfmt&lt;/code> 能用就用，&lt;code>pattern&lt;/code> 比 &lt;code>regexp&lt;/code> 好写且更快；正则只留给真正不规则的行。解析还失败的行记得用 &lt;code>__error__&lt;/code> 处理，别让它们混进结果。&lt;/li>
&lt;li>&lt;strong>指标查询控制时间范围和分组维度。&lt;/strong> 指标查询要扫描范围内所有行，&lt;code>[5m]&lt;/code> 和 &lt;code>[30d]&lt;/code> 的成本完全不同；&lt;code>by ()&lt;/code> 的分组维度越多，聚合开销越大。&lt;/li>
&lt;/ol>
&lt;p>对应的三个坑：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>标签基数爆炸&lt;/strong>。把 &lt;code>user_id&lt;/code>、&lt;code>request_id&lt;/code> 这类高基数值放进标签，流数量会指数级膨胀，索引和查询一起遭殃。它们属于日志正文，用行过滤或解析去查。&lt;/li>
&lt;li>&lt;strong>解析出的字段不进索引&lt;/strong>。&lt;code>| json&lt;/code> 提取的字段只在查询执行时生效，永远不要指望&amp;quot;解析过的字段下次查得更快&amp;rdquo;——索引里只有采集时写入的标签。&lt;/li>
&lt;li>&lt;strong>行过滤正则的 &lt;code>.&lt;/code> 匹配换行&lt;/strong>。这是官方文档专门警告的行为差异，跨行日志里写 &lt;code>.*&lt;/code> 很容易匹配到意料之外的内容。&lt;/li>
&lt;/ul>
&lt;h2 id="六下次卡住时三层定位把事实带给-ai">六、下次卡住时：三层定位，把事实带给 AI
&lt;/h2>&lt;p>开头那个面板问题，从&amp;quot;这日志没法看&amp;quot;到修复，用得最多的动作不是写查询，而是判断问题出在哪一层。Grafana 的日志链路是固定的三段——采集进 Loki、Loki 存起来、Grafana 查出来展示——所以&amp;quot;不知道怎么办&amp;quot;的时候，先对照症状定位层级，每层的下一步动作完全不同：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>层&lt;/th>
&lt;th>症状&lt;/th>
&lt;th>先做什么&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>采集层（Vector → Loki）&lt;/td>
&lt;td>Explore 里选不到标签，最宽的查询也没有数据&lt;/td>
&lt;td>去看采集端（Vector）容器日志有没有报错，确认标签在采集端配置了&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>查询层（LogQL 写错）&lt;/td>
&lt;td>有数据但查不出，或查询直接报错&lt;/td>
&lt;td>二分查询：只留 &lt;code>{选择器}&lt;/code> 看有没有数据，再逐段加回 &lt;code>| json&lt;/code>、&lt;code>| line_format&lt;/code>，哪段加上就坏，问题就在哪段&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>显示层（面板设置）&lt;/td>
&lt;td>查询结果是对的，就是难读&lt;/td>
&lt;td>检查面板 options：排序、换行；正文被 JSON 包住就补 &lt;code>| json | line_format&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>多数卡住的情况落在查询层，而二分法几分钟就能圈出问题段。&lt;/p>
&lt;p>定位到层级之后，无论是继续翻文档还是找人问，都要把&amp;quot;感受&amp;quot;换成&amp;quot;事实&amp;quot;。&amp;ldquo;日志好难看&amp;quot;这种描述，对方只能靠猜；能直接开工的提问包含五样东西，全部可以在 Explore 里一分钟内收集到：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>目标&lt;/strong>：想看到什么（&amp;ldquo;只看某个服务的正文，隐藏健康检查&amp;rdquo;）；&lt;/li>
&lt;li>&lt;strong>现状查询&lt;/strong>：当前在用的查询语句原文；&lt;/li>
&lt;li>&lt;strong>一条原始日志&lt;/strong>：随便展开一条完整复制——它决定该用哪种解析器；&lt;/li>
&lt;li>&lt;strong>标签列表&lt;/strong>：Label browser 里有哪些标签——它决定选择器能写多窄；&lt;/li>
&lt;li>&lt;strong>版本&lt;/strong>：Grafana 与 Loki 版本——LogQL 语法存在版本差异。&lt;/li>
&lt;/ol>
&lt;p>拼成一段完整的提问：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">我在 Grafana Explore 查 Loki 日志。目标是【X】。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">当前查询是【贴语句】，返回的是【贴一条原始返回】。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">可用标签有【A、B、C】，Loki 版本【x.y】。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">我试过【Z】没有效果。查询应该怎么改？
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这比&amp;quot;LogQL 怎么写&amp;quot;能得到的答案质量高一个量级：对方能根据真实的日志格式选解析器、根据真实标签写选择器，而不是丢一个通用示例让你自己套。&lt;/p>
&lt;h2 id="七什么时候不该用-logql">七、什么时候不该用 LogQL
&lt;/h2>&lt;p>诚实地说，这套体系不是万能的。&lt;/p>
&lt;p>如果你需要复杂的全文检索——模糊匹配、相关性排序、对日志正文里的任意嵌套字段做即席多维查询——Elasticsearch/OpenSearch 依然是更合适的工具。Loki 用&amp;quot;只索引标签&amp;quot;换来了便宜的写入和存储，代价就是查询能力向标签和行扫描收敛。&lt;/p>
&lt;p>反过来，如果你是中小团队、个人项目，日志量在每天几个 GB 量级，已经有 Docker + Grafana 在跑，Loki + Vector + LogQL 的组合几乎是最省心的选择：存储便宜、组件少、查询语言和 PromQL 同源。我这套&amp;quot;多台服务器各自跑 Vector 采集、集中写入一个 Loki&amp;quot;的部署里，采集端 Vector 的常驻内存只有约 18MB，几乎感觉不到它的存在。&lt;/p>
&lt;p>还有一个隐藏福利值得提：因为语法同源，会 PromQL 的工程师上手 LogQL 几乎零成本，Kubernetes 里用 Prometheus 的团队加一套 Loki 的边际学习成本接近于零。&lt;/p>
&lt;h2 id="总结">总结
&lt;/h2>&lt;p>LogQL 的全部设计都源于 Loki 的一个成本决定：不为日志正文建索引，只索引标签。理解了这一点，剩下的是一套清晰的规则：&lt;/p>
&lt;ul>
&lt;li>查询三段式：流选择器（走索引）→ 行过滤（分布式 grep）→ 解析与格式化（逐行付费）；&lt;/li>
&lt;li>四个行过滤操作符 &lt;code>|=&lt;/code>、&lt;code>!=&lt;/code>、&lt;code>|~&lt;/code>、&lt;code>!~&lt;/code> 是流水线里最便宜的表达式，永远放在解析器前面；&lt;/li>
&lt;li>解析器按 &lt;code>json&lt;/code>/&lt;code>logfmt&lt;/code> → &lt;code>pattern&lt;/code> → &lt;code>regexp&lt;/code> 的优先级选，解析失败的行带 &lt;code>__error__&lt;/code> 标签，不会消失；&lt;/li>
&lt;li>指标查询让告警可以直接建在日志内容上；&lt;/li>
&lt;li>标签在采集端规划，高基数值不要进标签。&lt;/li>
&lt;/ul>
&lt;p>行动清单：采集端先把 &lt;code>project&lt;/code>/&lt;code>service&lt;/code>/&lt;code>level&lt;/code> 三个标签挂好；面板查询统一加 &lt;code>| json | line_format &amp;quot;{{.message}}&amp;quot;&lt;/code>；建一个 &lt;code>count_over_time + sum by (level)&lt;/code> 的错误曲线；写复杂查询前先用 &lt;code>logcli&lt;/code> 在命令行验证；再往后的每一次提问，先花一分钟收集&amp;quot;目标、当前查询、原始日志、标签、版本&amp;quot;这五样事实。&lt;/p>
&lt;p>如果要留一句话：&lt;strong>LogQL 的快，不靠引擎魔法，而是逼你在写查询的第一秒就想清楚范围——这个约束恰恰是它比全文检索更快、也更便宜的原因。&lt;/strong>&lt;/p>
&lt;h2 id="参考">参考
&lt;/h2>&lt;ul>
&lt;li>&lt;a class="link" href="https://grafana.com/docs/loki/latest/query/log_queries/" target="_blank" rel="noopener"
>LogQL: Log queries — Grafana Loki 官方文档&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://grafana.com/docs/loki/latest/query/metric_queries/" target="_blank" rel="noopener"
>LogQL: Metric queries — Grafana Loki 官方文档&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://grafana.com/docs/loki/latest/get-started/overview/" target="_blank" rel="noopener"
>Loki Get started: 查询与存储模型&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://prometheus.io/docs/prometheus/latest/querying/basics/#instant-vector-selectors" target="_blank" rel="noopener"
>Prometheus 标签选择器规则&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://grafana.com/docs/loki/latest/query/logcli/getting-started/" target="_blank" rel="noopener"
>logcli 命令行工具&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Docker 和 Traefik 一键安装脚本</title><link>https://www.zata.cc/p/docker-traefik-install-script/</link><pubDate>Mon, 08 Jun 2026 00:30:00 +0800</pubDate><guid>https://www.zata.cc/p/docker-traefik-install-script/</guid><description>&lt;img src="https://www.zata.cc/p/docker-traefik-install-script/images/index/index.png" alt="Featured image of post Docker 和 Traefik 一键安装脚本" />&lt;p>在单台 VPS 上部署多个 Web 服务时，我现在更倾向于先准备一个公共入口层：Docker 负责跑应用，Traefik 负责根据域名把请求转发到不同容器，并自动接入 HTTPS。&lt;/p>
&lt;p>这篇文章放一个可直接运行的脚本，用来在 Ubuntu/Debian 服务器上安装 Docker Engine、Docker Compose 插件，并启动一个基础 Traefik 网关。&lt;/p>
&lt;p>脚本文件和这篇文章放在同一个目录里，可以直接查看或下载：&lt;a class="link" href="install-docker-traefik.sh" >install-docker-traefik.sh&lt;/a>。&lt;/p>
&lt;h2 id="适用场景">适用场景
&lt;/h2>&lt;p>适合这些情况：&lt;/p>
&lt;ul>
&lt;li>一台新的 Ubuntu/Debian 云服务器。&lt;/li>
&lt;li>准备用 Docker Compose 部署多个站点或服务。&lt;/li>
&lt;li>想用 Traefik 统一管理 &lt;code>80&lt;/code>、&lt;code>443&lt;/code> 入口。&lt;/li>
&lt;li>不想再为每个应用单独写 Nginx 配置。&lt;/li>
&lt;/ul>
&lt;p>不适合这些情况：&lt;/p>
&lt;ul>
&lt;li>已经使用 Kubernetes Ingress。&lt;/li>
&lt;li>已经由 1Panel、Coolify、Dokploy 等平台完整接管反向代理。&lt;/li>
&lt;li>需要复杂的企业级网关策略，比如多租户权限、统一认证、灰度发布等。&lt;/li>
&lt;/ul>
&lt;h2 id="快速运行">快速运行
&lt;/h2>&lt;p>如果只是安装 Docker 和 Traefik，不需要立即配置 HTTPS：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">chmod +x install-docker-traefik.sh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">./install-docker-traefik.sh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果要给真实网站签发 Let&amp;rsquo;s Encrypt 证书，建议填写 &lt;code>ACME_EMAIL&lt;/code>（&lt;strong>必须是真实邮箱&lt;/strong>，脚本会拒绝 &lt;code>you@example.com&lt;/code> 这类占位值，Let&amp;rsquo;s Encrypt 也只会用占位邮箱会让证书一直申请失败）：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">ACME_EMAIL&lt;/span>&lt;span class="o">=&lt;/span>you@your-domain.com ./install-docker-traefik.sh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>脚本会把 Traefik 配置写到：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">/opt/traefik
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Dashboard 默认只监听服务器本机：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">http://127.0.0.1:8080/dashboard/
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>远程查看可以用 SSH 端口转发：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">ssh -L 8080:127.0.0.1:8080 user@server
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="参数说明">参数说明
&lt;/h2>&lt;p>常用环境变量如下：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>变量&lt;/th>
&lt;th>默认值&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>TRAEFIK_DIR&lt;/code>&lt;/td>
&lt;td>&lt;code>/opt/traefik&lt;/code>&lt;/td>
&lt;td>Traefik 配置目录&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>TRAEFIK_NETWORK&lt;/code>&lt;/td>
&lt;td>&lt;code>traefik&lt;/code>&lt;/td>
&lt;td>公共 Docker 网络名&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>TRAEFIK_IMAGE&lt;/code>&lt;/td>
&lt;td>&lt;code>traefik:v3.7&lt;/code>&lt;/td>
&lt;td>Traefik 镜像版本&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>ACME_EMAIL&lt;/code>&lt;/td>
&lt;td>空&lt;/td>
&lt;td>Let&amp;rsquo;s Encrypt 邮箱，不填则不启用自动 HTTPS&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>ENABLE_HTTPS_REDIRECT&lt;/code>&lt;/td>
&lt;td>自动判断&lt;/td>
&lt;td>填了 &lt;code>ACME_EMAIL&lt;/code> 时默认开启 HTTP 到 HTTPS 跳转&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>INSTALL_SAMPLE&lt;/code>&lt;/td>
&lt;td>&lt;code>false&lt;/code>&lt;/td>
&lt;td>是否启动 &lt;code>whoami&lt;/code> 测试服务&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>WHOAMI_HOST&lt;/code>&lt;/td>
&lt;td>&lt;code>whoami.localhost&lt;/code>&lt;/td>
&lt;td>只给测试服务使用，不是你的真实网站域名&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;code>ACME_EMAIL&lt;/code> 可以不填。不填时，脚本仍然会安装 Docker 和 Traefik，但不会配置 Let&amp;rsquo;s Encrypt 证书解析器。&lt;/p>
&lt;p>&lt;code>WHOAMI_HOST&lt;/code> 也可以不填。它只在 &lt;code>INSTALL_SAMPLE=true&lt;/code> 时用于测试服务，真实网站应该在自己的 &lt;code>docker-compose.yml&lt;/code> 里配置 Traefik labels。&lt;/p>
&lt;h2 id="真实网站接入方式">真实网站接入方式
&lt;/h2>&lt;p>真实网站容器需要加入同一个 Traefik 网络：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">traefik&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">external&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>然后给 Web 服务加 labels：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">services&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">site&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">your-site-image&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">restart&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">unless-stopped&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">traefik&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">labels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.enable=true&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.routers.site.rule=Host(`example.com`)&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.routers.site.entrypoints=websecure&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.routers.site.tls=true&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.routers.site.tls.certresolver=letsencrypt&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.services.site.loadbalancer.server.port=80&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">traefik&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">external&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这里的 &lt;code>example.com&lt;/code> 要替换成真实域名，并且 DNS 需要提前解析到这台服务器 IP。服务器安全组或防火墙也要放行 &lt;code>80&lt;/code> 和 &lt;code>443&lt;/code>。&lt;/p>
&lt;h2 id="后续如何做-cd">后续如何做 CD
&lt;/h2>&lt;p>这个脚本只解决服务器入口层：安装 Docker、启动 Traefik、准备公共网络。它不会负责“代码变了以后怎么自动发布”。真正的 CD 需要额外建立一条发布链路：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">push 代码
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> -&amp;gt; CI/CD 平台构建 Docker 镜像
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> -&amp;gt; 推送镜像到镜像仓库
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> -&amp;gt; SSH 到服务器
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> -&amp;gt; 更新应用 compose 的镜像 tag
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> -&amp;gt; docker compose pull &amp;amp;&amp;amp; docker compose up -d
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> -&amp;gt; Traefik 根据 labels 接管流量
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这里用 GitHub Actions 举例，但思路对 GitLab CI、Woodpecker CI、Gitea Actions 也一样。Traefik 不关心你用哪个 CI/CD 平台，它只关心最终跑起来的容器是否在同一个 Docker 网络里，并且有没有正确的 labels。&lt;/p>
&lt;h3 id="一每个项目准备自己的镜像">一、每个项目准备自己的镜像
&lt;/h3>&lt;p>每个要部署的项目都应该能被构建成一个 Docker 镜像。不同技术栈的 &lt;code>Dockerfile&lt;/code> 不一样，但对 Traefik 来说只需要满足两点：&lt;/p>
&lt;ol>
&lt;li>容器内部有一个 HTTP 服务端口，比如 &lt;code>80&lt;/code>、&lt;code>3000&lt;/code>、&lt;code>8080&lt;/code>。&lt;/li>
&lt;li>不要直接把业务容器的端口暴露到公网，公网入口交给 Traefik。&lt;/li>
&lt;/ol>
&lt;p>如果是静态站点，可以用 Nginx 承载构建产物：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-dockerfile" data-lang="dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="k">FROM&lt;/span>&lt;span class="s"> nginx:alpine&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> public /usr/share/nginx/html&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果是 Node、Python、Go、Java 后端，则按对应技术栈构建镜像，只要最后服务监听一个明确端口即可。&lt;/p>
&lt;h3 id="二服务器上每个项目一个目录">二、服务器上每个项目一个目录
&lt;/h3>&lt;p>建议每个应用单独放到 &lt;code>/opt/apps/&amp;lt;app-name&amp;gt;&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">sudo mkdir -p /opt/apps/my-app
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> /opt/apps/my-app
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="组织方案选择">组织方案选择
&lt;/h4>&lt;p>每个项目目录里至少需要 &lt;code>.env&lt;/code>（存放部署变量）和 &lt;code>docker-compose.yml&lt;/code>（定义容器运行方式）。这两者的关系有几种组织方式：&lt;/p>
&lt;p>&lt;strong>方案 A：compose 文件直接放在项目目录（默认）&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">/opt/apps/my-app/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── .env
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── docker-compose.yml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>简单直观，适合 compose 文件不常变更的项目。&lt;/p>
&lt;p>&lt;strong>方案 B：compose 文件集中管理&lt;/strong>&lt;/p>
&lt;p>如果多个项目的 compose 模板相似，想统一维护，可以把 compose 文件放到共享目录：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">/opt/compose-templates/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── traefik-app.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── static-site.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/opt/apps/my-app/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── .env
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>部署时用 &lt;code>-f&lt;/code> 指定模板路径：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">docker compose -f /opt/compose-templates/traefik-app.yml --env-file /opt/apps/my-app/.env up -d
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>CD 流水线里也这样写，每次更新 compose 模板时只需要改 &lt;code>/opt/compose-templates/&lt;/code> 下的文件。&lt;/p>
&lt;p>&lt;strong>方案 C：用脚本封装&lt;/strong>&lt;/p>
&lt;p>在项目目录下放一个启动脚本，把模板路径写死在脚本里：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="c1"># /opt/apps/my-app/deploy.sh&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> /opt/compose-templates
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">docker compose -f traefik-app.yml --env-file /opt/apps/my-app/.env &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$@&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这样部署命令变成：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">/opt/apps/my-app/deploy.sh up -d
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">./deploy.sh logs -f
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>脚本本身也可以加入检查、重试、通知等逻辑，适合有统一运维规范的项目。&lt;/p>
&lt;p>&lt;strong>方案 D：用 git 仓库管理 compose 文件&lt;/strong>&lt;/p>
&lt;p>如果 CD 流水线已经配好了 SSH 密钥，服务器可以直接用 git 操作。只需要 clone 一次，之后 CD 时 &lt;code>git pull&lt;/code> 拉取最新配置：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git clone git@github.com:your-org/server-configs.git /opt/configs
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>目录结构：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">/opt/configs/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── compose.yml # git 管理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── .env.example # 提交 git，真实值在服务器上配置
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/opt/apps/my-app/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── .env # 不提交 git，只存在服务器
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>CD 部署时：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> /opt/configs &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> git pull &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> /opt/apps/my-app &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> docker compose -f /opt/configs/compose.yml --env-file .env up -d
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>.env&lt;/code> 里的密钥留在服务器本地，不进 git 仓库。compose 文件由 git 管理，可以 review 和回滚。&lt;/p>
&lt;p>&lt;strong>怎么选&lt;/strong>：如果 compose 模板基本固定、很少改，用默认的方案 A 就行。如果想统一管理模板、减少每个项目重复的 compose 内容，选方案 B 或 C。如果需要多人协作、版本控制和 PR review，选方案 D。&lt;/p>
&lt;p>下面以方案 A 为例继续说明。如果选了其他方案，记得相应调整后面的路径和命令。&lt;/p>
&lt;p>&lt;code>.env&lt;/code> 只放部署层变量：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">APP_IMAGE&lt;/span>&lt;span class="o">=&lt;/span>ghcr.io/your-org/my-app:initial
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">APP_HOST&lt;/span>&lt;span class="o">=&lt;/span>app.example.com
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">APP_PORT&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">3000&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>docker-compose.yml&lt;/code> 写成通用模板：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">services&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">app&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${APP_IMAGE}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">restart&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">unless-stopped&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">traefik&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">expose&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;${APP_PORT}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">labels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.enable=true&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.routers.my-app.rule=Host(`${APP_HOST}`)&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.routers.my-app.entrypoints=websecure&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.routers.my-app.tls=true&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.routers.my-app.tls.certresolver=letsencrypt&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.services.my-app.loadbalancer.server.port=${APP_PORT}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">traefik&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">external&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这里没有写 &lt;code>ports&lt;/code>。业务容器不需要直接占用宿主机端口，Traefik 会通过 &lt;code>traefik&lt;/code> 网络访问容器内部端口。&lt;/p>
&lt;p>如果你的 Traefik 没有启用 Let&amp;rsquo;s Encrypt，可以先用 HTTP：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">labels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.enable=true&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.routers.my-app.rule=Host(`${APP_HOST}`)&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.routers.my-app.entrypoints=web&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.services.my-app.loadbalancer.server.port=${APP_PORT}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>真实项目的数据库密码、API key 等运行时环境变量，建议放在另一个只存在服务器上的文件，例如 &lt;code>app.env&lt;/code>，然后在 compose 里引用：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">env_file&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">app.env&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>CD 流水线只更新 &lt;code>.env&lt;/code> 里的 &lt;code>APP_IMAGE&lt;/code>，不要覆盖服务器上的业务密钥文件。&lt;/p>
&lt;h3 id="三准备部署用户和-ssh-key">三、准备部署用户和 SSH key
&lt;/h3>&lt;p>生产环境建议创建专门的部署用户，不要长期用 &lt;code>root&lt;/code> 跑 CD：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">sudo adduser --disabled-password --gecos &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span> deploy
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo usermod -aG docker deploy
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>加入 &lt;code>docker&lt;/code> 组后，需要重新登录这个用户，组权限才会生效。&lt;/p>
&lt;p>生成一把专门给 CD 用的 SSH key：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">ssh-keygen -t ed25519 -C &lt;span class="s2">&amp;#34;cd-my-app&amp;#34;&lt;/span> -f ./cd-my-app -N &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>公钥放到服务器：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">sudo install -d -m &lt;span class="m">700&lt;/span> -o deploy -g deploy /home/deploy/.ssh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cat ./cd-my-app.pub &lt;span class="p">|&lt;/span> sudo tee -a /home/deploy/.ssh/authorized_keys
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo chmod &lt;span class="m">600&lt;/span> /home/deploy/.ssh/authorized_keys
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo chown -R deploy:deploy /home/deploy/.ssh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>私钥内容放到 CI/CD 平台的 Secret 里。以 GitHub Actions 为例，进入：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">Repository -&amp;gt; Settings -&amp;gt; Secrets and variables -&amp;gt; Actions
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>添加：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">SERVER_HOST 服务器 IP 或域名
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">SERVER_USER deploy
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">SERVER_SSH_KEY cd-my-app 私钥完整内容
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>注意：私钥不要提交到 Git 仓库。公钥留在服务器的 &lt;code>authorized_keys&lt;/code>，私钥只放 CI/CD Secret。&lt;/p>
&lt;h3 id="四准备镜像仓库">四、准备镜像仓库
&lt;/h3>&lt;p>镜像仓库可以用 GitHub Container Registry、Docker Hub、Harbor、阿里云/腾讯云镜像仓库等。通用原则是：&lt;/p>
&lt;ul>
&lt;li>CI/CD 需要有 &lt;code>push&lt;/code> 权限，用来推送新镜像。&lt;/li>
&lt;li>服务器需要有 &lt;code>pull&lt;/code> 权限，用来拉取新镜像。&lt;/li>
&lt;li>CD 部署时尽量使用不可变 tag，例如 Git commit SHA。&lt;/li>
&lt;li>&lt;code>latest&lt;/code> 可以保留给人工查看，但不要只依赖 &lt;code>latest&lt;/code> 做生产发布。&lt;/li>
&lt;/ul>
&lt;p>如果使用私有镜像，先在服务器上用部署用户登录一次：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">sudo -iu deploy
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;你的镜像仓库 token&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span> docker login ghcr.io -u your-user --password-stdin
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>登录信息会保存在部署用户自己的 Docker 配置里。之后 CD 执行 &lt;code>docker compose pull&lt;/code> 时，就能拉取私有镜像。&lt;/p>
&lt;h3 id="五github-actions-通用-cd-模板">五、GitHub Actions 通用 CD 模板
&lt;/h3>&lt;p>下面这个模板做三件事：&lt;/p>
&lt;ol>
&lt;li>构建镜像。&lt;/li>
&lt;li>推送 &lt;code>latest&lt;/code> 和当前 commit SHA 两个 tag。&lt;/li>
&lt;li>SSH 到服务器，把 &lt;code>.env&lt;/code> 里的 &lt;code>APP_IMAGE&lt;/code> 改成当前 commit SHA 对应的镜像，然后重启应用。&lt;/li>
&lt;/ol>
&lt;p>保存为：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">.github/workflows/cd.yml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">CD&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">push&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">workflow_dispatch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">permissions&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">contents&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">read&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">packages&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">write&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">env&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">REGISTRY_HOST&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ghcr.io&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">IMAGE_NAME&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ghcr.io/your-org/my-app&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">APP_DIR&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">/opt/apps/my-app&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">deploy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ubuntu-latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Checkout&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/checkout@v6&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Set up Docker Buildx&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">docker/setup-buildx-action@v4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Login to registry&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">docker/login-action@v4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">registry&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ env.REGISTRY_HOST }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">username&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ secrets.REGISTRY_USERNAME }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">password&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ secrets.REGISTRY_TOKEN }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Build and push image&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">docker/build-push-action@v7&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">context&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">.&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">push&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tags&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">|&lt;/span>&lt;span class="sd">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> ${{ env.IMAGE_NAME }}:${{ github.sha }}
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> ${{ env.IMAGE_NAME }}:latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Deploy on server&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">env&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">SERVER_HOST&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ secrets.SERVER_HOST }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">SERVER_USER&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ secrets.SERVER_USER }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">SERVER_SSH_KEY&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ secrets.SERVER_SSH_KEY }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">IMAGE&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ env.IMAGE_NAME }}:${{ github.sha }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">|&lt;/span>&lt;span class="sd">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> mkdir -p ~/.ssh
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> printf &amp;#39;%s\n&amp;#39; &amp;#34;$SERVER_SSH_KEY&amp;#34; &amp;gt; ~/.ssh/deploy_key
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> chmod 600 ~/.ssh/deploy_key
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> ssh-keyscan -H &amp;#34;$SERVER_HOST&amp;#34; &amp;gt;&amp;gt; ~/.ssh/known_hosts
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> ssh -i ~/.ssh/deploy_key &amp;#34;$SERVER_USER@$SERVER_HOST&amp;#34; \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> &amp;#34;cd &amp;#39;${APP_DIR}&amp;#39; &amp;amp;&amp;amp; \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> sed -i &amp;#39;s#^APP_IMAGE=.*#APP_IMAGE=${IMAGE}#&amp;#39; .env &amp;amp;&amp;amp; \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> docker compose pull &amp;amp;&amp;amp; \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> docker compose up -d --remove-orphans &amp;amp;&amp;amp; \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> docker image prune -f&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>对应需要在 GitHub Secrets 里添加：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">REGISTRY_USERNAME 镜像仓库用户名
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">REGISTRY_TOKEN 镜像仓库 token
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">SERVER_HOST 服务器 IP 或域名
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">SERVER_USER SSH 部署用户
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">SERVER_SSH_KEY SSH 私钥
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果使用 GitHub Container Registry，并且镜像属于当前仓库，构建推送阶段也可以用 &lt;code>${{ github.actor }}&lt;/code> 和 &lt;code>${{ secrets.GITHUB_TOKEN }}&lt;/code>。但服务器拉取私有镜像时，仍然需要能 &lt;code>pull&lt;/code> 该镜像的凭据，最清晰的做法是给服务器配置一份只读或低权限的 registry token。&lt;/p>
&lt;h3 id="六发布后检查和回滚">六、发布后检查和回滚
&lt;/h3>&lt;p>部署完成后，至少检查三处：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> /opt/apps/my-app
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">docker compose ps
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">docker compose logs -f
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">curl -I https://app.example.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果应用提供健康检查接口，可以在 workflow 里加一步：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">curl -fsS https://app.example.com/health
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>回滚的本质是把 &lt;code>APP_IMAGE&lt;/code> 改回旧镜像 tag：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> /opt/apps/my-app
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sed -i &lt;span class="s1">&amp;#39;s#^APP_IMAGE=.*#APP_IMAGE=ghcr.io/your-org/my-app:old-commit-sha#&amp;#39;&lt;/span> .env
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">docker compose pull
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">docker compose up -d --remove-orphans
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>所以每次发布都用 commit SHA 做镜像 tag 很重要。它让你能明确知道当前服务器运行的是哪一次代码，也能快速回到上一个可用版本。&lt;/p>
&lt;h3 id="七多项目部署约定">七、多项目部署约定
&lt;/h3>&lt;p>单台服务器跑多个项目时，建议保持这些约定：&lt;/p>
&lt;ul>
&lt;li>每个项目一个目录：&lt;code>/opt/apps/&amp;lt;app-name&amp;gt;&lt;/code>。&lt;/li>
&lt;li>每个项目一个 compose：只管理自己的业务容器。&lt;/li>
&lt;li>所有需要公网 HTTP/HTTPS 的服务都加入同一个 &lt;code>traefik&lt;/code> 网络。&lt;/li>
&lt;li>每个项目使用不同的 router/service 名称，例如 &lt;code>blog&lt;/code>、&lt;code>api&lt;/code>、&lt;code>admin&lt;/code>。&lt;/li>
&lt;li>每个项目只在 labels 里声明自己的域名和内部端口。&lt;/li>
&lt;li>CD 流水线只更新项目目录，不要改 &lt;code>/opt/traefik&lt;/code>。&lt;/li>
&lt;/ul>
&lt;p>这样 Traefik 是稳定的公共入口，业务项目各自独立发布。新增项目时，只需要新建项目目录、写自己的 compose、配置 DNS、接入一条 CD workflow。&lt;/p>
&lt;h2 id="完整脚本">完整脚本
&lt;/h2>&lt;p>完整脚本不再内嵌在正文里，避免博客内容和实际可执行文件不同步。脚本文件放在这篇文章同目录：&lt;a class="link" href="install-docker-traefik.sh" >install-docker-traefik.sh&lt;/a>。&lt;/p>
&lt;h2 id="运行后检查">运行后检查
&lt;/h2>&lt;p>查看 Traefik 容器：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">sudo docker compose --env-file /opt/traefik/.env -f /opt/traefik/docker-compose.yml ps
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>查看日志：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">sudo docker compose --env-file /opt/traefik/.env -f /opt/traefik/docker-compose.yml logs -f
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>测试服务可以这样启动（同样，&lt;code>ACME_EMAIL&lt;/code> 必须是真实邮箱）：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">ACME_EMAIL&lt;/span>&lt;span class="o">=&lt;/span>you@your-domain.com &lt;span class="nv">INSTALL_SAMPLE&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">true&lt;/span> &lt;span class="nv">WHOAMI_HOST&lt;/span>&lt;span class="o">=&lt;/span>whoami.example.com ./install-docker-traefik.sh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果 &lt;code>whoami.example.com&lt;/code> 能访问，说明 DNS、80/443、防火墙、Traefik 路由和证书申请基本都通了。&lt;/p>
&lt;h2 id="如果浏览器一直显示此网站的证书无效">如果浏览器一直显示&amp;quot;此网站的证书无效&amp;quot;
&lt;/h2>&lt;p>按本博客早期示例用过 &lt;code>ACME_EMAIL=admin@example.com&lt;/code> 之类占位邮箱的用户会撞到这个问题。Let&amp;rsquo;s Encrypt 静默拒绝占位邮箱，acme.json 一直不生成，Traefik 只能回落到自签证书。&lt;/p>
&lt;p>修法是直接把 &lt;code>traefik.yml&lt;/code> 里的 &lt;code>email:&lt;/code> 改成真实邮箱，不需要重装：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1) 把真实邮箱替换进 traefik.yml&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo sed -i &lt;span class="s1">&amp;#39;s#admin@example.com#you@your-domain.com#&amp;#39;&lt;/span> /opt/traefik/traefik.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># （如果之前是别的占位值，把 sed 第一个参数里的字面量对应替换）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2) 清掉任何残留的 acme.json，让 Traefik 重新申请&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo rm -f /opt/traefik/letsencrypt/acme.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo touch /opt/traefik/letsencrypt/acme.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo chmod &lt;span class="m">600&lt;/span> /opt/traefik/letsencrypt/acme.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3) 重启 Traefik，让它从第一个 HTTPS 请求开始走真正的 LE 申请&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> /opt/traefik &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> sudo docker compose restart traefik
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>修完后用下面命令验证证书已经换成真证书：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="p">|&lt;/span> openssl s_client -connect your-domain.com:443 -servername your-domain.com 2&amp;gt;/dev/null &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="p">|&lt;/span> openssl x509 -noout -issuer -subject -dates
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 应该看到 issuer 含 &amp;#34;Let&amp;#39;s Encrypt&amp;#34;，subject 是你的域名&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="注意事项">注意事项
&lt;/h2>&lt;ol>
&lt;li>脚本会按 Docker 官方安装方式添加 apt 仓库，并安装 &lt;code>docker-ce&lt;/code>、&lt;code>docker-ce-cli&lt;/code>、&lt;code>containerd.io&lt;/code>、&lt;code>docker-buildx-plugin&lt;/code>、&lt;code>docker-compose-plugin&lt;/code>。&lt;/li>
&lt;li>脚本会移除可能冲突的旧包，例如 &lt;code>docker.io&lt;/code>、旧版 &lt;code>docker-compose&lt;/code>、&lt;code>podman-docker&lt;/code>、&lt;code>containerd&lt;/code>、&lt;code>runc&lt;/code>。&lt;/li>
&lt;li>Traefik dashboard 使用 &lt;code>api.insecure: true&lt;/code>，但端口只绑定到 &lt;code>127.0.0.1:8080&lt;/code>，不要改成公网监听，除非你额外加认证。&lt;/li>
&lt;li>Traefik 通过只读方式挂载 &lt;code>/var/run/docker.sock&lt;/code>。这依然是高权限入口，生产环境要限制谁能创建带 Traefik labels 的容器。&lt;/li>
&lt;li>Let&amp;rsquo;s Encrypt HTTP challenge 需要 &lt;code>80&lt;/code> 端口能从公网访问，否则证书申请会失败。&lt;/li>
&lt;li>&lt;code>ACME_EMAIL&lt;/code> 必须是真实邮箱。脚本会拒绝 &lt;code>admin@example.com&lt;/code>、&lt;code>you@example.com&lt;/code>、&lt;code>*@example.com&lt;/code> 等占位值；不要被早期示例误导。&lt;/li>
&lt;/ol>
&lt;h2 id="参考">参考
&lt;/h2>&lt;ul>
&lt;li>&lt;a class="link" href="https://docs.docker.com/engine/install/ubuntu/" target="_blank" rel="noopener"
>Docker Engine Ubuntu 安装文档&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://docs.docker.com/engine/install/debian/" target="_blank" rel="noopener"
>Docker Engine Debian 安装文档&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://doc.traefik.io/traefik/providers/docker/" target="_blank" rel="noopener"
>Traefik Docker provider 文档&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://hub.docker.com/_/traefik" target="_blank" rel="noopener"
>Traefik Docker 官方镜像&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://docs.github.com/en/actions/tutorials/publish-packages/publish-docker-images" target="_blank" rel="noopener"
>GitHub Actions 发布 Docker 镜像&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://docs.github.com/en/actions/concepts/security/secrets" target="_blank" rel="noopener"
>GitHub Actions Secrets&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://docs.docker.com/guides/gha/" target="_blank" rel="noopener"
>Docker 的 GitHub Actions 指南&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Woodpecker CI 使用教程</title><link>https://www.zata.cc/p/woodpecker-ci-%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</link><pubDate>Sun, 07 Jun 2026 10:00:00 +0800</pubDate><guid>https://www.zata.cc/p/woodpecker-ci-%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</guid><description>&lt;img src="https://www.zata.cc/p/woodpecker-ci-%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/index.png" alt="Featured image of post Woodpecker CI 使用教程" />&lt;p>Woodpecker CI 是一个开源、轻量、容器优先的 CI/CD 工具。它的定位很清晰：代码仓库发生 push、pull request、tag、手动触发等事件后，Woodpecker 读取仓库里的 YAML 配置，然后把每个步骤放进容器里执行。&lt;/p>
&lt;p>如果你已经熟悉 GitHub Actions，可以把 Woodpecker 理解成一个更偏自托管、更轻量、更贴近 Drone CI 风格的流水线系统。它不绑定某一家代码托管平台，可以接 GitHub、GitLab、Gitea、Forgejo、Bitbucket 等 forge，适合团队希望把 CI/CD 控制权放在自己服务器上的场景。&lt;/p>
&lt;hr>
&lt;h2 id="一如何安装-woodpecker-ci">一、如何安装 Woodpecker CI
&lt;/h2>&lt;p>第一次了解 Woodpecker CI，建议先用 Docker Compose 跑一个最小可用版本。先跑起来，再理解 pipeline、workflow、step 这些概念会更直观。&lt;/p>
&lt;p>下面以接入 GitHub 为例。如果你使用 Gitea、Forgejo 或 GitLab，整体步骤类似，只是 forge 相关环境变量不同。&lt;/p>
&lt;p>这篇教程优先写 Docker Compose，是因为它最适合单台服务器和第一次试用。如果你已经有 Kubernetes 集群，应该优先看本节后面的 Helm 安装方式，Helm Chart 也是官方提供的部署方式。&lt;/p>
&lt;h3 id="1-安装前准备">1. 安装前准备
&lt;/h3>&lt;p>你需要准备：&lt;/p>
&lt;ul>
&lt;li>一台已经安装 Docker 和 Docker Compose 的服务器。&lt;/li>
&lt;li>一个能访问 Woodpecker Web UI 的地址，例如 &lt;code>https://ci.example.com&lt;/code>。&lt;/li>
&lt;li>一个代码平台账号，例如 GitHub、GitLab、Gitea、Forgejo。&lt;/li>
&lt;li>目标仓库的管理员权限，因为 Woodpecker 需要创建 webhook。&lt;/li>
&lt;li>一个 Server 和 Agent 共享的随机密钥。&lt;/li>
&lt;/ul>
&lt;p>生成共享密钥：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">openssl rand -hex &lt;span class="m">32&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="2-创建-github-oauth-app">2. 创建 GitHub OAuth App
&lt;/h3>&lt;p>如果接 GitHub，需要在 GitHub 创建 OAuth App，不是 GitHub App。&lt;/p>
&lt;p>路径：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">GitHub -&amp;gt; Settings -&amp;gt; Developer settings -&amp;gt; OAuth Apps -&amp;gt; New OAuth App
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>关键配置：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">Homepage URL: https://ci.example.com
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Authorization callback URL: https://ci.example.com/authorize
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>创建完成后，记录：&lt;/p>
&lt;ul>
&lt;li>&lt;code>Client ID&lt;/code>&lt;/li>
&lt;li>&lt;code>Client Secret&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>它们会分别填到 &lt;code>WOODPECKER_GITHUB_CLIENT&lt;/code> 和 &lt;code>WOODPECKER_GITHUB_SECRET&lt;/code>。&lt;/p>
&lt;h3 id="3-编写-docker-composeyaml">3. 编写 docker-compose.yaml
&lt;/h3>&lt;p>创建一个目录，例如：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">mkdir -p /opt/woodpecker
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> /opt/woodpecker
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>写入 &lt;code>docker-compose.yaml&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">services&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">woodpecker-server&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">woodpeckerci/woodpecker-server:v3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">restart&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">always&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ports&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;8000:8000&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">woodpecker-server-data:/var/lib/woodpecker/&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_OPEN=true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_HOST=${WOODPECKER_HOST}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_GITHUB=true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_GITHUB_CLIENT=${WOODPECKER_GITHUB_CLIENT}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_GITHUB_SECRET=${WOODPECKER_GITHUB_SECRET}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">woodpecker-agent&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">woodpeckerci/woodpecker-agent:v3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">agent&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">restart&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">always&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">depends_on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">woodpecker-server&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">woodpecker-agent-config:/etc/woodpecker&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">/var/run/docker.sock:/var/run/docker.sock&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_SERVER=woodpecker-server:9000&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">woodpecker-server-data&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">woodpecker-agent-config&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="4-编写-env">4. 编写 .env
&lt;/h3>&lt;p>同目录创建 &lt;code>.env&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">WOODPECKER_HOST&lt;/span>&lt;span class="o">=&lt;/span>https://ci.example.com
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">WOODPECKER_GITHUB_CLIENT&lt;/span>&lt;span class="o">=&lt;/span>你的 GitHub OAuth App Client ID
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">WOODPECKER_GITHUB_SECRET&lt;/span>&lt;span class="o">=&lt;/span>你的 GitHub OAuth App Client Secret
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">WOODPECKER_AGENT_SECRET&lt;/span>&lt;span class="o">=&lt;/span>用 openssl rand -hex &lt;span class="m">32&lt;/span> 生成的随机字符串
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这里最容易写错的是 &lt;code>WOODPECKER_HOST&lt;/code>。它必须是浏览器和代码平台 webhook 都能访问到的 Woodpecker 外部地址，不要写成容器内地址，也不要在末尾加 &lt;code>/&lt;/code>。&lt;/p>
&lt;h3 id="5-启动服务">5. 启动服务
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">docker compose up -d
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">docker compose ps
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>查看日志：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">docker compose logs -f woodpecker-server
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">docker compose logs -f woodpecker-agent
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果一切正常，打开：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">https://ci.example.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>使用 GitHub 登录，然后在 Woodpecker UI 里启用你的仓库。&lt;/p>
&lt;h3 id="6-让仓库真正跑起来">6. 让仓库真正跑起来
&lt;/h3>&lt;p>Woodpecker 安装完成后，还需要在仓库里添加流水线配置。最小示例是：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">.woodpecker/build.yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">when&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">event&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">push&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">hello&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">alpine&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">echo &amp;#34;hello woodpecker&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>提交并 push 到 &lt;code>main&lt;/code> 后，Woodpecker 应该会收到 webhook 并开始执行 pipeline。&lt;/p>
&lt;h3 id="7-已有-dokploy--traefik不需要-nginx">7. 已有 Dokploy / Traefik：不需要 Nginx
&lt;/h3>&lt;p>如果你已经习惯用 Dokploy 配合 Traefik 快速部署应用，Woodpecker 并不会变难。Woodpecker 不自带 Traefik，但它可以像普通 Web 应用一样接入现有 Traefik 网关。&lt;/p>
&lt;p>如果服务器还没有安装 Docker 和 Traefik，可以先按这篇文章准备公共入口层：&lt;a class="link" href="https://www.zata.cc/p/docker-traefik-install-script/" >Docker 和 Traefik 一键安装脚本&lt;/a>。&lt;/p>
&lt;p>核心思路是：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">https://ci.example.com
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> |
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> v
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Traefik / Dokploy 网关
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> |
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> v
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">woodpecker-server:8000
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Agent 不需要从公网访问 &lt;code>https://ci.example.com&lt;/code>。如果 &lt;code>woodpecker-server&lt;/code> 和 &lt;code>woodpecker-agent&lt;/code> 在同一个 Docker Compose 项目里，Agent 直接用内部地址连接即可：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">WOODPECKER_SERVER=woodpecker-server:9000
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>也就是说，Traefik 只负责 Web UI、OAuth 回调、webhook 入口；Agent 和 Server 的 gRPC 通信可以留在 Docker 内部网络里。&lt;/p>
&lt;p>如果由 Dokploy UI 管理域名，通常只需要：&lt;/p>
&lt;ol>
&lt;li>用 Dokploy 创建一个 Docker Compose 应用。&lt;/li>
&lt;li>填入 Woodpecker 的 compose 配置。&lt;/li>
&lt;li>给 &lt;code>woodpecker-server&lt;/code> 配域名，例如 &lt;code>ci.example.com&lt;/code>。&lt;/li>
&lt;li>让 Dokploy 把外部 HTTPS 转发到容器内部端口 &lt;code>8000&lt;/code>。&lt;/li>
&lt;li>&lt;code>.env&lt;/code> 中保持 &lt;code>WOODPECKER_HOST=https://ci.example.com&lt;/code>。&lt;/li>
&lt;/ol>
&lt;p>如果你直接写 Traefik labels，可以把 &lt;code>woodpecker-server&lt;/code> 改成类似下面这样。网络名、证书 resolver、entrypoint 要替换成你现有 Traefik 的配置：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">services&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">woodpecker-server&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">woodpeckerci/woodpecker-server:v3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">restart&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">always&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">expose&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;8000&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">woodpecker-server-data:/var/lib/woodpecker/&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_OPEN=true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_HOST=${WOODPECKER_HOST}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_GITHUB=true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_GITHUB_CLIENT=${WOODPECKER_GITHUB_CLIENT}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_GITHUB_SECRET=${WOODPECKER_GITHUB_SECRET}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">labels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.enable=true&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.routers.woodpecker.rule=Host(`ci.example.com`)&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.routers.woodpecker.entrypoints=websecure&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.routers.woodpecker.tls.certresolver=letsencrypt&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;traefik.http.services.woodpecker.loadbalancer.server.port=8000&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">traefik-public&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">default&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">woodpecker-agent&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">woodpeckerci/woodpecker-agent:v3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">agent&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">restart&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">always&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">depends_on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">woodpecker-server&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">woodpecker-agent-config:/etc/woodpecker&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">/var/run/docker.sock:/var/run/docker.sock&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_SERVER=woodpecker-server:9000&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">woodpecker-server-data&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">woodpecker-agent-config&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">traefik-public&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">external&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>注意这里没有暴露：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">ports&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;8000:8000&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>因为公网入口已经由 Traefik 接管。只有在没有 Traefik、Nginx、Caddy、Dokploy 这类网关时，才需要把端口直接映射出来。&lt;/p>
&lt;h3 id="8-kubernetes-环境用-helm-安装">8. Kubernetes 环境：用 Helm 安装
&lt;/h3>&lt;p>如果你的基础设施已经是 Kubernetes，不需要用上面的 Docker Compose。Woodpecker 官方提供了 Helm Chart，可以直接安装：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">helm install woodpecker oci://ghcr.io/woodpecker-ci/helm/woodpecker --version &amp;lt;VERSION&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>实际使用时建议带上 namespace：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">helm install woodpecker oci://ghcr.io/woodpecker-ci/helm/woodpecker &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --version &amp;lt;VERSION&amp;gt; &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --namespace woodpecker &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --create-namespace
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这里的 &lt;code>&amp;lt;VERSION&amp;gt;&lt;/code> 是 Helm Chart 版本，不一定等于 Woodpecker Server 的应用版本。安装前可以到官方 Helm 仓库或 release 页面确认当前 chart 版本。&lt;/p>
&lt;p>生产环境通常会准备一个 &lt;code>values.yaml&lt;/code>，把域名、OAuth、持久化、Ingress 等配置写进去。例如：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">server&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">env&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">WOODPECKER_OPEN&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;true&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">WOODPECKER_HOST&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;https://ci.example.com&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">WOODPECKER_GITHUB&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;true&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">WOODPECKER_GITHUB_CLIENT&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;你的 GitHub OAuth App Client ID&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">WOODPECKER_GITHUB_SECRET&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;你的 GitHub OAuth App Client Secret&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">WOODPECKER_AGENT_SECRET&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;用 openssl rand -hex 32 生成的随机字符串&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ingress&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ingressClassName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">nginx&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hosts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">host&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ci.example.com&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">paths&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">/&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pathType&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Prefix&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">agent&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>然后执行：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">helm upgrade --install woodpecker oci://ghcr.io/woodpecker-ci/helm/woodpecker &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --version &amp;lt;VERSION&amp;gt; &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --namespace woodpecker &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --create-namespace &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -f values.yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>选择 Docker Compose 还是 Helm，可以这样判断：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>场景&lt;/th>
&lt;th>推荐方式&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>单台云服务器、先学习、先跑通&lt;/td>
&lt;td>Docker Compose&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>已经用 Dokploy / Traefik 管理应用域名&lt;/td>
&lt;td>Docker Compose + 现有 Traefik&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>已经有 Kubernetes 集群&lt;/td>
&lt;td>Helm&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>需要 Ingress、StorageClass、PodMonitor、RBAC 等 K8s 能力&lt;/td>
&lt;td>Helm&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>不熟悉 Kubernetes，只想给个人项目跑 CI&lt;/td>
&lt;td>Docker Compose&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Helm 不是更高级就一定更适合。它适合已经有 K8s 运维体系的团队；如果只是个人服务器或小团队单机部署，Docker Compose 反而更容易维护。&lt;/p>
&lt;h3 id="9-中国服务器注意事项">9. 中国服务器注意事项
&lt;/h3>&lt;p>如果服务器在中国大陆，安装本身没有特殊问题，但镜像和依赖源要提前规划：&lt;/p>
&lt;ul>
&lt;li>把 &lt;code>woodpeckerci/woodpecker-server:v3&lt;/code>、&lt;code>woodpeckerci/woodpecker-agent:v3&lt;/code> 同步到国内镜像仓库。&lt;/li>
&lt;li>如果使用 Helm，&lt;code>oci://ghcr.io/woodpecker-ci/helm/woodpecker&lt;/code> 也可能受 GHCR 网络影响，必要时提前准备代理或内部镜像/制品仓库。&lt;/li>
&lt;li>CI 里用到的 &lt;code>node&lt;/code>、&lt;code>python&lt;/code>、&lt;code>golang&lt;/code> 等基础镜像也尽量走私有仓库。&lt;/li>
&lt;li>npm、pip、Go modules 配置国内源。&lt;/li>
&lt;li>如果 GitHub webhook 到国内服务器不稳定，更推荐自建 Gitea、Forgejo 或 GitLab。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="二为什么关注-woodpecker-ci">二、为什么关注 Woodpecker CI
&lt;/h2>&lt;p>Woodpecker CI 值得了解的原因主要有几个：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>轻量&lt;/strong>：核心组件少，部署成本比很多完整 DevOps 平台低。&lt;/li>
&lt;li>&lt;strong>容器化&lt;/strong>：每个 step 都运行在指定镜像里，构建环境可复现。&lt;/li>
&lt;li>&lt;strong>自托管友好&lt;/strong>：CI 服务、构建 agent、数据都可以放在自己的机器上。&lt;/li>
&lt;li>&lt;strong>YAML 简洁&lt;/strong>：常见的 build、test、deploy 流水线写法很直观。&lt;/li>
&lt;li>&lt;strong>多代码平台支持&lt;/strong>：不是只能依赖 GitHub Actions 这一类平台内置 CI。&lt;/li>
&lt;/ol>
&lt;p>它比较适合下面这些场景：&lt;/p>
&lt;ul>
&lt;li>使用 Gitea、Forgejo、GitLab 自建代码平台，希望配一套轻量 CI。&lt;/li>
&lt;li>项目需要访问内网环境，不方便把构建任务放到公有云 CI。&lt;/li>
&lt;li>小团队想要一个足够简单、可维护、可迁移的 CI/CD 系统。&lt;/li>
&lt;li>已经用 Docker 管理构建、测试和部署环境。&lt;/li>
&lt;/ul>
&lt;p>不太适合的场景：&lt;/p>
&lt;ul>
&lt;li>团队已经深度依赖 GitHub Actions Marketplace 或 GitLab CI 生态。&lt;/li>
&lt;li>需要复杂的企业级权限、审计、合规工作流。&lt;/li>
&lt;li>不希望维护任何 CI 基础设施。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="三核心架构">三、核心架构
&lt;/h2>&lt;p>Woodpecker CI 主要由两个组件组成：&lt;/p>
&lt;h3 id="1-server">1. Server
&lt;/h3>&lt;p>Server 负责 Web UI、用户登录、仓库管理、webhook 接收、流水线调度、状态回写等事情。&lt;/p>
&lt;p>代码平台有新事件时，例如 push 到 &lt;code>main&lt;/code>，平台会通过 webhook 通知 Woodpecker Server。Server 找到对应仓库的流水线配置，然后创建 pipeline。&lt;/p>
&lt;h3 id="2-agent">2. Agent
&lt;/h3>&lt;p>Agent 负责真正执行流水线任务。它从 Server 接收任务，然后启动容器运行 step。&lt;/p>
&lt;p>如果使用 Docker 后端，Agent 通常需要访问宿主机 Docker daemon，所以部署时经常会看到：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">/var/run/docker.sock:/var/run/docker.sock&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这意味着 Agent 可以控制宿主机 Docker，权限很高。生产环境里要认真限制谁能修改 CI 配置、谁能拿到 secret、哪些仓库可以运行构建。&lt;/p>
&lt;h3 id="3-执行流程">3. 执行流程
&lt;/h3>&lt;p>一个典型流程是：&lt;/p>
&lt;ol>
&lt;li>开发者 push 代码到仓库。&lt;/li>
&lt;li>Git 平台通过 webhook 通知 Woodpecker。&lt;/li>
&lt;li>Woodpecker Server 拉取仓库配置。&lt;/li>
&lt;li>Server 创建 pipeline，并分配给 Agent。&lt;/li>
&lt;li>Agent clone 代码，按 YAML 定义依次运行 step。&lt;/li>
&lt;li>每个 step 在独立容器里执行命令。&lt;/li>
&lt;li>Server 把成功或失败状态回写到代码平台。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="四基本概念">四、基本概念
&lt;/h2>&lt;h3 id="1-pipeline">1. Pipeline
&lt;/h3>&lt;p>Pipeline 是一次完整的 CI/CD 执行，例如某次 push 触发的一轮构建。&lt;/p>
&lt;h3 id="2-workflow">2. Workflow
&lt;/h3>&lt;p>一个 pipeline 至少包含一个 workflow。workflow 是一组共享同一个 workspace 的 step。最简单的配置可以写在 &lt;code>.woodpecker.yaml&lt;/code>，也可以把多个 workflow 拆成 &lt;code>.woodpecker/&lt;/code> 目录下的多个 YAML 文件。&lt;/p>
&lt;p>例如：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">.woodpecker/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> lint.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> test.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> deploy.yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Woodpecker 会把这些文件识别成多个 workflow。多个 workflow 可以并行执行，也可以通过 &lt;code>depends_on&lt;/code> 建立依赖。&lt;/p>
&lt;h3 id="3-step">3. Step
&lt;/h3>&lt;p>Step 是 workflow 里的一个执行单元。每个 step 指定一个镜像，然后在容器里运行命令。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">node:22&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm ci&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="4-plugin">4. Plugin
&lt;/h3>&lt;p>Plugin 本质上也是容器镜像，只是它把常见任务封装好了，例如上传文件、构建镜像、发送通知等。使用 plugin 时一般通过 &lt;code>settings&lt;/code> 传参。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">upload&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">woodpeckerci/plugin-s3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">settings&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">bucket&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">my-bucket&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">source&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">public/**/*&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">target&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">/site/&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">secret_key&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">from_secret&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">aws_secret_key&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="五创建第一条流水线">五、创建第一条流水线
&lt;/h2>&lt;p>在项目根目录创建：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">.woodpecker/build.yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>写入：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">when&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">event&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">push&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">install&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">node:22&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm ci&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">node:22&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">node:22&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm run build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这条流水线的含义：&lt;/p>
&lt;ul>
&lt;li>只有 push 到 &lt;code>main&lt;/code> 分支才运行。&lt;/li>
&lt;li>使用 &lt;code>node:22&lt;/code> 镜像作为执行环境。&lt;/li>
&lt;li>依次执行安装依赖、测试、构建。&lt;/li>
&lt;li>任意命令返回非 0 状态码，后续 step 默认不会继续执行，workflow 标记失败。&lt;/li>
&lt;/ul>
&lt;p>如果项目是 Python：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">when&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">event&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="l">push, pull_request]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">python:3.12&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">pip install -r requirements.txt&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">pytest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果项目是 Go：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">when&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">event&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="l">push, pull_request]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">golang:1.23&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">go test ./...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="六条件执行">六、条件执行
&lt;/h2>&lt;p>Woodpecker 使用 &lt;code>when&lt;/code> 控制 workflow 或 step 在什么情况下执行。&lt;/p>
&lt;h3 id="1-只在-main-分支执行">1. 只在 main 分支执行
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">when&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">event&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">push&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="2-tag-时发布">2. tag 时发布
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">release&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">alpine&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">echo &amp;#34;release version $CI_COMMIT_TAG&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">when&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">event&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">tag&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="3-pull-request-只跑测试不发布">3. pull request 只跑测试，不发布
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">node:22&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm ci&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">deploy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">alpine&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">./deploy.sh&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">when&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">event&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">push&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这个模式很重要：不要在 pull request 事件里暴露部署密钥，尤其是公开仓库。&lt;/p>
&lt;hr>
&lt;h2 id="七多个-workflow-的拆分">七、多个 workflow 的拆分
&lt;/h2>&lt;p>大型项目不建议把所有事情塞进一个 YAML。可以拆成：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">.woodpecker/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> lint.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> test.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> docker.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> deploy.yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>例如 &lt;code>.woodpecker/lint.yaml&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">lint&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">node:22&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm ci&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm run lint&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>.woodpecker/test.yaml&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">node:22&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm ci&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>.woodpecker/deploy.yaml&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">depends_on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">lint&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">when&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">event&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">push&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">deploy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">alpine&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">./deploy.sh&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这样做的好处：&lt;/p>
&lt;ul>
&lt;li>lint 和 test 可以更早反馈。&lt;/li>
&lt;li>不同 workflow 的状态可以分别回写到代码平台。&lt;/li>
&lt;li>workflow 可以并行跑，提升整体速度。&lt;/li>
&lt;li>deploy 明确依赖 lint 和 test 成功。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="八secret-管理">八、Secret 管理
&lt;/h2>&lt;p>CI/CD 经常要用密钥，例如 Docker registry 密码、SSH 私钥、云服务 token。不要把这些值写进仓库 YAML。&lt;/p>
&lt;p>Woodpecker 的 secret 可以通过 UI 或 CLI 设置，然后在 YAML 中用 &lt;code>from_secret&lt;/code> 引用：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">deploy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">alpine&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">SSH_KEY&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">from_secret&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">production_ssh_key&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">mkdir -p ~/.ssh&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">echo &amp;#34;$SSH_KEY&amp;#34; &amp;gt; ~/.ssh/id_rsa&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">chmod 600 ~/.ssh/id_rsa&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">./deploy.sh&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>也可以传给 plugin：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">publish-image&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">woodpeckerci/plugin-docker-buildx&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">settings&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">repo&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">registry.example.com/my-app&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tags&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">username&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">from_secret&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">registry_username&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">password&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">from_secret&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">registry_password&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Secret 使用建议：&lt;/p>
&lt;ul>
&lt;li>不要在日志里 &lt;code>echo&lt;/code> secret。&lt;/li>
&lt;li>不要默认把 secret 暴露给 pull request。&lt;/li>
&lt;li>公开仓库尤其要警惕来自 fork 的 PR。&lt;/li>
&lt;li>为生产环境和测试环境使用不同 secret。&lt;/li>
&lt;li>定期轮换部署密钥。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="九常见流水线模板">九、常见流水线模板
&lt;/h2>&lt;h3 id="1-前端项目测试并构建">1. 前端项目：测试并构建
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">when&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">event&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="l">push, pull_request]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">node:22&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm ci&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm run lint&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm run build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="2-docker-镜像构建">2. Docker 镜像构建
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">when&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">event&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">push&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">docker&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">woodpeckerci/plugin-docker-buildx&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">settings&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">repo&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">registry.example.com/my-app&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tags&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">${CI_COMMIT_SHA}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">username&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">from_secret&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">registry_username&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">password&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">from_secret&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">registry_password&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="3-部署到服务器">3. 部署到服务器
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">depends_on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">when&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">event&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">push&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">deploy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">alpine:3.20&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">SSH_KEY&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">from_secret&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">production_ssh_key&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">DEPLOY_HOST&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">from_secret&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">production_host&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">commands&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">apk add --no-cache openssh-client&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">mkdir -p ~/.ssh&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">echo &amp;#34;$SSH_KEY&amp;#34; &amp;gt; ~/.ssh/id_rsa&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">chmod 600 ~/.ssh/id_rsa&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">ssh -o StrictHostKeyChecking=no &amp;#34;$DEPLOY_HOST&amp;#34; &amp;#34;cd /opt/app &amp;amp;&amp;amp; docker compose pull &amp;amp;&amp;amp; docker compose up -d&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这个例子能跑通，但生产中建议更严谨：&lt;/p>
&lt;ul>
&lt;li>不要长期关闭 &lt;code>StrictHostKeyChecking&lt;/code>。&lt;/li>
&lt;li>使用最小权限部署用户。&lt;/li>
&lt;li>服务器端只允许执行必要命令。&lt;/li>
&lt;li>部署前保留当前版本，方便回滚。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="十和-github-actions-的区别">十、和 GitHub Actions 的区别
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>对比项&lt;/th>
&lt;th>Woodpecker CI&lt;/th>
&lt;th>GitHub Actions&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>部署方式&lt;/td>
&lt;td>主要面向自托管&lt;/td>
&lt;td>GitHub 托管为主，也支持 self-hosted runner&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>代码平台&lt;/td>
&lt;td>可接多种 forge&lt;/td>
&lt;td>深度绑定 GitHub&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>执行模型&lt;/td>
&lt;td>step 基于容器镜像&lt;/td>
&lt;td>action + shell + runner 环境&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>配置风格&lt;/td>
&lt;td>简洁，接近 Drone CI&lt;/td>
&lt;td>功能丰富，语法更庞大&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>生态&lt;/td>
&lt;td>插件生态较小&lt;/td>
&lt;td>Marketplace 很大&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>适合场景&lt;/td>
&lt;td>自建 Git、内网部署、轻量 CI&lt;/td>
&lt;td>GitHub 项目、丰富第三方 action、托管 CI&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>简单判断：&lt;/p>
&lt;ul>
&lt;li>你的代码主要放 GitHub，并且不想维护 CI 服务器：优先 GitHub Actions。&lt;/li>
&lt;li>你在用 Gitea/Forgejo，或者需要内网自托管：Woodpecker CI 很值得试。&lt;/li>
&lt;li>你希望 CI 配置尽量贴近容器和 shell：Woodpecker CI 的心智负担较低。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="十一生产使用建议">十一、生产使用建议
&lt;/h2>&lt;h3 id="1-给-ci-单独准备机器">1. 给 CI 单独准备机器
&lt;/h3>&lt;p>不要把 Woodpecker Agent 随便放在核心业务机器上。Agent 需要运行不可信代码，尤其在多人协作或开源仓库里，风险很高。&lt;/p>
&lt;h3 id="2-限制仓库和用户权限">2. 限制仓库和用户权限
&lt;/h3>&lt;p>谁能启用仓库、谁能改 &lt;code>.woodpecker/&lt;/code> 配置、谁能读取 secret，都要明确。&lt;/p>
&lt;h3 id="3-注意-docker-socket-风险">3. 注意 Docker socket 风险
&lt;/h3>&lt;p>挂载 &lt;code>/var/run/docker.sock&lt;/code> 等于让 Agent 拥有很高的宿主机控制能力。能不用特权就不用特权，能隔离 agent 就隔离 agent。&lt;/p>
&lt;h3 id="4-持久化和备份数据">4. 持久化和备份数据
&lt;/h3>&lt;p>Server 数据目录里包含用户、仓库、流水线等信息。Docker Compose 部署时要持久化 &lt;code>/var/lib/woodpecker/&lt;/code>，并做定期备份。&lt;/p>
&lt;h3 id="5-使用-https">5. 使用 HTTPS
&lt;/h3>&lt;p>&lt;code>WOODPECKER_HOST&lt;/code> 建议配置成 HTTPS 地址。已有 Dokploy、Traefik、Caddy、Nginx 或云平台网关时，直接复用现有网关即可，不需要为了 Woodpecker 额外改用 Nginx。&lt;/p>
&lt;h3 id="6-把流水线当代码审查">6. 把流水线当代码审查
&lt;/h3>&lt;p>&lt;code>.woodpecker/&lt;/code> 下的 YAML 能决定 CI 机器执行什么命令。它应该像业务代码一样经过 review。&lt;/p>
&lt;hr>
&lt;h2 id="十二排查问题的思路">十二、排查问题的思路
&lt;/h2>&lt;h3 id="1-仓库没有触发流水线">1. 仓库没有触发流水线
&lt;/h3>&lt;p>检查：&lt;/p>
&lt;ul>
&lt;li>仓库是否已在 Woodpecker UI 中启用。&lt;/li>
&lt;li>当前用户是否有仓库 admin 权限。&lt;/li>
&lt;li>代码平台 webhook 是否创建成功。&lt;/li>
&lt;li>&lt;code>.woodpecker.yaml&lt;/code> 或 &lt;code>.woodpecker/*.yaml&lt;/code> 路径是否正确。&lt;/li>
&lt;li>&lt;code>when&lt;/code> 条件是否把事件过滤掉了。&lt;/li>
&lt;/ul>
&lt;h3 id="2-agent-不执行任务">2. Agent 不执行任务
&lt;/h3>&lt;p>检查：&lt;/p>
&lt;ul>
&lt;li>&lt;code>woodpecker-agent&lt;/code> 容器是否在运行。&lt;/li>
&lt;li>&lt;code>WOODPECKER_SERVER&lt;/code> 是否能访问。&lt;/li>
&lt;li>&lt;code>WOODPECKER_AGENT_SECRET&lt;/code> 是否和 Server 一致。&lt;/li>
&lt;li>gRPC 端口是否被网络或反向代理挡住。&lt;/li>
&lt;li>Docker socket 是否挂载成功。&lt;/li>
&lt;/ul>
&lt;h3 id="3-step-找不到文件">3. step 找不到文件
&lt;/h3>&lt;p>检查：&lt;/p>
&lt;ul>
&lt;li>文件是否在仓库里。&lt;/li>
&lt;li>前一个 step 生成的文件是否写在 workspace 内。&lt;/li>
&lt;li>多 workflow 之间不共享 workspace，只有同一个 workflow 内的 step 共享。&lt;/li>
&lt;/ul>
&lt;h3 id="4-secret-为空">4. secret 为空
&lt;/h3>&lt;p>检查：&lt;/p>
&lt;ul>
&lt;li>secret 名称是否和 &lt;code>from_secret&lt;/code> 一致。&lt;/li>
&lt;li>当前事件是否允许使用该 secret。&lt;/li>
&lt;li>pull request 是否被默认限制访问 secret。&lt;/li>
&lt;li>secret 是否被限制到某些 plugin 或 image。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="十三总结">十三、总结
&lt;/h2>&lt;p>Woodpecker CI 的核心价值是：用较少的组件，搭建一套可自托管、容器化、配置直观的 CI/CD 系统。&lt;/p>
&lt;p>学习它时可以按这个顺序：&lt;/p>
&lt;ol>
&lt;li>先用 Docker Compose 或 Helm 跑一个最小实例。&lt;/li>
&lt;li>在仓库里创建 &lt;code>.woodpecker/build.yaml&lt;/code>，确认 webhook 能触发 pipeline。&lt;/li>
&lt;li>再理解 Server、Agent、Pipeline、Workflow、Step 的关系。&lt;/li>
&lt;li>掌握 &lt;code>steps&lt;/code>、&lt;code>commands&lt;/code>、&lt;code>when&lt;/code>、&lt;code>depends_on&lt;/code>、&lt;code>from_secret&lt;/code>。&lt;/li>
&lt;li>逐步拆分 lint、test、build、deploy 多个 workflow。&lt;/li>
&lt;li>最后考虑生产环境的权限、安全、备份和 agent 隔离。&lt;/li>
&lt;/ol>
&lt;p>如果你维护的是自建 Git 平台，或者项目部署强依赖内网环境，Woodpecker CI 是一个很务实的选择。&lt;/p>
&lt;hr>
&lt;h2 id="参考资料">参考资料
&lt;/h2>&lt;ul>
&lt;li>&lt;a class="link" href="https://woodpecker-ci.org/docs/intro" target="_blank" rel="noopener"
>Woodpecker CI 官方文档&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://woodpecker-ci.org/docs/administration/installation/docker-compose" target="_blank" rel="noopener"
>Woodpecker CI Docker Compose 安装&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://woodpecker-ci.org/docs/administration/installation/helm-chart" target="_blank" rel="noopener"
>Woodpecker CI Helm Chart 安装&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://woodpecker-ci.org/docs/usage/workflow-syntax" target="_blank" rel="noopener"
>Woodpecker CI Workflow syntax&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://woodpecker-ci.org/docs/usage/workflows" target="_blank" rel="noopener"
>Woodpecker CI Workflows&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://woodpecker-ci.org/docs/usage/secrets" target="_blank" rel="noopener"
>Woodpecker CI Secrets&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>云原生可观测性：从"监控"到"洞察"的进化之路</title><link>https://www.zata.cc/p/%E4%BA%91%E5%8E%9F%E7%94%9F%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7%E4%BB%8E%E7%9B%91%E6%8E%A7%E5%88%B0%E6%B4%9E%E5%AF%9F%E7%9A%84%E8%BF%9B%E5%8C%96%E4%B9%8B%E8%B7%AF/</link><pubDate>Wed, 27 May 2026 10:00:00 +0800</pubDate><guid>https://www.zata.cc/p/%E4%BA%91%E5%8E%9F%E7%94%9F%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7%E4%BB%8E%E7%9B%91%E6%8E%A7%E5%88%B0%E6%B4%9E%E5%AF%9F%E7%9A%84%E8%BF%9B%E5%8C%96%E4%B9%8B%E8%B7%AF/</guid><description>&lt;img src="https://www.zata.cc/p/%E4%BA%91%E5%8E%9F%E7%94%9F%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7%E4%BB%8E%E7%9B%91%E6%8E%A7%E5%88%B0%E6%B4%9E%E5%AF%9F%E7%9A%84%E8%BF%9B%E5%8C%96%E4%B9%8B%E8%B7%AF/images/index/index.png" alt="Featured image of post 云原生可观测性：从"监控"到"洞察"的进化之路" />&lt;h2 id="一引言为什么传统监控不够用了">一、引言：为什么传统监控不够用了？
&lt;/h2>&lt;p>十年前，监控一台服务器很简单：CPU 超过 80%？告警。磁盘满了？告警。服务无响应？告警。这种基于阈值的黑盒监控在单体架构时代工作得很好。&lt;/p>
&lt;p>但在云原生时代，事情变得复杂了：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>微服务架构&lt;/strong>：一个请求可能穿越几十个服务，单点监控无法还原全链路&lt;/li>
&lt;li>&lt;strong>容器与 Kubernetes&lt;/strong>：Pod 随时创建和销毁，IP 不再固定，传统主机监控模型失效&lt;/li>
&lt;li>&lt;strong>动态扩缩容&lt;/strong>：基础设施本身在变化，静态阈值频繁误报&lt;/li>
&lt;li>&lt;strong>分布式与多租户&lt;/strong>：问题可能藏在任何一个角落，且相互影响&lt;/li>
&lt;/ul>
&lt;p>于是，业界提出了一个新的理念——&lt;strong>可观测性（Observability）&lt;/strong>。&lt;/p>
&lt;h2 id="二可观测性三大支柱metricslogstraces">二、可观测性三大支柱：Metrics、Logs、Traces
&lt;/h2>&lt;p>可观测性的核心思想来源于控制理论：&lt;strong>通过系统的外部输出，推断其内部状态&lt;/strong>。在云原生实践中，这三大输出被归纳为：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>支柱&lt;/th>
&lt;th>解决的问题&lt;/th>
&lt;th>典型工具&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Metrics（指标）&lt;/strong>&lt;/td>
&lt;td>&amp;ldquo;什么&amp;quot;出了问题？系统负载、错误率、延迟的量化趋势&lt;/td>
&lt;td>Prometheus、Grafana&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Logs（日志）&lt;/strong>&lt;/td>
&lt;td>&amp;ldquo;为什么&amp;quot;出问题？详细的上下文和错误信息&lt;/td>
&lt;td>ELK、Loki&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Traces（链路）&lt;/strong>&lt;/td>
&lt;td>&amp;ldquo;哪里&amp;quot;出了问题？请求在分布式系统中的完整路径&lt;/td>
&lt;td>Jaeger、Zipkin、SkyWalking&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;blockquote>
&lt;p>&lt;strong>关键洞察&lt;/strong>：这三者不是孤立的。一条慢请求（Trace）可能对应高 CPU（Metrics）和某条错误日志（Log）。真正的可观测性在于&lt;strong>将它们关联起来&lt;/strong>。&lt;/p>
&lt;/blockquote>
&lt;h2 id="三云原生可观测性技术栈全景">三、云原生可观测性技术栈全景
&lt;/h2>&lt;h3 id="31-指标监控prometheus--grafana">3.1 指标监控：Prometheus + Grafana
&lt;/h3>&lt;p>&lt;strong>Prometheus&lt;/strong> 已成为云原生指标的事实标准：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Pull 模型&lt;/strong>：主动抓取目标端点，天然适合动态环境&lt;/li>
&lt;li>&lt;strong>多维数据模型&lt;/strong>：&lt;code>http_requests_total{method=&amp;quot;POST&amp;quot;,status=&amp;quot;500&amp;quot;}&lt;/code>，支持灵活聚合&lt;/li>
&lt;li>&lt;strong>PromQL&lt;/strong>：强大的查询语言，适合告警和仪表盘&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-promql" data-lang="promql">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 过去5分钟内的95分位延迟&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kr">histogram_quantile&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="mf">0.95&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">sum&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="kr">rate&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="nv">http_request_duration_seconds_bucket&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s">5m&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">))&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">by&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="nv">le&lt;/span>&lt;span class="o">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Grafana&lt;/strong> 则提供了卓越的 visualization 能力，支持从多个数据源（Prometheus、Loki、Tempo、Elasticsearch）构建统一仪表盘。&lt;/p>
&lt;h3 id="32-日志管理从-elk-到-loki">3.2 日志管理：从 ELK 到 Loki
&lt;/h3>&lt;p>传统 ELK（Elasticsearch + Logstash + Kibana）功能强大，但在云原生场景下面临资源消耗高、索引管理复杂的问题。&lt;/p>
&lt;p>&lt;strong>Grafana Loki&lt;/strong> 提供了更云原生的方案：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>只索引标签，不索引日志内容&lt;/strong>：大幅降低存储成本&lt;/li>
&lt;li>&lt;strong>与 Prometheus 标签对齐&lt;/strong>：相同的 &lt;code>job&lt;/code>、&lt;code>instance&lt;/code> 标签让指标和日志天然关联&lt;/li>
&lt;li>&lt;strong>LogQL&lt;/strong>：类似 PromQL 的查询语法&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">{job=&amp;#34;api-gateway&amp;#34;} |= &amp;#34;error&amp;#34; | json | status_code=&amp;#34;500&amp;#34;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="33-分布式追踪opentelemetry-统一标准">3.3 分布式追踪：OpenTelemetry 统一标准
&lt;/h3>&lt;p>追踪曾经是&amp;quot;碎片化&amp;quot;的重灾区——Zipkin、Jaeger、SkyWalking 各有自己的 SDK 和数据格式。&lt;/p>
&lt;p>&lt;strong>OpenTelemetry（OTel）&lt;/strong> 的出现改变了这一切：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>统一标准&lt;/strong>：一个 SDK 同时产生 Metrics、Logs、Traces&lt;/li>
&lt;li>&lt;strong>自动埋点&lt;/strong>：Java Agent、Python 自动 instrument，低侵入接入&lt;/li>
&lt;li>&lt;strong>厂商无关&lt;/strong>：数据可导出到 Jaeger、Tempo、AWS X-Ray、Azure Monitor 等任意后端&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">opentelemetry&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">trace&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tracer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">trace&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_tracer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="vm">__name__&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">with&lt;/span> &lt;span class="n">tracer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">start_as_current_span&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;process_order&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">span&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">span&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">set_attribute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;order.id&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order_id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">span&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">set_attribute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;user.tier&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;premium&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 业务逻辑...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="34-告警与事件从噪声到信号">3.4 告警与事件：从噪声到信号
&lt;/h3>&lt;p>可观测性的终点不是收集数据，而是&lt;strong>在正确的时间通知正确的人&lt;/strong>。&lt;/p>
&lt;p>&lt;strong>Prometheus Alertmanager&lt;/strong> 提供了：&lt;/p>
&lt;ul>
&lt;li>分组（Grouping）：将相关告警合并，避免告警风暴&lt;/li>
&lt;li>抑制（Inhibition）：高优先级告警自动抑制低优先级&lt;/li>
&lt;li>静默（Silencing）：维护窗口临时静默&lt;/li>
&lt;/ul>
&lt;p>更进一步，&lt;strong>SLO（Service Level Objective）&lt;/strong> 驱动的告警正在成为最佳实践：&lt;/p>
&lt;blockquote>
&lt;p>不是&amp;quot;CPU &amp;gt; 80%&amp;quot;，而是&amp;quot;过去 30 天内，99.9% 的请求延迟 &amp;lt; 200ms&amp;rdquo;。&lt;/p>
&lt;/blockquote>
&lt;p>这种基于&lt;strong>用户视角&lt;/strong>的告警，更能反映业务健康度。&lt;/p>
&lt;h2 id="四可观测性进阶从三大支柱到统一关联">四、可观测性进阶：从三大支柱到统一关联
&lt;/h2>&lt;h3 id="41-关联一切exemplars">4.1 关联一切：Exemplars
&lt;/h3>&lt;p>&lt;strong>Exemplars&lt;/strong> 是 Prometheus 的一个强大特性：在指标 histogram 的某个 bucket 中，附带一个具体的 Trace ID。&lt;/p>
&lt;p>这意味着：你在 Grafana 上看到延迟 spike 时，可以直接点击，跳转到对应的分布式追踪。从&amp;quot;什么问题&amp;quot;到&amp;quot;具体哪次请求&amp;rdquo;，只需一次点击。&lt;/p>
&lt;h3 id="42-持续剖析ebpf-带来的新维度">4.2 持续剖析：eBPF 带来的新维度
&lt;/h3>&lt;p>&lt;strong>eBPF&lt;/strong> 让内核可编程，催生了新一代可观测性工具：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Pixie / Coroot&lt;/strong>：无需修改应用，自动采集 HTTP/gRPC/Redis 等协议指标&lt;/li>
&lt;li>&lt;strong>Parca / Pyroscope&lt;/strong>：持续 CPU Profiling，找出生产环境的性能热点&lt;/li>
&lt;li>&lt;strong>Falco&lt;/strong>：基于 eBPF 的运行时安全检测&lt;/li>
&lt;/ul>
&lt;p>eBPF 的核心价值：&lt;strong>零侵入、高性能、全栈可见&lt;/strong>。&lt;/p>
&lt;h3 id="43-成本治理可观测性不是越多越好">4.3 成本治理：可观测性不是越多越好
&lt;/h3>&lt;p>可观测性数据量巨大，成本可能失控：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>策略&lt;/th>
&lt;th>做法&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>采样（Sampling）&lt;/strong>&lt;/td>
&lt;td>对高频低价值的 trace 进行头部或尾部采样&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>降精度（Downsampling）&lt;/strong>&lt;/td>
&lt;td>历史指标从高精度聚合为低精度&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>分层存储&lt;/strong>&lt;/td>
&lt;td>热数据 SSD、温数据对象存储、冷数据归档&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>日志结构化&lt;/strong>&lt;/td>
&lt;td>减少无意义的 debug 日志，优先结构化字段&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="五实践建议构建你的可观测性体系">五、实践建议：构建你的可观测性体系
&lt;/h2>&lt;h3 id="51-渐进式路线图">5.1 渐进式路线图
&lt;/h3>&lt;p>&lt;strong>阶段一：可见（See）&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>部署 Prometheus + Grafana，覆盖核心服务的 RED 指标（Rate、Errors、Duration）&lt;/li>
&lt;li>接入 Loki 或现有日志系统&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>阶段二：关联（Correlate）&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>引入 OpenTelemetry，实现分布式追踪&lt;/li>
&lt;li>在 Grafana 中统一 Metrics、Logs、Traces 视图&lt;/li>
&lt;li>配置基于 SLO 的告警&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>阶段三：洞察（Understand）&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>引入 eBPF 进行持续剖析&lt;/li>
&lt;li>建立错误预算（Error Budget）机制&lt;/li>
&lt;li>AIOps：异常检测、根因分析、自动扩容&lt;/li>
&lt;/ul>
&lt;h3 id="52-关键设计原则">5.2 关键设计原则
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>默认接入，而非可选&lt;/strong>：新服务必须通过 Helm chart / Operator 自动接入可观测性&lt;/li>
&lt;li>&lt;strong>标签标准化&lt;/strong>：统一 &lt;code>service&lt;/code>、&lt;code>version&lt;/code>、&lt;code>environment&lt;/code>、&lt;code>team&lt;/code> 等标签&lt;/li>
&lt;li>&lt;strong>告警即代码&lt;/strong>：用 PrometheusRule 等 GitOps 方式管理告警规则&lt;/li>
&lt;li>&lt;strong>可观测性也是代码&lt;/strong>：Dashboard、告警规则纳入版本控制，Code Review&lt;/li>
&lt;/ol>
&lt;h2 id="六结语">六、结语
&lt;/h2>&lt;p>云原生可观测性的本质，是从&amp;quot;监控系统是否正常&amp;quot;进化到&amp;quot;理解系统为什么这样行为&amp;rdquo;。&lt;/p>
&lt;p>三大支柱提供了数据基础，OpenTelemetry 提供了统一标准，eBPF 打开了新的维度，而真正的价值在于&lt;strong>将这些数据关联起来，形成对分布式系统的深刻理解&lt;/strong>。&lt;/p>
&lt;p>在云原生世界里，&lt;strong>你不能管理你看不见的东西&lt;/strong>——而可观测性，就是让你看见一切的那束光。&lt;/p>
&lt;hr>
&lt;blockquote>
&lt;p>如果你正在构建云原生可观测性体系，建议从 Prometheus + Grafana + OpenTelemetry 这个&amp;quot;黄金组合&amp;quot;开始，逐步演进。记住：最好的可观测性，是让工程师在出问题后 5 分钟内找到根因。&lt;/p>
&lt;/blockquote></description></item><item><title>通用模板规范GeneralTemplateSpecifications</title><link>https://www.zata.cc/p/%E9%80%9A%E7%94%A8%E6%A8%A1%E6%9D%BF%E8%A7%84%E8%8C%83generaltemplatespecifications/</link><pubDate>Wed, 31 Dec 2025 07:03:54 +0800</pubDate><guid>https://www.zata.cc/p/%E9%80%9A%E7%94%A8%E6%A8%A1%E6%9D%BF%E8%A7%84%E8%8C%83generaltemplatespecifications/</guid><description>&lt;img src="https://www.zata.cc/p/%E9%80%9A%E7%94%A8%E6%A8%A1%E6%9D%BF%E8%A7%84%E8%8C%83generaltemplatespecifications/images/index/index.png" alt="Featured image of post 通用模板规范GeneralTemplateSpecifications" />&lt;h1 id="template">Template
&lt;/h1>&lt;h2 id="git-commit">git commit
&lt;/h2>&lt;p>Git commit 消息的格式有多种最佳实践，其中最流行和推荐的是 &lt;strong>Conventional Commits&lt;/strong>（约定式提交）规范。这是一种轻量级的规范，能让 commit 历史更清晰、可读性强，便于自动化生成 changelog、语义化版本号（SemVer）等。&lt;/p>
&lt;p>Conventional Commits 标准格式
基本结构：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">&amp;lt;type&amp;gt;([optional scope]): &amp;lt;subject&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">[optional body]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">[optional footer(s)]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>
&lt;p>&lt;strong>type&lt;/strong>（必填）：提交类型，常见的有：&lt;/p>
&lt;ul>
&lt;li>&lt;code>feat&lt;/code>：新功能（feature）&lt;/li>
&lt;li>&lt;code>fix&lt;/code>：修复 bug&lt;/li>
&lt;li>&lt;code>docs&lt;/code>：文档修改&lt;/li>
&lt;li>&lt;code>style&lt;/code>：代码格式调整（不影响功能，如空格、缩进）&lt;/li>
&lt;li>&lt;code>refactor&lt;/code>：重构（既不是新功能也不是 bug 修复）&lt;/li>
&lt;li>&lt;code>perf&lt;/code>：性能优化&lt;/li>
&lt;li>&lt;code>test&lt;/code>：添加或修改测试&lt;/li>
&lt;li>&lt;code>build&lt;/code>：影响构建系统或外部依赖的变更（如 npm、gulp）&lt;/li>
&lt;li>&lt;code>ci&lt;/code>：CI 配置变更（如 GitHub Actions）&lt;/li>
&lt;li>&lt;code>chore&lt;/code>：其他杂项（不修改 src 或 test）&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>scope&lt;/strong>（可选）：影响范围，用圆括号括起，例如 &lt;code>(parser)&lt;/code> 或 &lt;code>(login)&lt;/code>，表示修改了哪个模块。如果有多个模块涉及更改，以主范围为主，其他在正文中说明，以保持简洁和可读性。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>subject&lt;/strong>（必填）：简短描述，使用&lt;strong>祈使语气、现在时&lt;/strong>（如 “添加” 而非 “添加了” 或 “添加过”），首字母小写（规范推荐），长度控制在 50 字符以内。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>body&lt;/strong>（可选）：详细说明，为什么修改、改了什么。换行分段，每行建议不超过 72 字符。用空行与 subject 分隔。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>footer&lt;/strong>（可选）：脚注，用于标注破坏性变更或关联 issue。&lt;/p>
&lt;ul>
&lt;li>破坏性变更：&lt;code>BREAKING CHANGE: &amp;lt;描述&amp;gt;&lt;/code>（会导致 major 版本升级）&lt;/li>
&lt;li>关联 issue：&lt;code>Closes #123&lt;/code> 或 &lt;code>Refs #456&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>示例&lt;/p>
&lt;ol>
&lt;li>
&lt;p>简单 commit：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">feat(login): 添加用户登录功能
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>带 body 和 footer：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">fix(cache): 防止缓存数据过期
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">使用请求 ID 来跟踪缓存有效性，移除旧的超时逻辑。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">BREAKING CHANGE: 移除旧 API 接口
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Closes #42
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>一般最佳实践（即使不严格用 Conventional Commits）&lt;/p>
&lt;ul>
&lt;li>第一行（subject）不超过 50 字符。&lt;/li>
&lt;li>用空行分隔 subject 和 body。&lt;/li>
&lt;li>body 每行不超过 72 字符。&lt;/li>
&lt;li>使用祈使语气（Imperative mood）：如 “修复 bug” 而非 “修复了 bug”。&lt;/li>
&lt;li>解释&lt;strong>为什么&lt;/strong>修改，而不是只说&lt;strong>改了什么&lt;/strong>（代码本身已显示改了什么）。&lt;/li>
&lt;li>避免无意义消息如 “fix” 或 “update”。&lt;/li>
&lt;/ul>
&lt;h2 id="code-comments-代码注释">code comments 代码注释
&lt;/h2>&lt;p>好的代码注释是提升代码可读性、可维护性和团队协作的关键。注释的核心原则是：&lt;strong>解释“为什么”（Why），而不是重复“做什么”（What）&lt;/strong>。如果通过良好的命名、结构和逻辑，代码已经足够自解释，则无需过多注释。&lt;/p>
&lt;hr>
&lt;p>&lt;code>通用注释原则（适用于所有语言）&lt;/code>&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>注释目的&lt;/strong>：解释复杂逻辑、设计决策、业务背景、潜在陷阱或历史原因。避免对明显代码重复解释（如 &lt;code>i++ // i加1&lt;/code>）。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>注释风格&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>简洁、准确、无歧义。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>与代码同步更新，杜绝过时注释。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>注释占比建议：普通代码 10%-20%，复杂逻辑可达 30%-50%。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>常见注释类型&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>文件/模块头部注释：说明整体功能、作者、版本、版权等。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>类/结构体/模块注释：说明用途、设计思路。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>函数/方法注释：说明功能、参数、返回值、异常、调用示例。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>代码块注释：解释一段复杂逻辑的目的或算法。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>行内注释：谨慎使用，仅用于关键点或魔法数字。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>最佳实践&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>优先使用可生成文档的注释格式（如 Docstring、Javadoc）。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>使用统一标记表示待办事项：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;code>TODO(作者): 说明待完成事项&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>FIXME(作者): 说明需要修复的问题&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>NOTE: 重要说明&lt;/code>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>修复 Bug 时，必须在相关位置注释原因及修复思路。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>避免大段注释块遮挡代码逻辑，必要时将复杂说明移至函数文档。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;p>&lt;code>文件头部注释模板（适用于大多数语言）&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/**
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> * 文件描述：简要描述本文件的主要功能和作用。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> *
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> * @author 你的名字 &amp;lt;email@example.com&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> * @version 1.0.0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> * @create 2025-12-30
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> * @update 2025-12-30: 初始版本
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> * xxxx-xx-xx: 修改内容简述
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> *
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> * Copyright (c) 2025 Your Company. All rights reserved.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> */
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>&lt;code>函数/方法注释模板（推荐文档式注释）&lt;/code>&lt;/p>
&lt;p>&lt;strong>Python（Google风格 Docstring）示例&lt;/strong>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">calculate_user_score&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">include_bonus&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">bool&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">float&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 计算用户综合评分。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 该函数根据用户历史行为、活跃度和奖励规则计算最终评分。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 评分公式经过多次 A/B 测试优化，当前权重为：活跃度 40%、成就 35%、奖励 25%。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 参数
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> ----------
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> user_id : int
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 用户唯一 ID，必须存在于数据库中。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> include_bonus : bool, optional
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 是否包含临时奖励加分（默认 True）。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 返回值
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> -------
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> float
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 用户综合评分，范围 0.0 ~ 100.0。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 异常
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> -----
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> ValueError
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 当 user_id 不存在或为负数时抛出。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> NotFoundError
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 当用户数据未加载时抛出。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 示例
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> --------
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;gt;&amp;gt;&amp;gt; calculate_user_score(12345)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 87.5
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;gt;&amp;gt;&amp;gt; calculate_user_score(12345, include_bonus=False)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 82.3
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 注意
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> ----
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 该函数依赖缓存，缓存失效时会自动重新计算。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Java/JavaScript/TypeScript（Javadoc/JSDoc）示例&lt;/strong>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cm">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * 计算用户综合评分。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * 该函数根据用户历史行为、活跃度和奖励规则计算最终评分。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * 评分公式经过多次 A/B 测试优化，当前权重为：活跃度 40%、成就 35%、奖励 25%。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * @param userId 用户唯一 ID，必须存在于数据库中
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * @param includeBonus 是否包含临时奖励加分，默认 true
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * @return 用户综合评分，范围 0.0 ~ 100.0
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * @throws ValueError 当 userId 不存在或为负数时抛出
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * @throws NotFoundError 当用户数据未加载时抛出
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * @example
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * calculateUserScore(12345) // 返回 87.5
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * @since 1.2.0
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">double&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">calculateUserScore&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">userId&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">boolean&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">includeBonus&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// ...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>&lt;code>代码块与行内注释示例&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ==============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 关键算法块：用户行为衰减权重计算&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 原因：近期行为对评分影响更大，使用指数衰减模型模拟“遗忘曲线”&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 公式：weight = base ^ (days_elapsed / half_life)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ==============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">record&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">user_records&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 计算行为发生天数间隔（基于当前日期）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">days_elapsed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">current_date&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">record&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timestamp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">days&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 半衰期为 30 天，即 30 天后权重减半&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">weight&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">decay_base&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">days_elapsed&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">HALF_LIFE_DAYS&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># NOTE: decay_base &amp;lt; 1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_score&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">record&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">value&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">weight&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>&lt;code>总结最佳实践&lt;/code>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>第一行（函数/类总结）控制在 50-72 字符以内&lt;/strong>，清晰表达核心目的。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>用空行分隔总结与详细说明&lt;/strong>。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>详细说明解释“为什么”这样设计&lt;/strong>，而非仅仅“做了什么”。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>使用祈使语气或陈述事实&lt;/strong>，保持专业、一致。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>避免无意义注释&lt;/strong>，如 “临时变量” 或 “循环”。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>保持注释与代码同步&lt;/strong>，这是最重要的一条。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="数据库字段定义规范">数据库字段定义规范
&lt;/h2>&lt;p>良好的数据库字段定义规范能确保数据一致性、提升查询性能、便于维护和扩展，同时降低因字段命名或类型不统一导致的 Bug。以下是企业级项目中推荐的数据库字段定义最佳实践（适用于 MySQL、PostgreSQL、Oracle 等关系型数据库）。&lt;/p>
&lt;hr>
&lt;p>&lt;code>通用原则&lt;/code>&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>命名规范&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>使用&lt;strong>小写字母 + 下划线&lt;/strong>（snake_case），禁止驼峰命名。&lt;/li>
&lt;li>字段名必须&lt;strong>语义明确、见名知意&lt;/strong>，避免缩写，除非是公认缩写（如 &lt;code>id&lt;/code>、&lt;code>url&lt;/code>、&lt;code>ip&lt;/code>）。
&lt;ul>
&lt;li>推荐：&lt;code>user_name&lt;/code>、&lt;code>order_status&lt;/code>、&lt;code>created_at&lt;/code>&lt;/li>
&lt;li>避免：&lt;code>uname&lt;/code>、&lt;code>stat&lt;/code>、&lt;code>cts&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>业务相关字段需体现业务含义，例如：
&lt;ul>
&lt;li>&lt;code>is_deleted&lt;/code> 而非 &lt;code>del_flag&lt;/code>&lt;/li>
&lt;li>&lt;code>order_amount&lt;/code> 而非 &lt;code>money&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>布尔类型字段以 &lt;code>is_xxx&lt;/code> 开头（如 &lt;code>is_vip&lt;/code>、&lt;code>is_deleted&lt;/code>）。&lt;/li>
&lt;li>外键字段命名：&lt;code>xxx_id&lt;/code>（如 &lt;code>user_id&lt;/code>、&lt;code>order_id&lt;/code>）。&lt;/li>
&lt;li>统一前缀避免冲突（如多表联查时）：如日志表用 &lt;code>log_&lt;/code> 开头。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>数据类型选择原则&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>优先选择更小的类型&lt;/strong>，节省存储空间并提升性能。&lt;/li>
&lt;li>整数：&lt;code>INT&lt;/code>（或 &lt;code>BIGINT&lt;/code>）优先于 &lt;code>VARCHAR&lt;/code> 存数字。&lt;/li>
&lt;li>金额：统一使用 &lt;code>DECIMAL(18,2)&lt;/code> 或 &lt;code>DECIMAL(20,6)&lt;/code>，&lt;strong>禁止使用 FLOAT/DOUBLE&lt;/strong>。&lt;/li>
&lt;li>时间：优先使用 &lt;code>DATETIME&lt;/code> 或 &lt;code>TIMESTAMP&lt;/code>，根据是否需要时区选择。
&lt;ul>
&lt;li>&lt;code>created_at&lt;/code>、&lt;code>updated_at&lt;/code> 推荐使用 &lt;code>DATETIME DEFAULT CURRENT_TIMESTAMP&lt;/code>。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>状态/类型枚举：优先使用 &lt;code>TINYINT&lt;/code> 或 &lt;code>SMALLINT&lt;/code>，配合注释说明枚举含义。&lt;/li>
&lt;li>IP 地址：使用 &lt;code>INT UNSIGNED&lt;/code>（通过 &lt;code>INET_ATON/INET_NTOA&lt;/code> 转换）或 &lt;code>VARCHAR(15)&lt;/code>。&lt;/li>
&lt;li>长文本：区分 &lt;code>VARCHAR(255)&lt;/code>、&lt;code>TEXT&lt;/code>、&lt;code>MEDIUMTEXT&lt;/code> 根据实际长度。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>字段属性规范&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>主键&lt;/strong>：统一命名为 &lt;code>id&lt;/code>，类型 &lt;code>BIGINT UNSIGNED AUTO_INCREMENT&lt;/code>。&lt;/li>
&lt;li>&lt;strong>NOT NULL&lt;/strong>：除明确允许为空的字段外，所有字段默认 &lt;code>NOT NULL&lt;/code>，并设置合理 &lt;code>DEFAULT&lt;/code> 值。
&lt;ul>
&lt;li>示例：&lt;code>status TINYINT NOT NULL DEFAULT 0&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>默认值&lt;/strong>：必须显式设置，避免隐式默认导致数据不一致。&lt;/li>
&lt;li>&lt;strong>注释&lt;/strong>：&lt;strong>每个字段必须有注释&lt;/strong>，说明业务含义、取值范围、枚举说明等。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>通用字段（推荐每张表必备）&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="n">id&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BIGINT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">UNSIGNED&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">AUTO_INCREMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">PRIMARY&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">KEY&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;主键ID&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">created_at&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">DATETIME&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">CURRENT_TIMESTAMP&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;创建时间&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">updated_at&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">DATETIME&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">CURRENT_TIMESTAMP&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">ON&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">UPDATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">CURRENT_TIMESTAMP&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;更新时间&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">is_deleted&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">TINYINT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;是否逻辑删除：0-正常，1-已删除&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">creator_id&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BIGINT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">UNSIGNED&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;创建人ID&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">updater_id&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BIGINT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">UNSIGNED&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;更新人ID&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;hr>
&lt;p>&lt;code>表定义模板示例&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">CREATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">TABLE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="k">user&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BIGINT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">UNSIGNED&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">AUTO_INCREMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;用户ID&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">PRIMARY&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">KEY&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">user_name&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">VARCHAR&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">50&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;用户名（登录名）&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">nick_name&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">VARCHAR&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">50&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;昵称&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">password&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">VARCHAR&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;密码（加密存储）&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">mobile&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">VARCHAR&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">20&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;手机号&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">email&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">VARCHAR&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;邮箱&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">status&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">TINYINT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;状态：0-禁用，1-正常，2-冻结&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">is_vip&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">TINYINT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;是否VIP：0-否，1-是&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">vip_expire_time&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">DATETIME&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;VIP到期时间（NULL表示非VIP）&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">created_at&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">DATETIME&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">CURRENT_TIMESTAMP&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;创建时间&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">updated_at&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">DATETIME&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">CURRENT_TIMESTAMP&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">ON&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">UPDATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">CURRENT_TIMESTAMP&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;更新时间&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">is_deleted&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">TINYINT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;逻辑删除：0-正常，1-已删除&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">creator_id&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BIGINT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">UNSIGNED&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;创建人ID&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">updater_id&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BIGINT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">UNSIGNED&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;更新人ID&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ENGINE&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">InnoDB&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">CHARSET&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">utf8mb4&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COMMENT&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;用户信息表&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>&lt;code>索引规范&lt;/code>&lt;/p>
&lt;ul>
&lt;li>主键自动建立聚簇索引。&lt;/li>
&lt;li>常用查询字段建立普通索引或唯一索引。&lt;/li>
&lt;li>联合索引字段顺序：&lt;strong>等值条件 &amp;gt; 范围条件 &amp;gt; 排序字段&lt;/strong>（最左前缀原则）。&lt;/li>
&lt;li>索引命名：&lt;code>idx_字段名1_字段名2&lt;/code>、&lt;code>uniq_字段名1_字段名2&lt;/code>。&lt;/li>
&lt;li>避免过多索引（建议单表索引数 ≤ 5 个）。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>&lt;code>其他最佳实践&lt;/code>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>字符集&lt;/strong>：统一使用 &lt;code>utf8mb4&lt;/code> 支持表情符号。&lt;/li>
&lt;li>&lt;strong>存储引擎&lt;/strong>：生产环境优先 &lt;code>InnoDB&lt;/code>。&lt;/li>
&lt;li>&lt;strong>表名&lt;/strong>：复数形式 + 下划线（如 &lt;code>orders&lt;/code>、&lt;code>user_logs&lt;/code>），或业务模块前缀（如 &lt;code>pay_orders&lt;/code>）。&lt;/li>
&lt;li>&lt;strong>版本控制&lt;/strong>：所有建表语句和变更语句放入 Git，配合 Flyway/Liquibase 等工具管理。&lt;/li>
&lt;li>&lt;strong>审核机制&lt;/strong>：所有 DDL 变更必须经过代码审查和测试环境验证。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>&lt;code>总结&lt;/code>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>字段名（subject）&lt;/strong>：控制在合理长度，清晰表达业务含义（50 字符以内为佳）。&lt;/li>
&lt;li>&lt;strong>字段注释（body）&lt;/strong>：详细说明“为什么这样设计”、取值范围、业务规则。&lt;/li>
&lt;li>&lt;strong>默认值与 NOT NULL&lt;/strong>：像 commit 的 footer，强制规范，避免隐式行为。&lt;/li>
&lt;li>&lt;strong>保持一致性&lt;/strong>：整个项目所有表风格统一，这是最重要的一条。&lt;/li>
&lt;/ul>
&lt;h2 id="logger-日志规范python-项目通用版">logger 日志规范（Python 项目通用版）
&lt;/h2>&lt;p>良好的日志配置和管理是保障系统可观测性、快速定位问题和长期稳定运行的基础。日志应提供清晰的结构化信息、合理的级别划分、可靠的输出渠道，同时避免性能开销过大或日志泛滥。&lt;/p>
&lt;p>本规范适用于所有 Python 项目（Web 服务、爬虫、脚本、数据处理等），旨在统一日志风格、提升排查效率。&lt;/p>
&lt;hr>
&lt;p>&lt;code>通用日志原则&lt;/code>&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>日志级别使用规范&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>DEBUG&lt;/strong>：详细调试信息（如中间变量、API 请求/响应详情）。仅开发/测试环境开启，生产环境关闭。&lt;/li>
&lt;li>&lt;strong>INFO&lt;/strong>：关键业务里程碑、正常流程节点（如“服务启动完成”“任务开始执行”“请求处理成功”）。&lt;/li>
&lt;li>&lt;strong>WARNING&lt;/strong>：潜在问题或降级处理（如“缓存未命中”“重试成功”“使用默认配置”）。&lt;/li>
&lt;li>&lt;strong>ERROR&lt;/strong>：业务异常、可捕获错误，必须附带异常堆栈和关键上下文。&lt;/li>
&lt;li>&lt;strong>CRITICAL&lt;/strong>：严重错误，导致进程/服务不可用（如配置缺失、数据库永久连接失败）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>日志内容要求&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>必须包含足够上下文（如 request_id、user_id、task_id、url 等关键标识）。&lt;/li>
&lt;li>敏感信息严格脱敏（手机号、身份证、密码、token 等禁止明文打印）。&lt;/li>
&lt;li>优先使用结构化日志（JSON 格式），便于 ELK、Loki 等系统解析。&lt;/li>
&lt;li>单条日志避免过长（建议 &amp;lt; 4KB），必要时拆分或仅记录关键字段。&lt;/li>
&lt;li>禁止在高频循环中记录 DEBUG/INFO 日志。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>最佳实践&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>全项目使用单一全局 logger 实例，避免重复初始化。&lt;/li>
&lt;li>支持控制台 + 文件双输出，生产环境必须落盘。&lt;/li>
&lt;li>日志文件建议按日期滚动，避免单个文件过大。&lt;/li>
&lt;li>支持动态调整日志级别（不重启进程）。&lt;/li>
&lt;li>异常捕获后必须记录 ERROR 日志并附带 exc_info=True。&lt;/li>
&lt;li>生产环境禁止使用 print() 输出业务日志。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;p>&lt;code>推荐日志配置实现（通用版）&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;全局日志配置模块
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">该模块提供项目统一的日志管理器，支持：
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">- 单例模式全局 logger
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">- 控制台 + 文件输出
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">- 日志文件按日期滚动（ RotatingFileHandler 或 TimedRotatingFileHandler ）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">- JSON 结构化格式可选
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">- 配置从 settings 或环境变量加载
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">logging&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">logging.handlers&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">sys&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">pathlib&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Path&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">typing&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Optional&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 项目配置示例（实际项目中可替换为自己的 config 模块或 pydantic Settings）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">LogConfig&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LOG_LEVEL&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;INFO&amp;#34;&lt;/span> &lt;span class="c1"># DEBUG/INFO/WARNING/ERROR/CRITICAL&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LOG_DIR&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;logs&amp;#34;&lt;/span> &lt;span class="c1"># 日志目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LOG_FILE_NAME&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;app.log&amp;#34;&lt;/span> &lt;span class="c1"># 日志文件名&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LOG_MAX_BYTES&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">50&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1024&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1024&lt;/span> &lt;span class="c1"># 单文件最大 50MB&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LOG_BACKUP_COUNT&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">10&lt;/span> &lt;span class="c1"># 保留 10 个备份文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LOG_JSON_FORMAT&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">bool&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">False&lt;/span> &lt;span class="c1"># 是否启用 JSON 结构化日志&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LOG_CONSOLE&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">bool&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span> &lt;span class="c1"># 是否输出到控制台&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 可替换为你的实际配置加载方式&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">config&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">LogConfig&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">LoggerManager&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;日志管理器（单例模式）&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_instance&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Optional&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;LoggerManager&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_logger&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Optional&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Logger&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__new__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">cls&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="s1">&amp;#39;LoggerManager&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="bp">cls&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_instance&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">cls&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_instance&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">super&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__new__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">cls&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">cls&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_instance&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_logger&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_setup_logger&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">_setup_logger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;初始化全局 logger&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;app&amp;#34;&lt;/span> &lt;span class="c1"># 可改为项目名，如 &amp;#34;myproject&amp;#34; 或 __name__&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_logger&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getLogger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">logger_name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setLevel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">getattr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">logging&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">LOG_LEVEL&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">upper&lt;/span>&lt;span class="p">()))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 避免重复添加 handler（多次导入模块时）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">handlers&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 创建日志目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">log_dir&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Path&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">LOG_DIR&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">log_dir&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">mkdir&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">parents&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">exist_ok&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">log_file&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">log_dir&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">LOG_FILE_NAME&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 格式化器&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">LOG_JSON_FORMAT&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 推荐第三方库：python-json-logger&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kn">from&lt;/span> &lt;span class="nn">python_json_logger.jsonlogger&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">JsonFormatter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">formatter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">JsonFormatter&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="si">%(asctime)s&lt;/span>&lt;span class="s1"> &lt;/span>&lt;span class="si">%(name)s&lt;/span>&lt;span class="s1"> &lt;/span>&lt;span class="si">%(levelname)s&lt;/span>&lt;span class="s1"> &lt;/span>&lt;span class="si">%(filename)s&lt;/span>&lt;span class="s1"> &lt;/span>&lt;span class="si">%(lineno)d&lt;/span>&lt;span class="s1"> &lt;/span>&lt;span class="si">%(message)s&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">ImportError&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="c1"># fallback&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">formatter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Formatter&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;{&amp;#34;time&amp;#34;:&amp;#34;&lt;/span>&lt;span class="si">%(asctime)s&lt;/span>&lt;span class="s1">&amp;#34;, &amp;#34;name&amp;#34;:&amp;#34;&lt;/span>&lt;span class="si">%(name)s&lt;/span>&lt;span class="s1">&amp;#34;, &amp;#34;level&amp;#34;:&amp;#34;&lt;/span>&lt;span class="si">%(levelname)s&lt;/span>&lt;span class="s1">&amp;#34;, &amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;&amp;#34;file&amp;#34;:&amp;#34;&lt;/span>&lt;span class="si">%(filename)s&lt;/span>&lt;span class="s1">:&lt;/span>&lt;span class="si">%(lineno)d&lt;/span>&lt;span class="s1">&amp;#34;, &amp;#34;message&amp;#34;:&lt;/span>&lt;span class="si">%(message)s&lt;/span>&lt;span class="s1">}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">formatter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Formatter&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fmt&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="si">%(asctime)s&lt;/span>&lt;span class="s1"> - &lt;/span>&lt;span class="si">%(name)s&lt;/span>&lt;span class="s1"> - &lt;/span>&lt;span class="si">%(levelname)s&lt;/span>&lt;span class="s1"> - &lt;/span>&lt;span class="si">%(filename)s&lt;/span>&lt;span class="s1">:&lt;/span>&lt;span class="si">%(lineno)d&lt;/span>&lt;span class="s1"> - &lt;/span>&lt;span class="si">%(message)s&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">datefmt&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s1"> %H:%M:%S&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 文件处理器 - 按大小滚动&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_handler&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">handlers&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">RotatingFileHandler&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">filename&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">log_file&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">maxBytes&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">LOG_MAX_BYTES&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">backupCount&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">LOG_BACKUP_COUNT&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">encoding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;utf-8&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_handler&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setLevel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">getattr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">logging&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">LOG_LEVEL&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">upper&lt;/span>&lt;span class="p">()))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_handler&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setFormatter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">formatter&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">addHandler&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_handler&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 可选：按天滚动（替代方案）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># file_handler = logging.handlers.TimedRotatingFileHandler(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># filename=log_file,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># when=&amp;#39;midnight&amp;#39;,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># interval=1,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># backupCount=30,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># encoding=&amp;#39;utf-8&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># )&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 控制台处理器&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">LOG_CONSOLE&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">console_handler&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">StreamHandler&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sys&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">console_handler&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setLevel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">getattr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">logging&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">LOG_LEVEL&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">upper&lt;/span>&lt;span class="p">()))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">console_handler&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setFormatter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">formatter&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">addHandler&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">console_handler&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_logger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Logger&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;获取配置好的全局 logger&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_logger&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 全局 logger 实例（项目中统一导入使用）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">logger&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">LoggerManager&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_logger&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>&lt;code>使用示例&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">logger&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">logger&lt;/span> &lt;span class="c1"># 假设文件名为 logger.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">process_task&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">task_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">url&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;task.start&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">task_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">task_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 推荐结构化键值对&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">fetch_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;fetch.success&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">task_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">task_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">data_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">process&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;task.success&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">task_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">task_id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">error&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;task.failed&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">task_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">task_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exc_info&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 自动打印堆栈&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">error&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>&lt;code>总结最佳实践&lt;/code>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>全项目只导入一个全局 logger&lt;/strong>，避免散乱创建 logging.getLogger()。&lt;/li>
&lt;li>&lt;strong>生产环境必须启用文件滚动&lt;/strong>，防止磁盘写满。&lt;/li>
&lt;li>&lt;strong>推荐逐步迁移到 JSON 结构化日志&lt;/strong>，极大提升日志查询效率。&lt;/li>
&lt;li>&lt;strong>敏感数据脱敏&lt;/strong> 是安全合规底线。&lt;/li>
&lt;li>&lt;strong>异常必须记录堆栈&lt;/strong>，不允许“吞异常”而不日志。&lt;/li>
&lt;li>&lt;strong>日志配置集中管理&lt;/strong>，支持通过环境变量或配置文件灵活调整。&lt;/li>
&lt;li>&lt;strong>写日志时站在“凌晨 3 点被告警叫醒”的角度&lt;/strong>：这条日志能否让你快速定位问题？&lt;/li>
&lt;/ul></description></item><item><title>开发问题与解法笔记</title><link>https://www.zata.cc/p/%E5%BC%80%E5%8F%91%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E6%B3%95%E7%AC%94%E8%AE%B0/</link><pubDate>Wed, 13 Aug 2025 00:03:46 +0800</pubDate><guid>https://www.zata.cc/p/%E5%BC%80%E5%8F%91%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E6%B3%95%E7%AC%94%E8%AE%B0/</guid><description>&lt;img src="https://www.zata.cc/p/%E5%BC%80%E5%8F%91%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E6%B3%95%E7%AC%94%E8%AE%B0/images/index/index.png" alt="Featured image of post 开发问题与解法笔记" />&lt;h2 id="目录">目录
&lt;/h2>&lt;ul>
&lt;li>&lt;a class="link" href="#WSL2%e4%b8%ad%ef%bc%8cDocker%e6%9c%8d%e5%8a%a1%e6%80%8e%e4%b9%88%e8%ae%a9%e6%88%91%e5%b1%80%e5%9f%9f%e7%bd%91%e4%b8%ad%e5%85%b6%e4%bb%96%e6%9c%ba%e5%99%a8%e8%ae%bf%e9%97%ae%ef%bc%9f" >WSL2中，Docker服务怎么让我局域网中其他机器访问？&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e6%88%91%e6%9c%89%e4%b8%80%e4%b8%aa%e9%a1%b9%e7%9b%ae%ef%bc%8c%e4%bd%bf%e7%94%a8%e5%88%b0%e4%ba%86%e4%b8%80%e4%b8%aa%e7%bd%91%e7%ab%99%e4%b8%8a%e6%88%91%e7%99%bb%e9%99%86%e5%90%8e%e5%88%b0cookie%e5%92%8cauthorization%e6%88%91%e7%8e%b0%e5%9c%a8%e6%98%af%e6%89%8b%e5%8a%a8%e6%9b%b4%e6%96%b0%e5%88%b0%e6%af%8f%e6%ac%a1%ef%bc%8c%e6%88%91%e6%84%9f%e8%a7%89%e5%a4%aa%e9%ba%bb%e7%83%a6%e4%ba%86%ef%bc%8c%e6%9c%89%e4%bb%80%e4%b9%88%e7%ae%80%e5%8d%95%e7%82%b9%e7%9a%84%e6%96%b9%e6%b3%95%e5%90%97" >我有一个项目，使用到了一个网站上我登陆后到cookie和authorization 我现在是手动更新到每次，我感觉太麻烦了，有什么简单点的方法吗&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="希望在本地电脑上能像操作本地文件一样直接访问和修改远程容器里的文件目录">希望在本地电脑上能像操作本地文件一样，直接访问和修改远程容器里的文件目录
&lt;/h2>&lt;p>这是一个非常常见的开发需求，有几种成熟且高效的解决方案可以实现，我将为你详细介绍。&lt;/p>
&lt;p>方案一：使用 SSHFS (最直接的“映射”方案)
SSHFS (SSH Filesystem) 是一个基于 FUSE (Filesystem in Userspace) 的文件系统客户端，它允许你通过 SSH 连接将远程目录挂载（Mount）到本地，让远程目录看起来就如同本地的一个文件夹一样。你对这个本地文件夹的所有读写操作，都会被实时地通过 SSH 协议传输到远程主机上。&lt;/p>
&lt;p>这是最符合你“目录映射”需求的方案。&lt;/p>
&lt;p>优点:&lt;/p>
&lt;p>无缝集成：挂载后，你可以用任何本地工具（IDE、命令行、文件管理器）直接操作远程文件，完全感觉不到差异。&lt;/p>
&lt;p>实时同步：所有修改都是实时的。&lt;/p>
&lt;p>缺点:&lt;/p>
&lt;p>性能依赖网络：由于所有文件操作都经过网络，如果网络延迟高或不稳定，读写速度会受影响。&lt;/p>
&lt;p>需要额外安装：本地系统需要安装 SSHFS 客户端。&lt;/p>
&lt;p>操作步骤：&lt;/p>
&lt;ol>
&lt;li>在本地机器上安装 SSHFS&lt;/li>
&lt;/ol>
&lt;p>macOS (使用 Homebrew):&lt;/p>
&lt;p>Bash&lt;/p>
&lt;p>brew install sshfs
注意：macOS 可能需要额外配置或允许系统扩展，请根据安装提示操作。&lt;/p>
&lt;p>Linux (Debian/Ubuntu):&lt;/p>
&lt;p>Bash&lt;/p>
&lt;p>sudo apt-get update
sudo apt-get install sshfs
Windows:&lt;/p>
&lt;p>安装 Winfsp (Windows File System Proxy)，这是一个 FUSE 的 Windows 实现。&lt;/p>
&lt;p>安装 SSHFS-Win，它提供了 SSHFS 的 Windows 版本。&lt;/p>
&lt;p>安装后，你可以在文件资源管理器的右键菜单中找到“Map Network Drive”，然后输入 SSH 连接信息。&lt;/p>
&lt;ol start="2">
&lt;li>创建一个本地空目录作为挂载点&lt;/li>
&lt;/ol>
&lt;p>Bash&lt;/p>
&lt;h1 id="例如在你的用户主目录下创建一个叫-remote-dev-的文件夹">例如，在你的用户主目录下创建一个叫 remote-dev 的文件夹
&lt;/h1>&lt;p>mkdir ~/remote-dev
3. 执行挂载命令&lt;/p>
&lt;p>基本命令格式为：sshfs [user@]hostname:[remote_directory] [local_mount_point]&lt;/p>
&lt;p>假设：&lt;/p>
&lt;p>远程SSH用户名：devuser&lt;/p>
&lt;p>远程主机（或容器的宿主机）IP/域名：192.168.1.100&lt;/p>
&lt;p>远程容器内的目录：/app&lt;/p>
&lt;p>本地挂载点：~/remote-dev&lt;/p>
&lt;p>执行以下命令：&lt;/p>
&lt;p>Bash&lt;/p>
&lt;p>sshfs &lt;a class="link" href="mailto:devuser@192.168.1.100" >devuser@192.168.1.100&lt;/a>:/app ~/remote-dev
如果你的SSH服务运行在非标准端口（如 2222），可以这样指定：&lt;/p>
&lt;p>Bash&lt;/p>
&lt;p>sshfs -p 2222 &lt;a class="link" href="mailto:devuser@192.168.1.100" >devuser@192.168.1.100&lt;/a>:/app ~/remote-dev
现在，你访问本地的 ~/remote-dev 目录，看到的就是远程服务器上 /app 目录的内容了。你可以直接用本地的 IDE 打开这个文件夹进行开发。&lt;/p>
&lt;ol start="4">
&lt;li>卸载映射&lt;/li>
&lt;/ol>
&lt;p>当你不需要这个映射时，可以卸载它：&lt;/p>
&lt;p>macOS / Linux:&lt;/p>
&lt;p>Bash&lt;/p>
&lt;p>umount ~/remote-dev
Windows: 在文件资源管理器中断开网络驱动器即可。&lt;/p>
&lt;h2 id="wsl2中docker服务怎么让我局域网中其他机器访问">WSL2中，Docker服务怎么让我局域网中其他机器访问？
&lt;/h2>&lt;p>&lt;img src="https://www.zata.cc/p/%E5%BC%80%E5%8F%91%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E6%B3%95%E7%AC%94%E8%AE%B0/images/index/index-1.png"
width="718"
height="5724"
srcset="https://www.zata.cc/p/%E5%BC%80%E5%8F%91%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E6%B3%95%E7%AC%94%E8%AE%B0/images/index/index-1_hu8192060096377456540.png 480w, https://www.zata.cc/p/%E5%BC%80%E5%8F%91%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E6%B3%95%E7%AC%94%E8%AE%B0/images/index/index-1_hu17603733634565047117.png 1024w"
loading="lazy"
alt="WSL2中，Docker服务怎么让我局域网中其他机器访问？"
class="gallery-image"
data-flex-grow="12"
data-flex-basis="30px"
>&lt;/p>
&lt;h2 id="我有一个项目使用到了一个网站上我登陆后到cookie和authorization我现在是手动更新到每次我感觉太麻烦了有什么简单点的方法吗">我有一个项目，使用到了一个网站上我登陆后到cookie和authorization我现在是手动更新到每次，我感觉太麻烦了，有什么简单点的方法吗
&lt;/h2>&lt;p>您好，每次手动更新Cookie和Authorization确实非常繁琐且效率低下。这通常是因为登录凭证（特别是Authorization Token）具有时效性，过期后就需要重新获取。&lt;/p>
&lt;p>要解决这个问题，核心思路就是&lt;strong>让你的程序/脚本自动模拟登录过程，以获取最新的Cookie和Authorization&lt;/strong>。以下是几种从易到难、适用不同场景的自动化解决方案：&lt;/p>
&lt;hr>
&lt;h3 id="方法一模拟登录请求最常用最高效">方法一：模拟登录请求（最常用、最高效）
&lt;/h3>&lt;p>这是最推荐的方法。原理是分析网站登录时浏览器发送了什么网络请求，然后用你的代码（例如Python的&lt;code>requests&lt;/code>库）去模仿这个请求，从而直接从服务器获取凭证。&lt;/p>
&lt;p>&lt;strong>操作步骤：&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>分析登录过程：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>在浏览器中打开该网站的登录页面。&lt;/li>
&lt;li>按 &lt;code>F12&lt;/code> 打开开发者工具，切换到 &lt;strong>“网络 (Network)”&lt;/strong> 面板。&lt;/li>
&lt;li>勾选 &lt;code>Preserve log&lt;/code> (或 &lt;code>Persist logs&lt;/code>) 以免页面跳转后日志被清空。&lt;/li>
&lt;li>输入用户名和密码，点击登录按钮。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>找到关键请求：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>在网络请求列表中，找到那个负责登录的请求。它通常是 &lt;code>POST&lt;/code> 方法，URL里可能包含 &lt;code>login&lt;/code>, &lt;code>auth&lt;/code>, &lt;code>signin&lt;/code>, &lt;code>token&lt;/code> 等关键词。&lt;/li>
&lt;li>点击这个请求，查看它的详细信息：
&lt;ul>
&lt;li>&lt;strong>Headers (标头):&lt;/strong> 查看 &lt;code>Request URL&lt;/code> (请求地址) 和 &lt;code>Request Method&lt;/code> (请求方法，通常是POST)。&lt;/li>
&lt;li>&lt;strong>Payload (负载) / Body (正文):&lt;/strong> 查看你提交了哪些数据，通常是包含用户名、密码的表单数据 (Form Data) 或JSON对象。&lt;/li>
&lt;li>&lt;strong>Response (响应):&lt;/strong> 查看服务器返回了什么。&lt;code>Authorization&lt;/code> 令牌（通常是一个很长的字符串，叫做 &lt;code>token&lt;/code>, &lt;code>access_token&lt;/code> 等）很可能就在返回的JSON数据里。&lt;/li>
&lt;li>&lt;strong>Response Headers (响应标头):&lt;/strong> 新的 &lt;code>Cookie&lt;/code> 通常在 &lt;code>Set-Cookie&lt;/code> 这个响应头里。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>编写代码实现：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>使用你项目的编程语言中的HTTP客户端库（如 Python 的 &lt;code>requests&lt;/code>，Node.js 的 &lt;code>axios&lt;/code>）来构造一个与浏览器完全相同的HTTP请求。&lt;/li>
&lt;li>将你的用户名和密码作为请求的 &lt;code>data&lt;/code> 或 &lt;code>json&lt;/code> 发送。&lt;/li>
&lt;li>发送请求后，从响应的JSON正文中提取 &lt;code>Authorization&lt;/code> 令牌，并从响应头中提取 &lt;code>Cookie&lt;/code>。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>示例 (使用Python &lt;code>requests&lt;/code>)：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">requests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. 登录获取token和cookie&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">login_url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;https://example.com/api/login&amp;#39;&lt;/span> &lt;span class="c1"># 替换为实际的登录URL&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">credentials&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;username&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;your_username&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;your_password&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建一个会话对象，它能自动管理cookie&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">session&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Session&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 发送登录请求&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 注意：根据网站要求，数据可能是 &amp;#39;json=credentials&amp;#39; 或 &amp;#39;data=credentials&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">post&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">login_url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">json&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">credentials&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 检查登录是否成功&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status_code&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">200&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;登录成功！&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. 从响应中提取数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 假设token在返回的JSON中&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">authorization_token&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;Bearer &amp;#39;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">response_data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;token&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 格式通常是 &amp;#39;Bearer &amp;lt;token&amp;gt;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Cookie会自动保存在session对象中，后续使用此session发起的请求会自动带上&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. 在后续的请求中使用获取到的凭证&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">headers&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Authorization&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">authorization_token&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 使用session对象发送需要登录权限的请求，它会自动带上cookie&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">protected_url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;https://example.com/api/data&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">protected_url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">headers&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">headers&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;受保护的API响应:&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">api_response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;登录失败，状态码：&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status_code&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;响应内容：&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>优点：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>高效、快速&lt;/strong>：没有浏览器界面的开销，执行速度快。&lt;/li>
&lt;li>&lt;strong>稳定&lt;/strong>：只要网站登录接口不变，脚本就能一直工作。&lt;/li>
&lt;li>&lt;strong>易于部署&lt;/strong>：非常适合在服务器或后台环境中运行。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>缺点：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>如果网站登录逻辑复杂（例如有复杂的JavaScript加密或验证码），分析和模拟会变得困难。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="方法二使用浏览器自动化工具">方法二：使用浏览器自动化工具
&lt;/h3>&lt;p>如果方法一难度太大（比如登录过程有无法绕过的验证码、密码经过了复杂的前端JS加密），你可以使用浏览器自动化工具来模拟真实用户操作。&lt;/p>
&lt;p>&lt;strong>常用工具：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Selenium:&lt;/strong> 最老牌、最通用的Web自动化框架。&lt;/li>
&lt;li>&lt;strong>Playwright:&lt;/strong> 由微软开发，更新、更快，API设计更现代化。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>操作步骤：&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>&lt;strong>安装相应的库&lt;/strong> (例如 &lt;code>pip install selenium&lt;/code> 或 &lt;code>pip install playwright&lt;/code>) 和浏览器驱动。&lt;/li>
&lt;li>&lt;strong>编写脚本&lt;/strong>来控制浏览器：
&lt;ul>
&lt;li>打开登录页面。&lt;/li>
&lt;li>定位到用户名和密码输入框，并填入你的凭证。&lt;/li>
&lt;li>模拟点击登录按钮。&lt;/li>
&lt;li>等待页面加载完成或跳转。&lt;/li>
&lt;li>从浏览器中提取Cookie和&lt;code>Authorization&lt;/code>。&lt;code>Authorization&lt;/code>可能存储在 &lt;code>localStorage&lt;/code> 或 &lt;code>sessionStorage&lt;/code> 中，这些工具都提供了访问它们的方法。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>优点：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>功能强大&lt;/strong>：可以处理非常复杂的、依赖JavaScript的网站。&lt;/li>
&lt;li>&lt;strong>所见即所得&lt;/strong>：模拟的是真实用户操作，更容易理解和调试。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>缺点：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>资源消耗大&lt;/strong>：需要启动一个完整的浏览器实例，慢且占用内存。&lt;/li>
&lt;li>&lt;strong>相对不稳定&lt;/strong>：网站前端UI（如元素ID、类名）的微小改动都可能导致脚本失效。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="方法三寻找网站的官方api">方法三：寻找网站的官方API
&lt;/h3>&lt;p>这是最理想但也是最少见的情况。检查一下该网站是否为开发者提供了官方的API。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>如何寻找&lt;/strong>：通常在网站的页脚可以找到 &amp;ldquo;API&amp;rdquo;、&amp;ldquo;开发者 (Developers)&amp;quot;、&amp;ldquo;集成 (Integrations)&amp;rdquo; 等链接。&lt;/li>
&lt;li>&lt;strong>如何使用&lt;/strong>：官方API会提供清晰的文档，告诉你如何通过OAuth 2.0或其他认证方式获取API密钥 (API Key) 或访问令牌 (Access Token)。这种方式是官方支持的，因此最稳定、最可靠。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="总结与建议">总结与建议
&lt;/h3>&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align: left">方法&lt;/th>
&lt;th style="text-align: left">优点&lt;/th>
&lt;th style="text-align: left">缺点&lt;/th>
&lt;th style="text-align: left">适用场景&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align: left">&lt;strong>模拟登录请求&lt;/strong>&lt;/td>
&lt;td style="text-align: left">&lt;strong>高效、稳定、资源占用少&lt;/strong>&lt;/td>
&lt;td style="text-align: left">登录逻辑复杂时难以实现&lt;/td>
&lt;td style="text-align: left">&lt;strong>首选方案&lt;/strong>，适用于绝大多数网站。&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;strong>浏览器自动化&lt;/strong>&lt;/td>
&lt;td style="text-align: left">功能强大，能处理复杂JS逻辑&lt;/td>
&lt;td style="text-align: left">慢、资源消耗大、易受UI变化影响&lt;/td>
&lt;td style="text-align: left">登录过程有复杂验证码或加密，无法直接模拟请求时。&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;strong>官方API&lt;/strong>&lt;/td>
&lt;td style="text-align: left">&lt;strong>最稳定、最可靠、官方支持&lt;/strong>&lt;/td>
&lt;td style="text-align: left">并非所有网站都提供&lt;/td>
&lt;td style="text-align: left">网站明确提供开发者API时。&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>给您的建议：&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>&lt;strong>首先尝试 &lt;code>方法一：模拟登录请求&lt;/code>&lt;/strong>。这是解决此类问题的标准工业实践。花一些时间用F12开发者工具分析，绝大多数情况都能成功。&lt;/li>
&lt;li>如果登录过程有难以处理的验证码或加密，再考虑使用 &lt;code>方法二：浏览器自动化&lt;/code> 作为备选方案。&lt;/li>
&lt;li>最后，别忘了检查一下网站是否有 &lt;code>方法三：官方API&lt;/code>，如果有，那将是最佳选择。&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>安全提示&lt;/strong>：在代码中处理用户名和密码时，建议使用环境变量或配置文件来存储，而不是直接硬编码在代码里，以确保安全。&lt;/p></description></item><item><title>项目中日志的使用教程</title><link>https://www.zata.cc/p/%E9%A1%B9%E7%9B%AE%E4%B8%AD%E6%97%A5%E5%BF%97%E7%9A%84%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</link><pubDate>Sun, 13 Jul 2025 15:12:12 +0800</pubDate><guid>https://www.zata.cc/p/%E9%A1%B9%E7%9B%AE%E4%B8%AD%E6%97%A5%E5%BF%97%E7%9A%84%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</guid><description>&lt;img src="https://www.zata.cc/p/%E9%A1%B9%E7%9B%AE%E4%B8%AD%E6%97%A5%E5%BF%97%E7%9A%84%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/index.png" alt="Featured image of post 项目中日志的使用教程" />&lt;p>在软件开发中，日志记录（Logging）是调试、监控和问题排查的重要工具。合理添加日志可以帮助开发者快速定位问题、跟踪系统行为，而不必要的日志则可能增加系统开销、降低性能或使日志难以分析。以下是一个详细的教程，介绍在项目中哪些代码需要加日志，哪些不需要，并提供最佳实践和示例。&lt;/p>
&lt;hr>
&lt;h2 id="一日志记录的核心原则">一、日志记录的核心原则
&lt;/h2>&lt;p>在决定是否需要加日志之前，需明确日志记录的核心原则：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>目的明确&lt;/strong>：日志应服务于调试、监控、审计或问题排查，记录的信息应有实际用途。&lt;/li>
&lt;li>&lt;strong>信息清晰&lt;/strong>：日志应包含足够上下文（如时间、模块、错误详情），但避免冗余。&lt;/li>
&lt;li>&lt;strong>性能考虑&lt;/strong>：日志记录可能影响性能，尤其在高并发场景，需权衡日志量和系统性能。&lt;/li>
&lt;li>&lt;strong>分级管理&lt;/strong>：使用不同日志级别（DEBUG、INFO、WARN、ERROR、FATAL）区分记录场景。&lt;/li>
&lt;li>&lt;strong>安全性&lt;/strong>：避免记录敏感信息（如密码、个人数据）。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="二哪些代码需要加日志">二、哪些代码需要加日志？
&lt;/h2>&lt;p>以下是项目中通常需要添加日志的场景，以及为什么需要记录日志：&lt;/p>
&lt;h3 id="1-系统关键事件">1. 系统关键事件
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>场景&lt;/strong>：系统启动、关闭、配置加载、初始化等关键生命周期事件。&lt;/li>
&lt;li>&lt;strong>原因&lt;/strong>：这些事件帮助开发者确认系统是否正常运行或异常终止。&lt;/li>
&lt;li>&lt;strong>日志级别&lt;/strong>：INFO 或 WARN（异常时）。&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 系统启动&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">logger&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Application started with version: {}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">appVersion&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 配置加载失败&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">logger&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">warn&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Failed to load configuration file: {}, using default settings&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">configFilePath&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;h3 id="2-业务逻辑的关键节点">2. 业务逻辑的关键节点
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>场景&lt;/strong>：重要业务操作的开始、结束或状态变化，如订单创建、支付处理、用户注册等。&lt;/li>
&lt;li>&lt;strong>原因&lt;/strong>：便于跟踪业务流程，验证功能是否按预期执行。&lt;/li>
&lt;li>&lt;strong>日志级别&lt;/strong>：INFO（正常流程）或 ERROR（失败时）。&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 订单创建&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Creating order for user &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">user_id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> with amount &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">amount&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">create_order&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Order &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> created successfully&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Failed to create order for user &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">user_id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;h3 id="3-异常和错误处理">3. 异常和错误处理
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>场景&lt;/strong>：捕获的异常、错误或失败的操作。&lt;/li>
&lt;li>&lt;strong>原因&lt;/strong>：记录异常详情（包括堆栈信息）有助于快速定位问题根因。&lt;/li>
&lt;li>&lt;strong>日志级别&lt;/strong>：ERROR 或 FATAL（严重错误）。&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">processPayment&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">orderId&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">catch&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PaymentException&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">logger&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Payment processing failed for order {}: {}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">orderId&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getMessage&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;h3 id="4-外部交互">4. 外部交互
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>场景&lt;/strong>：与外部系统（如数据库、API、消息队列）的交互，包括请求发送和响应接收。&lt;/li>
&lt;li>&lt;strong>原因&lt;/strong>：外部交互可能失败，日志有助于追踪调用是否成功、响应时间、错误码等。&lt;/li>
&lt;li>&lt;strong>日志级别&lt;/strong>：INFO（请求/响应摘要）或 ERROR（失败时）。&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Sending request to external API: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">api_url&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">post&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">payload&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status_code&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">200&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;API call to &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">api_url&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> succeeded with response: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;API call to &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">api_url&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> failed with status &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status_code&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;h3 id="5-性能监控">5. 性能监控
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>场景&lt;/strong>：关键操作的执行时间或资源使用情况。&lt;/li>
&lt;li>&lt;strong>原因&lt;/strong>：帮助识别性能瓶颈，优化系统。&lt;/li>
&lt;li>&lt;strong>日志级别&lt;/strong>：INFO 或 DEBUG。&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">long&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">startTime&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">currentTimeMillis&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">processLargeDataset&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kt">long&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">duration&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">currentTimeMillis&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">startTime&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">logger&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Processed dataset in {} ms&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">duration&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;h3 id="6-安全相关事件">6. 安全相关事件
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>场景&lt;/strong>：用户登录、权限变更、敏感操作等。&lt;/li>
&lt;li>&lt;strong>原因&lt;/strong>：便于审计和追踪潜在的安全问题。&lt;/li>
&lt;li>&lt;strong>日志级别&lt;/strong>：INFO 或 WARN（可疑操作）。&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;User &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">user_id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> logged in from IP &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">ip_address&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">failed_attempts&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">warn&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Multiple failed login attempts for user &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">user_id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> from IP &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">ip_address&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;h3 id="7-调试信息开发测试阶段">7. 调试信息（开发/测试阶段）
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>场景&lt;/strong>：开发或测试时，记录中间变量、状态或流程细节。&lt;/li>
&lt;li>&lt;strong>原因&lt;/strong>：帮助开发者理解代码执行路径，定位问题。&lt;/li>
&lt;li>&lt;strong>日志级别&lt;/strong>：DEBUG（生产环境中通常关闭）。&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">logger&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">debug&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sb">`Processing input data: &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">JSON&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">stringify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">input&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">`&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="三哪些代码不需要加日志">三、哪些代码不需要加日志？
&lt;/h2>&lt;p>以下是通常不需要添加日志的场景，以避免日志冗余或性能问题：&lt;/p>
&lt;h3 id="1-常规循环或高频操作">1. 常规循环或高频操作
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>场景&lt;/strong>：频繁执行的循环体或高频调用的函数。&lt;/li>
&lt;li>&lt;strong>原因&lt;/strong>：记录每一次循环会导致日志量激增，影响性能且难以分析。&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 不需要记录&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">1000&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">logger&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Processing item {}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// 错误：日志量过大&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">processItem&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 正确做法：记录循环整体&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">logger&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Starting to process 1000 items&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">1000&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">processItem&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">logger&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Finished processing 1000 items&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;h3 id="2-临时或中间变量">2. 临时或中间变量
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>场景&lt;/strong>：仅用于计算的中间变量或临时状态。&lt;/li>
&lt;li>&lt;strong>原因&lt;/strong>：这些信息通常对问题排查无帮助，增加日志噪音。&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 不需要记录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">temp_result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">calculate_temp_value&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">debug&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Temporary result: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">temp_result&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 冗余日志&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;h3 id="3-敏感信息">3. 敏感信息
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>场景&lt;/strong>：包含密码、Token、个人身份信息（PII）等敏感数据。&lt;/li>
&lt;li>&lt;strong>原因&lt;/strong>：记录敏感信息可能违反隐私法规（如GDPR）或导致安全风险。&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 不需要记录&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">logger&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;User password: {}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getPassword&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// 错误：泄露敏感信息&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 正确做法&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">logger&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;User {} authentication attempt&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getId&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;h3 id="4-确定性且无意义的重复操作">4. 确定性且无意义的重复操作
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>场景&lt;/strong>：无状态变化或无意义的重复操作，如定时任务的每次心跳。&lt;/li>
&lt;li>&lt;strong>原因&lt;/strong>：这些日志无助于问题排查，且增加存储和分析成本。&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 不需要记录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">while&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Heartbeat check&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 冗余日志&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">60&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 正确做法：仅记录异常或关键状态&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Heartbeat service started&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;h3 id="5-静态或配置信息">5. 静态或配置信息
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>场景&lt;/strong>：硬编码的常量、静态配置或无需动态监控的信息。&lt;/li>
&lt;li>&lt;strong>原因&lt;/strong>：这些信息固定不变，重复记录无意义。&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 不需要记录&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">logger&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;API endpoint: {}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">API_ENDPOINT&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// 静态信息，无需重复记录&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="四日志记录的最佳实践">四、日志记录的最佳实践
&lt;/h2>&lt;p>为确保日志的有效性和可维护性，遵循以下最佳实践：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>使用适当的日志级别&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>DEBUG&lt;/strong>：开发调试信息，生产环境通常禁用。&lt;/li>
&lt;li>&lt;strong>INFO&lt;/strong>：记录正常操作或关键事件。&lt;/li>
&lt;li>&lt;strong>WARN&lt;/strong>：潜在问题或非致命错误。&lt;/li>
&lt;li>&lt;strong>ERROR&lt;/strong>：业务或系统错误，需关注。&lt;/li>
&lt;li>&lt;strong>FATAL&lt;/strong>：导致系统崩溃的严重错误（较少使用）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>结构化日志&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>使用结构化日志（如JSON格式）便于机器解析和分析。&lt;/li>
&lt;li>示例：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;timestamp&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;2025-07-12T21:07:00Z&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;level&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;INFO&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;module&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;payment&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;message&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Payment processed&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;order_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;12345&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;amount&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mf">100.50&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>添加上下文信息&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>包括请求ID、用户ID、时间戳等，方便追踪问题。&lt;/li>
&lt;li>示例：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">logger&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Processing request [{}] for user {}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">requestId&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">userId&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>避免日志泛滥&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>使用采样或限制日志频率（如每分钟记录一次汇总信息）。&lt;/li>
&lt;li>示例：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mf">0.1&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="c1"># 10%采样率&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">debug&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Sampled log: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>集中式日志管理&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>使用日志框架（如Log4j、SLF4J、Python logging）集中管理日志。&lt;/li>
&lt;li>将日志输出到文件、数据库或日志系统（如ELK、Loki）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>定期清理和归档&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>配置日志轮转（rotation）和过期策略，避免存储空间不足。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>测试日志覆盖率&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>在开发阶段，确保关键路径和异常场景都有日志覆盖。&lt;/li>
&lt;li>使用日志分析工具验证日志是否清晰、完整。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="五实现示例以python为例">五、实现示例（以Python为例）
&lt;/h2>&lt;p>以下是一个完整的Python示例，展示如何在项目中合理添加日志：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">logging&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 配置日志&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">basicConfig&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">level&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">INFO&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">format&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="si">%(asctime)s&lt;/span>&lt;span class="s1"> [&lt;/span>&lt;span class="si">%(levelname)s&lt;/span>&lt;span class="s1">] &lt;/span>&lt;span class="si">%(name)s&lt;/span>&lt;span class="s1">: &lt;/span>&lt;span class="si">%(message)s&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">filename&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;app.log&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">logger&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getLogger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;MyApp&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">process_payment&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">order_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Starting payment processing for order &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">order_id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, amount &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">amount&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 模拟支付处理&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">amount&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Invalid amount&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Payment for order &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">order_id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> processed successfully&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Payment failed for order &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">order_id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">exc_info&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Application started&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">orders&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">100.0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mf">50.0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">200.0&lt;/span>&lt;span class="p">)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 不需要为每个订单项记录日志，只记录汇总&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Processing &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">orders&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> orders&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">order_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">orders&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">process_payment&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">order_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Finished processing orders&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>输出日志（app.log）&lt;/strong>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">2025-07-12 21:07:00,123 [INFO] MyApp: Application started
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">2025-07-12 21:07:00,124 [INFO] MyApp: Processing 3 orders
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">2025-07-12 21:07:01,125 [INFO] MyApp: Starting payment processing for order 1, amount 100.0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">2025-07-12 21:07:02,126 [INFO] MyApp: Payment for order 1 processed successfully
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">2025-07-12 21:07:02,127 [INFO] MyApp: Starting payment processing for order 2, amount -50.0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">2025-07-12 21:07:03,128 [ERROR] MyApp: Payment failed for order 2: Invalid amount
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Traceback (most recent call last):
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> File &amp;#34;...&amp;#34;, line 15, in process_payment
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> raise ValueError(&amp;#34;Invalid amount&amp;#34;)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ValueError: Invalid amount
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">2025-07-12 21:07:03,129 [INFO] MyApp: Starting payment processing for order 3, amount 200.0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">2025-07-12 21:07:04,130 [INFO] MyApp: Payment for order 3 processed successfully
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">2025-07-12 21:07:04,131 [INFO] MyApp: Finished processing orders
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="六常见问题与解答">六、常见问题与解答
&lt;/h2>&lt;ol>
&lt;li>
&lt;p>&lt;strong>如何判断日志是否足够？&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>检查是否能通过日志复现问题、定位错误根因。&lt;/li>
&lt;li>确保关键路径和异常场景都有日志覆盖。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>如何避免日志过多？&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>使用DEBUG级别仅在开发环境记录。&lt;/li>
&lt;li>对高频操作进行采样或汇总。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>如何处理敏感信息？&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>使用脱敏工具或过滤器，避免记录敏感数据。&lt;/li>
&lt;li>示例：将密码替换为&lt;code>***&lt;/code>。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>生产环境中如何管理日志？&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>使用日志收集系统（如ELK、Graylog）。&lt;/li>
&lt;li>配置日志级别为INFO或以上，关闭DEBUG。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="七总结">七、总结
&lt;/h2>&lt;ul>
&lt;li>&lt;strong>需要加日志的场景&lt;/strong>：系统关键事件、业务逻辑节点、异常处理、外部交互、性能监控、安全事件、调试信息。&lt;/li>
&lt;li>&lt;strong>不需要加日志的场景&lt;/strong>：高频循环、临时变量、敏感信息、重复操作、静态信息。&lt;/li>
&lt;li>&lt;strong>最佳实践&lt;/strong>：使用适当日志级别、结构化日志、添加上下文、避免泛滥、集中管理、定期清理。&lt;/li>
&lt;/ul>
&lt;p>通过遵循上述原则和实践，可以在项目中实现高效、清晰的日志记录，助力开发和运维工作。如果你有具体的项目场景或代码片段需要进一步分析，请提供详情，我可以帮你优化日志策略！&lt;/p></description></item><item><title>代码写作心得-使用教程</title><link>https://www.zata.cc/p/%E4%BB%A3%E7%A0%81%E5%86%99%E4%BD%9C%E5%BF%83%E5%BE%97-%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</link><pubDate>Wed, 11 Jun 2025 14:42:33 +0800</pubDate><guid>https://www.zata.cc/p/%E4%BB%A3%E7%A0%81%E5%86%99%E4%BD%9C%E5%BF%83%E5%BE%97-%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</guid><description>&lt;img src="https://www.zata.cc/p/%E4%BB%A3%E7%A0%81%E5%86%99%E4%BD%9C%E5%BF%83%E5%BE%97-%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/index.png" alt="Featured image of post 代码写作心得-使用教程" />&lt;h3 id="日志的编写">日志的编写
&lt;/h3>&lt;p>在项目中写日志是一个非常重要也是非常好的习惯，可以帮我错误的溯源。我习惯于创建一个get_logger(name)方法，然后其他文件都使用这个方法去创建日志
&lt;img src="https://www.zata.cc/p/%E4%BB%A3%E7%A0%81%E5%86%99%E4%BD%9C%E5%BF%83%E5%BE%97-%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image.png"
width="1416"
height="691"
srcset="https://www.zata.cc/p/%E4%BB%A3%E7%A0%81%E5%86%99%E4%BD%9C%E5%BF%83%E5%BE%97-%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image_hu2115254663713972843.png 480w, https://www.zata.cc/p/%E4%BB%A3%E7%A0%81%E5%86%99%E4%BD%9C%E5%BF%83%E5%BE%97-%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image_hu5529201018325630629.png 1024w"
loading="lazy"
alt="日志结构"
class="gallery-image"
data-flex-grow="204"
data-flex-basis="491px"
>&lt;/p>
&lt;p>下面是logger.py的写法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">logging&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建日志器 &amp;#34;Create a logger&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">logger&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getLogger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Upick&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setLevel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DEBUG&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 设置全局日志级别&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建日志处理器（输出到控制台） &amp;#34;Create a log handler (output to the console)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">console_handler&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">StreamHandler&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">console_handler&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setLevel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">INFO&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 控制台显示 INFO 及以上级别&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建日志处理器（输出到文件） &amp;#34;Create a log handler (output to the file)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">log_dir&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;logs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exists&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">log_dir&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">makedirs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">log_dir&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">file_handler&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">FileHandler&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">log_dir&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;app.log&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">encoding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;utf-8&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">file_handler&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setLevel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DEBUG&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 文件记录 DEBUG 及以上级别&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 设置日志格式 &amp;#34;Set the log format&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">formatter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Formatter&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">%(asctime)s&lt;/span>&lt;span class="s2"> - &lt;/span>&lt;span class="si">%(name)s&lt;/span>&lt;span class="s2"> - &lt;/span>&lt;span class="si">%(levelname)s&lt;/span>&lt;span class="s2"> - &lt;/span>&lt;span class="si">%(filename)s&lt;/span>&lt;span class="s2">:&lt;/span>&lt;span class="si">%(lineno)d&lt;/span>&lt;span class="s2"> - &lt;/span>&lt;span class="si">%(message)s&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">console_handler&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setFormatter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">formatter&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">file_handler&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setFormatter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">formatter&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 将处理器添加到日志器 &amp;#34;Add the handler to the logger&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">addHandler&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">console_handler&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">addHandler&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_handler&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 提供获取日志器的方法 &amp;#34;Provide a method to get the logger&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_logger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Get a logger with the given name.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Args:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> name (str): The name of the logger.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Returns:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> logging.Logger: The logger.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getLogger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Upick.&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>使用的时候就使用logger = get_logger(&lt;strong>name&lt;/strong>)这样的方法 来创建&lt;/p></description></item><item><title>软件项目开发流程使用教程</title><link>https://www.zata.cc/p/%E8%BD%AF%E4%BB%B6%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91%E6%B5%81%E7%A8%8B%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</link><pubDate>Wed, 23 Apr 2025 17:50:29 +0800</pubDate><guid>https://www.zata.cc/p/%E8%BD%AF%E4%BB%B6%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91%E6%B5%81%E7%A8%8B%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</guid><description>&lt;img src="https://www.zata.cc/p/%E8%BD%AF%E4%BB%B6%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91%E6%B5%81%E7%A8%8B%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/index.png" alt="Featured image of post 软件项目开发流程使用教程" />&lt;table>
&lt;thead>
&lt;tr>
&lt;th>&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>- &lt;a class="link" href="#%e5%b8%b8%e7%94%a8" >常用&lt;/a>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="常用">常用
&lt;/h2>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 项目需要创建的文件名&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">demandAnalysis
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">projectArchitecture
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">prototyping &lt;span class="c1"># 原型&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>软件项目的开发流程是一个复杂但结构化的过程，旨在将需求转化为高质量、可用的软件产品。以下是对软件开发流程的详细描述，涵盖每个阶段的活动、工具、参与角色、常见挑战以及最佳实践，结合主流开发方法（如敏捷、瀑布和 DevOps）。我将从需求分析到维护与迭代逐一展开，并提供具体示例和注意事项。&lt;/p>
&lt;hr>
&lt;h3 id="1-需求分析">1. 需求分析
&lt;/h3>&lt;p>&lt;strong>目标&lt;/strong>：明确软件需要解决的问题、功能需求、非功能需求以及约束条件，确保开发方向与客户或用户期望一致。&lt;/p>
&lt;h4 id="活动">活动
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>需求收集&lt;/strong>：
&lt;ul>
&lt;li>通过访谈、问卷、焦点小组或观察与客户、最终用户及利益相关者沟通。&lt;/li>
&lt;li>识别核心功能（如“用户需要登录系统”）和非功能需求（如“系统需支持 1000 个并发用户”）。&lt;/li>
&lt;li>示例：为一个电商平台，需求可能包括“用户浏览商品、加入购物车、下单支付”以及“系统需在 2 秒内响应”。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>需求分析&lt;/strong>：
&lt;ul>
&lt;li>分析需求的优先级、可行性和潜在冲突。&lt;/li>
&lt;li>使用工具如用户故事（User Stories）或用例（Use Cases）描述需求。例如：“作为用户，我希望能通过手机号快速注册，以便节省时间。”&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>需求文档化&lt;/strong>：
&lt;ul>
&lt;li>编写需求规格说明书（SRS），包括功能描述、性能要求、约束条件等。&lt;/li>
&lt;li>可视化需求，如流程图、用例图或实体关系图（ERD）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h4 id="参与角色">参与角色
&lt;/h4>&lt;ul>
&lt;li>产品经理（Product Manager）：定义产品愿景，协调需求。&lt;/li>
&lt;li>业务分析师（Business Analyst）：细化需求，编写文档。&lt;/li>
&lt;li>客户/利益相关者：提供业务背景和期望。&lt;/li>
&lt;li>开发团队代表：评估技术可行性。&lt;/li>
&lt;/ul>
&lt;h4 id="工具">工具
&lt;/h4>&lt;ul>
&lt;li>需求管理：Jira、Confluence、Trello。&lt;/li>
&lt;li>建模工具：Lucidchart、Draw.io、Enterprise Architect。&lt;/li>
&lt;/ul>
&lt;h4 id="挑战">挑战
&lt;/h4>&lt;ul>
&lt;li>需求模糊或频繁变更。&lt;/li>
&lt;li>客户与开发团队的期望不一致。&lt;/li>
&lt;li>遗漏关键需求（如安全性或可扩展性）。&lt;/li>
&lt;/ul>
&lt;h4 id="最佳实践">最佳实践
&lt;/h4>&lt;ul>
&lt;li>使用 SMART 原则（Specific、Measurable、Achievable、Relevant、Time-bound）定义需求。&lt;/li>
&lt;li>定期与客户确认需求，避免误解。&lt;/li>
&lt;li>建立需求追踪矩阵，确保每个需求可追溯到最终实现。&lt;/li>
&lt;/ul>
&lt;h4 id="输出">输出
&lt;/h4>&lt;ul>
&lt;li>需求规格说明书（SRS）。&lt;/li>
&lt;li>用户故事或用例集。&lt;/li>
&lt;li>初步项目范围和预算估计。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="2-规划与设计">2. 规划与设计
&lt;/h3>&lt;p>&lt;strong>目标&lt;/strong>：为开发提供清晰的蓝图，包括系统架构、用户界面和技术选型，同时制定项目执行计划。&lt;/p>
&lt;h4 id="活动-1">活动
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>系统架构设计&lt;/strong>：
&lt;ul>
&lt;li>确定技术栈（如前端使用 React，后端使用 Node.js，数据库使用 PostgreSQL）。&lt;/li>
&lt;li>设计系统组件（如微服务架构、前后端分离）。&lt;/li>
&lt;li>规划安全性（如认证授权、数据加密）和可扩展性。&lt;/li>
&lt;li>示例：为电商平台设计 RESTful API，包含用户、商品、订单等模块。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>用户界面/体验设计（UI/UX）&lt;/strong>：
&lt;ul>
&lt;li>创建线框图（Wireframes）和高保真原型（Mockups）。&lt;/li>
&lt;li>进行用户测试，优化交互流程。&lt;/li>
&lt;li>示例：设计直观的购物车页面，减少用户操作步骤。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>项目计划&lt;/strong>：
&lt;ul>
&lt;li>制定时间表，划分里程碑（如“完成用户模块开发”）。&lt;/li>
&lt;li>分配资源（开发人员、测试人员等）。&lt;/li>
&lt;li>评估风险（如技术债务、依赖第三方 API）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>技术选型&lt;/strong>：
&lt;ul>
&lt;li>选择编程语言、框架、库和工具。&lt;/li>
&lt;li>考虑开发效率、社区支持和长期维护成本。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h4 id="参与角色-1">参与角色
&lt;/h4>&lt;ul>
&lt;li>架构师：设计系统结构。&lt;/li>
&lt;li>UI/UX 设计师：创建界面原型。&lt;/li>
&lt;li>项目经理：制定计划，协调资源。&lt;/li>
&lt;li>开发团队：提供技术建议。&lt;/li>
&lt;/ul>
&lt;h4 id="工具-1">工具
&lt;/h4>&lt;ul>
&lt;li>设计：Figma、Sketch、Adobe XD。&lt;/li>
&lt;li>架构建模：Visio、ArchiMate。&lt;/li>
&lt;li>项目管理：Microsoft Project、Asana、Jira。&lt;/li>
&lt;/ul>
&lt;h4 id="挑战-1">挑战
&lt;/h4>&lt;ul>
&lt;li>架构设计过于复杂，导致开发成本高。&lt;/li>
&lt;li>忽略长期维护需求，选择不合适的框架。&lt;/li>
&lt;li>计划过于乐观，忽略缓冲时间。&lt;/li>
&lt;/ul>
&lt;h4 id="最佳实践-1">最佳实践
&lt;/h4>&lt;ul>
&lt;li>遵循 KISS（Keep It Simple, Stupid）原则，设计简洁的架构。&lt;/li>
&lt;li>使用设计模式（如 MVC、微服务）提高代码可维护性。&lt;/li>
&lt;li>制定灵活的计划，预留 10-20% 的时间应对意外。&lt;/li>
&lt;/ul>
&lt;h4 id="输出-1">输出
&lt;/h4>&lt;ul>
&lt;li>系统架构图（如 UML 图、ERD）。&lt;/li>
&lt;li>UI/UX 原型。&lt;/li>
&lt;li>项目计划（甘特图、任务分解结构）。&lt;/li>
&lt;li>技术选型报告。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="3-开发编码">3. 开发（编码）
&lt;/h3>&lt;p>&lt;strong>目标&lt;/strong>：根据设计文档实现软件功能，编写高质量、可维护的代码。&lt;/p>
&lt;h4 id="活动-2">活动
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>代码实现&lt;/strong>：
&lt;ul>
&lt;li>前端开发：构建用户界面（如 React、Vue.js）。&lt;/li>
&lt;li>后端开发：实现业务逻辑和 API（如 Spring Boot、Django）。&lt;/li>
&lt;li>数据库开发：设计和优化数据库 schema（如 MySQL、MongoDB）。&lt;/li>
&lt;li>示例：为电商平台开发“添加商品到购物车”的 API 和前端交互。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>版本控制&lt;/strong>：
&lt;ul>
&lt;li>使用 Git 进行代码管理，创建分支（如 feature、bugfix）。&lt;/li>
&lt;li>通过 Pull Request（PR）进行代码审查。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>敏捷开发（可选）&lt;/strong>：
&lt;ul>
&lt;li>按迭代（通常 2-4 周）开发，交付最小可行产品（MVP）。&lt;/li>
&lt;li>每日站会（Daily Standup）跟踪进度。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>文档编写&lt;/strong>：
&lt;ul>
&lt;li>编写 API 文档（如 Swagger）。&lt;/li>
&lt;li>维护代码注释和技术文档。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h4 id="参与角色-2">参与角色
&lt;/h4>&lt;ul>
&lt;li>开发人员（前端、后端、全栈）：编写代码。&lt;/li>
&lt;li>技术负责人（Tech Lead）：指导技术实现，审查代码。&lt;/li>
&lt;li>产品经理：确保功能符合需求。&lt;/li>
&lt;/ul>
&lt;h4 id="工具-2">工具
&lt;/h4>&lt;ul>
&lt;li>IDE：VS Code、IntelliJ IDEA、PyCharm。&lt;/li>
&lt;li>版本控制：GitHub、GitLab、Bitbucket。&lt;/li>
&lt;li>文档：Swagger、Postman（API 测试）。&lt;/li>
&lt;/ul>
&lt;h4 id="挑战-2">挑战
&lt;/h4>&lt;ul>
&lt;li>技术债务（如快速实现功能但代码质量差）。&lt;/li>
&lt;li>团队协作问题（如代码冲突）。&lt;/li>
&lt;li>需求变更导致返工。&lt;/li>
&lt;/ul>
&lt;h4 id="最佳实践-2">最佳实践
&lt;/h4>&lt;ul>
&lt;li>遵循编码规范（如 PEP 8 for Python）。&lt;/li>
&lt;li>编写单元测试（如 JUnit、PyTest）确保代码质量。&lt;/li>
&lt;li>定期重构代码，减少技术债务。&lt;/li>
&lt;/ul>
&lt;h4 id="输出-2">输出
&lt;/h4>&lt;ul>
&lt;li>可运行的软件模块。&lt;/li>
&lt;li>API 文档。&lt;/li>
&lt;li>单元测试用例。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="4-测试">4. 测试
&lt;/h3>&lt;p>&lt;strong>目标&lt;/strong>：验证软件是否满足需求，确保功能正确、性能可靠、无重大缺陷。&lt;/p>
&lt;h4 id="活动-3">活动
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>测试类型&lt;/strong>：
&lt;ul>
&lt;li>&lt;strong>单元测试&lt;/strong>：测试单个函数或模块（如测试“计算订单总价”函数）。&lt;/li>
&lt;li>&lt;strong>集成测试&lt;/strong>：测试模块间交互（如前端与后端 API 集成）。&lt;/li>
&lt;li>&lt;strong>系统测试&lt;/strong>：测试整个系统功能（如端到端流程）。&lt;/li>
&lt;li>&lt;strong>性能测试&lt;/strong>：测试系统在高负载下的表现（如 1000 用户并发）。&lt;/li>
&lt;li>&lt;strong>安全测试&lt;/strong>：检查漏洞（如 SQL 注入、XSS）。&lt;/li>
&lt;li>&lt;strong>用户验收测试（UAT）&lt;/strong>：客户验证软件是否满足业务需求。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>测试执行&lt;/strong>：
&lt;ul>
&lt;li>自动化测试：使用工具运行回归测试。&lt;/li>
&lt;li>手动测试：探索性测试，验证复杂场景。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>缺陷管理&lt;/strong>：
&lt;ul>
&lt;li>记录 bug（如通过 Jira），分配给开发人员修复。&lt;/li>
&lt;li>验证修复后的功能。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h4 id="参与角色-3">参与角色
&lt;/h4>&lt;ul>
&lt;li>测试工程师（QA）：设计和执行测试用例。&lt;/li>
&lt;li>开发人员：修复 bug，编写自动化测试。&lt;/li>
&lt;li>客户：参与 UAT。&lt;/li>
&lt;/ul>
&lt;h4 id="工具-3">工具
&lt;/h4>&lt;ul>
&lt;li>测试框架：Selenium、Cypress、JUnit。&lt;/li>
&lt;li>性能测试：JMeter、LoadRunner。&lt;/li>
&lt;li>缺陷管理：Jira、Bugzilla。&lt;/li>
&lt;/ul>
&lt;h4 id="挑战-3">挑战
&lt;/h4>&lt;ul>
&lt;li>测试覆盖率不足，遗漏边缘情况。&lt;/li>
&lt;li>测试环境与生产环境不一致。&lt;/li>
&lt;li>时间压力导致测试不充分。&lt;/li>
&lt;/ul>
&lt;h4 id="最佳实践-3">最佳实践
&lt;/h4>&lt;ul>
&lt;li>编写自动化测试覆盖核心功能，减少手动测试负担。&lt;/li>
&lt;li>使用测试驱动开发（TDD），先写测试再写代码。&lt;/li>
&lt;li>定期更新测试用例，适应需求变化。&lt;/li>
&lt;/ul>
&lt;h4 id="输出-3">输出
&lt;/h4>&lt;ul>
&lt;li>测试计划和用例。&lt;/li>
&lt;li>测试报告（包括缺陷统计）。&lt;/li>
&lt;li>稳定的软件版本。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="5-部署">5. 部署
&lt;/h3>&lt;p>&lt;strong>目标&lt;/strong>：将软件部署到生产环境，供用户使用。&lt;/p>
&lt;h4 id="活动-4">活动
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>环境准备&lt;/strong>：
&lt;ul>
&lt;li>配置生产服务器、数据库、负载均衡器等。&lt;/li>
&lt;li>确保安全性（如 SSL 证书、防火墙）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>部署流程&lt;/strong>：
&lt;ul>
&lt;li>使用 CI/CD 管道（如 Jenkins、GitHub Actions）自动化部署。&lt;/li>
&lt;li>可能采用蓝绿部署或金丝雀部署，降低上线风险。&lt;/li>
&lt;li>示例：将电商平台部署到 AWS，使用 Docker 容器化。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>用户支持&lt;/strong>：
&lt;ul>
&lt;li>提供用户手册、培训或在线帮助。&lt;/li>
&lt;li>设置反馈渠道（如客服系统）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h4 id="参与角色-4">参与角色
&lt;/h4>&lt;ul>
&lt;li>运维工程师（DevOps）：配置和部署系统。&lt;/li>
&lt;li>开发人员：支持部署中的问题排查。&lt;/li>
&lt;li>客户支持团队：协助用户使用。&lt;/li>
&lt;/ul>
&lt;h4 id="工具-4">工具
&lt;/h4>&lt;ul>
&lt;li>部署：Docker、Kubernetes、Ansible。&lt;/li>
&lt;li>CI/CD：Jenkins、CircleCI、GitLab CI。&lt;/li>
&lt;li>云服务：AWS、Azure、Google Cloud。&lt;/li>
&lt;/ul>
&lt;h4 id="挑战-4">挑战
&lt;/h4>&lt;ul>
&lt;li>部署失败（如配置错误）。&lt;/li>
&lt;li>生产环境问题未在测试中暴露。&lt;/li>
&lt;li>用户反馈不佳。&lt;/li>
&lt;/ul>
&lt;h4 id="最佳实践-4">最佳实践
&lt;/h4>&lt;ul>
&lt;li>使用基础设施即代码（IaC，如 Terraform）管理环境。&lt;/li>
&lt;li>监控部署过程，快速回滚失败部署。&lt;/li>
&lt;li>分阶段部署（如先部署到部分用户）。&lt;/li>
&lt;/ul>
&lt;h4 id="输出-4">输出
&lt;/h4>&lt;ul>
&lt;li>上线运行的软件。&lt;/li>
&lt;li>用户文档或培训材料。&lt;/li>
&lt;li>部署日志。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="6-维护与迭代">6. 维护与迭代
&lt;/h3>&lt;p>&lt;strong>目标&lt;/strong>：确保软件长期稳定运行，持续改进以满足新需求或技术变化。&lt;/p>
&lt;h4 id="活动-5">活动
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>监控与维护&lt;/strong>：
&lt;ul>
&lt;li>监控系统性能（如 CPU 使用率、响应时间）。&lt;/li>
&lt;li>修复运行时问题（如内存泄漏、数据库死锁）。&lt;/li>
&lt;li>示例：监控电商平台高峰期的订单处理速度。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>功能迭代&lt;/strong>：
&lt;ul>
&lt;li>根据用户反馈添加新功能（如支持新的支付方式）。&lt;/li>
&lt;li>优化现有功能（如提高搜索效率）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>技术更新&lt;/strong>：
&lt;ul>
&lt;li>更新依赖库、框架或操作系统，修复安全漏洞。&lt;/li>
&lt;li>迁移到新平台（如从本地服务器到云）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h4 id="参与角色-5">参与角色
&lt;/h4>&lt;ul>
&lt;li>运维团队：监控和维护系统。&lt;/li>
&lt;li>开发团队：开发新功能，修复问题。&lt;/li>
&lt;li>产品经理：规划迭代方向。&lt;/li>
&lt;/ul>
&lt;h4 id="工具-5">工具
&lt;/h4>&lt;ul>
&lt;li>监控：Prometheus、Grafana、New Relic。&lt;/li>
&lt;li>日志管理：ELK Stack、Splunk。&lt;/li>
&lt;li>更新管理：Dependabot、Snyk。&lt;/li>
&lt;/ul>
&lt;h4 id="挑战-5">挑战
&lt;/h4>&lt;ul>
&lt;li>维护成本高，技术债务累积。&lt;/li>
&lt;li>用户对新功能的接受度低。&lt;/li>
&lt;li>旧系统迁移困难。&lt;/li>
&lt;/ul>
&lt;h4 id="最佳实践-5">最佳实践
&lt;/h4>&lt;ul>
&lt;li>建立完善的监控和告警系统，快速响应问题。&lt;/li>
&lt;li>定期回顾用户反馈，优先解决高价值问题。&lt;/li>
&lt;li>规划技术债务偿还时间，避免系统老化。&lt;/li>
&lt;/ul>
&lt;h4 id="输出-5">输出
&lt;/h4>&lt;ul>
&lt;li>软件更新或新版本。&lt;/li>
&lt;li>维护报告。&lt;/li>
&lt;li>用户反馈分析。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="主流开发方法">主流开发方法
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>瀑布模型&lt;/strong>：
&lt;ul>
&lt;li>线性流程，每个阶段完成后进入下一阶段。&lt;/li>
&lt;li>适合需求明确、变更少的项目（如政府系统）。&lt;/li>
&lt;li>缺点：缺乏灵活性，难以适应需求变化。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>敏捷开发&lt;/strong>（Scrum、Kanban）：
&lt;ul>
&lt;li>按短迭代（2-4 周）交付功能，强调用户反馈。&lt;/li>
&lt;li>适合需求可能变化的项目（如初创公司产品）。&lt;/li>
&lt;li>实践：每日站会、冲刺计划、回顾会议。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>DevOps&lt;/strong>：
&lt;ul>
&lt;li>整合开发和运维，强调 CI/CD 和自动化。&lt;/li>
&lt;li>适合需要频繁部署的项目（如 SaaS 平台）。&lt;/li>
&lt;li>实践：自动化测试、基础设施即代码、监控。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h3 id="通用最佳实践">通用最佳实践
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>持续沟通&lt;/strong>：开发团队、产品经理和客户需保持透明沟通，使用工具如 Slack 或 Microsoft Teams。&lt;/li>
&lt;li>&lt;strong>质量优先&lt;/strong>：通过代码审查、测试和监控确保高质量交付。&lt;/li>
&lt;li>&lt;strong>用户为中心&lt;/strong>：从需求到维护，始终关注用户体验和反馈。&lt;/li>
&lt;li>&lt;strong>灵活性&lt;/strong>：根据项目规模和复杂性调整流程（如小型项目可简化文档）。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="示例开发一个电商平台的流程">示例：开发一个电商平台的流程
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>需求分析&lt;/strong>：收集需求，如“用户可搜索商品、下单支付”，“系统支持 5000 并发用户”。&lt;/li>
&lt;li>&lt;strong>规划与设计&lt;/strong>：设计微服务架构（用户服务、商品服务、订单服务），创建 UI 原型。&lt;/li>
&lt;li>&lt;strong>开发&lt;/strong>：前端使用 React 实现商品展示，后端用 Spring Boot 开发 API，数据库用 MySQL。&lt;/li>
&lt;li>&lt;strong>测试&lt;/strong>：运行单元测试验证 API，执行负载测试模拟高峰流量。&lt;/li>
&lt;li>&lt;strong>部署&lt;/strong>：使用 AWS ECS 部署 Docker 容器，配置 CloudWatch 监控。&lt;/li>
&lt;li>&lt;strong>维护&lt;/strong>：监控订单处理速度，根据用户反馈添加“推荐商品”功能。&lt;/li>
&lt;/ol>
&lt;hr></description></item><item><title>怎么保存.env文件到github公开的仓库</title><link>https://www.zata.cc/p/%E6%80%8E%E4%B9%88%E4%BF%9D%E5%AD%98.env%E6%96%87%E4%BB%B6%E5%88%B0github%E5%85%AC%E5%BC%80%E7%9A%84%E4%BB%93%E5%BA%93/</link><pubDate>Wed, 05 Mar 2025 11:49:38 +0800</pubDate><guid>https://www.zata.cc/p/%E6%80%8E%E4%B9%88%E4%BF%9D%E5%AD%98.env%E6%96%87%E4%BB%B6%E5%88%B0github%E5%85%AC%E5%BC%80%E7%9A%84%E4%BB%93%E5%BA%93/</guid><description>&lt;img src="https://www.zata.cc/p/%E6%80%8E%E4%B9%88%E4%BF%9D%E5%AD%98.env%E6%96%87%E4%BB%B6%E5%88%B0github%E5%85%AC%E5%BC%80%E7%9A%84%E4%BB%93%E5%BA%93/images/index/index.png" alt="Featured image of post 怎么保存.env文件到github公开的仓库" />&lt;h3 id="如何安全地将-env-文件保存到-github-公开仓库">如何安全地将 .env 文件保存到 GitHub 公开仓库
&lt;/h3>&lt;p>&lt;img src="https://www.zata.cc/p/%E6%80%8E%E4%B9%88%E4%BF%9D%E5%AD%98.env%E6%96%87%E4%BB%B6%E5%88%B0github%E5%85%AC%E5%BC%80%E7%9A%84%E4%BB%93%E5%BA%93/images/index/index.png"
width="624"
height="574"
srcset="https://www.zata.cc/p/%E6%80%8E%E4%B9%88%E4%BF%9D%E5%AD%98.env%E6%96%87%E4%BB%B6%E5%88%B0github%E5%85%AC%E5%BC%80%E7%9A%84%E4%BB%93%E5%BA%93/images/index/index_hu6347196281552445238.png 480w, https://www.zata.cc/p/%E6%80%8E%E4%B9%88%E4%BF%9D%E5%AD%98.env%E6%96%87%E4%BB%B6%E5%88%B0github%E5%85%AC%E5%BC%80%E7%9A%84%E4%BB%93%E5%BA%93/images/index/index_hu11359646987435289252.png 1024w"
loading="lazy"
alt="使用7-zip加密自己的.env文件"
class="gallery-image"
data-flex-grow="108"
data-flex-basis="260px"
>&lt;/p>
&lt;h4 id="背景">背景
&lt;/h4>&lt;p>&lt;code>.env&lt;/code> 文件通常用于存储敏感信息（如 API 密钥、数据库凭据等），直接将其上传到 GitHub 公开仓库会导致安全风险。为了在公开仓库中保存 &lt;code>.env&lt;/code> 文件，同时保护其内容，一种可行的方法是使用加密压缩（如 &lt;code>.zip&lt;/code> 文件）并设置只有自己知道的密码。&lt;/p>
&lt;h4 id="操作步骤">操作步骤
&lt;/h4>&lt;ol>
&lt;li>
&lt;p>&lt;strong>准备 .env 文件&lt;/strong>&lt;br>
确保你的 &lt;code>.env&lt;/code> 文件已经包含所有必要的环境变量，例如：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">API_KEY=your_api_key
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">DB_PASSWORD=your_password
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>加密压缩文件&lt;/strong>&lt;br>
使用工具（如 &lt;code>7-Zip&lt;/code> 或命令行工具）将 &lt;code>.env&lt;/code> 文件压缩为 &lt;code>.zip&lt;/code> 文件，并设置密码：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Windows (使用 7-Zip)&lt;/strong>&lt;br>
右键 &lt;code>.env&lt;/code> 文件 → 选择“添加到压缩包” → 在“加密”部分输入密码 → 确认生成 &lt;code>.env.zip&lt;/code>。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>上传到 GitHub&lt;/strong>&lt;br>
将生成的 &lt;code>.env.zip&lt;/code> 文件提交并推送到 GitHub 公开仓库：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">git add env.zip
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &amp;#34;Add encrypted .env file&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>使用时解密&lt;/strong>&lt;br>
下载 &lt;code>.env.zip&lt;/code> 文件后，使用密码解密：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>命令行&lt;/strong>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">unzip -P your_password env.zip
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>或者使用解压软件，输入密码手动解压，比如在windows系统还是使用7-zip。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h4 id="注意事项">注意事项
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>密码管理&lt;/strong>：密码不要记录在任何公开的地方，建议使用密码管理器保存。&lt;/li>
&lt;li>&lt;strong>安全性&lt;/strong>：&lt;code>.zip&lt;/code> 的加密强度有限，若涉及高度敏感信息，可考虑更强的加密工具（如 GPG）。&lt;/li>
&lt;li>&lt;strong>gitignore&lt;/strong>：确保未加密的 &lt;code>.env&lt;/code> 文件已被添加到 &lt;code>.gitignore&lt;/code>，避免意外上传。&lt;/li>
&lt;/ul></description></item><item><title>企业AI工具平台架构设计：拥抱快速变化的AI生态</title><link>https://www.zata.cc/p/ai-platform-architecture/</link><pubDate>Wed, 15 Jan 2025 10:00:00 +0800</pubDate><guid>https://www.zata.cc/p/ai-platform-architecture/</guid><description>&lt;img src="https://www.zata.cc/p/ai-platform-architecture/images/index/index.svg" alt="Featured image of post 企业AI工具平台架构设计：拥抱快速变化的AI生态" />&lt;h1 id="企业ai工具平台架构设计拥抱快速变化的ai生态">企业AI工具平台架构设计：拥抱快速变化的AI生态
&lt;/h1>&lt;blockquote>
&lt;p>&amp;ldquo;唯一不变的是变化本身&amp;rdquo; —— 这句话在AI领域尤为贴切。本文探讨如何设计一个既能满足当前需求，又能优雅应对未来变化的企业AI工具平台。&lt;/p>
&lt;/blockquote>
&lt;h2 id="核心理念">核心理念
&lt;/h2>&lt;blockquote>
&lt;p>&lt;strong>&amp;ldquo;数据是资产，必须持久化；Agent是工具，可以随时替换&amp;rdquo;&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;p>这是本平台设计的核心哲学，贯穿整个架构设计。&lt;/p>
&lt;h3 id="为什么这样设计">为什么这样设计？
&lt;/h3>&lt;p>AI领域的变化速度远超传统软件：&lt;/p>
&lt;ul>
&lt;li>去年最好的模型，今年可能已经被超越&lt;/li>
&lt;li>今年流行的Agent框架，明年可能就有更好的替代&lt;/li>
&lt;li>今天支持的协议，明天可能就有更优的标准&lt;/li>
&lt;/ul>
&lt;p>如果平台紧耦合某个特定的AI服务或Agent框架，当它过时或出问题的时候，平台就会陷入困境。&lt;/p>
&lt;p>而用户的数据——创建的智能体、积累的知识、对话的历史——这些才是真正的资产，不应该因为技术迭代而被丢失。&lt;/p>
&lt;h3 id="分层设计思想">分层设计思想
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 分层架构 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Layer 1: 持久化层 (数据资产) │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ PostgreSQL + 对象存储 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ • 用户数据 • Agent配置 • 知识库原文 • 对话历史 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ★ 永久保留，跨版本迁移，跨供应商迁移 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ (可重建) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Layer 2: 索引层 (可重建) │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 向量数据库 + 搜索引擎 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ • 向量索引 • 倒排索引 • 全文索引 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ← 从 Layer 1 可以100%重建 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ (可替换) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Layer 3: Agent工具层 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 从注册中心动态加载 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ • Claude Code • OpenCAW • OpenCode • Custom... │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ← 随时可替换，配置不变 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ (可扩展) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Layer 4: AI模型层 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 适配器模式 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ • OpenAI • Claude • GLM • Qwen • DeepSeek... │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ← 新模型接入只需实现适配器 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="设计原则">设计原则
&lt;/h3>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>原则&lt;/th>
&lt;th>含义&lt;/th>
&lt;th>实践&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>数据主权&lt;/strong>&lt;/td>
&lt;td>用户的数据属于用户&lt;/td>
&lt;td>可导出、可迁移、可删除&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>存储与计算分离&lt;/strong>&lt;/td>
&lt;td>数据持久化，Agent按需调用&lt;/td>
&lt;td>数据库存数据，运行时加载工具&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>接口稳定，实现可变&lt;/strong>&lt;/td>
&lt;td>契约不变，实现灵活&lt;/td>
&lt;td>固定接口定义，适配器可替换&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>核心稳定，边缘灵活&lt;/strong>&lt;/td>
&lt;td>核心不变，边缘扩展&lt;/td>
&lt;td>稳定层vs灵活层&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Layer 1 是唯一真相&lt;/strong>&lt;/td>
&lt;td>原始数据不可丢失&lt;/td>
&lt;td>索引可重建，原始数据不可&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="三个不怕">三个&amp;quot;不怕&amp;quot;
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 不怕换模型 不怕换Agent 不怕换向量数据库 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ───────── ───────── ────────────── │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 适配器模式 注册中心 索引重建服务 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 接口不变 热插拔 从Layer 1重建 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 配置在DB 配置在DB 原文在PostgreSQL │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 模型随便换 Agent随便换 向量随便换 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="核心价值">核心价值
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>面向未来&lt;/strong>：新模型、新Agent、新协议出现时，可以轻松接入&lt;/li>
&lt;li>&lt;strong>数据安全&lt;/strong>：用户数据永久保留，不因技术迭代而丢失&lt;/li>
&lt;li>&lt;strong>成本可控&lt;/strong>：根据业务需求灵活选择性价比最优的方案&lt;/li>
&lt;li>&lt;strong>员工激励&lt;/strong>：贡献的知识和配置可以跨版本使用&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="背景与挑战">背景与挑战
&lt;/h2>&lt;h3 id="ai领域的现状">AI领域的现状
&lt;/h3>&lt;p>当前AI领域呈现出几个显著特点：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>模型快速迭代&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>国际：GPT-4o、GPT-o1、Claude 3.5、Gemini 2.0 等不断推陈出新&lt;/li>
&lt;li>国内：智谱GLM-4、通义Qwen、DeepSeek、百度文心、字节豆包等百花齐放&lt;/li>
&lt;li>每个模型都有其擅长的领域：推理、创作、长文本、多模态&amp;hellip;&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>工具生态繁荣&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>RAG（检索增强生成）能力日益成熟&lt;/li>
&lt;li>Agent（智能体）框架快速演进&lt;/li>
&lt;li>Function Calling、Tool Use 成为标配&lt;/li>
&lt;li>MCP（Model Context Protocol）协议崭露头角&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>企业需求多样&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>不同部门需要不同的AI能力组合&lt;/li>
&lt;li>不同项目有不同的数据隔离要求&lt;/li>
&lt;li>不同的成本和合规考虑&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>员工参与诉求&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>希望员工能自主创建智能体&lt;/li>
&lt;li>希望能设计适合团队的工作流&lt;/li>
&lt;li>希望能贡献和分享知识&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h3 id="核心痛点">核心痛点
&lt;/h3>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>痛点&lt;/th>
&lt;th>描述&lt;/th>
&lt;th>影响&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>紧耦合&lt;/td>
&lt;td>AI模型直接嵌入业务代码&lt;/td>
&lt;td>新模型接入成本高&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>信息孤岛&lt;/td>
&lt;td>各部门重复建设AI能力&lt;/td>
&lt;td>资源浪费，标准不一&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>难复用&lt;/td>
&lt;td>好的智能体/工作流难以分享&lt;/td>
&lt;td>重复造轮子&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>无激励&lt;/td>
&lt;td>员工贡献无人知晓&lt;/td>
&lt;td>参与度低&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="设计目标">设计目标
&lt;/h3>&lt;p>基于这些背景，我们的设计必须满足：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>扩展性优先&lt;/strong>：新模型、新工具能低成本接入&lt;/li>
&lt;li>&lt;strong>灵活性&lt;/strong>：支持多容器、多项目隔离&lt;/li>
&lt;li>&lt;strong>激励性&lt;/strong>：鼓励员工贡献智能体和工作流&lt;/li>
&lt;li>&lt;strong>核心收敛&lt;/strong>：用户管理与工具接口作为稳定内核&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="整体架构设计">整体架构设计
&lt;/h2>&lt;h3 id="分层架构概览">分层架构概览
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 用户层 (User Layer) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Web Console │ CLI │ API Gateway │ SDK │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├─────────────────────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 业务应用层 (App Layer) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 智能体 │ │ 工作流 │ │ 知识库 │ │ 插件市场 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Agent │ │ Workflow │ │ Knowledge │ │ Marketplace│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├─────────────────────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 编排调度层 (Orchestration) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Agent Runtime │ Workflow Engine │ Task Scheduler │ Event Bus │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├─────────────────────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 核心服务层 (Core Services) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 用户管理 │ │ 容器管理 │ │ 项目管理 │ │ 权限管理 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ User Mgmt │ │ Tenant │ │ Project │ │ Permission │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├─────────────────────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 集成层 (Integration Layer) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Adapter Registry │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ┌────────┐ ┌────────┐┌────────┐ ┌────────┐ ┌────────┐ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ OpenAI │ │Claude │ │ Gemini │ │ 智谱 │ │ 通义 │ ... │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │Adapter │ │Adapter │ │Adapter │ │Adapter │ │Adapter │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├─────────────────────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 外部AI服务 (External AI Services) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ OpenAI │ Anthropic │ Google │ 智谱AI │ 阿里云 │ 百度 │ ... │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="各层职责详解">各层职责详解
&lt;/h3>&lt;h4 id="1-用户层-user-layer">1. 用户层 (User Layer)
&lt;/h4>&lt;p>这是用户与平台交互的入口点，提供多种访问方式：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>入口&lt;/th>
&lt;th>说明&lt;/th>
&lt;th>典型场景&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Web Console&lt;/strong>&lt;/td>
&lt;td>浏览器访问的管理控制台&lt;/td>
&lt;td>日常管理、智能体创建&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>CLI&lt;/strong>&lt;/td>
&lt;td>命令行工具&lt;/td>
&lt;td>开发者集成、自动化脚本&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>API Gateway&lt;/strong>&lt;/td>
&lt;td>RESTful API&lt;/td>
&lt;td>第三方集成、系统对接&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>SDK&lt;/strong>&lt;/td>
&lt;td>多语言SDK&lt;/td>
&lt;td>应用内集成&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h4 id="2-业务应用层-app-layer">2. 业务应用层 (App Layer)
&lt;/h4>&lt;p>这是平台的核心业务能力：&lt;/p>
&lt;h5 id="21-智能体-agent">2.1 智能体 (Agent)
&lt;/h5>&lt;p>智能体是平台的核心生产力单元：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Agent&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">description&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_config&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ModelConfig&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 组成要素&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">instructions&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 系统提示词&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tools&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 关联的工具&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">knowledge_ids&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 关联的知识库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 元数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_by&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">project_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">updated_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 分享与激励&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">is_public&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">bool&lt;/span> &lt;span class="c1"># 是否公开分享&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">likes&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="c1"># 点赞数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">uses&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="c1"># 使用次数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 版本控制&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">version&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">version_history&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">dict&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">list&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>智能体类型&lt;/strong>：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>类型&lt;/th>
&lt;th>说明&lt;/th>
&lt;th>示例&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>对话型&lt;/td>
&lt;td>问答交互&lt;/td>
&lt;td>客服机器人&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>任务型&lt;/td>
&lt;td>完成特定任务&lt;/td>
&lt;td>代码审查助手&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>分析型&lt;/td>
&lt;td>数据分析处理&lt;/td>
&lt;td>报表生成器&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>创作型&lt;/td>
&lt;td>内容生成&lt;/td>
&lt;td>文案撰写助手&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h5 id="22-工作流-workflow">2.2 工作流 (Workflow)
&lt;/h5>&lt;p>工作流实现复杂的自动化流程编排：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Workflow&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">description&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 工作流定义&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">nodes&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">WorkflowNode&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">edges&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">WorkflowEdge&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 执行配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">trigger_type&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">TriggerType&lt;/span> &lt;span class="c1"># manual/scheduled/event&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">trigger_config&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeout&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">300&lt;/span> &lt;span class="c1"># 超时时间(秒)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 元数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_by&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">project_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">is_public&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">bool&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">likes&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">WorkflowNode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BaseModel&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">type&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">NodeType&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">config&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">position&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">tuple&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">WorkflowEdge&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BaseModel&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">source&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">target&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">condition&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span> &lt;span class="c1"># 条件判断&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">label&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>工作流节点类型&lt;/strong>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌──────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 工作流节点类型 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├──────────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 开始 │ │ Agent │ │ 工具 │ │ 条件 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Start │ │ │ │ Tool │ │ Condition│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ ▼ ▼ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 输入 │ │ LLM │ │ 搜索 │ │ 分支 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Input │ │ Call │ │ Search │ │ Branch │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ ▼ ▼ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 输出 │ │ 知识库 │ │ 脚本 │ │ 循环 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Output │ │ RAG │ │ Script │ │ Loop │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └────────────┴────────────┴────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 结束 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ End │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└──────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="23-知识库-knowledge">2.3 知识库 (Knowledge)
&lt;/h5>&lt;p>支持多种知识来源：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>类型&lt;/th>
&lt;th>说明&lt;/th>
&lt;th>格式支持&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>文档库&lt;/strong>&lt;/td>
&lt;td>上传文档&lt;/td>
&lt;td>PDF、Word、PPT、TXT、Markdown&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>网页抓取&lt;/strong>&lt;/td>
&lt;td>同步网页内容&lt;/td>
&lt;td>URL&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>数据库&lt;/strong>&lt;/td>
&lt;td>连接数据库&lt;/td>
&lt;td>MySQL、PostgreSQL、MongoDB&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>API&lt;/strong>&lt;/td>
&lt;td>接入外部API&lt;/td>
&lt;td>REST API&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>向量库&lt;/strong>&lt;/td>
&lt;td>直接导入向量&lt;/td>
&lt;td>Embedding批量导入&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h5 id="24-插件市场-marketplace">2.4 插件市场 (Marketplace)
&lt;/h5>&lt;p>开放的插件生态：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Plugin&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">version&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">author&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">description&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 插件类型&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">type&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">PluginType&lt;/span> &lt;span class="c1"># model/tool/memory/middleware&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 能力定义&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">capabilities&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">config_schema&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">default_config&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 分享与激励&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">downloads&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rating&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">float&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">reviews&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">Review&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">list&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="3-编排调度层-orchestration">3. 编排调度层 (Orchestration)
&lt;/h4>&lt;p>这一层负责智能体和工作的运行调度：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>组件&lt;/th>
&lt;th>职责&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Agent Runtime&lt;/strong>&lt;/td>
&lt;td>智能体的运行时环境，管理会话、上下文、工具调用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Workflow Engine&lt;/strong>&lt;/td>
&lt;td>工作流的执行引擎，处理节点调度、条件分支、循环&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Task Scheduler&lt;/strong>&lt;/td>
&lt;td>任务调度器，支持定时任务、延迟任务、优先级队列&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Event Bus&lt;/strong>&lt;/td>
&lt;td>事件总线，解耦组件间通信，支持发布订阅模式&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h4 id="4-核心服务层-core-services">4. 核心服务层 (Core Services)
&lt;/h4>&lt;p>这是平台最稳定的基础能力：&lt;/p>
&lt;h5 id="41-用户管理-user-management">4.1 用户管理 (User Management)
&lt;/h5>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">User&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">email&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">phone&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">avatar&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 组织关系&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tenant_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 所属容器&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">department&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 部门&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">position&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 职位&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 角色与权限&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">role&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UserRole&lt;/span> &lt;span class="c1"># admin/editor/viewer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 贡献积分&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">contribution_score&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">badges&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">list&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 时间戳&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">last_login_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">UserRole&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Enum&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">TENANT_ADMIN&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span> &lt;span class="c1"># 容器管理员&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PROJECT_ADMIN&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span> &lt;span class="c1"># 项目管理员&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">EDITOR&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;editor&amp;#34;&lt;/span> &lt;span class="c1"># 编辑者&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">VIEWER&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;viewer&amp;#34;&lt;/span> &lt;span class="c1"># 查看者&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="42-容器管理-tenant-management">4.2 容器管理 (Tenant Management)
&lt;/h5>&lt;p>容器是最大的隔离单元，通常对应一个部门或业务线：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Tenant&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 容器名称，如&amp;#34;研发中心&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">code&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 唯一标识，如&amp;#34;rd&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">config&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">TenantConfig&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 配额&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">quotas&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">TenantQuotas&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 成员&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">member_count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">project_count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 状态&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">status&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">TenantStatus&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TenantStatus&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ACTIVE&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">TenantConfig&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># AI模型配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">allowed_providers&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 允许使用的AI提供商&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">default_provider&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 默认提供商&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_restrictions&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span> &lt;span class="c1"># 模型限制&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 功能开关&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">features&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span> &lt;span class="c1"># 功能开关&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 安全配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">allowed_ips&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># IP白名单&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data_retention_days&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="c1"># 数据保留天数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">TenantQuotas&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_users&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="c1"># 最大用户数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_projects&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="c1"># 最大项目数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_agents&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="c1"># 最大智能体数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_workflows&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="c1"># 最大工作流数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_storage_gb&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="c1"># 最大存储(GB)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">monthly_token_limit&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="c1"># 月度Token限额&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="43-项目管理-project-management">4.3 项目管理 (Project Management)
&lt;/h5>&lt;p>项目是容器内的业务单元：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Project&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tenant_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 所属容器&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">code&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 项目标识&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">description&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">icon&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 成员&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">owner_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 项目负责人&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">members&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">ProjectMember&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">config&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ProjectConfig&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 统计&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">agent_count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">workflow_count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">knowledge_count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">updated_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">ProjectMember&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">role&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ProjectRole&lt;/span> &lt;span class="c1"># owner/admin/member&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">joined_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="44-权限管理-permission-control">4.4 权限管理 (Permission Control)
&lt;/h5>&lt;p>采用RBAC（基于角色的访问控制）模型：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">PermissionMatrix&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;权限矩阵&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PERMISSIONS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 用户管理&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;user:create&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;user:invite&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;user:remove&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 容器管理&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;tenant:view&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;tenant:edit&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;tenant:quota&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 项目管理&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;project:create&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;project:view&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;member&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;project:edit&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;project:delete&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 智能体管理&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;agent:create&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;editor&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;agent:view&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;editor&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;viewer&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;agent:edit&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;editor&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;agent:delete&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;editor&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;agent:publish&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;editor&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 工作流管理&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;workflow:create&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;editor&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;workflow:view&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;editor&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;viewer&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;workflow:edit&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;editor&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;workflow:delete&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;editor&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 知识库管理&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;knowledge:create&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;editor&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;knowledge:view&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;editor&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;viewer&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;knowledge:edit&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;editor&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;knowledge:delete&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tenant_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;project_admin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;editor&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@classmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">check&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">cls&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">role&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UserRole&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">permission&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">bool&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">role&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">value&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">cls&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">PERMISSIONS&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">permission&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[])&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="5-集成层-integration-layer">5. 集成层 (Integration Layer)
&lt;/h4>&lt;p>这是平台的核心扩展机制：&lt;/p>
&lt;h5 id="51-统一ai-provider接口">5.1 统一AI Provider接口
&lt;/h5>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">AIProvider&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Protocol&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;所有AI提供者必须实现的接口&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;提供商名称&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">supported_models&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;支持的模型列表&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">chat_completion&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">messages&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">temperature&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">float&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.7&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_tokens&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tools&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">Tool&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">ChatResponse&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;聊天补全&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">embeddings&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">texts&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;embeddings&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">EmbeddingResponse&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;文本嵌入&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">images_generate&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">size&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;1024x1024&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">ImageResponse&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;图像生成&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">models_list&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">ModelInfo&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;获取可用模型列表&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">health_check&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">bool&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;健康检查&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="52-适配器实现示例">5.2 适配器实现示例
&lt;/h5>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">OpenAIAdapter&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;OpenAI适配器&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_key&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_base&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;https://api.openai.com/v1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeout&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">60&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">api_key&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">api_base&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">OpenAIClient&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">api_base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">timeout&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;openai&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">supported_models&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;gpt-4o&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;gpt-4o-mini&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;gpt-4-turbo&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;gpt-3.5-turbo&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;text-embedding-3-small&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;text-embedding-3-large&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;dall-e-3&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;dall-e-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">chat_completion&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">messages&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;gpt-4o&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">ChatResponse&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">chat&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">completions&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">messages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_dict&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">messages&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">ChatResponse&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_openai&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">embeddings&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">texts&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;text-embedding-3-small&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">EmbeddingResponse&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">embeddings&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">input&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">texts&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">EmbeddingResponse&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_openai&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">ClaudeAdapter&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Anthropic Claude适配器&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_key&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_base&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;https://api.anthropic.com/v1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeout&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">60&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">api_key&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">api_base&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AnthropicClient&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">api_base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">timeout&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;anthropic&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">supported_models&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;claude-sonnet-4-20250514&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;claude-3-5-sonnet-latest&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;claude-3-opus-latest&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;claude-3-haiku-latest&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">chat_completion&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">messages&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;claude-sonnet-4-20250514&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">ChatResponse&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">messages&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">messages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_anthropic_format&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">messages&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">ChatResponse&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_anthropic&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">DeepSeekAdapter&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;DeepSeek适配器 - 演示新模型接入的简易性&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">api_key&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">api_key&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">OpenAICompatibleClient&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_base&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;https://api.deepseek.com/v1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;deepseek&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">supported_models&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;deepseek-chat&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;deepseek-coder&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">chat_completion&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">messages&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;deepseek-chat&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">chat&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">completions&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">messages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_dict&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">messages&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">ChatResponse&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_openai&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="53-适配器注册中心">5.3 适配器注册中心
&lt;/h5>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">AdapterRegistry&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;适配器注册中心 - 核心扩展机制&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_adapters&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">AIProvider&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_metadata&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">AdapterMetadata&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">register&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">adapter&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">AIProvider&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">metadata&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">AdapterMetadata&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;注册适配器&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_adapters&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">adapter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_metadata&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">metadata&lt;/span> &lt;span class="ow">or&lt;/span> &lt;span class="n">AdapterMetadata&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">version&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;1.0.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">capabilities&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;chat&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;embeddings&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Registered adapter: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">unregister&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;注销适配器&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">name&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_adapters&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">del&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_adapters&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">del&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_metadata&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Unregistered adapter: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">AIProvider&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;获取适配器&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_adapters&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">list_adapters&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;列出所有适配器&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_adapters&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">keys&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">list_by_capability&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">capability&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;按能力筛选适配器&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">meta&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_metadata&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">capability&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">meta&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">capabilities&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">health_check_all&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">bool&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;检查所有适配器健康状态&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">results&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">adapter&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_adapters&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">results&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">adapter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">health_check&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Health check failed for &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">results&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">results&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">AdapterMetadata&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">version&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">capabilities&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">description&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">author&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">docs_url&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="54-工具注册中心">5.4 工具注册中心
&lt;/h5>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">ToolCapability&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Protocol&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;工具能力抽象&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">description&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_schema&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">ToolSchema&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;获取工具定义schema，用于LLM function calling&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">execute&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">context&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ExecutionContext&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">params&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">ToolResult&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;执行工具&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">ToolType&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Enum&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;工具类型枚举&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">RETRIEVER&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;retriever&amp;#34;&lt;/span> &lt;span class="c1"># 知识检索&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">WEB_SEARCH&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;web_search&amp;#34;&lt;/span> &lt;span class="c1"># 网络搜索&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CALCULATOR&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;calculator&amp;#34;&lt;/span> &lt;span class="c1"># 计算器&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CODE_INTERPRETER&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;code&amp;#34;&lt;/span> &lt;span class="c1"># 代码执行&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">FILE_SYSTEM&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;filesystem&amp;#34;&lt;/span> &lt;span class="c1"># 文件操作&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">DATABASE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;database&amp;#34;&lt;/span> &lt;span class="c1"># 数据库查询&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">API_CALL&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;api_call&amp;#34;&lt;/span> &lt;span class="c1"># API调用&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IMAGE_PROCESSOR&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;image&amp;#34;&lt;/span> &lt;span class="c1"># 图像处理&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">DOCUMENT_PARSER&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;document&amp;#34;&lt;/span> &lt;span class="c1"># 文档解析&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CUSTOM&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;custom&amp;#34;&lt;/span> &lt;span class="c1"># 自定义工具&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">ToolRegistry&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;工具注册中心&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_tools&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ToolCapability&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_by_type&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">ToolType&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">defaultdict&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">list&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">register&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tool&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ToolCapability&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">types&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">ToolType&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;注册工具&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_tools&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">tool&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tool&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">tool_type&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">types&lt;/span> &lt;span class="ow">or&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">ToolType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CUSTOM&lt;/span>&lt;span class="p">]):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_by_type&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">tool_type&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tool&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Registered tool: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">tool&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">execute&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tool_name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">params&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">context&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ExecutionContext&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">ToolResult&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;执行工具&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tool&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_tools&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tool_name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">tool&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="n">ToolNotFoundError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Tool not found: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">tool_name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">tool&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">context&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">params&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">list_by_type&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tool_type&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ToolType&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">ToolCapability&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;按类型列出工具&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tool_names&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_by_type&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tool_type&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_tools&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">name&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">tool_names&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="55-外部agent框架集成重点">5.5 外部Agent框架集成（重点！）
&lt;/h5>&lt;p>这是你提到的关键需求：平台需要能随时接入市面上的Agent框架，如OpenCAW、Claude Code、OpenCode等。&lt;/p>
&lt;h6 id="551-主流agent框架分析">5.5.1 主流Agent框架分析
&lt;/h6>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>框架&lt;/th>
&lt;th>特点&lt;/th>
&lt;th>接入方式&lt;/th>
&lt;th>复杂度&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Claude Code&lt;/strong>&lt;/td>
&lt;td>Anthropic官方CLI，支持代码编写、审查、重构&lt;/td>
&lt;td>CLI调用/stdio&lt;/td>
&lt;td>⭐⭐&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>OpenCode&lt;/strong>&lt;/td>
&lt;td>开源多语言支持，强大的代码编辑能力&lt;/td>
&lt;td>CLI调用/stdio&lt;/td>
&lt;td>⭐⭐&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Codex&lt;/strong>&lt;/td>
&lt;td>OpenAI出品，强大的代码生成能力&lt;/td>
&lt;td>API调用&lt;/td>
&lt;td>⭐&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Devin&lt;/strong>&lt;/td>
&lt;td>独立Agent，强大的自主完成任务能力&lt;/td>
&lt;td>API调用&lt;/td>
&lt;td>⭐⭐⭐&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>OpenCAW&lt;/strong>&lt;/td>
&lt;td>国产开源，开放架构，易于扩展&lt;/td>
&lt;td>MCP/CLI&lt;/td>
&lt;td>⭐⭐&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>SWE-agent&lt;/strong>&lt;/td>
&lt;td>专门针对软件工程的Agent&lt;/td>
&lt;td>CLI调用&lt;/td>
&lt;td>⭐⭐&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Devika&lt;/strong>&lt;/td>
&lt;td>开源AI软件工程师，类Devin&lt;/td>
&lt;td>API调用&lt;/td>
&lt;td>⭐⭐&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h6 id="552-统一agent集成接口">5.5.2 统一Agent集成接口
&lt;/h6>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">abc&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">ABC&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">typing&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Protocol&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Any&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">dataclasses&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">dataclass&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">field&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">enum&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Enum&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">asyncio&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">AgentFramework&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Enum&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;支持的Agent框架&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CLAUDE_CODE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;claude_code&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">OPENCODE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;opencode&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CODEX&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;codex&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">DEVIN&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;devin&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">OPENCAW&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;opencaw&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SWE_AGENT&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;swe_agent&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CUSTOM&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;custom&amp;#34;&lt;/span> &lt;span class="c1"># 支持自定义框架&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">AgentExecutionRequest&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Agent执行请求&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">task&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 任务描述&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">framework&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">AgentFramework&lt;/span> &lt;span class="c1"># 使用的框架&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">working_dir&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 工作目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeout&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">300&lt;/span> &lt;span class="c1"># 超时时间(秒)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">allowed_tools&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span> &lt;span class="c1"># 允许的工具&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">extra_config&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">dict&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 框架特定配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">AgentExecutionResponse&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Agent执行响应&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">success&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">bool&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">error&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">session_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">duration_ms&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_used&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">dict&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">metadata&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">dict&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">AgentFrameworkMetadata&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;框架元数据&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">version&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">capabilities&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># [&amp;#34;code_generation&amp;#34;, &amp;#34;code_review&amp;#34;, ...]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">supported_languages&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 支持的编程语言&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">requires_permissions&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 需要的权限&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">config_schema&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span> &lt;span class="c1"># 配置schema&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">auth_method&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 认证方式: &amp;#34;api_key&amp;#34;, &amp;#34;oauth&amp;#34;, &amp;#34;cli_auth&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">ExternalAgentAdapter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ABC&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;外部Agent框架适配器基类&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">config&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">config&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">AgentExecutionRequest&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">AgentExecutionResponse&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;执行Agent任务&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">health_check&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">bool&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;健康检查&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_status&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;获取Agent状态&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_metadata&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">AgentFrameworkMetadata&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;获取框架元数据&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">NotImplementedError&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h6 id="553-claude-code适配器实现">5.5.3 Claude Code适配器实现
&lt;/h6>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">subprocess&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">asyncio&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">pathlib&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Path&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">ClaudeCodeAdapter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ExternalAgentAdapter&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Claude Code适配器&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">config&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cli_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;cli_path&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;claude&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;api_key&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 可选，使用ANTHROPIC_API_KEY&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">default_model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;default_model&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;sonnet&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_metadata&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">AgentFrameworkMetadata&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">AgentFrameworkMetadata&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;Claude Code&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">version&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;2.x&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">capabilities&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;code_generation&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;code_review&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;refactoring&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;bug_fixing&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;test_writing&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;git_operations&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">supported_languages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;python&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;javascript&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;typescript&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;go&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;rust&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;java&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;c&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;cpp&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;csharp&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;ruby&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;php&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">requires_permissions&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;file_read&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;file_write&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;bash&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">config_schema&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;cli_path&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;default&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;claude&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;default_model&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;enum&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;values&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;sonnet&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;opus&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;haiku&amp;#34;&lt;/span>&lt;span class="p">]},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;max_turns&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;int&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;default&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">auth_method&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;api_key&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">AgentExecutionRequest&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">AgentExecutionResponse&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;执行Claude Code任务&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start_time&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_event_loop&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 构建命令&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cmd&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cli_path&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;-p&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">task&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;--model&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">extra_config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;model&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">default_model&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;--output-format&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;json&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;--max-turns&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">extra_config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;max_turns&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 处理工具限制&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">allowed_tools&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cmd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">extend&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="s2">&amp;#34;--allowedTools&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;,&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">allowed_tools&lt;/span>&lt;span class="p">)])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 权限绕过（生产环境需谨慎）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">extra_config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;skip_permissions&amp;#34;&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cmd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;--dangerously-skip-permissions&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">subprocess&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cmd&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cwd&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">working_dir&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">capture_output&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">text&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timeout&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">duration_ms&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_event_loop&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start_time&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">returncode&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 解析JSON输出&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">loads&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">AgentExecutionResponse&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">success&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">output&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;result&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">session_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">output&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;session_id&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">duration_ms&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">duration_ms&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_used&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">output&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;usage&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">AgentExecutionResponse&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">success&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">error&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stderr&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">duration_ms&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">duration_ms&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="n">subprocess&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TimeoutExpired&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">AgentExecutionResponse&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">success&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">error&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Task timeout after &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timeout&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">s&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">duration_ms&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timeout&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">AgentExecutionResponse&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">success&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">error&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">duration_ms&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_event_loop&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start_time&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">health_check&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">bool&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;检查Claude Code是否可用&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">subprocess&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cli_path&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;--version&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">capture_output&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">text&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">returncode&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_status&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;获取Claude Code状态&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">subprocess&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cli_path&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;auth&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;status&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;--text&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">capture_output&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">text&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">10&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;installed&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;authenticated&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;logged in&amp;#34;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">lower&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;version&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="s2">&amp;#34;unknown&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;installed&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;error&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">)}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h6 id="554-opencaw适配器实现">5.5.4 OpenCAW适配器实现
&lt;/h6>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">OpenCAWAdapter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ExternalAgentAdapter&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;OpenCAW适配器 - 国产开源Agent框架&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">config&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;api_base&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;http://localhost:8080&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;api_key&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ws_endpoint&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;ws_endpoint&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_metadata&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">AgentFrameworkMetadata&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">AgentFrameworkMetadata&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;OpenCAW&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">version&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;1.x&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">capabilities&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;code_generation&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;code_review&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;mcp_integration&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;multi_agent&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">supported_languages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;python&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;javascript&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;typescript&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;go&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">requires_permissions&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;file_read&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;file_write&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;bash&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;network&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">config_schema&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;api_base&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;api_key&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ws_endpoint&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">auth_method&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;api_key&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">AgentExecutionRequest&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">AgentExecutionResponse&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;通过HTTP API执行OpenCAW任务&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kn">import&lt;/span> &lt;span class="nn">aiohttp&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start_time&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_event_loop&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">headers&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Authorization&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Bearer &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Content-Type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;application/json&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">payload&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;task&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">task&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;working_dir&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">working_dir&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;timeout&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timeout&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;config&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">extra_config&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">with&lt;/span> &lt;span class="n">aiohttp&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ClientSession&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">with&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">post&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_base&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/api/execute&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">json&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">payload&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">headers&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">headers&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">aiohttp&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ClientTimeout&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">total&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timeout&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">duration_ms&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_event_loop&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start_time&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">200&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">AgentExecutionResponse&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">success&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;result&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">session_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;session_id&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">duration_ms&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">duration_ms&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">metadata&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;metadata&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">AgentExecutionResponse&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">success&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">error&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;error&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Unknown error&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">duration_ms&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">duration_ms&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">AgentExecutionResponse&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">success&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">error&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">duration_ms&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_event_loop&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start_time&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">health_check&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">bool&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;检查OpenCAW服务状态&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kn">import&lt;/span> &lt;span class="nn">aiohttp&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">with&lt;/span> &lt;span class="n">aiohttp&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ClientSession&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">with&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_base&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/health&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">aiohttp&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ClientTimeout&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">total&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">200&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_status&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;获取OpenCAW状态&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kn">import&lt;/span> &lt;span class="nn">aiohttp&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">with&lt;/span> &lt;span class="n">aiohttp&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ClientSession&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">with&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_base&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/api/status&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">headers&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;Authorization&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Bearer &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;error&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">)}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h6 id="555-mcp协议集成">5.5.5 MCP协议集成
&lt;/h6>&lt;p>MCP（Model Context Protocol）是连接AI模型与外部工具的新标准，主流Agent框架正在逐步支持：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">MCPBridge&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;MCP协议桥接器 - 连接平台与外部Agent&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">servers&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">MCPServer&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tools_cache&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">ToolSchema&lt;/span>&lt;span class="p">]]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">connect_server&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">command&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">args&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">env&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">transport&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;stdio&amp;#34;&lt;/span> &lt;span class="c1"># stdio | http | sse&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">bool&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;连接MCP服务器&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">server&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">MCPServer&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">command&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">command&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">args&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">args&lt;/span> &lt;span class="ow">or&lt;/span> &lt;span class="p">[],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">env&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">env&lt;/span> &lt;span class="ow">or&lt;/span> &lt;span class="p">{},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">transport&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">transport&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">await&lt;/span> &lt;span class="n">server&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">start&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">await&lt;/span> &lt;span class="n">server&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">initialize&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 获取可用工具&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tools&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">server&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">list_tools&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">servers&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">server&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tools_cache&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tools&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Connected MCP server: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> with &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tools&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> tools&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Failed to connect MCP server &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">disconnect_server&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;断开MCP服务器&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">name&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">servers&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">servers&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stop&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">del&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">servers&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">del&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tools_cache&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">call_tool&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">server_name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tool_name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">arguments&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;调用MCP工具&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">server&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">servers&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">server_name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">server&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="n">MCPServerNotFoundError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Server not found: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">server_name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">server&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">call_tool&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tool_name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">arguments&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_all_tools&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">dict&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;获取所有MCP服务器的工具清单&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">all_tools&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">server_name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tools&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tools_cache&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">tool&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">tools&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">all_tools&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;server&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">server_name&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">tool&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">tool&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">description&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;input_schema&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">tool&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">input_schema&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">all_tools&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">MCPServer&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">command&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">args&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">env&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">transport&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">process&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">subprocess&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Process&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">capabilities&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">dict&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">start&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;启动MCP服务器进程&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">env&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">env&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">process&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create_subprocess_exec&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">command&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">env&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">env&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stdin&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">subprocess&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">PIPE&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stdout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">subprocess&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">PIPE&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">initialize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;初始化MCP协议&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 发送initialize请求&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">request&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;jsonrpc&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;2.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;method&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;initialize&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;params&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;protocolVersion&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;2024-11-05&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;capabilities&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;clientInfo&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;ai-platform&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;version&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;1.0&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># ...协议处理&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h6 id="556-agent框架注册中心">5.5.6 Agent框架注册中心
&lt;/h6>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">AgentFrameworkRegistry&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Agent框架注册中心 - 统一管理所有外部Agent&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_adapters&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">AgentFramework&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ExternalAgentAdapter&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_metadata&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">AgentFramework&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">AgentFrameworkMetadata&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_mcp_bridge&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">MCPBridge&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_execution_history&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">AgentExecutionResponse&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">register&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">framework&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">AgentFramework&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">adapter&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ExternalAgentAdapter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;注册Agent框架&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_adapters&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">framework&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">adapter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_metadata&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">framework&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">adapter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_metadata&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Registered agent framework: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">framework&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">unregister&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">framework&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">AgentFramework&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;注销Agent框架&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">framework&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_adapters&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">del&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_adapters&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">framework&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">del&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_metadata&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">framework&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Unregistered agent framework: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">framework&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_adapter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">framework&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">AgentFramework&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">ExternalAgentAdapter&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;获取适配器&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_adapters&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">framework&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">list_frameworks&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">AgentFrameworkMetadata&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;列出所有注册的框架&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_metadata&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">values&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">execute&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">request&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">AgentExecutionRequest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">AgentExecutionResponse&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;统一执行入口&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">adapter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_adapters&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">framework&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">adapter&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="n">AgentFrameworkNotFoundError&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Framework not supported: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">framework&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">adapter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_execution_history&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 记录执行统计&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_record_execution_stats&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">framework&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">response&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">execute_with_fallback&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">request&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">AgentExecutionRequest&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fallback_frameworks&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">AgentFramework&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">AgentExecutionResponse&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;带降级的执行 - 主框架失败时尝试备选框架&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 首先尝试主框架&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">success&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">response&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">warning&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Primary framework failed: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 尝试备选框架&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">framework&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">fallback_frameworks&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">framework&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">framework&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">success&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Fallback to &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">framework&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> succeeded&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">response&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">warning&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Fallback framework &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">framework&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> failed: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">AgentExecutionResponse&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">success&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">error&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;All frameworks failed&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">health_check_all&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">AgentFramework&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">bool&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;检查所有Agent框架健康状态&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">results&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">framework&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">adapter&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_adapters&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">results&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">framework&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">adapter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">health_check&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">results&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">framework&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">results&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h6 id="557-平台集成架构图">5.5.7 平台集成架构图
&lt;/h6>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 外部Agent框架集成层 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├─────────────────────────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Agent Framework Registry (注册中心) │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌──────────┐ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │Claude Code │ │ OpenCAW │ │ Codex │ │ Custom │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ Adapter │ │ Adapter │ │ Adapter │ │ Adapter │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └────────────┘ └────────────┘ └────────────┘ └──────────┘ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │ │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └──────────┼──────────────┼──────────────┼───────────────┼────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ ▼ ▼ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ MCP Bridge (协议桥接) │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌──────────┐ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ MCP │ │ MCP │ │ MCP │ │ MCP │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ Server 1 │ │ Server 2 │ │ Server 3 │ │ ... │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ (GitHub) │ │ ( Postgres) │ │ (Filesystem) │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └────────────┘ └────────────┘ └────────────┘ └──────────┘ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└──────────────────────────────┼──────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ▼
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 平台编排调度层 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Agent │ │ Workflow │ │ Task │ │ Event │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Runtime │ │ Engine │ │ Scheduler │ │ Bus │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Execution Router (执行路由) │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ • 框架选择策略 • 降级策略 • 并发控制 • 超时管理 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h6 id="558-新增框架接入指南">5.5.8 新增框架接入指南
&lt;/h6>&lt;p>&lt;strong>快速接入新框架只需3步：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Step 1: 实现适配器&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">NewFrameworkAdapter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ExternalAgentAdapter&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">config&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 初始化配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_metadata&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">AgentFrameworkMetadata&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">AgentFrameworkMetadata&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;NewFramework&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">version&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;1.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">capabilities&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;...&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">supported_languages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;...&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">requires_permissions&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;...&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">config_schema&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">auth_method&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">AgentExecutionRequest&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">AgentExecutionResponse&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 实现执行逻辑&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">health_check&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">bool&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 健康检查&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Step 2: 注册到框架注册中心&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">registry&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AgentFrameworkRegistry&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">registry&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">register&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">AgentFramework&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;new_framework&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">NewFrameworkAdapter&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;api_key&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;...&amp;#34;&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Step 3: 在平台中使用&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">registry&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">AgentExecutionRequest&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">task&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;帮我修复这个bug&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">framework&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">AgentFramework&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;new_framework&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">working_dir&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/path/to/project&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="核心设计原则数据资产化--agent工具化">核心设计原则：数据资产化 · Agent工具化
&lt;/h2>&lt;blockquote>
&lt;p>这是本平台最重要的架构设计原则：&lt;strong>用户的数据是核心资产，必须持久化；Agent是工具，可以随时替换。&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;h3 id="设计哲学">设计哲学
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌───────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 数据资产 (Data Assets) │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ 知识库 │ │ 对话记录 │ │ 使用痕迹 │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ Knowledge │ │ Sessions │ │ Usage Logs │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ 智能体 │ │ 工作流 │ │ 配置文件 │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ Config │ │ Config │ │ Settings │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ★ 持久化存储 ★ 跨版本迁移 ★ 数据主权 ★ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └───────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌───────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Agent工具 (Agent Tools) │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ Claude Code │ │ OpenCAW │ │ Custom │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ • 即插即用 • 版本迭代 • 随时替换 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └───────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="核心原则">核心原则
&lt;/h3>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>原则&lt;/th>
&lt;th>说明&lt;/th>
&lt;th>实践&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>数据主权&lt;/strong>&lt;/td>
&lt;td>用户数据属于用户，平台只是保管者&lt;/td>
&lt;td>数据可导出、可迁移、可删除&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>存储与计算分离&lt;/strong>&lt;/td>
&lt;td>数据持久化，Agent按需调用&lt;/td>
&lt;td>数据在数据库，Agent在注册中心&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>接口稳定，实现可变&lt;/strong>&lt;/td>
&lt;td>数据模型稳定，Agent实现灵活&lt;/td>
&lt;td>固定AIProvider接口，适配器可替换&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>版本兼容&lt;/strong>&lt;/td>
&lt;td>新版本必须兼容旧数据&lt;/td>
&lt;td>数据迁移脚本，版本回滚支持&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="数据模型设计">数据模型设计
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用户数据层 (必须持久化)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">UserData&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;用户核心数据 - 永久存储&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">email&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tenant_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 创建的数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_agents&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 创建的智能体ID列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_workflows&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 创建的工作流ID列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_knowledge&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 创建的知识库ID列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 配置与偏好&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">preferences&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UserPreferences&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_keys&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">APIKey&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 绑定的API密钥&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 元数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">updated_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">UserPreferences&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;用户偏好设置&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">default_model&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">theme&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;light&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">language&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;zh-CN&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">notification_enabled&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">bool&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">AgentConfig&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;智能体配置 - 持久化&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 所有者&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 配置内容（持久化的核心）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">description&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">instructions&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 系统提示词&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_config&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ModelConfig&lt;/span> &lt;span class="c1"># 模型配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 关联数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tool_ids&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 关联的工具ID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">knowledge_ids&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 关联的知识库ID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 版本控制&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">version&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">version_history&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">AgentVersion&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 公开属性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">is_public&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">bool&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tags&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">list&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">updated_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">WorkflowConfig&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;工作流配置 - 持久化&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">project_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">description&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">nodes&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">WorkflowNode&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 节点定义（持久化）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">edges&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">WorkflowEdge&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 连线定义（持久化）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">trigger_config&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">version&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">is_public&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">bool&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">updated_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 知识库 - 持久化 (分层设计)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">KnowledgeBase&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;知识库 - 分层持久化设计&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">project_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">description&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># ========== 持久化层 (原始数据，不可丢失) ==========&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. 原始文档 - 对象存储 (真正持久化)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">raw_documents&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">RawDocument&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># PDF/Word/MD等原始文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. 解析后的结构化数据 - PostgreSQL&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">parsed_content&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">ParsedDocument&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 提取的文本、结构&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. 元数据 - PostgreSQL&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">metadata&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">KnowledgeMetadata&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># ========== 可重建索引层 (可以从原始数据重新生成) ==========&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 4. 向量索引 - 向量数据库 (可重建)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vector_index_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span> &lt;span class="c1"># 指向向量数据库中的索引&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embedding_model&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 5. 统计信息 - PostgreSQL&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">doc_count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunk_count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_size_bytes&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">updated_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">RawDocument&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;原始文档 - 真正持久化到对象存储&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">knowledge_base_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 存储位置（对象存储路径）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">storage_path&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># s3://bucket/knowledge/{kb_id}/{doc_id}/file.pdf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">storage_bucket&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">storage_region&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 文件信息&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">filename&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_size&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mime_type&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># application/pdf, text/markdown, ...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 内容哈希（完整性校验）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">content_hash&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># SHA256&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 版本控制&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">version&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">previous_versions&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 历史版本ID列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">uploaded_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">updated_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">ParsedDocument&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;解析后的文档内容 - PostgreSQL持久化&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">raw_document_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 解析后的文本内容（原始文本副本）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">content&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 完整文本内容&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">content_length&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 结构化提取&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">title&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">author&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_date&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sections&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">DocumentSection&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 分节信息&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 预处理标记&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">language&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">encoding&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">parsed_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">DocumentSection&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;文档章节&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">title&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start_char&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">end_char&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">level&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="c1"># 1=h1, 2=h2, 3=h3...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">subsections&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">DocumentSection&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">list&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">KnowledgeMetadata&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;知识库元数据 - PostgreSQL&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">knowledge_base_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 索引状态&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">index_status&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">IndexStatus&lt;/span> &lt;span class="c1"># pending/processing/completed/failed&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vector_index_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span> &lt;span class="c1"># 向量数据库中的索引ID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 嵌入配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embedding_model&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># &amp;#34;text-embedding-3-small&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunk_size&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">512&lt;/span> &lt;span class="c1"># 块大小&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunk_overlap&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">50&lt;/span> &lt;span class="c1"># 重叠大小&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 统计&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_documents&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_chunks&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">indexed_chunks&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 最后一次索引时间&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">last_indexed_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">last_error&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">VectorIndex&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;向量索引记录 - 记录索引元信息，可重建&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">knowledge_base_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 索引来源&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">source_document_ids&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 关联的原始文档&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 索引配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embedding_model&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dimension&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">metric&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># &amp;#34;cosine&amp;#34; / &amp;#34;euclidean&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 向量数据库连接信息&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vector_db_type&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># &amp;#34;milvus&amp;#34; / &amp;#34;qdrant&amp;#34; / &amp;#34;pinecone&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vector_db_endpoint&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">collection_name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 状态&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">status&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># &amp;#34;active&amp;#34; / &amp;#34;rebuilding&amp;#34; / &amp;#34;failed&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 统计&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_vectors&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vector_count_by_doc&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">dict&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># doc_id -&amp;gt; count&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">updated_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 会话数据层 (重要的运行时数据)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Session&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;会话 - 重要数据，需持久化&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">agent_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 使用的智能体&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 对话历史（持久化核心）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">messages&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 会话上下文&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">context&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span> &lt;span class="c1"># 会话级别的上下文变量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 统计&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">message_count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">token_usage&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">TokenUsage&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 状态&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">status&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">SessionStatus&lt;/span> &lt;span class="c1"># active/archived/deleted&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pinned&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">bool&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">updated_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Message&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;消息&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">session_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">role&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">MessageRole&lt;/span> &lt;span class="c1"># user/assistant/system/tool&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">content&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 工具调用记录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tool_calls&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">ToolCall&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 元数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># 使用的模型&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">latency_ms&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_used&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">TokenUsage&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Token使用统计 - 用于计费和监控&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">input_tokens&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output_tokens&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_tokens&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 按模型统计&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">by_model&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">dict&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 按时间统计&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">daily_usage&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">dict&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># date -&amp;gt; tokens&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">UsageLog&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;使用日志 - 必须持久化&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tenant_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 使用信息&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">resource_type&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ResourceType&lt;/span> &lt;span class="c1"># agent/workflow/knowledge&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">resource_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">action&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># chat/run/search&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 消耗&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_used&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">latency_ms&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cost_usd&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">float&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 上下文（用于分析）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">session_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Agent运行时层 (临时，可替换)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">AgentRuntime&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Agent运行时 - 不持久化，动态创建&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">AgentConfig&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">adapter&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ExternalAgentAdapter&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">config&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">config&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">adapter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">adapter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">session_context&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">chat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;聊天执行&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 使用adapter执行&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">adapter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">...&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">result&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">stream_chat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">AsyncGenerator&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;流式聊天&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">chunk&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">adapter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stream_execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">...&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">yield&lt;/span> &lt;span class="n">chunk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 数据流向&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">┌─────────────────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ 用户数据流向 │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ User ─────────────────────────────────────────────────────────────────▶ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ 1. 创建数据 │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ ▼ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ 知识库 │────▶│ 智能体 │────▶│ 工作流 │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ 持久化存储 │ │ 配置 │ │ 配置 │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ └─────────────┘ └─────────────┘ └─────────────┘ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ │ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ │ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ ▼ │ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ ┌─────────────┐ │ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ 会话 │◀──────────┤ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ 历史 │ │ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ └─────────────┘ │ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ │ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ │ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ ▼ ▼ ▼ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ PostgreSQL / 向量数据库 │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ (数据永久存储，可迁移、可导出) │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">└─────────────────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">┌─────────────────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ Agent调用流程 │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ User Request │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ ▼ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ 加载 │────▶│ 调用 │────▶│ 返回 │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ AgentConfig │ │ Agent │ │ Response │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ (从DB读取) │ │ Runtime │ │ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ └─────────────┘ └──────┬──────┘ └─────────────┘ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ ▼ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ ┌─────────────┐ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ Agent │ ← 可以随时替换 │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ Adapter │ (Claude/DeepSeek/...) │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │ (不持久化) │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ └─────────────┘ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">│ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">└─────────────────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="数据持久化策略">数据持久化策略
&lt;/h3>&lt;blockquote>
&lt;p>&lt;strong>核心原则：原始数据必须持久化，索引数据可以重建&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 分层存储策略&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">DataPersistenceStrategy&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;数据持久化策略 - 分层设计&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> ┌─────────────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ 分层存储架构 │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ Layer 1: 原始数据层 (真正持久化，不可丢失) │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ • 原始文档文件 → 对象存储 (S3/MinIO) │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ • 解析后文本内容 → PostgreSQL TEXT字段 │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ • 用户配置/元数据 → PostgreSQL │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ ★ 保留策略: FOREVER (永久) │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ ★ 备份策略: 多副本实时同步 │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ ★ 供应商锁定: 无 (标准化S3协议) │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ ▼ (可重建) │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ Layer 2: 索引数据层 (可重建，不要作为唯一数据源) │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ • 向量索引 → 向量数据库 (Milvus/Qdrant/Pinecone) │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ • 倒排索引 → Elasticsearch │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ • 全文索引 → Elasticsearch / PostgreSQL FTS │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ ★ 保留策略: 按需 (重建成本低) │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ ★ 备份策略: 可选 (重建成本低) │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │ ★ 供应商锁定: 有 (换供应商需重建) │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> │ │
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> └─────────────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 数据分类与存储&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">STORAGE_CONFIG&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">#核心数据 - Layer 1: 永久保留&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;layer&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;storage&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">StorageType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">PRIMARY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;database&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;postgresql&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;replication&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ReplicationType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">SYNC&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;backup&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">BackupType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DAILY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;retention&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">RetentionPolicy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">FOREVER&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;agent_config&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;layer&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;storage&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">StorageType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">PRIMARY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;database&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;postgresql&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;replication&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ReplicationType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">SYNC&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;backup&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">BackupType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DAILY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;retention&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">RetentionPolicy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">FOREVER&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;workflow_config&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;layer&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;storage&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">StorageType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">PRIMARY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;database&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;postgresql&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;replication&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ReplicationType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">SYNC&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;backup&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">BackupType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DAILY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;retention&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">RetentionPolicy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">FOREVER&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 知识库数据 - 分层存储&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;raw_document&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;layer&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 原始文档真正持久化&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;storage&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">StorageType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">OBJECT&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;database&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;s3_compatible&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;replication&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ReplicationType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">SYNC&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;backup&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">BackupType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">REALTIME&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;retention&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">RetentionPolicy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">FOREVER&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;parsed_content&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;layer&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 解析后文本持久化&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;storage&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">StorageType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">PRIMARY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;database&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;postgresql&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;field_type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;TEXT&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 完整文本内容&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;replication&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ReplicationType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">SYNC&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;backup&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">BackupType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DAILY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;retention&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">RetentionPolicy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">FOREVER&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;knowledge_metadata&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;layer&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;storage&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">StorageType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">PRIMARY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;database&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;postgresql&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;replication&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ReplicationType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">SYNC&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;backup&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">BackupType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DAILY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;retention&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">RetentionPolicy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">FOREVER&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;vector_index&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="c1"># 向量索引只是索引&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;layer&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;storage&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">StorageType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">VECTOR&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;database&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;milvus/qdrant/pinecone&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;replication&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ReplicationType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">NONE&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 向量数据库自己管理&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;backup&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">BackupType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">NONE&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 不单独备份，可重建&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;retention&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">RetentionPolicy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">REBUILDABLE&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 会话数据 - 用户控制&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;session&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;layer&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;storage&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">StorageType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">PRIMARY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;database&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;postgresql&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;replication&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ReplicationType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ASYNC&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;backup&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">BackupType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">WEEKLY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;retention&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">RetentionPolicy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">USER_CONTROLLED&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;default_days&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">90&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;message&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;layer&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 消息内容也持久化&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;storage&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">StorageType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">PRIMARY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;database&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;postgresql&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;field_type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;TEXT&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;replication&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ReplicationType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">NONE&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;backup&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">BackupType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">MONTHLY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;retention&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">RetentionPolicy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">USER_CONTROLLED&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;default_days&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">30&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;usage_log&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;layer&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;storage&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">StorageType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">COLD&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;database&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;postgresql&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;replication&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ReplicationType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">NONE&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;backup&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">BackupType&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">MONTHLY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;retention&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">RetentionPolicy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">COMPLIANCE&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;min_days&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">365&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">VectorIndexRebuilder&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;向量索引重建服务 - 当向量数据库出问题时的救星&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">document_store&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">DocumentStore&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vector_db&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">VectorDatabase&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embedding_service&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">EmbeddingService&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">document_store&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">document_store&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">vector_db&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">vector_db&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">embedding_service&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">embedding_service&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">rebuild_index&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">knowledge_base_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">progress_callback&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Callable&lt;/span>&lt;span class="p">[[&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">RebuildResult&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;从原始数据重建向量索引&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. 获取知识库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">kb&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_knowledge_base&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">knowledge_base_id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. 清理旧索引&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">kb&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">metadata&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">vector_index_id&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">vector_db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">delete_collection&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">kb&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">metadata&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">vector_index_id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. 创建新索引&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">new_collection&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">vector_db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create_collection&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;kb_&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">knowledge_base_id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dimension&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">embedding_service&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_dimension&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">kb&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">metadata&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">embedding_model&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">metric&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;cosine&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 4. 遍历所有原始文档，重建向量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">documents&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">document_store&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_parsed_documents&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">kb&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_chunks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">processed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">doc&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">documents&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 分块&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">chunker&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">chunk&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">doc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">content&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">kb&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">metadata&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 生成向量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embeddings&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">embedding_service&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">embed_texts&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">c&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">chunks&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">kb&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">metadata&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">embedding_model&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">#写入向量数据库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">vector_db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">insert&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">collection&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">new_collection&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vectors&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">embeddings&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">metadatas&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">metadata&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">c&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">chunks&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ids&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">id&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">c&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">chunks&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_chunks&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">chunks&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">processed&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">progress_callback&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">progress_callback&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">processed&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">documents&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 5. 更新元数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">update_knowledge_base_metadata&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">kb&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;vector_index_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">new_collection&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;index_status&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">IndexStatus&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">COMPLETED&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;last_indexed_at&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">now&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;total_chunks&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">total_chunks&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">RebuildResult&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">success&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">knowledge_base_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">knowledge_base_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_documents&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">documents&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_chunks&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">total_chunks&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">duration_seconds&lt;/span>&lt;span class="o">=...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">incremental_update&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">document_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">operation&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="c1"># &amp;#34;add&amp;#34; / &amp;#34;update&amp;#34; / &amp;#34;delete&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">IncrementalResult&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;增量更新向量索引&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">doc&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">document_store&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_document&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">document_id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">operation&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;delete&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 删除向量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">vector_db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">delete_by_metadata&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;document_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">document_id&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 重新生成向量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">chunker&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">chunk&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">doc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">content&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embeddings&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">embedding_service&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">embed_texts&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">c&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">chunks&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">operation&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;add&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">vector_db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">insert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">...&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="c1"># update&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">vector_db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">delete_by_metadata&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;document_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">document_id&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">vector_db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">insert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">...&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">IncrementalResult&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">success&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">IndexRebuildTrigger&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;索引重建触发器&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">TRIGGERS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 向量数据库服务不可用&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;vector_db_unavailable&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;check&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;health_check_failed&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;action&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;failover_to_backup&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;timeout&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">30&lt;/span> &lt;span class="c1"># 秒&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 索引数据损坏&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;index_corruption&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;check&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;checksum_mismatch&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;action&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;rebuild_from_source&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;timeout&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3600&lt;/span> &lt;span class="c1"># 1小时&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 供应商通知迁移&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;provider_migration&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;check&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;migration_notice_received&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;action&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;preemptive_rebuild&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;timeout&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">86400&lt;/span> &lt;span class="c1"># 24小时&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 定期验证&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;periodic_validation&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;check&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;daily_spot_check&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;action&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;validate_sample_vectors&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;interval&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">86400&lt;/span> &lt;span class="c1"># 每天&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>class DataExportService:
&amp;ldquo;&amp;ldquo;&amp;ldquo;数据导出服务 - 用户数据主权&amp;rdquo;&amp;rdquo;&amp;rdquo;&lt;/p>
&lt;pre>&lt;code>async def export_user_data(
self,
user_id: str,
format: ExportFormat # json/csv/zip
) -&amp;gt; ExportResult:
&amp;quot;&amp;quot;&amp;quot;导出用户所有数据&amp;quot;&amp;quot;&amp;quot;
data = {
&amp;quot;user_profile&amp;quot;: await self.get_user_profile(user_id),
&amp;quot;agents&amp;quot;: await self.get_user_agents(user_id),
&amp;quot;workflows&amp;quot;: await self.get_user_workflows(user_id),
&amp;quot;knowledge_bases&amp;quot;: await self.get_user_knowledge(user_id),
&amp;quot;sessions&amp;quot;: await self.get_user_sessions(user_id),
&amp;quot;usage_stats&amp;quot;: await self.get_user_usage(user_id)
}
# 打包导出
return await self.package_export(data, format)
async def import_user_data(
self,
user_id: str,
import_file: UploadedFile
) -&amp;gt; ImportResult:
&amp;quot;&amp;quot;&amp;quot;导入用户数据&amp;quot;&amp;quot;&amp;quot;
# 验证格式
data = await self.parse_import_file(import_file)
# 转换并导入
await self.import_agents(user_id, data[&amp;quot;agents&amp;quot;])
await self.import_workflows(user_id, data[&amp;quot;workflows&amp;quot;])
await self.import_knowledge(user_id, data[&amp;quot;knowledge_bases&amp;quot;])
return ImportResult(success=True, items_imported=...)
async def delete_user_data(
self,
user_id: str,
scope: DeleteScope # all/specific
) -&amp;gt; DeleteResult:
&amp;quot;&amp;quot;&amp;quot;删除用户数据 - GDPR合规&amp;quot;&amp;quot;&amp;quot;
# 删除所有关联数据
await self.db.users.delete(user_id)
await self.db.agents.delete_many({&amp;quot;user_id&amp;quot;: user_id})
await self.db.sessions.delete_many({&amp;quot;user_id&amp;quot;: user_id})
# ... 其他数据
return DeleteResult(completed_at=datetime.now())
&lt;/code>&lt;/pre>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">### Agent适配器生命周期
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">```python
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">class AgentAdapterLifecycle:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &amp;#34;&amp;#34;&amp;#34;Agent适配器生命周期管理&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> def __init__(self, registry: AgentFrameworkRegistry):
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> self.registry = registry
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> self._active_adapters: dict[str, ExternalAgentAdapter] = {}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> def get_or_create_adapter(
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> self,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> framework: AgentFramework,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> config: dict
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ) -&amp;gt; ExternalAgentAdapter:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &amp;#34;&amp;#34;&amp;#34;获取或创建适配器实例&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> adapter_key = f&amp;#34;{framework.value}:{hash_config(config)}&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> if adapter_key not in self._active_adapters:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> # 创建新实例
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> adapter = self.registry.get_adapter(framework)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> if not adapter:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> raise AgentNotAvailableError(framework)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> self._active_adapters[adapter_key] = adapter
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> return self._active_adapters[adapter_key]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> def swap_adapter(
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> self,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> old_framework: AgentFramework,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> new_framework: AgentFramework,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> new_config: dict
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ):
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &amp;#34;&amp;#34;&amp;#34;热切换适配器 - 不影响已有数据&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> # 1. 验证新适配器可用
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> new_adapter = self.registry.get_adapter(new_framework)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> if not new_adapter:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> raise AgentNotAvailableError(new_framework)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> # 2. 切换（已有的AgentConfig等数据完全不变）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> logger.info(f&amp;#34;Swapping agent adapter: {old_framework} -&amp;gt; {new_framework}&amp;#34;)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> # 3. 清理旧实例
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> old_keys = [k for k in self._active_adapters
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> if k.startswith(old_framework.value)]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> for key in old_keys:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> del self._active_adapters[key]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> def rollback_adapter(
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> self,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> framework: AgentFramework,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> config: dict
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ):
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &amp;#34;&amp;#34;&amp;#34;回滚适配器版本&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> # 适配器版本管理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">class AgentMigrationService:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &amp;#34;&amp;#34;&amp;#34;Agent迁移服务 - 支持跨适配器迁移&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> async def migrate_agent(
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> self,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> agent_id: str,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> from_adapter: AgentFramework,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> to_adapter: AgentFramework
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ) -&amp;gt; MigrationResult:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &amp;#34;&amp;#34;&amp;#34;迁移智能体到新的Agent框架&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> agent = await self.get_agent(agent_id)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> # 1. 验证目标适配器
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> if not self.registry.get_adapter(to_adapter):
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> raise MigrationError(f&amp;#34;Target adapter not available: {to_adapter}&amp;#34;)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> # 2. 创建新版本配置
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> new_config = await self.translate_config(
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> agent.config,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> from_adapter,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> to_adapter
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> )
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> # 3. 更新配置（保持原有数据不变）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> agent.model_config = new_config
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> agent.adapter_type = to_adapter.value
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> agent.version += 1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> agent.version_history.append(AgentVersion(
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> version=agent.version,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> adapter=to_adapter.value,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> migrated_at=datetime.now(),
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> migrated_by=&amp;#34;system&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ))
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> await self.save_agent(agent)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> return MigrationResult(
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> success=True,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> old_adapter=from_adapter,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> new_adapter=to_adapter,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> data_preserved=True # 关键：数据完整保留
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> )
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="版本兼容性保障">版本兼容性保障
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">VersionCompatibility&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;版本兼容性管理&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CURRENT_VERSION&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;2.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 版本迁移路径&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">MIGRATION_PATHS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;1.0&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;1.1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;1.2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;2.0&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;1.1&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;1.2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;2.0&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;1.2&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;2.0&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">migrate_if_needed&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;必要时执行数据迁移&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">current_version&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;version&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;1.0&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">current_version&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CURRENT_VERSION&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">data&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 执行迁移&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">migration_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_migration_path&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">current_version&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">target_version&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">migration_path&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">migrate_to&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">target_version&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">data&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">migrate_to&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">target_version&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;迁移到指定版本&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">migrator&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">getattr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;migrate_to_&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">target_version&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;.&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;_&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">migrator&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">migrator&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">data&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">rollback&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">target_version&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;回滚到指定版本&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 支持回滚，确保数据不丢失&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="数据隔离与安全">数据隔离与安全
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">DataIsolation&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;数据隔离保障&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">verify_ownership&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">resource_type&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">resource_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">bool&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;验证数据所有权&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">resource&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_resource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">resource_type&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">resource_id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">resource&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">user_id&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">user_id&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">list_user_accessible&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">resource_type&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;列出用户可访问的资源&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. 自己创建的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">owned&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">resource_type&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;user_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">user_id&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. 公开分享的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">shared&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">resource_type&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;is_public&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;tenant_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_user_tenant&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user_id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. 项目内共享的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">project_shared&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_project_shared_resources&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">resource_type&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">deduplicate&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">owned&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">shared&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">project_shared&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">enforce_data_retention&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tenant_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">resource_type&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">retention_days&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;执行数据保留策略&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cutoff_date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">now&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">timedelta&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">days&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">retention_days&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 删除过期数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">deleted&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">resource_type&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">delete_many&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;tenant_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">tenant_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;created_at&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;$lt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">cutoff_date&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;status&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;archived&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Deleted &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">deleted&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">count&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> expired &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">resource_type&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> records&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="多容器多项目隔离设计">多容器/多项目隔离设计
&lt;/h2>&lt;h3 id="层级关系">层级关系
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 平台层 Platform │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├────────────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌──────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 容器层 (Tenant) │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ 容器 A │ │ 容器 B │ │ 容器 C │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ 研发中心 │ │ 市场部 │ │ 行政部 │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │ │ │ │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ ┌─────────┐│ │ ┌─────────┐│ │ ┌─────────┐│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │项目 A1 ││ │ │项目 B1 ││ │ │项目 C1 ││ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │项目 A2 ││ │ │项目 B2 ││ │ │项目 C2 ││ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ └─────────┘│ │ └─────────┘│ │ └─────────┘│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │ │ │ │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ ┌─────────┐│ │ │ │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │共享知识 ││ │ │ │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ └─────────┘│ │ │ │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └──────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌──────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 共享资源层 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ • 公共模型库（平台统一采购的模型） │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ • 全局知识库（公司制度、流程文档） │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ • 组织配置（角色、权限模板） │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ • 审计日志（操作记录、合规审计） │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ • 贡献排行（员工激励数据） │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └──────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="隔离策略">隔离策略
&lt;/h3>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>隔离维度&lt;/th>
&lt;th>实现方式&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>数据隔离&lt;/strong>&lt;/td>
&lt;td>租户ID + 项目ID&lt;/td>
&lt;td>所有资源关联租户/项目ID&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>模型隔离&lt;/strong>&lt;/td>
&lt;td>租户级模型配置&lt;/td>
&lt;td>不同租户可配置不同的AI提供商&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>配额隔离&lt;/strong>&lt;/td>
&lt;td>租户级配额限制&lt;/td>
&lt;td>Token用量、存储空间等&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>权限隔离&lt;/strong>&lt;/td>
&lt;td>RBAC模型&lt;/td>
&lt;td>租户管理员、项目管理员、普通用户&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>成本隔离&lt;/strong>&lt;/td>
&lt;td>租户级计费&lt;/td>
&lt;td>各容器独立核算AI使用成本&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>审计隔离&lt;/strong>&lt;/td>
&lt;td>租户级日志&lt;/td>
&lt;td>操作日志按租户隔离存储&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="数据模型关系">数据模型关系
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌─────────────┐ ┌─────────────┐ ┌─────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Tenant │────&amp;lt;│ Project │────&amp;lt;│ User │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ (容器) │ │ (项目) │ │ (用户) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────┘ └─────────────┘ └─────────────┘
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ▼ ▼ ▼
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">┌─────────────┐ ┌─────────────┐ ┌─────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Agent │ │ Workflow │ │ UserRole │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ (智能体) │ │ (工作流) │ │ (用户角色) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────┘ └─────────────┘ └─────────────┘
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ▼
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">┌─────────────┐ ┌─────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Knowledge │ │ Tool │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ (知识库) │ │ (工具) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────┘ └─────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="员工激励机制设计">员工激励机制设计
&lt;/h2>&lt;h3 id="设计理念">设计理念
&lt;/h3>&lt;p>让员工从&amp;quot;被动使用&amp;quot;转变为&amp;quot;主动贡献&amp;quot;，形成平台与员工的良性循环：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 员工激励飞轮 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌──────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 贡献者 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Create │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └──────┬───────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 发布到平台 Publish │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 被其他人使用 Use │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 获得认可 Like/Favorite │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌──────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 积分奖励 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Score │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └──────┬───────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌──────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 更多激励 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ More │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └──────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="贡献积分系统">贡献积分系统
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">UserContribution&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;用户贡献统计&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tenant_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 贡献数量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">agent_count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">workflow_count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">knowledge_count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">plugin_count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 被认可情况&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">likes_received&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">uses_received&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">favorites_received&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">reviews_count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 综合评分&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_score&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 徽章&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">badges&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">list&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">ContributionTracker&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;贡献追踪器&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 积分规则&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">POINTS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 创建贡献&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;create_agent&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;create_workflow&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">15&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;create_knowledge&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;create_plugin&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">20&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 被认可&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;receive_like&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;receive_use&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;receive_favorite&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;receive_review&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 被评为优质&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;featured_by_admin&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">50&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 排行榜&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;weekly_top_agent&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">50&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;monthly_best&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 持续贡献&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;streak_7_days&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;streak_30_days&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">record&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">user_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">action&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">target_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;记录贡献行为&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">points&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">POINTS&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">action&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">contribution_records&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">insert&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;user_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">user_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;action&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">action&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;target_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">target_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;points&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">points&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;created_at&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">now&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_update_user_score&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user_id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">_update_user_score&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">user_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;更新用户总分&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">contribution_records&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">aggregate&lt;/span>&lt;span class="p">([&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;$match&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;user_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">user_id&lt;/span>&lt;span class="p">}},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;$group&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;$user_id&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;total&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;$sum&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;$points&amp;#34;&lt;/span>&lt;span class="p">}}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">users&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">update_one&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">user_id&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;$set&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;contribution_score&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">total&lt;/span>&lt;span class="p">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">leaderboard&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tenant_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">period&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;monthly&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">limit&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">10&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">UserContribution&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;贡献排行榜&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start_date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_get_period_start&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">period&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pipeline&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;$match&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;tenant_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">tenant_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;created_at&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;$gte&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">start_date&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;$group&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;$user_id&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;total_score&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;$sum&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;$points&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;$sort&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;total_score&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">}},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;$limit&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">limit&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">contribution_records&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">aggregate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pipeline&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="徽章系统">徽章系统
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 徽章定义&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">BADGES&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;first_agent&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;初露锋芒&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;创建了第一个智能体&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;icon&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;🌟&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;condition&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="k">lambda&lt;/span> &lt;span class="n">u&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">u&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">agent_count&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;agent_master&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;智能体大师&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;创建了10个智能体&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;icon&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;🏆&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;condition&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="k">lambda&lt;/span> &lt;span class="n">u&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">u&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">agent_count&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">10&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;workflow_expert&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;工作流专家&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;创建了5个工作流&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;icon&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;⚙️&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;condition&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="k">lambda&lt;/span> &lt;span class="n">u&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">u&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">workflow_count&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;knowledge_curator&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;知识守护者&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;贡献了100条知识&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;icon&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;📚&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;condition&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="k">lambda&lt;/span> &lt;span class="n">u&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">u&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">knowledge_count&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">100&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;popular_creator&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;人气创作者&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;累计获得100个赞&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;icon&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;❤️&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;condition&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="k">lambda&lt;/span> &lt;span class="n">u&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">u&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">likes_received&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">100&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;top_contributor&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;月度之星&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;本月贡献排行第一&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;icon&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;🌙&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;condition&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="k">lambda&lt;/span> &lt;span class="n">u&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">u&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_monthly_top&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;streak_master&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;坚持达人&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;连续30天有贡献&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;icon&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;🔥&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;condition&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="k">lambda&lt;/span> &lt;span class="n">u&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">u&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">streak_days&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">30&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="技术栈选型">技术栈选型
&lt;/h2>&lt;h3 id="推荐技术栈">推荐技术栈
&lt;/h3>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>层级&lt;/th>
&lt;th>推荐技术&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>API Gateway&lt;/strong>&lt;/td>
&lt;td>Kong / Traefik&lt;/td>
&lt;td>高性能网关，支持插件扩展&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>后端框架&lt;/strong>&lt;/td>
&lt;td>FastAPI / Go&lt;/td>
&lt;td>异步高性能，类型安全&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>数据库&lt;/strong>&lt;/td>
&lt;td>PostgreSQL + Redis&lt;/td>
&lt;td>主数据存储 + 缓存&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>消息队列&lt;/strong>&lt;/td>
&lt;td>Kafka / RabbitMQ&lt;/td>
&lt;td>工作流异步处理&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>向量数据库&lt;/strong>&lt;/td>
&lt;td>Qdrant / Milvus&lt;/td>
&lt;td>知识库向量检索&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>全文搜索&lt;/strong>&lt;/td>
&lt;td>Elasticsearch&lt;/td>
&lt;td>知识库全文检索&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>容器编排&lt;/strong>&lt;/td>
&lt;td>Kubernetes&lt;/td>
&lt;td>多容器隔离&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>前端&lt;/strong>&lt;/td>
&lt;td>React + Ant Design&lt;/td>
&lt;td>管理控制台&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>工作流引擎&lt;/strong>&lt;/td>
&lt;td>Temporal / Prefect&lt;/td>
&lt;td>工作流编排&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="技术选型考量">技术选型考量
&lt;/h3>&lt;h4 id="1-后端框架对比">1. 后端框架对比
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>框架&lt;/th>
&lt;th>优势&lt;/th>
&lt;th>劣势&lt;/th>
&lt;th>适用场景&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>FastAPI&lt;/strong>&lt;/td>
&lt;td>异步、类型安全、自动文档&lt;/td>
&lt;td>运行时性能略低&lt;/td>
&lt;td>快速迭代、中小型规模&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Go&lt;/strong>&lt;/td>
&lt;td>高性能、并发强、部署简单&lt;/td>
&lt;td>生态较新、泛型支持弱&lt;/td>
&lt;td>高并发、大规模场景&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Python&lt;/strong>&lt;/td>
&lt;td>AI生态丰富、开发快&lt;/td>
&lt;td>GIL限制、性能一般&lt;/td>
&lt;td>AI集成优先的场景&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h4 id="2-工作流引擎对比">2. 工作流引擎对比
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>引擎&lt;/th>
&lt;th>优势&lt;/th>
&lt;th>劣势&lt;/th>
&lt;th>适用场景&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Temporal&lt;/strong>&lt;/td>
&lt;td>强大的持久化、可观测&lt;/td>
&lt;td>学习曲线陡、资源占用高&lt;/td>
&lt;td>复杂长时任务&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Prefect&lt;/strong>&lt;/td>
&lt;td>Python原生、简洁&lt;/td>
&lt;td>分布式能力较弱&lt;/td>
&lt;td>Python团队、简单流程&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>自研&lt;/strong>&lt;/td>
&lt;td>完全可控、定制灵活&lt;/td>
&lt;td>开发维护成本高&lt;/td>
&lt;td>有特殊需求的场景&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="实施路线图">实施路线图
&lt;/h2>&lt;h3 id="总体规划">总体规划
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 实施路线图 Roadmap │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├─────────────────────────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Phase 1 Phase 2 Phase 3 Phase 4 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 核心搭建 功能完善 生态建设 高级特性 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 8-10周 8-10周 8-10周 8-10周 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ MVP发布 │ │ 正式版 │ │ 平台化 │ │ 智能化 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ V1.0 │────▶│ V2.0 │────▶│ V3.0 │────▶│ V4.0 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="phase-1-核心搭建8-10周">Phase 1: 核心搭建（8-10周）
&lt;/h3>&lt;h4 id="目标">目标
&lt;/h4>&lt;p>搭建平台基础骨架，实现最小可用产品。&lt;/p>
&lt;h4 id="里程碑">里程碑
&lt;/h4>&lt;ul>
&lt;li>&lt;input disabled="" type="checkbox"> 用户注册、登录、认证&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 基础用户管理（CRUD、角色）&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 单容器支持&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 至少2个AI适配器（OpenAI + 1个国产模型）&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 基础的智能体创建界面&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 简单的对话功能&lt;/li>
&lt;/ul>
&lt;h4 id="详细任务分解">详细任务分解
&lt;/h4>&lt;p>&lt;strong>Week 1-2: 项目初始化&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 项目结构搭建
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── backend/ # 后端代码
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ ├── app/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ ├── core/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ └── api/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── frontend/ # 前端代码
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ ├── src/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ └── public/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── infra/ # 基础设施
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ ├── docker/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ └── k8s/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── docs/ # 文档
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 技术选型确认
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 开发环境搭建
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 代码规范制定
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ Git流程确定
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 3-4: 核心服务&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 数据库设计
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── users
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── tenants
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── projects
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── roles
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── permissions
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 用户认证模块
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── JWT实现
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 登录/登出
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── 刷新Token
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 用户管理API
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── CRUD接口
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 角色分配
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── 权限校验
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 容器管理API
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 创建容器
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── 配额管理
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 5-6: 集成层&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ AI Provider接口定义
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ OpenAI适配器实现
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 国产模型适配器实现（智谱/通义）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 适配器注册中心
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 统一调用入口
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 模型路由基础功能
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 7-8: 智能体基础&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 智能体数据模型
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 智能体CRUD API
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 基础对话API
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 会话管理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 简单的管理界面
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 9-10: 集成测试&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 端到端测试
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 性能测试
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 安全测试
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 文档完善
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ MVP发布
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="phase-1-交付物">Phase 1 交付物
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>交付物&lt;/th>
&lt;th>说明&lt;/th>
&lt;th>验收标准&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>用户认证系统&lt;/td>
&lt;td>完整的注册登录流程&lt;/td>
&lt;td>支持邮箱/手机登录&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>用户管理&lt;/td>
&lt;td>增删改查用户&lt;/td>
&lt;td>支持角色分配&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>单容器支持&lt;/td>
&lt;td>基础的多租户隔离&lt;/td>
&lt;td>数据隔离验证&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2个AI适配器&lt;/td>
&lt;td>OpenAI + 国产模型&lt;/td>
&lt;td>可切换调用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>智能体创建&lt;/td>
&lt;td>创建和管理智能体&lt;/td>
&lt;td>可配置提示词和模型&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>基础对话&lt;/td>
&lt;td>与智能体对话&lt;/td>
&lt;td>支持多轮对话&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h3 id="phase-2-功能完善8-10周">Phase 2: 功能完善（8-10周）
&lt;/h3>&lt;h4 id="目标-1">目标
&lt;/h4>&lt;p>完善核心功能，增加项目管理、知识库、工作流。&lt;/p>
&lt;h4 id="里程碑-1">里程碑
&lt;/h4>&lt;ul>
&lt;li>&lt;input disabled="" type="checkbox"> 多容器支持&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 项目管理&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 知识库管理&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 工作流基础&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 工具系统&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 贡献激励基础&lt;/li>
&lt;/ul>
&lt;h4 id="详细任务分解-1">详细任务分解
&lt;/h4>&lt;p>&lt;strong>Week 11-12: 多容器与项目&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 容器管理完善
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 配额系统
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 容器配置
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── 容器监控
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 项目管理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 项目CRUD
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 项目成员管理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── 项目级配置
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ RBAC权限完善
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 权限矩阵
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 资源级权限
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── 审计日志
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 13-14: 知识库&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 知识库模型设计
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 文档上传与解析
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── PDF解析
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── Word解析
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── Markdown解析
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 向量化处理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 知识检索API
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 知识库管理界面
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 15-16: 工作流引擎&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 工作流数据模型
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 可视化编辑器
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 节点拖拽
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 连线绘制
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── 属性配置
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 工作流执行引擎
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 节点执行
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 条件分支
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── 异常处理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 工作流API
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 工作流执行监控
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 17-18: 工具系统&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 工具接口定义
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 内置工具实现
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 网络搜索
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 计算器
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 代码执行
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── 文档处理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 工具注册中心
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 工具管理界面
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 智能体工具配置
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 19-20: 贡献激励&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 贡献积分系统
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 贡献记录追踪
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 排行榜API
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 徽章系统
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 激励展示界面
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="phase-2-交付物">Phase 2 交付物
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>交付物&lt;/th>
&lt;th>说明&lt;/th>
&lt;th>验收标准&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>多容器支持&lt;/td>
&lt;td>完整的租户隔离&lt;/td>
&lt;td>配额、配置、监控&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>项目管理&lt;/td>
&lt;td>项目级资源隔离&lt;/td>
&lt;td>成员管理、权限控制&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>知识库&lt;/td>
&lt;td>文档管理和检索&lt;/td>
&lt;td>支持多种格式、支持向量检索&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>工作流引擎&lt;/td>
&lt;td>可视化流程编排&lt;/td>
&lt;td>拖拽设计、循环、条件分支&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>工具系统&lt;/td>
&lt;td>扩展工具能力&lt;/td>
&lt;td>内置5+工具、支持自定义&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>贡献激励&lt;/td>
&lt;td>积分和徽章&lt;/td>
&lt;td>积分记录、排行榜、徽章展示&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h3 id="phase-3-生态建设8-10周">Phase 3: 生态建设（8-10周）
&lt;/h3>&lt;h4 id="目标-2">目标
&lt;/h4>&lt;p>构建开放生态，支持插件市场、员工分享。&lt;/p>
&lt;h4 id="里程碑-2">里程碑
&lt;/h4>&lt;ul>
&lt;li>&lt;input disabled="" type="checkbox"> 插件市场&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 模板中心&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 分享机制&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 评论系统&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> API开放平台&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 第三方集成&lt;/li>
&lt;/ul>
&lt;h4 id="详细任务分解-2">详细任务分解
&lt;/h4>&lt;p>&lt;strong>Week 21-22: 插件市场&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 插件数据模型
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 插件上传与审核
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 插件发现与搜索
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 插件安装/卸载
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 插件市场界面
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 插件评分与评论
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 23-24: 模板中心&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 模板市场设计
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 预置模板开发
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 客服机器人模板
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 代码审查模板
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 报表生成模板
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── 内容创作模板
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 模板分类与推荐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 模板一键使用
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 25-26: 分享机制&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 分享流程设计
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 公开/私有切换
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 分享权限控制
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 分享记录追踪
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 分享效果统计
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 热门内容推荐
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 27-28: API开放平台&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ API文档自动生成
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ API密钥管理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ API调用监控
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 速率限制
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ SDK自动生成
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 开发者门户
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 29-30: 高级特性&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 批量导入导出
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 智能体版本管理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ A/B测试支持
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 实验追踪
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 效果分析
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 优化建议
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="phase-3-交付物">Phase 3 交付物
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>交付物&lt;/th>
&lt;th>说明&lt;/th>
&lt;th>验收标准&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>插件市场&lt;/td>
&lt;td>开放的插件生态&lt;/td>
&lt;td>支持第三方插件、审核流程&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>模板中心&lt;/td>
&lt;td>预置和社区模板&lt;/td>
&lt;td>10+预置模板、一键使用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>分享机制&lt;/td>
&lt;td>智能体和工作流分享&lt;/td>
&lt;td>公开/私有、权限控制&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>API开放平台&lt;/td>
&lt;td>第三方集成能力&lt;/td>
&lt;td>完整API、SDK、文档&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>开发者门户&lt;/td>
&lt;td>开发者资源中心&lt;/td>
&lt;td>文档、示例、社区&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h3 id="phase-4-高级特性8-10周">Phase 4: 高级特性（8-10周）
&lt;/h3>&lt;h4 id="目标-3">目标
&lt;/h4>&lt;p>实现高级AI能力，提升平台智能化水平。&lt;/p>
&lt;h4 id="里程碑-3">里程碑
&lt;/h4>&lt;ul>
&lt;li>&lt;input disabled="" type="checkbox"> 智能模型路由&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 多模态支持&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> Agent协作&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 自定义训练&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 企业级安全&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 高可用部署&lt;/li>
&lt;/ul>
&lt;h4 id="详细任务分解-3">详细任务分解
&lt;/h4>&lt;p>&lt;strong>Week 31-32: 智能路由&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 模型评估体系
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 任务分类器
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 智能路由策略
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 成本优先
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── 速度优先
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── 质量优先
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 动态模型切换
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 路由效果追踪
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 成本优化建议
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 33-34: 多模态&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 图像理解支持
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 语音合成/识别
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 视频理解
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 多模态智能体
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 多模态工作流
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 跨模态检索
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 35-36: Agent协作&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ 多Agent通信协议
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ Agent协作工作流
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ Agent角色分配
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 协作状态管理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 协作效果评估
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 协作模板市场
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 37-38: 自定义训练&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ Fine-tuning平台
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 数据集管理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 训练任务管理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 模型评估
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 模型发布
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 成本控制
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Week 39-40: 企业级特性&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">□ SSO集成
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── SAML
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── OIDC
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── LDAP
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 合规审计
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 数据加密
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 私有化部署
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 高可用架构
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">□ 灾备方案
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="phase-4-交付物">Phase 4 交付物
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>交付物&lt;/th>
&lt;th>说明&lt;/th>
&lt;th>验收标准&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>智能路由&lt;/td>
&lt;td>自动选择最优模型&lt;/td>
&lt;td>支持多种策略、成本降低30%+&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>多模态&lt;/td>
&lt;td>图像/语音/视频支持&lt;/td>
&lt;td>全模态覆盖&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Agent协作&lt;/td>
&lt;td>多智能体协作&lt;/td>
&lt;td>通信协议、协作模板&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>自定义训练&lt;/td>
&lt;td>Fine-tuning能力&lt;/td>
&lt;td>支持主流模型、数据闭环&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>企业级安全&lt;/td>
&lt;td>完整的企业安全&lt;/td>
&lt;td>SSO、审计、私有化&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h3 id="资源规划">资源规划
&lt;/h3>&lt;h4 id="团队规模建议">团队规模建议
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>阶段&lt;/th>
&lt;th>后端&lt;/th>
&lt;th>前端&lt;/th>
&lt;th>DevOps&lt;/th>
&lt;th>产品&lt;/th>
&lt;th>测试&lt;/th>
&lt;th>总计&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Phase 1&lt;/td>
&lt;td>2-3&lt;/td>
&lt;td>1-2&lt;/td>
&lt;td>1&lt;/td>
&lt;td>1&lt;/td>
&lt;td>1&lt;/td>
&lt;td>6-8&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Phase 2&lt;/td>
&lt;td>2-3&lt;/td>
&lt;td>1-2&lt;/td>
&lt;td>1&lt;/td>
&lt;td>1&lt;/td>
&lt;td>1&lt;/td>
&lt;td>6-8&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Phase 3&lt;/td>
&lt;td>1-2&lt;/td>
&lt;td>1-2&lt;/td>
&lt;td>1&lt;/td>
&lt;td>1&lt;/td>
&lt;td>1&lt;/td>
&lt;td>5-7&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Phase 4&lt;/td>
&lt;td>1-2&lt;/td>
&lt;td>1&lt;/td>
&lt;td>1&lt;/td>
&lt;td>1&lt;/td>
&lt;td>1&lt;/td>
&lt;td>5-6&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h4 id="基础设施估算">基础设施估算
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>资源&lt;/th>
&lt;th>Phase 1&lt;/th>
&lt;th>Phase 2&lt;/th>
&lt;th>Phase 3&lt;/th>
&lt;th>Phase 4&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>云服务器&lt;/td>
&lt;td>4-8核&lt;/td>
&lt;td>8-16核&lt;/td>
&lt;td>16-32核&lt;/td>
&lt;td>32-64核&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>数据库&lt;/td>
&lt;td>100GB&lt;/td>
&lt;td>500GB&lt;/td>
&lt;td>1TB&lt;/td>
&lt;td>2TB+&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>向量数据库&lt;/td>
&lt;td>-&lt;/td>
&lt;td>100GB&lt;/td>
&lt;td>500GB&lt;/td>
&lt;td>1TB+&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>API调用量&lt;/td>
&lt;td>10万/月&lt;/td>
&lt;td>100万/月&lt;/td>
&lt;td>500万/月&lt;/td>
&lt;td>1000万+/月&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="开发路线图">开发路线图
&lt;/h2>&lt;h3 id="整体规划">整体规划
&lt;/h3>&lt;blockquote>
&lt;p>&lt;strong>核心原则：小步快跑，先跑通核心，再迭代完善&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 开发路线图 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Phase 1 (MVP) Phase 2 (完善) Phase 3 (扩展) Phase 4 (企业级) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ─────────── ─────────── ─────────── ───────────── │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 核心框架 智能体支持 生态建设 企业级安全 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 2-3个月 3-4个月 3-4个月 2-3个月 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────┴─────────────────┴─────────────────┴────────────► │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 2025 Q1 2025 Q2 2025 Q3 2025 Q4 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="phase-1-mvp-month-1-3">Phase 1: MVP (Month 1-3)
&lt;/h3>&lt;h4 id="目标-4">目标
&lt;/h4>&lt;blockquote>
&lt;p>&lt;strong>跑通核心流程：用户 → 创建Agent → 调用 → 持久化数据&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;h4 id="核心功能">核心功能
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>功能&lt;/th>
&lt;th>优先级&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>用户管理&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>注册、登录、角色、权限&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>容器管理&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>多容器隔离、配额管理&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>项目管理&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>多项目、成员管理&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Agent创建&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>基础配置、模型选择&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Agent对话&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>基础对话能力&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>数据持久化&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>PostgreSQL存储&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>适配器框架&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>OpenAI/Claude适配器&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h4 id="技术债务">技术债务
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>内容&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>用户认证&lt;/td>
&lt;td>JWT / OAuth2&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>基础监控&lt;/td>
&lt;td>日志、错误追踪&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>基础测试&lt;/td>
&lt;td>单元测试覆盖&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h4 id="phase-1-架构图">Phase 1 架构图
&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Phase 1 MVP 架构 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Web │ │ API │ │ CLI │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └────┬────┘ └────┬────┘ └────┬────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └──────────────┼──────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 业务逻辑层 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ • 用户管理 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ • 容器管理 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ • Agent对话 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └────────┬─────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌──────────────┼──────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ ▼ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ PG │ │ 适配器 │ │ Agent │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 用户 │ │ 框架 │ │ Runtime │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 配置 │ │ │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────┘ └─────────┘ └─────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="phase-1-验收标准">Phase 1 验收标准
&lt;/h4>&lt;ul>
&lt;li>✅ 用户可以注册、登录&lt;/li>
&lt;li>✅ 可以创建容器和项目&lt;/li>
&lt;li>✅ 可以创建Agent并配置模型&lt;/li>
&lt;li>✅ 可以与Agent对话&lt;/li>
&lt;li>✅ 对话历史可以持久化存储&lt;/li>
&lt;li>✅ 支持 OpenAI / Claude 模型&lt;/li>
&lt;li>✅ 基础测试覆盖&lt;/li>
&lt;/ul>
&lt;h4 id="phase-1-交付物-1">Phase 1 交付物
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>交付物&lt;/th>
&lt;th>说明&lt;/th>
&lt;th>验收标准&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>用户系统&lt;/td>
&lt;td>注册/登录/角色&lt;/td>
&lt;td>3种角色、RBAC权限&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>容器管理&lt;/td>
&lt;td>多容器隔离&lt;/td>
&lt;td>容器创建、配额限制&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Agent对话&lt;/td>
&lt;td>基础对话&lt;/td>
&lt;td>流畅对话、持久化&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>适配器框架&lt;/td>
&lt;td>模型接入&lt;/td>
&lt;td>2个以上适配器&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h3 id="phase-2-智能体支持-month-4-7">Phase 2: 智能体支持 (Month 4-7)
&lt;/h3>&lt;h4 id="目标-5">目标
&lt;/h4>&lt;blockquote>
&lt;p>&lt;strong>扩展Agent能力：支持工具、知识库、工作流&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;h4 id="核心功能-1">核心功能
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>功能&lt;/th>
&lt;th>优先级&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Agent工具&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>工具注册、调用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>知识库RAG&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>文档上传、向量检索&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>工作流&lt;/td>
&lt;td>P1&lt;/td>
&lt;td>基础编排能力&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>会话管理&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>多会话、上下文&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>MCP支持&lt;/td>
&lt;td>P1&lt;/td>
&lt;td>MCP协议桥接&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h4 id="phase-2-架构图">Phase 2 架构图
&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Phase 2 智能体架构 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 业务应用层 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │Agent管理│ │知识库 │ │工作流 │ │会话管理 │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ +工具 │ │ RAG │ │编排 │ │上下文 │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 编排调度层 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ Agent │ │ Workflow│ │ Task │ │ MCP │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ Runtime │ │ Engine │ │Scheduler│ │ Bridge │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 数据层 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ PG │ │对象存储│ │向量数据库│ │ 搜索 │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ 配置+会话│ │ 文档 │ │ RAG │ │ 增强 │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="phase-2-验收标准">Phase 2 验收标准
&lt;/h4>&lt;ul>
&lt;li>✅ Agent可以使用多种工具&lt;/li>
&lt;li>✅ 可以上传文档构建知识库&lt;/li>
&lt;li>✅ 可以实现RAG增强对话&lt;/li>
&lt;li>✅ 可以设计简单工作流&lt;/li>
&lt;li>✅ 支持MCP协议&lt;/li>
&lt;/ul>
&lt;h4 id="phase-2-交付物-1">Phase 2 交付物
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>交付物&lt;/th>
&lt;th>说明&lt;/th>
&lt;th>验收标准&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Agent工具&lt;/td>
&lt;td>多工具支持&lt;/td>
&lt;td>5种以上内置工具&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>知识库RAG&lt;/td>
&lt;td>文档检索&lt;/td>
&lt;td>支持PDF/Word/MD&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>工作流&lt;/td>
&lt;td>可视化编排&lt;/td>
&lt;td>基础节点类型&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>MCP支持&lt;/td>
&lt;td>协议桥接&lt;/td>
&lt;td>GitHub/FS工具&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h3 id="phase-3-生态建设-month-8-11">Phase 3: 生态建设 (Month 8-11)
&lt;/h3>&lt;h4 id="目标-6">目标
&lt;/h4>&lt;blockquote>
&lt;p>&lt;strong>开放生态：插件市场、员工激励、协作分享&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;h4 id="核心功能-2">核心功能
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>功能&lt;/th>
&lt;th>优先级&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>插件市场&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>发布、发现、安装插件&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>智能体市场&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>分享、发现、使用Agent&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>员工激励&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>积分、徽章、排行榜&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>工作流模板&lt;/td>
&lt;td>P1&lt;/td>
&lt;td>模板市场、模板创建&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>团队协作&lt;/td>
&lt;td>P1&lt;/td>
&lt;td>共享、评论、版本控制&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h4 id="phase-3-架构图">Phase 3 架构图
&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Phase 3 生态架构 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 用户层 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ 创建者 │ │ 使用者 │ │ 贡献者 │ │ 评审者 │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 市场层 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │Agent市场│ │插件市场│ │模板市场│ │知识市场│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─────────────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 激励层 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ 积分 │ │ 徽章 │ │ 排行 │ │ 成就 │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─────────────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="phase-3-验收标准">Phase 3 验收标准
&lt;/h4>&lt;ul>
&lt;li>✅ 可以发布Agent到市场&lt;/li>
&lt;li>✅ 可以发布插件到市场&lt;/li>
&lt;li>✅ 有完整的积分激励系统&lt;/li>
&lt;li>✅ 有排行榜和徽章系统&lt;/li>
&lt;li>✅ 支持工作流模板分享&lt;/li>
&lt;/ul>
&lt;h4 id="phase-3-交付物-1">Phase 3 交付物
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>交付物&lt;/th>
&lt;th>说明&lt;/th>
&lt;th>验收标准&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Agent市场&lt;/td>
&lt;td>分享发现Agent&lt;/td>
&lt;td>搜索、评分、评论&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>插件市场&lt;/td>
&lt;td>插件生态&lt;/td>
&lt;td>发布、审核、安装&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>激励机制&lt;/td>
&lt;td>积分徽章&lt;/td>
&lt;td>积分系统、徽章墙&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>工作流模板&lt;/td>
&lt;td>模板市场&lt;/td>
&lt;td>模板创建、分享&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h3 id="phase-4-企业级安全-month-12-14">Phase 4: 企业级安全 (Month 12-14)
&lt;/h3>&lt;h4 id="目标-7">目标
&lt;/h4>&lt;blockquote>
&lt;p>&lt;strong>企业级能力：安全、合规、可观测&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;h4 id="核心功能-3">核心功能
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>功能&lt;/th>
&lt;th>优先级&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>SSO/LDAP&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>企业身份集成&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>审计日志&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>完整操作记录&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>数据加密&lt;/td>
&lt;td>P0&lt;/td>
&lt;td>传输/存储加密&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>私有化部署&lt;/td>
&lt;td>P1&lt;/td>
&lt;td>离线部署支持&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>高可用&lt;/td>
&lt;td>P1&lt;/td>
&lt;td>集群、灾备&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h4 id="phase-4-验收标准">Phase 4 验收标准
&lt;/h4>&lt;ul>
&lt;li>✅ 支持SSO/LDAP&lt;/li>
&lt;li>✅ 完整审计日志&lt;/li>
&lt;li>✅ 数据加密&lt;/li>
&lt;li>✅ 可私有化部署&lt;/li>
&lt;li>✅ 高可用保障&lt;/li>
&lt;/ul>
&lt;h4 id="phase-4-交付物-1">Phase 4 交付物
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>交付物&lt;/th>
&lt;th>说明&lt;/th>
&lt;th>验收标准&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>SSO集成&lt;/td>
&lt;td>企业身份&lt;/td>
&lt;td>SAML/OIDC/LDAP&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>审计日志&lt;/td>
&lt;td>合规要求&lt;/td>
&lt;td>操作记录、查询&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>私有部署&lt;/td>
&lt;td>离线方案&lt;/td>
&lt;td>Docker/K8s部署&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>高可用&lt;/td>
&lt;td>99.9%可用&lt;/td>
&lt;td>集群、灾备&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h3 id="开发优先级矩阵">开发优先级矩阵
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl"> 高影响
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ▲
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ┌───────────────┼───────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ 快速胜利 │ 主要目标 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ (Quick Win) │ (Big Bet) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> 低优先级┼───────────────┼───────────────┼高优先级
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ 后缓 │ 策略性 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ (Later) │ (Strategic) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └───────────────┼───────────────┘
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ▼
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> 低影响
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>象限&lt;/th>
&lt;th>内容&lt;/th>
&lt;th>策略&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>快速胜利&lt;/td>
&lt;td>基础功能、核心持久化&lt;/td>
&lt;td>优先做，低成本高回报&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>主要目标&lt;/td>
&lt;td>Agent能力、知识库&lt;/td>
&lt;td>Phase 1-2重点&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>策略性&lt;/td>
&lt;td>生态建设、企业安全&lt;/td>
&lt;td>Phase 3-4重点&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>后缓&lt;/td>
&lt;td>高级特性、实验功能&lt;/td>
&lt;td>按需安排&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="风险与应对">风险与应对
&lt;/h2>&lt;h3 id="技术风险">技术风险
&lt;/h3>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>风险&lt;/th>
&lt;th>可能性&lt;/th>
&lt;th>影响&lt;/th>
&lt;th>应对措施&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>AI模型不稳定&lt;/td>
&lt;td>高&lt;/td>
&lt;td>高&lt;/td>
&lt;td>多模型冗余、降级策略&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>适配器接口变化&lt;/td>
&lt;td>中&lt;/td>
&lt;td>中&lt;/td>
&lt;td>版本隔离、接口适配层&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>性能瓶颈&lt;/td>
&lt;td>中&lt;/td>
&lt;td>中&lt;/td>
&lt;td>提前压测、缓存策略&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>安全漏洞&lt;/td>
&lt;td>低&lt;/td>
&lt;td>高&lt;/td>
&lt;td>安全审计、渗透测试&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="业务风险">业务风险
&lt;/h3>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>风险&lt;/th>
&lt;th>可能性&lt;/th>
&lt;th>影响&lt;/th>
&lt;th>应对措施&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>员工参与度低&lt;/td>
&lt;td>中&lt;/td>
&lt;td>中&lt;/td>
&lt;td>激励机制优化、引导运营&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>需求变更频繁&lt;/td>
&lt;td>高&lt;/td>
&lt;td>中&lt;/td>
&lt;td>敏捷开发、迭代交付&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>成本超支&lt;/td>
&lt;td>中&lt;/td>
&lt;td>高&lt;/td>
&lt;td>配额管理、成本监控&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>合规风险&lt;/td>
&lt;td>低&lt;/td>
&lt;td>高&lt;/td>
&lt;td>法务介入、定期审计&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="应对策略">应对策略
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>技术风险应对&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>建立模型抽象层，隔离底层变化&lt;/li>
&lt;li>实现降级策略，保证核心功能可用&lt;/li>
&lt;li>持续性能监控，及时发现瓶颈&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>业务风险应对&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>设计简洁的激励机制，降低参与门槛&lt;/li>
&lt;li>采用敏捷开发，快速响应需求&lt;/li>
&lt;li>建立成本预警机制&lt;/li>
&lt;li>提前介入合规审查&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="总结">总结
&lt;/h2>&lt;h3 id="核心设计思想">核心设计思想
&lt;/h3>&lt;blockquote>
&lt;p>&lt;strong>&amp;ldquo;数据是资产，必须持久化；Agent是工具，可以随时替换&amp;rdquo;&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 稳定核心 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 用户管理 · 权限控制 · 容器/项目管理 · 审计日志 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Layer 1 持久化 · PostgreSQL + 对象存储 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 灵活边缘 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ AI模型 · 工具能力 · 插件生态 · 工作流节点 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ Layer 2 索引 · Layer 3 Agent · Layer 4 模型 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ▼ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌────────────────────────────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 社区参与 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ 智能体分享 · 工作流模板 · 知识贡献 · 激励机制 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └────────────────────────────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="三个不怕-1">三个&amp;quot;不怕&amp;quot;
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 不怕换模型 不怕换Agent 不怕换向量数据库 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ───────── ───────── ────────────── │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 适配器模式 注册中心 索引重建服务 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 接口不变 热插拔 从Layer 1重建 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 配置在DB 配置在DB 原文在PostgreSQL │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 模型随便换 Agent随便换 向量随便换 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="开发路线图-1">开发路线图
&lt;/h3>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>阶段&lt;/th>
&lt;th>时间&lt;/th>
&lt;th>目标&lt;/th>
&lt;th>交付物&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Phase 1&lt;/td>
&lt;td>1-3月&lt;/td>
&lt;td>MVP核心框架&lt;/td>
&lt;td>用户系统、Agent对话、持久化&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Phase 2&lt;/td>
&lt;td>4-7月&lt;/td>
&lt;td>智能体支持&lt;/td>
&lt;td>工具、知识库RAG、工作流&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Phase 3&lt;/td>
&lt;td>8-11月&lt;/td>
&lt;td>生态建设&lt;/td>
&lt;td>市场、激励、协作&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Phase 4&lt;/td>
&lt;td>12-14月&lt;/td>
&lt;td>企业级安全&lt;/td>
&lt;td>SSO、审计、私有部署&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="架构优势">架构优势
&lt;/h3>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>优势&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>快速扩展&lt;/strong>&lt;/td>
&lt;td>新模型接入只需实现适配器，1-2天完成&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>灵活隔离&lt;/strong>&lt;/td>
&lt;td>容器/项目多级隔离，满足各种组织需求&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>员工激励&lt;/strong>&lt;/td>
&lt;td>贡献可见、积分排行、徽章荣誉&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>成本可控&lt;/strong>&lt;/td>
&lt;td>租户级配额和计费，避免资源浪费&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>持续演进&lt;/strong>&lt;/td>
&lt;td>插件市场、生态共建，平台不断丰富&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>数据安全&lt;/strong>&lt;/td>
&lt;td>Layer 1 永久保留，不因技术迭代丢失&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="关键成功因素">关键成功因素
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>核心理念要坚守&lt;/strong> - &amp;ldquo;数据是资产，Agent是工具&amp;quot;贯穿始终&lt;/li>
&lt;li>&lt;strong>接口设计要稳定&lt;/strong> - 核心接口设计好后尽量不变&lt;/li>
&lt;li>&lt;strong>激励机制要简单&lt;/strong> - 门槛低、反馈及时、荣誉可见&lt;/li>
&lt;li>&lt;strong>扩展机制要开放&lt;/strong> - 让员工和第三方都能贡献&lt;/li>
&lt;li>&lt;strong>迭代节奏要快&lt;/strong> - 小步快跑、快速验证、及时调整&lt;/li>
&lt;/ol>
&lt;hr>
&lt;p>&lt;em>&amp;ldquo;AI的世界变化很快，但好的架构设计可以让你的平台从容应对这些变化。数据是唯一不变的资产，Agent只是工具。&amp;rdquo;&lt;/em>&lt;/p>
&lt;p>&lt;em>本文档持续更新中，欢迎提出建议和讨论。&lt;/em>&lt;/p></description></item></channel></rss>