SRS 代码阅读工作流详解:基于 learn-code.md 的零修改溯源方法论
2026/9/10 2:19:57 网站建设 项目流程

SRS 代码阅读工作流详解:基于 learn-code.md 的零修改溯源方法论

【免费下载链接】srsSRS is a simple, high-performance, AI-driven real-time media server supporting RTMP, WebRTC, HLS, HTTP-FLV, HTTP-TS, SRT, MPEG-DASH, and GB28181, with codec support for H.264, H.265, AV1, VP9, AAC, Opus, and G.711.项目地址: https://gitcode.com/GitHub_Trending/sr/srs

SRS 仓库的skills/srs-develop技能集定义了六类开发任务,其中Learn Code(学习代码)是专门用于“只读理解现有 SRS 或 Oryx 实现”的工作流:在不修改任何项目文件的前提下,回答关于实现原理、架构设计、控制流、数据流和模块边界的问题。本文基于 Learn Code 工作流文档,结合 srs-develop 主技能 的任务路由、代码地图路由 与 文档路由 的实际结构,完整拆解这套四步工作流的路由规则、可信范围约束与答案规范,并以 Go 代理服务的真实源码(cmd/proxy/main.go、internal/bootstrap/proxy.go、internal/lb/lb.go)作为贯穿示例,展示如何落地执行“先文档、再代码、后对账”的阅读路径。

一、工作流定位:前置条件与适用范围

Learn Code 文档 开篇即给出两条强约束:

  • 前置条件(Prerequisite):只有当 srs-develop 主技能 中的Task Router(任务路由器)选中 Learn Code 之后才能执行该工作流,不允许直接触发。
  • 适用范围(Scope):解释现有 SRS 或 Oryx 代码如何工作,不修改任何一侧项目。回答必须覆盖实现、架构、控制流、数据流、模块边界和行为,且一切结论都要立足当前代码与项目文档。

1.1 Task Router:为什么不能直接执行

skills/srs-develop/SKILL.md 的 Task Router 章节明确要求:⚠️ 必须首先执行路由步骤,绝不能跳过,也不能直接跳入某个任务;每个请求必须被路由到且仅一个任务类型。六类任务分别为:

任务类型适用场景工作流文档
Develop Code任何计划中的 SRS、Oryx、Dev Docker、文档或技能变更develop-code.md
Scan Issues只读扫描近期活跃且可能需要关注的开放 issuescan-issues.md
Scan PRs只读评估指定 PR(或最近更新的 PR)scan-prs.md
Fix a Bugissue 报告了损坏、异常或不安全行为,可能需要调查或修复fix-a-bug.md
Learn Code用户希望在不改动项目的前提下理解现有实现、架构、控制流或行为learn-code.md
Review a PR变更已存在于本地的维护者集成流程review-a-pr.md

Task Router 对 Learn Code 的路由描述是:“当用户希望在不进行项目变更的情况下,获得对现有 SRS 或 Oryx 实现、架构、控制流或行为的解释时使用。路由到最小相关的文档与代码地图,对账后以聚焦的源码引用作答。” 此外还有两条配套规则:

  • 若路由到的任务尚不支持,必须停止并告知用户任务类型、暂不支持、未来会加入支持——而不是勉强执行;
  • 每个任务在执行前必须先识别产品是SRS 还是 Oryx;若产品不明且该选择会改变仓库、issue 跟踪器、代码地图或验证方式,应先向用户澄清,不得把 SRS 与 Oryx 的工作混为一谈。

这一设计解释了 Learn Code 的第一句话:“Do not execute it directly”——工作流的输入不是裸问题,而是已经过产品判别和任务分类的请求

1.2 核心原则:代码与文档是唯一真相

skills/srs-develop/SKILL.md 的 Core Principle 章节是整个工作流的哲学基础:

Code and documents are the only truth.Issue 描述可能不准确,Pull Request 可能有误导性,功能描述可能不充分。始终基于实际源码和项目文档来建立理解。文档承载了设计意图、架构动机和代码本身无法表达的复杂背景——它们是代码的另一种形式。当代码与文档冲突时,去调查,而不是假设其中一方是错的。

这条原则直接决定了 Learn Code 第三步“对账(reconcile)”的存在意义:文档与代码不一致不是选边站,而是要作为“冲突”去调查。

二、Step 1:先路由并阅读文档

