<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Production | 杨劲松 - Java后端 / AI应用开发工程师</title><link>https://1byteone.github.io/tags/production/</link><atom:link href="https://1byteone.github.io/tags/production/index.xml" rel="self" type="application/rss+xml"/><description>Production</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>zh-Hans</language><lastBuildDate>Fri, 21 Aug 2026 00:00:00 +0000</lastBuildDate><image><url>https://1byteone.github.io/media/icon_hu_1c0e9cb08cfb822a.png</url><title>Production</title><link>https://1byteone.github.io/tags/production/</link></image><item><title>生产级 RAG 架构：权限、版本与可观测性</title><link>https://1byteone.github.io/blog/rag-production-architecture/</link><pubDate>Fri, 21 Aug 2026 00:00:00 +0000</pubDate><guid>https://1byteone.github.io/blog/rag-production-architecture/</guid><description>&lt;p&gt;&lt;em&gt;上图：RAG — 生产级 RAG 架构。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;从 demo 到生产的差距主要在边界条件：谁能看到文档、索引如何更新、答案如何引用、上游不可用时怎么办。&lt;/p&gt;
&lt;h2 id="核心心智模型"&gt;核心心智模型&lt;/h2&gt;
&lt;p&gt;把系统分成 ingestion、indexing、query serving 和 evaluation 四个平面；在线请求只读当前 active index，更新在后台构建并原子切换。&lt;/p&gt;
&lt;h2 id="关键机制"&gt;关键机制&lt;/h2&gt;
&lt;p&gt;权限过滤必须在检索阶段执行；缓存键包含 tenant、权限摘要、query 规范化版本和 index version；删除文档要能传播到所有副本。&lt;/p&gt;
&lt;h2 id="python-示例"&gt;Python 示例&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;QueryContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tenant_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;allowed_collections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;index_version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cache_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;QueryContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;scopes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;,&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allowed_collections&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;rag:v2:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tenant_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_version&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;scopes&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="课程定位"&gt;课程定位&lt;/h2&gt;
&lt;p&gt;这篇文章把白板上的模块拆成可以落地的工程边界：先定义输入和输出，再决定状态、失败策略与可观测性。示例使用 Python，重点是设计原则而不是绑定某个供应商版本；上线前请以当前依赖的官方文档为准。&lt;/p&gt;
&lt;h2 id="工程实践"&gt;工程实践&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;将业务规则放在应用层，不要藏进难以测试的提示词或路由函数。&lt;/li&gt;
&lt;li&gt;为外部调用设置超时、重试上限和幂等键；重试不是错误处理的全部。&lt;/li&gt;
&lt;li&gt;记录 request id、耗时、输入版本、模型/索引版本和结果状态，避免记录敏感原文。&lt;/li&gt;
&lt;li&gt;用小规模固定数据集做回归测试，再用线上抽样监控质量与成本。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="常见错误"&gt;常见错误&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;只画 happy path，没有画超时、空结果、限流和回滚路径。&lt;/li&gt;
&lt;li&gt;让一个函数同时负责解析、调用外部服务、拼接提示词和持久化。&lt;/li&gt;
&lt;li&gt;用字符串约定代替类型契约，导致改动只能靠人工联调。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="生产检查清单"&gt;生产检查清单&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 输入、输出和错误响应均有明确 schema&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 外部依赖有 timeout、retry、rate limit 和 fallback&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 日志、指标、trace 能关联到同一次请求&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 关键路径有单元测试、集成测试和一组离线评测样本&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 密钥、用户内容和供应商响应按最小权限与隐私策略处理&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="练习建议"&gt;练习建议&lt;/h2&gt;
&lt;p&gt;先实现白板中的最小闭环，再故意注入一个超时、一个空结果和一个格式错误，观察系统能否给出稳定且可诊断的结果。最后补一条指标，证明你的优化确实改善了质量或延迟。&lt;/p&gt;
&lt;h2 id="动手练习"&gt;动手练习&lt;/h2&gt;
&lt;p&gt;设计 active/candidate 两套索引，模拟一次失败发布和一次文档删除，检查流量是否仍读到旧权限数据，并为每次回答保存 evidence ids。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;当白板上的每个箭头都能对应到一个输入、输出和失败策略时，AI 功能才从 demo 变成可维护的系统。&lt;/p&gt;</description></item><item><title>生产级 Spring Boot 架构：可观测的服务边界</title><link>https://1byteone.github.io/blog/spring-boot-production-architecture/</link><pubDate>Fri, 21 Aug 2026 00:00:00 +0000</pubDate><guid>https://1byteone.github.io/blog/spring-boot-production-architecture/</guid><description>&lt;p&gt;&lt;em&gt;上图：Production Spring Boot Architecture 白板图；重点不是罗列名词，而是把一次真实请求如何穿过系统、在哪些边界失败画清楚。&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="为什么要从场景理解这张图"&gt;为什么要从场景理解这张图&lt;/h2&gt;
&lt;p&gt;这张图围绕“A flash-sale service protects the database with cache, bounded writes, idempotency, and asynchronous inventory events.”展开。学习 Production Spring Boot Architecture 时，不能只记住组件名称：要能说明输入从哪里来、状态由谁持有、哪个组件承担失败、以及如何用指标证明系统仍然健康。白板中的箭头对应代码边界，红色感叹号对应需要显式处理的风险。&lt;/p&gt;
&lt;h2 id="逐层拆解"&gt;逐层拆解&lt;/h2&gt;
&lt;p&gt;主流程是：&lt;strong&gt;Gateway → Service → Cache / DB / MQ → Observability&lt;/strong&gt;。前半段是请求或数据的进入路径，后半段是运行时、存储或执行结果。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;边界契约&lt;/strong&gt;：先确定输入、输出和错误结构；不要让隐式类型、未校验参数或共享可变状态穿透多层。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;核心机制&lt;/strong&gt;：Nginx / Gateway → auth + rate limit；Service → idempotency + transaction。这些机制决定延迟、吞吐和可测试性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;资源与状态&lt;/strong&gt;：Redis → cache-aside with TTL；MySQL → source of truth。生产系统必须说明资源何时创建、何时释放，以及状态是否可恢复。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;失败路径&lt;/strong&gt;：RocketMQ → async side effects；必要时再结合 &lt;strong&gt;Metrics + Logs + Traces → feedback loop&lt;/strong&gt; 做降级、重试或回滚。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="一个可落地的最小实现"&gt;一个可落地的最小实现&lt;/h2&gt;
&lt;p&gt;下面的片段只展示边界，不代表完整业务。它的价值在于把“可以替换、可以测试、可以观测”的位置固定下来。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;request → idempotency → transaction → outbox event
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → Redis / MySQL / MQ → trace + metrics
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在真实项目中，应把外部依赖封装在 adapter 或 repository 中；业务层只依赖稳定接口。这样本地测试可以使用 fake，压测可以替换慢依赖，线上故障也更容易定位。&lt;/p&gt;
&lt;h2 id="场景中的工程决策"&gt;场景中的工程决策&lt;/h2&gt;
&lt;p&gt;以白板右侧的生产场景为例：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;先保护依赖&lt;/strong&gt;：连接池、线程池、并发信号量或缓存都要有上限，不能用无限队列掩盖下游过载。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;再保证正确性&lt;/strong&gt;：幂等键、事务边界、版本号、锁或 schema 校验至少要有一种明确机制，避免重试带来重复写入。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;最后优化性能&lt;/strong&gt;：先用 trace、慢查询、GC pause、队列长度、p99 延迟等数据定位，再选择索引、缓存、批处理或并发策略。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;让故障可恢复&lt;/strong&gt;：超时、重试、限流、熔断、回滚和告警必须能在演练中被验证，而不是只写在文档里。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="常见误区"&gt;常见误区&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;只画成功路径，没有画超时、空数据、拒绝、回滚或副本延迟。&lt;/li&gt;
&lt;li&gt;把框架默认行为当成业务契约，升级依赖后才发现边界改变。&lt;/li&gt;
&lt;li&gt;用“加机器”替代测量，忽略连接池、锁竞争、慢 SQL、对象分配或事件循环阻塞。&lt;/li&gt;
&lt;li&gt;将日志当作唯一观测手段，缺少指标、trace、采样和敏感数据脱敏。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="生产检查清单"&gt;生产检查清单&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 输入、输出和错误响应有明确 schema&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 外部调用设置 timeout、retry 上限、rate limit 和 fallback&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 资源池有容量、排队和拒绝指标&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 关键状态有幂等、事务或恢复策略&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 日志、metrics、trace 可关联同一个 request id&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 用接近生产的数据做回归、压测和故障演练&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;真正掌握这张白板图，不是能背出每个框的定义，而是能从一次具体请求出发，解释每个箭头的输入输出、每个风险的处置方式，以及上线后用什么信号判断系统需要改进。&lt;/p&gt;</description></item></channel></rss>