feat:简化部分代码

This commit is contained in:
2026-09-29 07:23:42 -07:00
parent af84485e8d
commit 352d144823
13 changed files with 123 additions and 306 deletions
+12 -57
View File
@@ -1,10 +1,8 @@
"""统一获取普通模型或绑定结构化输出的模型"""
from functools import cache
from typing import Literal, TypeVar, cast, overload
from typing import Any, TypeVar, overload
from langchain_core.language_models import LanguageModelInput
from langchain_core.language_models.chat_models import BaseChatModel
from langchain_core.runnables import Runnable
from langchain_openai import ChatOpenAI
from pydantic import BaseModel
@@ -12,7 +10,6 @@ from pydantic import BaseModel
from app.config import settings
OutputModel = TypeVar("OutputModel", bound=BaseModel)
StructuredMethod = Literal["function_calling", "json_schema", "json_mode"]
@cache
@@ -29,64 +26,22 @@ def _get_base_llm() -> ChatOpenAI:
)
# 下面两个 @overload 只给类型检查器和编辑器看,运行时不会执行
# 不传 schema:返回普通聊天模型,输出是自由文本
@overload
def get_llm(
schema: type[OutputModel],
*,
method: StructuredMethod = "function_calling",
strict: bool | None = False,
client: BaseChatModel | None = None,
) -> Runnable[LanguageModelInput, OutputModel]: ...
def get_llm() -> ChatOpenAI: ...
# 传入 Pydantic 类:返回结构化调用器,ainvoke 的结果就是该类的实例
# OutputModel 让返回类型跟着传入的类走,例如 get_llm(Requirement) 得到 Runnable[..., Requirement]
@overload
def get_llm(
schema: None = None,
*,
method: StructuredMethod = "function_calling",
strict: bool | None = False,
client: None = None,
) -> ChatOpenAI: ...
def get_llm(schema: type[OutputModel]) -> Runnable[Any, OutputModel]: ...
@overload
def get_llm(
schema: None = None,
*,
method: StructuredMethod = "function_calling",
strict: bool | None = False,
client: BaseChatModel,
) -> BaseChatModel: ...
def get_llm(
schema: type[OutputModel] | None = None,
*,
method: StructuredMethod = "function_calling",
strict: bool | None = False,
client: BaseChatModel | None = None,
) -> BaseChatModel | Runnable[LanguageModelInput, OutputModel]:
"""不传 schema 返回普通模型,传入 Pydantic 类则返回结构化调用器
client 用于注入模型,省略时使用缓存客户端
strict 控制服务端 schema 约束,本地仍由 Pydantic 校验
"""
if schema is not None and (
not isinstance(schema, type) or not issubclass(schema, BaseModel)
):
raise TypeError("schema 必须是 Pydantic BaseModel 类")
if method not in ("function_calling", "json_schema", "json_mode"):
raise ValueError(f"不支持的结构化输出方式: {method}")
if schema is None and (method != "function_calling" or strict not in (False, None)):
raise ValueError("设置结构化输出参数时必须提供 schema")
if method == "json_mode" and strict is True:
raise ValueError("json_mode 不支持 strict=True")
llm = client if client is not None else _get_base_llm()
# 真正的实现:schema 用 type[BaseModel] | None 覆盖上面两种调用
# 返回类型由 overload 决定,这里不再重复标注
def get_llm(schema: type[BaseModel] | None = None) -> Any:
llm = _get_base_llm()
if schema is None:
return llm
# json_mode 不接受 strict 参数,提示词还需要明确要求 JSON 及其结构
structured = llm.with_structured_output(
schema, method=method, strict=None if method == "json_mode" else strict
)
return cast(Runnable[LanguageModelInput, OutputModel], structured)
return llm.with_structured_output(schema, method="function_calling", strict=False)