寻求LangChain中ChatBedrock替代ChatOpenAI实现结构化输出路由的方案
替代ChatBedrock缺失
with_structured_output的查询路由方案 针对AWS ChatBedrock无法使用with_structured_output实现查询路由的问题,以下是三种可落地的替代方案,均能实现从指定列表选择数据源、输出无冗余结构化结果的核心需求:
方法一:自定义Prompt + Pydantic输出解析器
这是通用型方案,适配Bedrock上所有支持文本输出的模型。核心思路是在Prompt中明确告知模型输出格式,再用LangChain的PydanticOutputParser解析结果。
from typing import List, Literal from langchain_core.prompts import ChatPromptTemplate from langchain_core.pydantic_v1 import BaseModel, Field from langchain_core.output_parsers import PydanticOutputParser from langchain_aws import ChatBedrock # 定义路由规则模型 class RouteQuery(BaseModel): """路由用户查询到最相关的数据源""" datasources: List[Literal["python_docs", "js_docs", "golang_docs"]] = Field( ..., description="从给定列表中选择与用户问题最相关的数据源,只能选列表内选项" ) # 初始化Pydantic解析器 parser = PydanticOutputParser(pydantic_object=RouteQuery) # 构造约束型Prompt,强制输出纯净JSON system_prompt = f"""你是专业查询路由专家,根据问题涉及的编程语言匹配对应数据源。 必须严格按照以下格式输出JSON,禁止添加任何解释性文字: {parser.get_format_instructions()} 注意:datasources只能从["python_docs", "js_docs", "golang_docs"]中选择,支持多选。""" prompt = ChatPromptTemplate.from_messages( [ ("system", system_prompt), ("human", "{question}"), ] ) # 初始化Bedrock模型(以Claude 3 Sonnet为例) llm = ChatBedrock( model_id="anthropic.claude-3-sonnet-20240229-v1:0", temperature=0, model_kwargs={"max_tokens": 200} ) # 构建路由链 router_chain = prompt | llm | parser # 测试调用 result = router_chain.invoke({ "question": "Python和JS版本的OpenAI聊天模型功能是否一致?" }) print(result) # 输出:RouteQuery(datasources=['python_docs', 'js_docs'])
方法二:利用Bedrock模型原生结构化输出能力
部分Bedrock模型(如Anthropic Claude、Amazon Titan)支持原生工具调用/结构化输出功能,可直接生成符合要求的结果,减少解析步骤。
以Claude 3为例,利用其工具调用格式:
from typing import List, Literal from langchain_core.messages import HumanMessage, SystemMessage from langchain_core.pydantic_v1 import BaseModel, Field from langchain_aws import ChatBedrock class RouteQuery(BaseModel): """路由用户查询到最相关的数据源""" datasources: List[Literal["python_docs", "js_docs", "golang_docs"]] = Field( ..., description="选择与用户问题最相关的数据源,只能从指定列表选取" ) # 定义工具描述(符合Claude工具调用规范) tool_definition = { "name": "route_query", "description": "将用户查询路由到最相关的数据源", "input_schema": RouteQuery.model_json_schema() } # 构造系统提示,强制使用指定工具返回结果 system_prompt = """你是查询路由专家,必须使用提供的route_query工具返回结果,直接输出工具调用的JSON格式,无需其他内容。""" messages = [ SystemMessage(content=system_prompt), HumanMessage( content="Python和JS版本的OpenAI聊天模型功能是否一致?", additional_kwargs={"tools": [tool_definition]} ) ] # 初始化Bedrock Claude模型 llm = ChatBedrock( model_id="anthropic.claude-3-sonnet-20240229-v1:0", temperature=0, model_kwargs={"max_tokens": 200} ) # 调用并解析结果 response = llm.invoke(messages) tool_call = response.additional_kwargs.get("tool_calls", [])[0] result = RouteQuery(**tool_call["input"]) print(result) # 输出:RouteQuery(datasources=['python_docs', 'js_docs'])
方法三:使用JSON输出解析器(简化版)
如果不需要严格的Pydantic验证,可直接用JsonOutputParser快速实现需求:
from typing import List, Literal from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import JsonOutputParser from langchain_aws import ChatBedrock from langchain_core.pydantic_v1 import BaseModel, Field class RouteQuery(BaseModel): datasources: List[Literal["python_docs", "js_docs", "golang_docs"]] # 定义JSON Schema json_schema = RouteQuery.model_json_schema() parser = JsonOutputParser() # 构造约束Prompt system_prompt = f"""你是查询路由专家,根据问题选择对应的数据源,只能从["python_docs", "js_docs", "golang_docs"]中选取。 必须输出符合以下JSON Schema的纯净JSON,无任何额外内容: {json_schema}""" prompt = ChatPromptTemplate.from_messages( [("system", system_prompt), ("human", "{question}")] ) llm = ChatBedrock( model_id="anthropic.claude-3-haiku-20240307-v1:0", temperature=0 ) # 构建链 chain = prompt | llm | parser # 调用并转换为Pydantic对象(可选) result = chain.invoke({"question": "Python和JS版本的OpenAI聊天模型功能是否一致?"}) route_result = RouteQuery(**result) print(route_result)
关键注意事项
- Prompt约束要绝对明确:必须强调只能从指定数据源列表选择,且输出只能是结构化内容,禁止添加任何解释性文字。
- 优先选择结构化友好模型:如Claude 3系列,这类模型对格式约束的依从性更高,能降低解析失败概率。
- 固定温度参数:将
temperature设为0,确保输出稳定性,避免随机结果干扰后续逻辑。
内容的提问来源于stack exchange,提问作者Mischa
相关产品推荐
相关产品推荐