Learn Code 第一步要求:先加载 internal-docs-for-srs/SKILL.md 并使用它的 Reference Router(引用路由器),在阅读任何项目文档之前完成路由。具体有三条子规则:

  1. 先按产品分类,再按服务器代际、服务、协议或功能细分;选择并阅读最小相关文档集,覆盖设计意图、架构和已记录的行为;
  2. 若文档路由器没有匹配的路由,或路由解析出的文件不可用,记录文档缺口(documentation gap)并继续进入代码路由,而不是大范围搜索文档目录、更不是编造设计意图。

2.1 文档路由器(Reference Router)的实际结构

skills/internal-docs-for-srs/SKILL.md 的 Reference Router 是一份“主题 → 可信文档”的映射表,按五个分区组织,每个条目都带有一句话描述,供选择“最小相关文档集”:

  • C++ 媒体服务器发布记录trunk/doc/CHANGELOG.md—— 所有 SRS 版本的完整变更日志,每个已合并 PR 对应一条记录和一个版本提升;
  • C++ 媒体服务器用户文档:共 28 篇,如references/cpp-docs/doc/introduction.md(概述、支持协议、State Threads 架构、学习路径)、getting-started.md(Docker 快速开始、各协议 URL 模式)、rtmp.mdhls.mdwebrtc.md(WHIP/WHEP、SFU 架构、RTMP 转 RTC)、srt.mdlow-latency.md(延迟调优)、performance.md(perf、Valgrind、ASAN 与基准测试方法论)、origin-cluster.md(代理式负载均衡与 Go 代理架构)等;
  • C++ 媒体服务器官网页面:FAQ、License、产品里程碑、安全公告等 4 篇;
  • Oryx 文档:Oryx 概览与部署、FAQ、oryx/README.mdoryx/DEVELOPER.md,以及一批按日期命名的场景博客(部署、HTTPS、认证、录制、转码、AI 字幕、翻译、OCR 等)。文档还给出优先级规则:Oryx 问题优先使用 getting-started 指南、FAQ 和仓库文档,带日期的博客视为场景化指导;当命令、UI 标签或行为不一致时,优先选择与用户 Oryx 版本匹配的文档;
  • RTMP Go API 示例internal/rtmp/example_test.go—— AMF0、握手与协议流程的 RTMP API 示例;
  • WHEP 性能分析references/perf/proxy-whep.md—— 用 pprof 和 srs-bench 剖析 WHEP 的 CPU、分配、堆、goroutine 与 trace 数据;
  • 下一代 Go 代理文档:6 篇,包括references/proxy/features.md(功能状态与限制)、proxy-design.md(无状态代理设计、内置负载均衡、Redis 模式、水平扩展)、proxy-protocol.md(后端注册、调试后端、心跳协议与环境变量)、proxy-usage.md(构建、启动、注册、推流验证)、proxy-load-balancer.md(内存/Redis 负载均衡器行为)、proxy-origin-cluster.md(生产多源站集群)。

路由器同时附带核心规则:只加载与任务相关的文档,不要全部加载;只有被该技能或所选引用列出的项目文件才视为可信文档;没有路由覆盖的任务要如实报告“文档路由器未覆盖”,而不是扫描或大范围 grep 文档目录。

以“Go 代理的启动流程”为例,按 Step 1 的规则应选中references/proxy/proxy-design.mdproxy-protocol.md两篇文档(架构 + 协议注册),而非 6 篇全读——这就是“最小相关文档集”的含义。

三、Step 2:路由到负责的代码

Learn Code 第二步同样要求先路由、后读码,共有四条子规则:

  1. 加载 internal-codemap-for-srs/SKILL.md,用其 Reference Router 选择相关的 SRS 或 Oryx 代码地图;若选错产品或服务器代际会实质性改变答案,必须向用户澄清
  2. 用所选地图的描述定位负责模块与最小相关文件集;当地图列出的是目录而非文件时,先只列出该目录内的文件名,再挑选文件;
  3. 只读取或搜索所选文件;仅当证据显示实现跨越了第一个模块边界时,才追加路由下一个模块;
  4. 对 Oryx:保持当前工作目录不变,通过项目根相对的oryx/路径查看(它可能是目录,也可能是指向用户首选 checkout 的符号链接);若不可用,请用户在该位置提供 checkout,不要搜索其他 checkout

