instructor 项目协作开发指南:从命令、架构到发布的全流程规范
【免费下载链接】instructorstructured outputs for llms项目地址: https://gitcode.com/GitHub_Trending/in/instructor
本文档(仓库根目录的 AGENT.md)是 instructor 项目面向人类贡献者与 AI Agent(如 Cursor)的"协作说明书",覆盖开发环境的安装与测试命令、项目架构地图、代码风格约束、Conventional Commits 的 PR 规范以及完整的版本发布流程。读完本文,你将能独立完成一个从「环境准备 → 代码修改 → 提交 PR → 更新 CHANGELOG → 发布新版本」的完整贡献闭环,并理解 instructor 当前 v1/v2 双轨架构与统一的
from_provider()客户端工厂背后的设计意图。
一、环境准备与高频开发命令
AGENT.md 将日常开发命令集中放在文档开头,作为任何贡献者的第一站。instructor 采用uv作为主要包管理器(同时兼容 Poetry),Python 版本要求为>=3.9,<4.0(见 pyproject.toml)。
1.1 安装开发环境
uv pip install -e ".[dev]" # 或使用 Poetry poetry install --with dev其中dev是一组可选的开发依赖(见 pyproject.toml),包括pytest、pytest-asyncio、coverage、jsonref、pytest-xdist、pre-commit、ty以及固定的anthropic==0.93.0、xmltodict等,用于跑测试、类型检查与静态分析。
1.2 运行测试
项目在 pyproject.toml 中注册了三类 pytest marker,分别对应不同粒度的测试:
unit:快速单元测试,无外部依赖;integration:集成测试,可能要求配置 API Key;llm:真实调用 LLM 的测试(会消耗额度)。
由此派生出以下测试命令:
# 运行全部测试 uv run pytest tests/ # 运行单个测试(按路径与用例名精确定位) uv run pytest tests/path_to_test.py::test_name # 跳过 LLM 与 OpenAI 相关测试(日常本地开发的默认姿势) uv run pytest tests/ -k 'not llm and not openai'如果需要为某次运行临时引入依赖(不改动环境),AGENT.md 推荐使用uv run --with:
uv run --with pytest-asyncio --with anthropic pytest tests/...这与 AGENT.md 中"不要 mock,测试使用真实 API 调用"的约定相辅相成——-k 'not llm'的存在,正是为了让没有 API Key 的贡献者也能快速跑通大部分测试。仓库中大量用例正是这样组织的,例如 tests/v2/test_genai_config_reuse.py 这类确定性回归测试不需要真实调用即可验证配置复用语义。
1.3 类型检查、Lint 与格式化
# 类型检查:使用 ty(配置见 ty.toml / ty-tests.toml) uv run ty check # Lint:对源码、示例与测试统一检查 uv run ruff check instructor examples tests # 格式化:Ruff 采用 Black 风格约定 uv run ruff format instructor examples testsAGENT.md 明确要求"严格类型标注",ty是仓库选定的类型检查器,且ty==0.0.44被固定进 dev 依赖。Lint/Format 的检查范围同时覆盖instructor(库代码)、examples(示例)与tests(测试)三处。
1.4 构建文档
# 本地热更新预览 uv run mkdocs serve # 生产构建(正式发布文档) ./build_mkdocs.sh仓库根目录的 mkdocs.yml 是文档站配置,docs 目录(含concepts/、integrations/、examples/、blog/等)即 mkdocs 的源内容;build_mkdocs.sh负责生产环境的构建与部署。
1.5 关于"等待"
AGENT.md 特别提示:当需要显式等待(例如 CI 等待或等待外部进程完成)时,使用sleep <seconds>,而不是其他非标准的挂起方式——这是给 Agent 的明确行为约定,保证命令可预测、可审计。
二、架构地图:十分钟读懂 instructor
AGENT.md 用极简篇幅勾勒出项目的架构骨架,理解它能让后续的代码修改事半功倍。
2.1 核心目录与职责
- Core(核心):
instructor/本身即"基于 Pydantic 的 LLM 结构化输出"库。注意当前实现大量委托给 v2:例如 instructor/core/client.py 仅有兼容导出,真正的Instructor与AsyncInstructor位于 instructor/v2/core/client.py;同样 instructor/auto_client.py 也只是把from_provider转发到 instructor/v2/auto_client.py。 - 基类:
Instructor与AsyncInstructor(同步/异步两种客户端,定义于client.py)。 - Provider 层:instructor/providers/ 下为 OpenAI、Anthropic、Gemini、Cohere、Bedrock、Mistral、Groq、Writer、xAI 等各家的客户端文件(
client_*.py);而 instructor/v2/providers/ 则承载 v2 架构下按 provider 拆分的 handler 与 client 实现,并以 instructor/v2/core/provider_specs.py 中的ProviderSpec作为 provider 能力(支持/不支持的模式、别名、SDK 模块、legacy 模式映射)的唯一事实来源。 - 工厂模式:
from_provider()负责自动识别 provider(见下文)。 - DSL 扩展:instructor/dsl/ 提供 Partial(流式局部结果)、Iterable(迭代输出)、Maybe(可空结果)、Citation(引用)等扩展;v2 对应实现位于 instructor/v2/dsl/。
- 关键模块:
patch.py(客户端打补丁)、process_response.py(响应解析,v2 为v2/core/response.py)、function_calls.py(生成 schema,v2 为v2/core/function_calls.py)。
2.2 懒加载导出:__init__.py的工程设计
从 instructor/init.py 可以看到,顶层导出并非在 import 时立即加载,而是维护了一张_LAZY_IMPORTS表,通过模块级__getattr__按需导入(如Instructor、from_provider、Mode、Partial等),并在_add_optional_export中依据依赖包是否安装来条件暴露from_anthropic、from_gemini、from_bedrock等可选入口。这解释了 AGENT.md 中"客户端创建统一走from_provider()"的动机:大量 provider 入口是可选依赖,统一工厂可避免强依赖某一家的 SDK。
2.3 统一客户端工厂from_provider()
AGENT.md 明确约定:永远使用instructor.from_provider("provider_name/model_name"),而不是 provider 专属的from_openai()、from_anthropic()等方法。源码佐证如下(instructor/v2/auto_client.py):
client = instructor.from_provider("openai/gpt-4") client = instructor.from_provider("anthropic/claude-3-sonnet") # 异步客户端 async_client = instructor.from_provider("openai/gpt-4", async_client=True) # 携带缓存适配器(AutoCache/RedisCache 等透明响应缓存) cache = AutoCache(maxsize=1000) client = instructor.from_provider("openai/gpt-4", cache=cache)其行为要点:
- 模型串格式必须为
"provider/model-name",provider 与模型名缺一不可,否则抛出ConfigurationError(错误类型定义于 instructor/v2/core/errors.py); - 支持通过
api_key显式传 Key,也支持在 kwargs 中透传 provider 专属选项; - 若 provider 未注册,会报出支持列表(
supported_providers取自ALIAS_TO_PROVIDER,见 instructor/v2/core/provider_specs.py); - 未安装对应 SDK 时会抛出带安装提示的
ImportError/ConfigurationError。
2.4 Mode 体系:结构化输出的实现方式
AGENT.md 虽未展开 Mode,但它是理解 provider 差异的关键。在 instructor/v2/core/mode.py 中,Mode枚举定义了全部结构化模式,并归类为:
- 工具调用类(
tool_modes()):TOOLS、TOOLS_STRICT、PARALLEL_TOOLS、ANTHROPIC_TOOLS、GEMINI_TOOLS、BEDROCK_TOOLS、COHERE_TOOLS、RESPONSES_TOOLS等; - JSON 类(
json_modes()):JSON、JSON_SCHEMA、MD_JSON、ANTHROPIC_JSON、GEMINI_JSON、COHERE_JSON_SCHEMA、PERPLEXITY_JSON等; - 另有 xAI、Mistral、Vertex AI 等专属模式,以及被标记为 deprecated 的
FUNCTIONS。
不同 provider 的ProviderSpec会声明各自supported_modes/unsupported_modes与legacy_modes映射(例如 OpenAI 兼容系将废弃的FUNCTIONS映射到TOOLS),这是"同一套 API 抽象多 provider"的底层支撑。
2.5 GenAI 请求所有权约定
AGENT.md 特别记录了一条实现事实:GenAI 请求参数的所有权——_clone_kwargs会在 mode handler 合并并翻译采样选项之前,先深拷贝嵌套的generation_config,以保证调用方传入的配置对象可复用、不会被 handler 原地修改;对应回归测试在 tests/v2/test_genai_config_reuse.py。这提醒贡献者:在处理 provider 请求参数时,复制后再合并,避免污染调用方对象。
三、代码风格约定
- 类型标注:所有函数/方法要求严格类型标注;结构化输出模型统一继承
BaseModel(Pydantic v2)。 - 导入顺序:标准库 → 第三方 → 本地模块,三段式排列。
- 格式化:Ruff,遵循 Black 风格(
ruff format可直接收敛)。 - 错误处理:优先使用 instructor/exceptions.py 中的自定义异常(v2 侧在 instructor/v2/core/exceptions.py),并借助 Pydantic 校验;仓库还有专门的向后兼容测试 tests/core/test_exception_backwards_compat.py。
- 命名:函数/变量
snake_case,类PascalCase。 - 禁止 Mock:测试一律使用真实 API 调用(也因此要用
-k 'not llm'做本地过滤)。 - 客户端创建:一律
instructor.from_provider("provider/model"),禁止 provider 专属工厂方法(详见 2.3 节)。仓库中的集成测试即遵循该约定,例如 tests/llm/test_new_client.py 等。
四、Pull Request 规范
4.1 PR 标题:Conventional Commits
PR 标题即 squash merge 的提交信息,必须采用<type>(<scope>): <short summary>格式:
- 尽量控制在 70 字符以内;
- 使用祈使语气(
add、fix、update),不以句号结尾; - 若含破坏性变更,在 type 或 scope 后加
!(如feat(api)!:)。
好的示例:
fix(openai): handle empty tool_calls in streaming feat(retry): add backoff for JSON parse failures docs(agents): add conventional commit PR title guidelines test(schema): cover nested union edge cases ci(ruff): enforce formatting in pre-commit常用 type 一览(来自 AGENT.md):
| type | 含义 |
|---|---|
feat | 新功能 |
fix | 缺陷修复 |
docs | 仅文档改动 |
refactor | 非修复非新功能的代码调整 |
perf | 性能优化 |
test | 新增/更新测试 |
build | 构建系统或依赖变更 |
ci | CI 流水线变更 |
chore | 维护性工作 |
推荐的 scope(就近选择):
- Provider:
openai、anthropic、gemini、vertexai、bedrock、mistral、groq、writer; - 核心:
core、patch、process_response、function_calls、retry、dsl; - 仓库层面:
docs、examples、tests、ci、build。
4.2 PR 描述模板
PR 描述保持精简、便于评审:
- What:1–3 句话说明改了什么;
- Why:为什么需要这次改动(尽量关联 issue);
- Changes:3–7 条要点列出主要编辑;
- Testing:运行了什么测试(或为什么没有运行)。
若 PR 由 Cursor 撰写,须在描述中注明 "This PR was written by Cursor"。
4.3 CHANGELOG 强制要求
任何改变行为的 PR 都必须更新CHANGELOG.md(CHANGELOG.md 位于仓库根目录)。规则如下:
- 在
## [Unreleased](或进行中的版本小节)下追加条目; - 条目格式:
- **Area**: Short description of the change (#PR_NUMBER); - 按
Security、Fixed、Added、Changed、Deprecated、Removed、Tests / CI分组; - 纯文档或纯示例改动(除非修复了用户可见问题)不必写 CHANGELOG。
五、版本发布流程
AGENT.md 以v1.15.0为例给出了可执行的发布 SOP,仓库当前版本号为1.17.1(pyproject.toml):
确保 CI 通过:在 merge 进 staging 前,staging PR 的 CI 必须全绿;
合并:通过 GitHub PR 将 staging 合并到 main;
提升版本号:修改 pyproject.toml 中
version = "X.Y.Z",随后更新锁文件:uv lock提交并打 tag(tag 使用小写
v前缀):git add pyproject.toml uv.lock git commit -m "chore(release): vX.Y.Z" git tag vX.Y.Z git push origin main --tags创建 GitHub Release:对 tag 创建 Release 会触发
.github/workflows/python-publish.yml,利用PYPI_TOKENsecret 自动构建并发布到 PyPI。
版本号升档规则(依据距上个 tag 以来的提交类型):
feat!:/fix!:/BREAKING→major(主版本)feat:→minor(次版本)fix:/chore:及其他 →patch(补丁版本)
这解释了 4.1 节中"破坏性变更必须加!"的硬性要求——它直接驱动发布工具的版本决策。此外 scripts/prepare_release.py 与配套测试 tests/test_prepare_release.py 也在仓库中承担发布前的自动化检查职责。
六、总结
AGENT.md 虽短,却是 instructor 仓库"人机协作"的枢纽文档:它以一条命令清单覆盖了开发、测试、质检与文档构建的完整工具链;以一张架构地图交代了 Core/v2、Provider、DSL、工厂模式与关键模块的分工;以一份风格与 PR 规范保证了多贡献者(包括 AI Agent)产出的可评审性;并以一套版本发布 SOP 将 Conventional Commits、CHANGELOG 与自动发布流水线串成闭环。对想要为 instructor 贡献代码或深入理解其工程治理的开发者来说,这份文档就是最好的起点——按图索骥,即可在 AGENT.md、pyproject.toml、instructor/v2/auto_client.py、instructor/v2/core/provider_specs.py 与 tests/ 之间自由穿行。
【免费下载链接】instructorstructured outputs for llms项目地址: https://gitcode.com/GitHub_Trending/in/instructor
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考