Language Models
Language Models 是 Heta 调用 LLM 的统一入口。构建步骤和 query engines 只依赖 LanguageModel、ModelRequest 和 ModelResult,不需要直接处理不同 provider 的请求格式。
当前实现使用 LiteLLM 作为底层适配层。Heta 负责提供稳定接口,LiteLLM 负责把请求发送到 OpenAI、DashScope OpenAI-compatible endpoint、Anthropic、Gemini 等具体服务。
Quick Start
from heta_framework.common.models import LanguageModel, ModelRequest
llm = LanguageModel(
model_name="openai/gpt-4o-mini",
api_key="...",
request_timeout=120,
max_retries=3,
max_concurrent_requests=20,
)
result = await llm.invoke(
ModelRequest(
prompt="从下面文本中抽取实体:...",
response_schema={"type": "object"},
trace_context={"stage": "entity_extraction", "chunk_id": "chunk-001"},
)
)
entities = result.parsed
调用 DashScope OpenAI-compatible endpoint 时,设置 api_base 并使用 LiteLLM 的 OpenAI 路由前缀:
llm = LanguageModel(
model_name="openai/qwen-plus",
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
api_key="...",
provider_options={"enable_thinking": False},
)
model_name 遵循 LiteLLM 命名规则。openai/ 前缀表示按 OpenAI-compatible 协议发送请求,不一定表示模型来自 OpenAI。
Core Objects
| 对象 | 说明 |
|---|---|
LanguageModel |
长生命周期模型客户端,负责请求执行、并发限制和 LiteLLM 调用。 |
LanguageModelProtocol |
语言模型能力协议,用于 Recipe、steps、query engines 和自定义模型。 |
ModelRequest |
一次模型请求,包含 prompt、系统提示词、调用参数和 trace 信息。 |
TextPart / ImagePart |
多模态请求内容片段,用于图文输入。 |
ModelOptions |
单次请求参数,例如温度、输出长度、停止序列和结构化输出格式。 |
ModelResult |
非流式调用结果,包含文本、结构化解析结果、token usage 和原始响应。 |
ModelChunk |
流式调用结果,包含当前文本增量、结束原因和原始 chunk。 |
LanguageModelProtocol 是结构化协议,不要求用户继承某个父类。自定义语言模型只要实现 invoke、invoke_many 和 stream,就可以被 recipe 或自定义 step 接收。
Configuration
llm = LanguageModel(
model_name="openai/gpt-4o-mini",
api_key="...",
api_base=None,
request_timeout=120,
max_retries=3,
max_concurrent_requests=10,
default_temperature=0.1,
drop_unsupported_params=True,
provider_options=None,
)
| 参数 | 说明 |
|---|---|
model_name |
传给 LiteLLM 的模型名。 |
api_key |
模型服务 API key,也可以通过服务方支持的环境变量提供。 |
api_base |
自定义 API endpoint,常用于 OpenAI-compatible 服务。 |
request_timeout |
单次请求超时时间,单位为秒。 |
max_retries |
底层请求失败后的重试次数。 |
max_concurrent_requests |
当前模型实例允许的最大并发请求数。 |
default_temperature |
请求未显式设置温度时使用的默认值。 |
drop_unsupported_params |
让 LiteLLM 丢弃当前模型不支持的参数。 |
provider_options |
长生命周期透传参数,适合放服务方固定选项。 |
同一个 LanguageModel 实例可以在 recipe 中复用。批量处理 chunks、图文描述、实体抽取或关系抽取时,并发请求会被 max_concurrent_requests 控制。
Calling The Model
result = await llm.invoke(request)
results = await llm.invoke_many([request_1, request_2])
async for chunk in llm.stream(request):
print(chunk.text_delta, end="")
| 方法 | 说明 |
|---|---|
invoke |
执行一次非流式请求,返回完整 ModelResult。 |
invoke_many |
并发执行多次请求,返回顺序与输入顺序一致。 |
stream |
执行一次流式请求,返回 AsyncIterator[ModelChunk]。 |
stream 当前不支持 response_schema。需要结构化输出时使用 invoke。
Request Format
纯文本任务通常使用 prompt:
from heta_framework.common.models import ModelOptions, ModelRequest
request = ModelRequest(
prompt="从文本中抽取实体和关系。",
system_prompt="你是一个知识图谱抽取器。",
options=ModelOptions(
temperature=0.1,
max_output_tokens=4096,
top_p=0.9,
stop_sequences=None,
response_format={"type": "json_object"},
provider_options={"enable_thinking": False},
),
response_schema={"type": "object"},
trace_context={"stage": "graph_extraction", "chunk_id": "chunk-001"},
)
图文输入使用 content。prompt 和 content 二选一。
from heta_framework.common.models import ImagePart, ModelRequest, TextPart
request = ModelRequest(
content=[
TextPart(text="描述这张图,并提取图中的关键信息。"),
ImagePart.from_uri("https://example.com/image.png", detail="high"),
],
trace_context={"stage": "image_description", "document_id": "doc-001"},
)
ImagePart 支持三种图片来源:
ImagePart.from_uri("https://example.com/image.png")
ImagePart.from_file("./images/page-001.png")
ImagePart.from_bytes(image_bytes, mime_type="image/png")
path 和 data 会被转换成 data:image/...;base64,... 后发送给模型。FastAPI 上传文件时通常使用 from_bytes:
@app.post("/describe-image")
async def describe_image(file: UploadFile):
image_bytes = await file.read()
result = await llm.invoke(
ModelRequest(
content=[
TextPart(text="描述这张图片。"),
ImagePart.from_bytes(
image_bytes,
mime_type=file.content_type or "image/png",
),
]
)
)
return {"description": result.text}
| 字段 | 说明 |
|---|---|
prompt |
本次纯文本任务输入。 |
content |
本次多模态任务输入,可包含 TextPart 和 ImagePart。 |
system_prompt |
系统提示词,可选。 |
options |
本次请求的模型参数,可选。 |
response_schema |
结构化输出约束,可选。设置后解析结果写入 ModelResult.parsed。 |
trace_context |
调用追踪信息,不会发送给模型。 |
ModelOptions.provider_options 会覆盖 LanguageModel.provider_options 中的同名字段,适合在单次请求中调整服务方专有参数。
Result
result.text
result.parsed
result.model_name
result.token_usage
result.finish_reason
result.trace_context
result.raw_response
| 字段 | 说明 |
|---|---|
text |
模型原始文本输出。 |
parsed |
按 response_schema 解析后的结构化结果。 |
model_name |
当前 LanguageModel 配置的模型名。 |
token_usage |
token 消耗信息。 |
finish_reason |
模型服务返回的结束原因。 |
trace_context |
请求携带的追踪信息。 |
raw_response |
LiteLLM 返回的原始响应字典。 |
如果设置了 response_schema,业务代码通常读取 parsed;否则读取 text。
Errors
模型层不会把失败请求转换为空字符串。
| 错误 | 含义 |
|---|---|
ModelError |
模型层基础错误。 |
ModelRequestError |
请求模型服务失败,或请求参数不适用于当前调用方式。 |
ModelResponseError |
响应格式错误,或结构化输出解析失败。 |
错误对象会保留 trace_context,方便定位失败发生在哪个任务阶段、文档或 chunk。
Scope
Models 层负责:
- 统一模型调用入口。
- 异步请求和批量并发。
- 文本和图文输入。
- 非流式与流式输出。
- 结构化 JSON 解析。
- token usage、原始响应和追踪上下文保留。
- 向 LiteLLM 透传模型服务专有参数。
Models 不负责文档解析、chunk 切分、prompt 业务内容、向量入库、图谱构建或 KnowledgeBase 生命周期管理。
模型服务覆盖范围由 LiteLLM 决定。接入新模型时,优先确认 LiteLLM 是否支持对应 model_name 和 provider 参数。