3.1 代码地图路由器(Reference Router)的实际结构

skills/internal-codemap-for-srs/SKILL.md 的 Reference Router 将代码域映射到六份引用地图:

代码域使用时机加载的地图
C++ 媒体服务器第一代 origin/edge 服务器、trunk/src/trunk/conf/、协议、媒体处理、State Threadscpp-server.md
下一代 Go 服务器Go 代理、未来的 Go origin/edge 服务、cmd/internal/go-server.md
浏览器推流端与播放器WHIP、WHEP、HTTP-FLV、HLS 的浏览器推流/播放,含trunk/research/players/browser-clients.md
SRS Docker 构建镜像ossrs/dev-docker、依赖与缓存镜像、打包的 FFmpeg 等构建工具dev-docker.md
测试与验证需要选择或运行 C++ 单元测试、黑盒测试、E2E、复现或基准验证testing.md
Oryx 一体化视频方案ossrs/oryxoryx/、Go 平台、React 仪表盘、SRS/Redis 运行时集成、安装与发布oryx.md

跨代际比较或迁移任务需同时加载两份服务器地图;只有需要 SRS 验证时才追加测试引用;跨越独立 SRS 与 Oryx 的任务则加载 Oryx 地图加最小负责的 SRS 地图。

3.2 可信导航范围与禁止行为

代码地图技能的核心规则中,对“如何读码”给出了强约束,这些约束是 Learn Code 第二步的执行细则:

  • 以当前工作目录为项目根,不搜索父目录、不发现其他仓库根
  • 外部仓库仅有两个例外:dev-docker/oryx/路径(均通过git -C访问、保持当前工作目录不变、不解析符号链接、不搜索备用 checkout);
  • 只有被所选引用列出的文件和模块目录才是可信导航范围
  • 禁止 grep 仓库根或trunk/src/cmd/internal/oryx/platform/oryx/ui/这类宽泛目录树——这保证了“从地图进文件”,而非“从海量搜索碰文件”;
  • 模块目录只列文件名再挑选,读码只发生在被选文件上;
  • 没有路由覆盖时如实报告,不做临时发明路由;
  • 报告“路由文件缺失”之前,先直接检查其完全解析后的路径。

3.3 用两份地图看实际模块划分

Go 服务器地图(go-server.md)描述了cmd/+internal/的完整模块结构。可以据此快速回答“某个行为归谁负责”:

  • cmd/proxy—— 无状态反向代理,位于一个或多个 SRS C++ origin 之前;接受 RTMP、HTTP-FLV/HLS、WebRTC WHIP/WHEP、SRT 客户端连接,通过负载均衡器解析后端 origin 后透明转发流量;不缓存流、不处理媒体——只转发字节;全部通过环境变量(或.env文件)配置,无配置文件;入口为 cmd/proxy/main.go;
  • internal/bootstrap—— 启动与生命周期编排:日志上下文、信号处理、环境加载、强制退出定时器、可选 pprof、负载均衡器初始化(按PROXY_LOAD_BALANCER_TYPE选内存或 Redis),随后顺序启动六个服务器(RTMP、WebRTC、HTTP API、SRT、System API、HTTP Stream),阻塞直到 context 取消,每个服务器通过defer Close()优雅关闭;
  • internal/proxy—— 五个代理服务器实现:RTMP(rtmp.go,解析 connect/publish/play 提取流 URL,双向复制 RTMP 消息)、HTTP 流(http.go,静态文件 + HTTP-FLV/TS 反代 + HLS m3u8 的spbhid重写)、WebRTC(rtc.go,两阶段:WHIP/WHEP 信令 SDP 改写 + 基于 STUN ufrag 的 UDP 媒体转发,有状态)、SRT(srt.go,本地拦截 SRT 四步握手、解析 stream ID、与后端重放握手,有状态)、HTTP API + System API(api.go,System API 提供/api/v1/srs/register供后端 SRS C++ 服务器注册);
  • internal/rtmp—— RTMP 协议实现(解析而非代理):完整 chunk 流与消息协议、四种格式类型、扩展时间戳、消息重组,以及完整 AMF0 编解码器;
  • internal/lb—— 负载均衡抽象与两种实现:内存 LB(mem.gosync.Map、按流 URL 粘性随机挑选、单代理部署)与 Redis LB(redis.go,TTL 过期、多代理水平扩展);
  • 其余基础设施模块:internal/env(环境变量配置,默认端口 RTMP=11935、HTTP API=11985、HTTP Stream=18080、WebRTC=18000、SRT=20080、System API=12025)、internal/logger(slog JSON 日志,每条连接带 7 位十六进制上下文 ID)、internal/errors(带堆栈的错误包装)、internal/sync(泛型 sync.Map)、internal/signal(SIGINT/SIGTERM 与 30 秒强制退出兜底)、internal/debug(pprof)、internal/utils(URL/协议/网络辅助函数)等。

