伦敦证券交易所集团用 Instructor 构建 AI 市场监控系统:生产级结构化输出的金融实战案例
【免费下载链接】instructorstructured outputs for llms项目地址: https://gitcode.com/GitHub_Trending/in/instructor
导读
本文基于 Instructor 官方博客案例,深入剖析伦敦证券交易所集团(LSEG)如何将 Instructor 部署到生产环境,支撑其 AI 驱动的市场监控(Market Surveillance)系统:通过 Amazon Bedrock 调用 Anthropic Claude 模型,对海量监管新闻做高精度的价格敏感性分类。文章在完整还原 LSEG 案例的规模、指标与技术架构之外,还结合当前仓库的 Bedrock 集成文档、Anthropic 集成文档、分类示例与 Pydantic 校验源码,给出可复现的两阶段分类管线实现,帮助你掌握如何在强监管、高吞吐的金融场景中落地 LLM 结构化输出。
案例背景:为什么市场监控需要结构化输出
伦敦证券交易所集团每年处理超过£1 万亿的证券交易,涉及400 家会员机构,因此必须构建精细的市场滥用(market abuse)检测机制。其全新 AI 驱动的Surveillance Guide(监控指南)系统,承担一个关键任务:自动分析海量监管新闻,判断其中哪些内容属于价格敏感信息(price-sensitive news),从而辅助分析师快速复核被标记为潜在市场滥用的交易。
这一场景对 AI 系统的核心诉求是准确性与可靠性优先于一切——金融监管合规领域不允许随意的、格式不稳定的模型输出。LSEG 选择 Instructor 正是因为它能把 LLM 的自由文本输出强制转换为类型安全、可校验的 Pydantic 结构,让下游 Python 管道可以零摩擦地消费这些结果,这正是 Instructor 的核心能力(项目描述即为 "structured outputs for llms")。
生产环境的实际效果
据官方博客公布的数据,LSEG 的市场监控系统取得了非常亮眼的运行指标:
- 100% 精确率(precision):识别"非敏感新闻"时无一误判;
- 100% 召回率(recall):检测"价格敏感内容"时无一漏报;
- 自动化分析了250,000+ 篇监管新闻文章;
- 显著降低了人工分析师的工作负担。
需要说明的是,上述指标来自官方博客案例的公开表述;从仓库内部我们无法复现其评测集,因此这些数字应视为 LSEG 对外公布的运行结论而非本仓库可验证的基准。结合仓库中的分类示例(如 examples/classification/classifiy_with_validation.py)可以推断,这类"零漏报、零误报"的目标依赖两件事:一是足够清晰的任务定义与枚举约束,二是完善的校验与重试机制,下文将逐一展开。
技术架构:Instructor × Claude × Amazon Bedrock
LSEG 的技术栈包含三个关键层次:
- Instructor 库:与 Claude 模型无缝集成,负责把 LLM 输出约束为结构化、可校验的响应模型;
- Amazon Bedrock:可扩展的基础模型基础设施,托管并调用 Anthropic Claude 模型;
- 自定义 Python 管道:负责数据处理与分析,消费 Instructor 产出的结构化结果。
整条链路的核心是两阶段分类方法:监管新闻先经过初步分类,再进入后续分析环节,Instructor 在其中确保 LLM 返回可靠、结构化的响应,供下游分析直接使用。
在仓库中定位这套技术栈
这套架构在当前仓库中有完整的一手资料支撑:
- docs/integrations/bedrock.md:完整的 Bedrock 接入指南,含环境配置、同步/异步示例、支持的模式与模型列表;
- docs/integrations/anthropic.md:Anthropic Claude 的结构化输出教程,涵盖工具调用、流式与思考模式;
- instructor/providers/bedrock/client.py:Bedrock 兼容层源码,
from_bedrock从instructor.v2.providers.bedrock.client导入,说明当前版本已统一走 v2 实现; - instructor/providers/:包含 bedrock、anthropic 等全部官方 provider 目录。
第一步:从零搭建 Bedrock 结构化输出客户端
安装与环境准备
LSEG 使用的核心依赖是 AWS Bedrock + Claude 模型。按仓库集成文档,安装命令为:
pip install "instructor[bedrock]"前提条件:拥有可访问 Bedrock 的 AWS 账户及相应权限,并配置好 AWS 凭证,可通过环境变量或 AWS CLI 两种方式:
# 方式一:环境变量 export AWS_ACCESS_KEY_ID=your_access_key export AWS_SECRET_ACCESS_KEY=your_secret_key export AWS_DEFAULT_REGION=us-east-1 # 方式二:AWS CLI aws configure用 from_provider 创建客户端
当前版本推荐使用统一的from_provider入口(见 docs/concepts/from_provider.md),一行代码即可完成客户端创建,并自动处理 AWS 凭证探测、区域配置(默认us-east-1)以及基于模型的模式选择(Claude 模型默认使用TOOLS模式):
import instructor # Auto client with model specification client = instructor.from_provider("bedrock/anthropic.claude-sonnet-5")如果已有自定义的 boto3 客户端(例如需要指定区域或凭证),也可以显式传入:
import boto3 import instructor bedrock_client = boto3.client( 'bedrock-runtime', region_name='us-west-2', aws_access_key_id='your_key', aws_secret_access_key='your_secret', ) client = instructor.from_provider( "bedrock/anthropic.claude-sonnet-5", client=bedrock_client, mode=instructor.Mode.TOOLS, )一个值得注意的兼容性细节:Bedrock 集成同时支持 OpenAI 风格与 Bedrock 原生两种消息格式,甚至可以在同一次请求中混用;模型参数既可以用 OpenAI 风格的model,也可以用 Bedrock 原生的modelId(两者同时提供时modelId优先)。这意味着团队可以把既有的 OpenAI 风格代码平滑迁移到 Bedrock 之上。
一个完整的同步分类调用
下面是一个可复制运行的入门示例(结构与 docs/integrations/bedrock.md 中的 Sync Example 一致):
import boto3 import instructor from pydantic import BaseModel bedrock_client = boto3.client('bedrock-runtime') client = instructor.from_provider("bedrock/anthropic.claude-sonnet-5") class User(BaseModel): name: str age: int user = client.create( modelId="anthropic.claude-sonnet-5", messages=[ {"role": "user", "content": "Extract: Jason is 25 years old"}, ], response_model=User, ) print(user) #> User(name='Jason', age=25)第二步:用枚举 + 校验构建"零误报"分类模型
市场监控分类对结果边界的约束极为严格。仓库的 枚举指南 明确建议:用 Enum 约束标准化字段,并始终提供一个 "Other" 兜底选项,让模型能够表达不确定性,从而防止数据错位(data misalignment)。
对照 LSEG 的两阶段分类场景,可以设计出如下响应模型——第一阶段判断新闻是否价格敏感:
from enum import Enum from pydantic import BaseModel, Field, field_validator class NewsSensitivity(str, Enum): PRICE_SENSITIVE = "price_sensitive" NON_SENSITIVE = "non_sensitive" OTHER = "other" class FirstStageClassification(BaseModel): """第一阶段:判断监管新闻是否属于价格敏感信息""" sensitivity: NewsSensitivity = Field( description=( "Correctly assign one of the predefined sensitivity levels " "based on whether the news could move the price of a listed security." ) ) tickers: list[str] = Field( default_factory=list, description="Securities or issuers mentioned in the article, if any", ) rationale: str = Field( description="One-sentence rationale supporting the classification" ) @field_validator("sensitivity") @classmethod def require_sensitivity(cls, v): if v == NewsSensitivity.OTHER: raise ValueError( "Unable to determine sensitivity; please re-read the article " "and provide a definite classification." ) return v这里有两个关键设计:
- 枚举约束输出边界:模型只能从固定取值中选择,彻底消除了"敏感""不敏感""价格敏感"这类同义表述不一致带来的下游解析难题(这正是 examples/classification/simple_prediction.py 中
Labels枚举做法的生产化延伸)。 - 校验器把模糊回答挡在门外:借助
@field_validator(参考 docs/concepts/validation.md),一旦模型给出OTHER这类含糊结论就主动触发失败,从而驱动 Instructor 的重试机制——这正是实现"100% 精确率 / 100% 召回率"目标的基础设施保障。
底层原理:验证失败自动重试
当校验器抛出ValueError时,Instructor 会把校验错误信息反馈给 LLM并让其重新生成(见 docs/concepts/reask_validation.md 与 docs/getting-started.md 的验证小节):
重试次数可以通过max_retries参数配置。在监管合规场景中,建议显式设置合理的重试上限,并在最终失败时走人工复核队列,避免静默吞掉异常——仓库的错误处理指南提供了完整的异常类型与捕获模式。
第三步:两阶段分类管线的生产化实现
将上述模型组合进两阶段流水线,即可还原 LSEG "先分类、再分析"的架构思路。第二阶段对已判定为价格敏感的新闻做更细粒度的市场影响分析:
import instructor from pydantic import BaseModel, Field class MarketImpact(BaseModel): """第二阶段:评估价格敏感新闻的市场影响维度""" direction: str = Field( description="Expected price direction: 'up', 'down', or 'neutral'" ) magnitude: str = Field( description="Expected impact magnitude: 'low', 'medium', or 'high'" ) affected_sector: str | None = Field( default=None, description="Sector most likely affected, if identifiable", ) key_evidence: list[str] = Field( description="Quoted facts supporting this assessment" ) client = instructor.from_provider("bedrock/anthropic.claude-sonnet-5") SENSITIVITY_PROMPT = ( "You are a market surveillance analyst. Determine whether the following " "regulatory news is price-sensitive for any listed security. " "Classify into exactly one of: price_sensitive, non_sensitive, other." ) IMPACT_PROMPT = ( "The article below was flagged as price-sensitive. " "Analyze the expected market impact with precise, evidence-based reasoning." ) def analyze_article(article: str) -> tuple[FirstStageClassification, MarketImpact | None]: """两阶段分析:先判敏感性,敏感新闻再评估市场影响""" first_stage = client.create( response_model=FirstStageClassification, max_retries=3, messages=[ {"role": "system", "content": SENSITIVITY_PROMPT}, {"role": "user", "content": article}, ], ) if first_stage.sensitivity != NewsSensitivity.PRICE_SENSITIVE: return first_stage, None impact = client.create( response_model=MarketImpact, max_retries=3, messages=[ {"role": "system", "content": IMPACT_PROMPT}, {"role": "user", "content": article}, ], ) return first_stage, impact生产化调优要点
- 推理参数:在低延迟敏感、结果要求保守的金融场景,可显式降低温度。Bedrock 集成支持透传
inferenceConfig:
user = client.create( modelId="anthropic.claude-sonnet-5", messages=[{"role": "user", "content": "Analyze this news"}], response_model=FirstStageClassification, inferenceConfig={ "maxTokens": 2048, "temperature": 0.1, "topP": 0.9, "stopSequences": ["STOP"], }, )批处理:面对 25 万+ 篇新闻的规模,逐条同步调用显然不够。仓库在 docs/concepts/batch.md 与 docs/concepts/parallel.md 中提供了批量与并行处理方案,并配套 examples/batch_classification/(含
run.py、run_langsmith.py、run-cache.py)等可直接参考的分类批处理示例。监控与可观测性:生产部署需要记录每次分类的原始完成信息。Instructor 的
create_with_completion(见 docs/concepts/raw_response.md)可以同时返回解析后的 Pydantic 对象与底层 completion,便于审计与重放。
模式选择:Claude 模型下的结构化输出机制
在 Bedrock 上运行 Claude 模型时,Instructor 会根据模型能力与你的选择在几种核心模式间切换(详见 docs/integrations/bedrock.md 的 Supported Modes 一节):
Mode.TOOLS:使用函数调用(function calling)返回结构化结果,Claude 系列模型默认走此模式;Mode.JSON_SCHEMA:针对支持原生 JSON Schema 约束解码的模型;Mode.TOOLS_STRICT:针对支持严格工具使用的模型的原生 schema 强制;Mode.MD_JSON:直接生成 JSON 文本响应(作为文本抽取的回退方案)。
仓库还明确指出:旧版模式BEDROCK_TOOLS、BEDROCK_JSON已废弃,分别映射到Mode.TOOLS与Mode.MD_JSON;而原生结构化输出需要boto3 1.42.42 或更高版本,且不同模型支持能力不同,选择JSON_SCHEMA或TOOLS_STRICT时应以 AWS 官方结构化输出文档为准。
另外,docs/integrations/anthropic.md 还展示了 Claude 专属的增强能力:在Mode.TOOLS下传入thinking={"type": "adaptive"}可启用自适应扩展思考,让模型在输出结构化结果前先进行推理,且要求显式设置tool_choice={"type": "auto"}——这对于需要"推理链 + 严格 schema"的复杂监管判定场景非常契合。
生产化扩展:语义校验与人工兜底
金融场景仅靠字段级校验(枚举、数值范围)还不够,一些判定标准难以用规则表达。仓库在 docs/concepts/validation.md 中提供了llm_validator语义校验模式,用第二个 LLM 调用检查语义层面的合规性;examples/validators/moderation.py 展示了用AfterValidator(openai_moderation(...))在结果返回前做内容审核的做法。这类"规则校验 + 语义校验"的组合,正是把 LSEG 案例中"分析师复核"环节自动化的可行路径。
同时,从源码结构看(instructor/validation/ 下的llm_validators.py、async_validators.py),Instructor 将校验器与重试循环深度集成:任何校验失败都会自动触发"把错误反馈给模型并重试"的闭环,最终仍失败则抛出异常,交由业务侧人工介入。这种设计保证了生产系统在追求自动化的同时,永远保留可审计、可兜底的出口。
总结:从 LSEG 案例中可复用的工程模式
LSEG 的 Surveillance Guide 案例证明了 Instructor 在"准确性、可靠性至高无上"的金融监管场景中的生产可行性。从案例与仓库证据中可以提炼出四条可复用的工程经验:
- 用枚举收紧输出边界:分类、标签类字段一律使用
Enum/Literal并提供OTHER兜底,从源头消灭自由文本歧义(见 docs/concepts/enums.md); - 用校验器驱动自动重试:把"不可接受"的模型回答(如模糊分类)通过
@field_validator显式判失败,让 Instructor 的重试闭环自动纠正,并用max_retries控制成本与延迟(见 docs/getting-started.md); - 用统一入口对接多模型:
from_provider("bedrock/...")一行切换基础设施,配合 Bedrock 的 OpenAI 兼容输入格式,降低供应商绑定成本(见 docs/concepts/from_provider.md); - 用结构化响应支撑批处理与审计:25 万+ 文章规模必须走批量与并行管道,并保留原始 completion 供审计追踪(见 docs/concepts/batch.md)。
如果你也想构建自己的生产级结构化输出应用,推荐从 getting-started 快速上手 开始,并结合 examples/classification/ 的分类示例与 docs/integrations/bedrock.md 的 Bedrock 接入文档落地第一版管线。
【免费下载链接】instructorstructured outputs for llms项目地址: https://gitcode.com/GitHub_Trending/in/instructor
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考