ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Pipecat /provider-research 技能:用子 Agent 编排批量供应商能力调研的全流程解析

Pipecat /provider-research 技能:用子 Agent 编排批量供应商能力调研的全流程解析 Pipecat /provider-research 技能用子 Agent 编排批量供应商能力调研的全流程解析【免费下载链接】pipecatOpen Source framework for voice agents, multimodal apps, and realtime AI. Maintained by Daily and the community.项目地址: https://gitcode.com/GitHub_Trending/pi/pipecatPipecat 仓库内置了一个名为/provider-research的 Claude Code 技能用于对 Pipecat 每个服务所依赖的供应商LLM、STT、TTS、Realtime 等做一次系统性的能力对账逐个服务单元调研供应商的新模型与新 API 参数为每个单元产出一份带日期的报告并对改动明确的情况直接留下一个已提交的本地分支。读完全文你将掌握这套编排技能的四步工作流、参数语义、子 Agent 载荷结构、只产本地产物、绝不发布的护栏设计以及配套的inventory.py/probe.py/digest.py/publish.py工具链各自承担的角色。技能定位本地调研编排器不是发布器该技能定义在 SKILL.md 中frontmatter 有几个值得注意的字段name: provider-research技能名即命令/provider-researchdisable-model-invocation: true禁止模型自行隐式调用只能由人显式触发因为一次 sweep 会派生数十个 researcher 子 Agent且可能产出 PRargument-hint给出了参数签名[--only a,b] [--date YYYY-MM-DD] [--limit N] [--concurrency N]。SKILL.md 的第一段就划定了职责边界Everything stays local — this skill publishes nothing.推送报告、在 pipecat 上开 draft PR、提交 digest issue全部是 scripts/provider-watch/publish.py 的职责由调用该技能的人在调研结束后运行技能本身只负责把对应的命令打印出来。而实际的调研工作由provider-watch-researcher子 Agent 完成其行为由同目录的 RESEARCH_GUIDE.md 定义——编排器本技能与调研者子 Agent之间通过一份 JSON 载荷解耦。配套的 Codex 侧元数据见 openai.yaml其中allow_implicit_invocation: false与disable-model-invocation互为镜像注释明确解释了原因A sweep spawns dozens of researcher agents and can open PRs, so it runs only when someone invokes it explicitly.参数详解与典型用法技能的参数签名与语义在 SKILL.md 的 Arguments 一节中完整给出/provider-research [--only a,b] [--date YYYY-MM-DD] [--limit N] [--concurrency N]参数语义默认值--only a,b限定供应商名或单元 id如openai、deepgram/stt全部单元--date YYYY-MM-DD本次运行的日期相同日期、互不重叠的--only切片可以合并为一次完整 sweep今天--limit N只调研选中的前 N 个单元确定性顺序用于测试不限--concurrency N每批并发 researcher 数6线性测试用 1文档给出的两个示例/provider-research --only deepgram,groq --limit 2 --concurrency 1—— 冒烟测试/provider-research --only groq—— 验证分支产出路径用报告里打印的命令审阅分支。--date的切片合并语义是这套流程的一个重要设计不同时间、不同--only切片的多轮运行只要日期相同最终都会汇成同一天的完整调研结果且后文的publish.py也是幂等地按日期从磁盘收齐所有产物因此多次运行可以自然叠加。步骤一解析路径与前置条件SKILL.md 的 Step 1 规定了五个前置动作每一步都有明确的失败语义解析参数记录RUN_DATE--date或今天YYYY-MM-DD格式与PIPECAT_COMMITgit rev-parse --short HEAD。这两个值会写入每份报告的 frontmatter成为这份报告对应哪个 Pipecat 快照的坐标。选择仓库外的临时目录会话 scratchpad或mktemp -d -t provider-research。所有易失产物——载荷、run.jsonl、worktree——都放在这里保证主 checkout 不被污染。准备报告 checkout./_reports仓库内已 gitignore。不存在则gh repo clone pipecat-ai/provider-watch-reports _reportsclone 失败则git init _reports无历史继续。已存在且有 remote 则git -C _reports pull --ff-only保证本次运行读到的是当前记忆。校验清单工具若uv run python scripts/provider-watch/inventory.py --md失败则带着清晰的错误信息停止。收集团队决策decision intake团队把决策记录为 digest issue 的评论researcher 会将其并入各单元的decisions.md。SKILL.md 给出了一段现成命令用gh issue list取最近 3 个标题含 Provider watch 的 issue再用gh issue view把标题、URL 和评论渲染到scratch/digest-comments.md。若gh或仓库不可用则写入空文件。每个 researcher 拿到的是同一份文件各自筛选与自己单元相关的评论。步骤二用 inventory.py 构建单元清单uv run python scripts/provider-watch/inventory.py --json [--only ...] [--limit N] scratch/units.jsonSKILL.md 强调Do not hand-edit or re-derive this; the researcher gets the entry verbatim.每个条目是一个调研单元id 形如cartesia/tts携带其服务类、默认模型、Settings 字段、thin-wrapper 标记以及指向 CLI 注册表、环境变量、示例 bot 和文档 URL 的指针。清单如何生成可以看 inventory.py 的源码。它是纯 AST 扫描The scan is pureastoversrc/pipecat/servicesso it runs beforeuv syncand in offline tests遍历src/pipecat/services下每个 Python 文件用正则(Service|Search|Processor)(MLX|REST)?$识别具体服务类排除Base...抽象基类在__init__中查找self.Settings(model...)调用解析出每个类的default_model支持引用模块级字符串常量如DEFAULT_MODEL ...按路径末段llm/stt/tts/realtime子包等把类归入provider/type单元openai/responses/llm这类子包路径会合并成openai/responses-llm这样的单元 idTHIN_WRAPPER_BASESOpenAILLMService、BaseWhisperSTTService、GoogleLLMService等用于标记只继承实现、改端点和默认模型的薄封装服务这类单元调研范围会被收窄见下文研究步骤后续的enrich()把 CLI 注册表pipecat.cli.registry.service_metadata.ServiceRegistry、env.example中的环境变量、scripts/release-evals/manifest.yaml的示例 bot、README 中 docs.pipecat.ai 的服务文档链接 join 到每个单元上。--only的过滤逻辑在select()中匹配单元 id 精确相等、id 前缀 /、或 provider 名再按--limit截取——这解释了为什么--only deepgram和--only deepgram/stt是两种不同粒度的切片。步骤三分批派发 researcher 子 AgentStep 3 是技能的核心按--concurrency大小分批处理单元顺序即inventory.py的输出顺序每个单元派一个provider-watch-researcher子 Agentprompt 中携带如下 JSON 载荷{ unit: the inventory entry, run_date: RUN_DATE, pipecat_commit: PIPECAT_COMMIT, repo_root: absolute path of this checkout, reports_path: absolute path of ./_reports, report_path: reports/provider/unit-suffix/RUN_DATE.md, report_file: reports_path/reports/provider/unit-suffix/RUN_DATE.md, previous_report_file: newest existing reports/provider/unit-suffix/*.md, or null, decisions_file: reports_path/reports/provider/unit-suffix/decisions.md, digest_comments_file: scratch/digest-comments.md, scratch_dir: scratch }其中unit-suffix是单元 id 斜杠后的部分如tts、responses-llm。SKILL.md 对此做了细致的语义区分report_path是仓库相对路径用于 frontmatter 和链接report_file是绝对路径让 researcher 无需再做任何路径解析previous_report_file指向该目录下最新一份按日期命名的历史报告decisions.md不算报告首次运行为nulldecisions_file可能尚不存在由 researcher 首次记录决策时创建。子 Agent 的定义有两份薄壳thin shimClaude Code 侧是 provider-watch-researcher.mdAgent 工具subagent_type: provider-watch-researchermodel: opusmaxTurns: 90工具白名单为Read, Grep, Glob, Bash, Write, Edit, WebFetch, WebSearchCodex 侧是 provider-watch-researcher.tomlsandbox_mode workspace-write不固定模型。两份定义都只是先引导 Agent 读RESEARCH_GUIDE.md和REPORT_TEMPLATE.md真正的调研规程在指南里SKILL.md 还规定在没有子 Agent 能力的执行环境中编排者自己按RESEARCH_GUIDE.md逐单元执行同样载荷的工作。批次循环的规则SKILL.md Rules for the batch loop整批一次性全部启动以并发运行全部等待结束后才开始下一批researcher 只产本地产物报告、当评论或 PR 状态构成决策时该单元的decisions.md、以及scratch下至多一个已提交的provider-watch/*分支在 worktree 中。绝不 push、绝不开 PR每个 researcher 精确返回一行 JSON{service, default_model, prs, gaps, error, summary, report_path}追加到scratch/run.jsonl。若 researcher 失败或返回不可用的东西编排者自己按 REPORT_TEMPLATE.md 补写报告、error字段写明发生了什么不含机密并追加对应行——单个 researcher 失败绝不中断整个运行若主 checkout 的git status出现非本次运行造成的改动立即停止并报告。researcher 做什么RESEARCH_GUIDE.md 的规程子 Agent 的完整规程在 RESEARCH_GUIDE.md 中核心是回答一个带证据的问题to keep this Pipecat service up to date with its provider, what do we need to do, if anything? 要点如下Step 0 — 读记忆先读上一份报告gaps及其first_seen、prs、models_seen、default_model、用了哪些 Sources、本单元的decisions.md被现行决策覆盖的条目不再是 gaprevisit 日期已过的条目删除即重新成为 gap、digest 评论文件只挑与本单元相关的显式决策wont do、skip、tracked in #1234 等讨论不是决策再用gh pr view核对历史prs的状态merged ⇒ gap 关闭closed 未合并 ⇒ 记为一条反决策open ⇒ 原样延续。六项调研问题按序回答供应商现在提供什么跑probe.py list-models退出码 3 表示无目录改用文档与probe.py sdk-versions对比pyproject.toml中 SDK pin 与 PyPI 最新版若最新版领先则读其间发布说明再读供应商 changelog新模型或新取值能否原样传入检查代码中的门禁——硬 allowlist如sarvam/llm.py的_SUPPORTED_MODELS、按模型的表elevenlabs/tts.py的ELEVENLABS_*_MODELS、camb/tts.py的MODEL_SAMPLE_RATES、Literal[...]类型、写死的版本 URL/header、pyproject.toml里的 SDK 版本下限默认模型该不该换须同时满足三条——供应商把新模型定位为继任者GA/recommended/旧模型弃用preview/beta 永不作默认probe 显示延迟不差LLM 用--repeat 5的 TTFAT 中位数在平凡与触发推理两种 prompt 下各测TTS/STT 用 TTFB 中位数10% 以内算不差对 LLM 还要在 aiewf-eval 的aiwf_medium_context榜单上不低于当前默认只读榜单、从不自己跑 benchmark低通过率是延迟无法弥补的质量回退未暴露的 API 能力把供应商请求 schema 与类的Settings字段、构造参数、请求构建代码含嵌套结构对比列出有意义的缺口弃用与破坏性变更当前默认或硬编码的模型/版本是否被弃用、改名、排期下线——这是最紧急的发现薄封装unit.is_thin_wrapper: true只查默认模型、base_url、供应商怪癖不支持的参数、限流、必需 header和目录。四级 probe 阶梯由便宜到贵probe.py list-models仅目录→probe.py run走真实 Pipecat 类的一轮真实交互可同时传当前默认与候选模型做可比延迟--repeat 5得到交错采样下的中位数→ 在scratch_dir写临时脚本仅限 probe.py 回答不了的问题少量调用、不循环遍历模型、输出先脱敏→ 行为 evalpipecat eval suite scripts/release-evals/manifest.yaml ...仅当本地 judge 在跑且身处分支 worktree 内。指南反复强调每个works / faster的断言都需要 probe 支撑且真实账户花钱每模型至多几次调用不循环重试不长音频。报告的形态REPORT_TEMPLATE.md每份报告必须严格遵循 REPORT_TEMPLATE.md因为 frontmatter会被digest.py、publish.py和下一次运行机器读取——键名和取值词表都不能改动。模板以 cartesia/tts 为例的 frontmatter 字段--- service: cartesia/tts # 来自 inventory.py 的 unit id classes: [CartesiaTTSService, CartesiaHttpTTSService] date: 2026-08-20 pipecat_commit: abc1234 default_model: sonic-3.5 # 代码当前发版值 summary: One sentence a maintainer can act on. models_seen: # 排序后来自 probe.py list-models 或文档 - sonic-3 - sonic-3.5 gaps: - item: Default sonic-3.5 is superseded by sonic-4 (GA 2026-08-12) first_seen: 2026-08-20 action: pr # 有 prs 条目覆盖 - item: Cartesias new emotion controls are not reachable from Settings first_seen: 2026-08-06 action: consider priority: medium # high | medium | low note: a field plus a pass-through in _build_request would do it needs: not every sonic-4 voice supports emotion; ... prs: - branch: provider-watch/cartesia-tts-sonic-4 state: branch summary: Default CartesiaTTSService to sonic-4 error: null # 或一行该单元为何无法调研 ---语义规则gaps是当前完整的缺口清单。同一 gap 延续上一份报告的first_seen这样 digest 能显示一个缺口开放了多久action只有pr有prs条目与consider需人工决策或更多工作两种每个consider条目必带needs——一行点名把它挡在自动 PR 之外的那个决策或未决问题priority决定 digest 排序high是用户当下或即将受影响会被拒绝的请求、崩溃路径、即将下线的默认medium是用户可能想要但服务表达不出来的能力缺Settings字段、allowlist 挡住的模型、落后于供应商主版本的 SDK pinlow是卫生类命名、文档在别的仓库、preview 模型待复查prs条目要么是留下的分支{branch, state: branch, summary}要么是去重时发现的既有 PR{url, state: open|merged|closed, opened, summary}。publish.py会把branch转成open并填入 URL正文结构固定为一行结论、Whats new for Pipecat下设### PRs与### To consider、## Verification列出每一次 probe含失败与作为对照的当前默认LLM 引 TTFAT 与思考耗时、其他引 TTFB决定性的对比引中位数 of N、## Sources每个页面/端点/规范/SDK 一行说明它告诉了你什么——next researcher starts from it。空章节写一个词Nothing.YAML 中以反引号、*、、[、{、#、|、、%、开头或含: 的值必须加引号否则解析失败被记为错误。模板还定义了决策文件reports/provider/unit-suffix/decisions.md的形态与按日期命名的报告并列存放一个决策一条 bullet记录条目名、评论者原话的决策、链接到评论或 PR 的出处与日期决策失效时revisit 日期已过或代码使其失效删除该条——git 历史是归档文件只保存当前生效的决策。这正是 SKILL.md 中 digest 评论收集步骤的落点researcher 把评论里的决策折进这个文件。何时留下分支PR 的提出条件与分支配方指南规定 researcher从不 push、从不开 PR而是通过留下一个已提交的分支来提议PR每个单元每次运行至多一个分支每个独立改动一个 commit。一个改动合格当且仅当同时满足改动属于五类之一默认模型升到供应商指定继任者往硬 allowlist/表里加一个模型使其可用修正服务、docstring 或examples/中被改名/退役的模型/版本字符串新模型需要的一行常量采样率、header加一个简单Settings字段顶层或嵌套把单个有文档的供应商参数直通到请求对改动后的类跑probe.py run通过默认模型升换还要求延迟不差且 LLM 的 aiewf-eval 通过率不低于当前默认新Settings字段要用--setting keyvalue在真实 API 上验证diff 小而自解释无新构造参数、无新服务类、无新 extra、除值本身外无行为变化新Settings字段必须是可选、默认不设置、命名与类型按供应商文档、直通请求且不动其他逻辑团队没有反对此事见该单元decisions.md。其余一切都是action: consider的 gap进 To consider 章节并诚实标注priority。分支配方branch recipe先做去重gh pr list --repo pipecat-ai/pipecat --label provider-watch --state all --search provider unit-suffix加上上一份报告的prs——已有 open PR 覆盖该改动则只记录不重复开分支closed 未合并的同题 PR 视为反决策记入decisions_file且不再提议。然后cd repo_root git fetch origin main 2/dev/null || true BRANCHprovider-watch/provider-unit-suffix-short-slug # e.g. provider-watch/cartesia-tts-sonic-4 BASE$(git rev-parse --verify origin/main /dev/null 21 echo origin/main || echo main) if git rev-parse --verify --quiet $BRANCH /dev/null; then git worktree add scratch_dir/wt-provider-unit-suffix $BRANCH # 续接早前运行的分支 else git worktree add scratch_dir/wt-provider-unit-suffix -b $BRANCH $BASE fi cd scratch_dir/wt-provider-unit-suffixworktree 机制保证了并发的多个 researcher 互不触碰主 checkout。在 worktree 内对每个改动循环四步做改动同步 docstring 里的Defaults to ...文案与固定旧值的测试 fixture加 changelog 碎片changelog/short-slug.changed.md一行、面向用户绝不猜测 PR 号——publish.py会在 PR 开出后把碎片重命名为真实编号用仓库自身的 pre-commit hooks 检查借助UV_NO_SYNC1 UV_PROJECT_ENVIRONMENTrepo_root/.venv复用主环境再跑pytest tests/test_provider*.py -qhooks 含 pyright 且会部分自动修复需重跑至全绿并把修复一并提交提交——每个独立改动一个 commit信息说明改动内容与理由并引用供应商声明然后停住不 push、不gh pr create在报告 frontmatter 的prs中记{branch, state: branch, summary}在 PRs 章节按模板规定的精确行形- branch — review: git show branch — summary记录publish.py之后会把前缀改写成 PR URL。步骤四清理与总结Step 4 只有三件事且边界清晰在主 checkout 里git worktree prune删除scratch/wt-*目录。分支保留——它们是本次运行的产物打印总结表单元、默认模型、分支、待考虑改动、错误并给出每个分支的审阅命令git show branch打印——绝不执行——属于调用者的下一步命令每条附解释uv run python scripts/provider-watch/publish.py --date RUN_DATE发布该日期磁盘上的一切——推分支、开 draft PR、推报告。幂等可在同日追加调研后重跑只捡新增部分/provider-research-digest --date RUN_DATE由该日期所有报告渲染出_reports/digests/RUN_DATE.md顶部加上人工撰写的高亮 bulletuv run python scripts/provider-watch/publish.py --date RUN_DATE --finalize同一发布流程加 digest——推送 digest 并开或更新digest issue。digest 技能本身在 provider-research-digest/SKILL.md 中定义同样是本地渲染、绝不发布它 sync 报告 checkout、跑digest.py出草稿、撰写至多 5 条高亮、再渲染最终版并打印--finalize命令。工具链源码佐证inventory / probe / digest / publish四个脚本与技能文档的分工一一对应且源码 docstring 与 SKILL.md 的承诺互相印证inventory.py纯 AST 扫描src/pipecat/services生成单元清单前文已述--json/--md两种输出--only/--limit与技能参数同义registry/manifest/docs 的 join 是 best-effort退化时留空字段。probe.py以用户真实用法构造服务凭据来自环境、settingsCls.Settings(model...)推一轮真实交互过三处理器管线按类型断言首个输出帧LLM 取首个LLMTextFrameTTS 取首个TTSAudioRawFrameSTT 用内置 16 kHz 语音片段取首个TranscriptionFramerealtime 做连接检查。延迟优先取服务自身指标ttfb_msLLM 另有ttfat_ms与thinking_ms否则回退到墙钟。list-models查供应商模型目录sdk-versions对比pyproject.tomlpin 与 PyPI 最新版。安全设计从.env加载时不带 override导出的变量优先CI 可无.env运行任何看起来是机密的环境变量值都会被脱敏缺失凭据只打印变量名。退出码语义0 全过、1 有失败、2 缺凭据、3 不支持无此服务类型的 probe / 无模型目录——这解释了 RESEARCH_GUIDE 中exit 3 改用文档exit 2 则把error设为变量名的规程。digest.py读取_reports下所有reports/provider/unit/date.md的 YAML frontmatter渲染一个 Markdown 页待审 PR、等待开 PR 的分支、待考虑改动含缺口开放时长、无法调研的单元、无新意的单元各带报告链接可选 highlights 文件插在最前。publish.py完全从磁盘工作——该日期的报告与本地provider-watch/*分支。对每个含state: branch条目的报告推分支、开 draft PR标题与正文取自分支 commit 信息附报告链接再把报告 frontmatter 改写为state: open加 URL、正文分支行改写为 PR URL随后扫 open 的 provider-watch PR把所有slugchangelog 碎片重命名为真实 PR 号最后提交并推送_reports。--finalize时另发布 digest 并开/更新 digest issue。每一步幂等已在 origin 的分支不重推已有 open PR 的分支直接接管该 PR已指向 PR URL 的报告不动digest issue 是编辑而非重复创建。护栏小结为什么整套流程绝不发布SKILL.md 末尾的 Guardrails 三条与 researcher 定义中的 Hard rules 形成了同一套约束的编排层与执行层两个副本机密零泄漏永不打印、提交或粘贴环境变量值、Authorizationheader、原始 API key——报告与输出里都不行probe.py负责脱敏临场输出必须人工检查本地闭环不 push、不开 PR/issue、不跑publish.py而是打印它的命令researcher 遵循同样规则在主 checkout 里只允许只读 git 命令git rev-parse、git fetch、git worktree add、gh pr list/view所有代码改动都发生在scratch_dir下的 worktree不即兴只有scripts/provider-watch/*、RESEARCH_GUIDE.md与REPORT_TEMPLATE.md定义 researcher 的行为除载荷外不为任何单元即兴追加指令。这套设计的收益是明确的调研可失败、可重试、可切片与发布幂等、一次收齐、人负责触发彻底解耦失败隔离到单个 researcher所有中间状态以磁盘上的报告 本地分支这种可检视的形式存在维护者用git show branch即可审阅first_seen与decisions.md则让多轮运行之间形成连续的记忆。【免费下载链接】pipecatOpen Source framework for voice agents, multimodal apps, and realtime AI. Maintained by Daily and the community.项目地址: https://gitcode.com/GitHub_Trending/pi/pipecat创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进