C++ 服务器地图(cpp-server.md)则把trunk/src/分为四层,并给出文件命名约定srs_{模块}_{主题}.cpp/.hpp

  • main/main_servermain()入口;
  • core/:基础定义——核心宏与配置、按主版本划分的版本定义(core_versioncore_version8)、SrsUniquePtr智能指针、性能调优常量、平台抽象、时间类型;
  • kernel/:无网络、无协议逻辑的底层构件——编解码/容器(FLV、MP4、TS、PS、H.264/H.265/AAC 解析)、缓冲与 I/O(SrsBufferSrsSimpleStream、文件读写)、RTC 原语(RTP/RTCP 编解码、重排队列)、工具(错误码、日志、常量、kernel_hourglass定时器协程、kernel_balance轮询负载均衡);
  • protocol/:线上格式——RTMP chunk 流与 AMF 命令、HTTP 栈(含来自 Node.js 的 llhttp)、WebRTC 原语(STUN、SDP、RTP 打包)、SRT socket 封装、RTSP、裸 H.264/H.265 流(Annex-B ↔ AVCC 转换)、JSON 与 Protobuf 辅助;
  • app/:应用逻辑——app_server主服务器、app_config配置解析、RTMP 连接与源(app_rtmp_connapp_rtmp_source管理消费者、GOP 缓存与 hub)、HTTP API/回调/静态/流、WebRTC 全套(服务器、连接、源、WHIP/WHEP API、DTLS、音频转码)、SRT、RTSP、GB28181、HLS/DASH 复用器、DVR 录制、Edge/Forward/Bridge、Ingest/Transcode/FFmpeg 进程管理、安全规则、统计、心跳、熔断器等。

该地图还特别说明了两条容易误判的依赖路径:C++ 服务器通过两条独立路径使用 FFmpeg——app_rtc_codec进程内调用libavcodec/libswresample/libavutil做 AAC/MP3/Opus 音频转换(编译期依赖裁剪版trunk/3rdparty/ffmpeg-4-fit/,需SRS_FFMPEG_FIT),以及app_ingest/app_encoder通过app_ffmpeg拼装 CLI 参数并经app_processfork/exec 外部 FFmpeg 可执行文件;两条路径不可混为一谈。这类“边界澄清”正是代码地图存在的价值:Learn Code 第二步“定位负责模块”能否准确,直接取决于地图对边界的刻画。

四、Step 3:追踪并对账实现

第三步是 Learn Code 的“引擎”,包含四条子规则,每条都对应一个具体的阅读动作:

  1. 追踪最窄有用路径:从功能入口点(配置、API、监听器、协议处理器或公开接口)出发,穿过负责模块与必需的底层依赖;
  2. 分离通用路径与协议/服务特有行为:识别相关的默认值、平台相关行为、回退与限制;
  3. 文档对账代码:对实质性冲突要去调查,而不是静默地偏向任一方;明确区分“已确认行为、合理推断、未知”;
  4. 按需验证:仅在用户要求运行时验证、或静态证据对重要结论不足时,才使用测试与验证地图(testing.md);Learn Code 过程中不得修改代码或测试

下面以“Go 代理的启动流程”为例,演示 Step 1 → Step 3 的完整落地。

4.1 追踪:从入口到六个服务器

按 go-server 地图,入口点是 cmd/proxy/main.go。其main()只有三行实质逻辑:

bs := bootstrap.NewProxyBootstrap() if err := bs.Start(context.Background()); err != nil { // Error already logged in bootstrap.Start(). os.Exit(-1) }

入口只做了“构造 bootstrap 并 Start”,所有编排都在 internal/bootstrap/proxy.go 中。Start()(L144-L161)先给 context 注入日志上下文,打印SRSX-Proxy/版本 started日志,然后安装信号处理器,最后调用run()并忽略用户取消导致的 error(ctx.Err() == context.Canceled时不记错误日志)。

run()(L165-L196)按顺序完成五件事:

  1. b.newEnvironment(ctx)创建环境(读取进程环境变量与.env文件);
  2. InstallForceQuit安装强制退出定时器——注释解释了动机:“正常情况下主线程在 context 取消后退出;但有时主线程可能被阻塞,因此需要强制退出兜底以确保程序终止”;
  3. debug.HandleGoPprof可选启动 pprof(由GO_PPROF环境变量控制,见 internal/debug/pprof.go);
  4. initializeLoadBalancer(L199-L213)按environment.LoadBalancerType()分支:值为"redis"时构造 Redis LB,其余任何值都回退到内存 LB——这是地图中“single-proxy(内存)/multi-proxy(Redis)”两种部署模式的代码对应点;
  5. startServers解析GraceQuitTimeout()后顺序启动服务器。

startServers()(L216-L263)按固定顺序启动六个服务器,每个都先Run(ctx)defer Close():RTMP → WebRTC → HTTP API(传入 webRTCProxyServer 引用)→ SRT → System API → HTTP Stream,最后<-ctx.Done()阻塞等待取消。这与 go-server 地图对internal/bootstrap的描述逐句吻合——地图文档与源码对账一致,可作为“已确认行为”写入答案。

值得注意的是proxyBootstrap结构体(L72-L123):每个组件都是函数型构造字段newEnvironmentnewRedisLoadBalancernewRTMPProxyServer……),默认值指向真实实现,测试可通过函数式选项注入 fake(如proxyfakes.FakeRTMPProxyServer)而不绑定真实端口。从源码结构看,这一设计让 internal/bootstrap/proxy_test.go 能在不启动任何网络监听的情况下验证编排逻辑本身——这正是“静态证据 + 测试证据”双重支撑的典型形态。

4.2 分离:负载均衡的通用接口与两种实现

Step 3 第二条“分离通用路径与特有行为”在 internal/lb/lb.go 中体现得很清楚。该文件定义了四个接口与一个核心结构体:

  • OriginServer(L38-L61):后端 origin 的注册信息——IP、用户配置的DeviceID、持久化的ServerID(存于文件、重启不变)、每次重启都变化的ServiceIDPID,以及 RTMP/HTTP/API/SRT/RTC 五类监听端点和最后更新时间。ID()ServerID-ServiceID-PID拼出,天然区分同一台机器的不同进程;
  • OriginService(L128-L133):Update(记录注册或心跳)与Pick(按流 URL 挑选后端);
  • HLSService(L136-L141):按流 URL 与SPBHID(SRS Proxy Backend HLS ID)索引 HLS 会话状态,对应 HTTP 代理中 m3u8 的spbhid重写机制;
  • RTCService(L144-L149):按流 URL 存储、按 ICE ufrag 查找 WebRTC 连接;
  • OriginLoadBalancer(L152-L158):组合上述三组能力加Initialize

文件头部的两个常量同样值得注意:HLSAliveDurationRTCAliveDuration均为 120 秒(“在该时长内有更新即视为存活”),而parseOriginServerTTLPROXY_ORIGIN_SERVER_TTL解析为源站存活 TTL、未设置时默认 300 秒且必须为正数。这类“默认值与限制”正是 Step 3 第二条要求显式识别的要素。

内存实现与 Redis 实现分别位于 internal/lb/mem.go 与 internal/lb/redis.go(均有对应单测 mem_test.go、redis_test.go),前者用sync.Map做按流 URL 的粘性随机挑选(单代理),后者用带 TTL 的 Redis 键实现多代理共享状态(水平扩展)——地图文档中“single-proxy / multi-proxy”两种部署模式的静态证据链到此闭合。

4.3 对账:区分确认、推断与未知

Step 3 第三条要求答案中明确区分三类陈述。对照上例:

  • 已确认行为:启动顺序、defer Close()优雅关闭、"redis"分支与内存回退——均有 internal/bootstrap/proxy.go 源码直接支撑;
  • 合理推断:例如“六个服务器顺序启动而非并发启动”——源码确实如此,但若结论需要外推到“并发启动会怎样”,则超出证据边界,应标注为推断;
  • 未知/冲突:若地图文档与源码不一致(比如文档说“默认 TTL 300 秒”而代码写的是别的),Learn Code 要求“调查而非偏向任一方”,并把该冲突作为答案的一部分报告出来。

4.4 按需验证:测试与验证地图

第四步的验证只“按需”触发,而验证手段由 skills/internal-codemap-for-srs/references/testing.md 定义。该地图把验证分为五类,并给出“是否需要运行服务器 / 是否走网络 / 是否有 pass/fail”的判别矩阵:

类型服务器是否运行测试网络Pass/fail
单元测试隔离的内部逻辑
黑盒测试是,自管理全服务器行为
E2E是,外部管理协议工作流
跨组件集成脚本自管理代理、源站、边缘、路由与协议互操作
基准测试是,外部管理性能与容量否,仅指标

对应的真实测试资产包括:trunk/src/utest/ 下的 C++ 单元测试(构建运行方式为cd trunk && ./configure --utest && make utest && ./objs/srs_utest,含 AI 编写的srs_utest_ai01ai24、手工编写的srs_utest_manual_*与工作流测试srs_utest_workflow_*);trunk/3rdparty/srs-bench/blackbox/ 下的黑盒测试(每个测试用NewSRSServer()自管理 SRS 进程,用 FFmpeg/FFprobe 推流播放并校验输出,覆盖 RTMP、HLS、SRT、RTSP、HEVC、DVR、HTTP API、MP3);trunk/3rdparty/srs-bench/srs/ 下针对外部启动 SRS 的 E2E 协议测试(真实 Pion WebRTC、RTMP 与 HTTP API 客户端);以及 trunk/3rdparty/srs-bench/ 本身的性能基准(模拟并发 WHIP、WHEP、RTMP、重连、DVR、明文 RTC、Janus 负载,只报指标、无 pass/fail 断言)。Go 侧则以各模块的*_test.go(如 internal/bootstrap/proxy_test.go、internal/lb/lb_test.go、internal/rtmp/rtmp_test.go)和 counterfeiter 生成的 fake(internal/bootstrap/proxy_test.go注入的proxyfakeslbfakes)作为静态与单元测试证据。

测试地图还特别强调:skills/srs-develop/scripts/ 下的proxy-*脚本是跨组件集成验证,其命名标识的是入口拓扑而非“仅限代理变更”——这一点与 skills/srs-develop/SKILL.md 的 Cross-Component Verification 章节呼应:对 Go 代理或 C++ 媒体服务器的任何独立运行时变更,都要在模块级验证之外运行 integration-tests.md 定义的完整套件。不过按 Learn Code 规则,这些验证只在“用户要求运行时验证或静态证据不足”时才被触发,且阅读过程中绝不修改代码或测试

五、Step 4:给出答案的五条规范

Learn Code 第四步规定了答案的输出形态,逐条对应如下:

  1. 先直接回答用户问题,再描述调查过程——结论前置;
  2. 声明被检查的产品与组件;当行为可能随版本变化时,声明所属仓库的当前分支与 commit——把“答案适用边界”写进答案;
  3. 引用负责文件并给出聚焦的行号范围,解释各文件职责如何衔接;不得返回无结构的文件堆砌(file dump)——前文 internal/bootstrap/proxy.go 的run()分析就是这一规范的示例形态:文件路径 + 行号范围 + 职责衔接说明;
  4. 报告相关的文档缺口、代码/文档冲突、限制与未解决问题——Step 1 记录的 documentation gap、Step 3 发现的冲突,都在这一步浮出水面;
  5. 不做任何项目变更。若调查发现疑似 bug 或期望的变更,报告它,由用户另行发起 Fix a Bug 或 Develop Code 任务——这保证了六类任务互不越界,Learn Code 的只读属性在流程终点再次被锁定。

六、路径解析约定:路由文件“从哪里找”

四步工作流中反复出现“加载skills/...的某个 SKILL.md 或 references 文件”,这些路径如何解析由 skills/srs-develop/SKILL.md 的 Path Resolution 章节统一规定:

  • 以当前工作目录为项目根,不搜索父目录、不发现其他仓库根;
  • Oryx 一律通过项目根相对的oryx/路径(git -C)访问,dev-docker同理;两者均可能是目录或指向用户首选 checkout 的符号链接,不可用时请求用户提供,不自动创建、不解析符号链接、不搜索备用 checkout;
  • references/scripts/assets/agents/开头的捆绑路径相对于所在 SKILL.md 的目录解析,而非当前工作目录;而trunk/internal/cmd/skills/这类仓库路径则相对于当前工作目录解析;
  • 使用当前被调用的技能目录,不在.agents/.kiro/.claude/等工具专属目录下搜索备用副本;
  • 报告路由文件缺失之前,先直接检查其完全解析后的路径。

这套规则让 Learn Code 的两步路由(文档路由、代码路由)在多工具、多 checkout 环境下保持确定性和可重复性。

七、工作流全景与执行清单

将 learn-code.md 的四步与支撑技能汇总,一次 Learn Code 任务的标准执行路径是:

用户问题 │ ▼ Task Router(skills/srs-develop/SKILL.md) ├─ 判定产品:SRS 还是 Oryx?代际是否影响答案?必要时澄清 └─ 判定任务类型:Learn Code │ ▼ Step 1 文档路由(skills/internal-docs-for-srs/SKILL.md) ├─ 按产品 → 代际 → 服务/协议/功能 分类 ├─ 选择最小相关文档集(28 篇 C++ 文档 / Oryx 文档 / 6 篇 Go 代理文档 / 示例与性能文档) └─ 无路由 → 记录文档缺口,继续 │ ▼ Step 2 代码路由(skills/internal-codemap-for-srs/SKILL.md) ├─ 选择地图:cpp-server / go-server / browser-clients / dev-docker / testing / oryx ├─ 目录级模块:先列文件名,再挑最小文件集 ├─ 只读所选文件;证据显示跨模块边界时才追加 └─ Oryx 走 oryx/ 路径,不解析符号链接、不搜索备用 checkout │ ▼ Step 3 追踪与对账 ├─ 从入口(配置/API/监听器/协议处理器)追踪最窄路径 ├─ 分离通用路径与协议特有行为;识别默认值、平台差异、回退、限制 ├─ 文档 vs 代码 冲突 → 调查并区分 确认 / 推断 / 未知 └─ 仅在需要时调用测试地图(五类验证),不改代码 │ ▼ Step 4 回答 ├─ 先结论后过程;声明产品/组件/分支/commit ├─ 文件 + 聚焦行号 + 职责衔接;不做文件堆砌 ├─ 报告文档缺口、冲突、限制、未解问题 └─ 零变更;疑似 bug 移交 Fix a Bug / Develop Code

八、小结:这套方法论解决了什么

Learn Code 工作流的本质,是把“读一个大型媒体服务器代码库”这一模糊任务,转化为一条有路由、有边界、有对账、有输出规范的确定性流水线:

  • 路由优先:文档先于代码、地图先于文件。两份路由器(文档 28+ 篇可信文档、代码 6 张模块地图)把“可信范围”显式化,禁止 grep 仓库根,保证阅读成本与问题规模成比例;
  • 最小文件集:从目录到文件逐级收敛,只有证据显示实现跨越模块边界时才扩圈——这与internal/lb只含OriginLoadBalancer接口与两个实现、跨模块协作全部通过接口(HLSServiceRTCService)暴露的架构风格天然契合;
  • 对账而非选边:文档承载设计意图、代码承载实际行为,冲突是调查对象而不是噪音,答案中强制区分“确认 / 推断 / 未知”三级证据;
  • 只读契约:从前置条件到 Step 3 的“不改代码或测试”,再到 Step 4 的“疑似问题移交其他任务”,Learn Code 的零修改属性在流程首、中、尾三次被锁定,使其可以安全地用于任何“想懂 SRS/Oryx 某个行为”而不愿承担改动风险的场景。

对于想理解 SRS 某段代码“为什么这样写”的读者,最直接的实践方式就是按本文路径走一遍:先读 skills/srs-develop/SKILL.md 完成产品与任务判定,再用 skills/internal-docs-for-srs/SKILL.md 和 skills/internal-codemap-for-srs/SKILL.md 的两张路由器锁定最小文档集与最小文件集,最后按 Step 3/4 的规范完成追踪、对账与作答。

【免费下载链接】srsSRS is a simple, high-performance, AI-driven real-time media server supporting RTMP, WebRTC, HLS, HTTP-FLV, HTTP-TS, SRT, MPEG-DASH, and GB28181, with codec support for H.264, H.265, AV1, VP9, AAC, Opus, and G.711.项目地址: https://gitcode.com/GitHub_Trending/sr/srs

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询