Azure OpenAI on your data 的 prompt_token 是否影响计费?
结论
会影响计费。响应中的 prompt_tokens 会计入模型的输入 token。即使请求中的 system 内容为空,最终提交给模型的提示词也不一定为空。
Azure OpenAI On Your Data 的作用是利用企业数据为回答提供依据,提高相关性并减少幻觉,并非减少 token 用量。服务会在后台构造完整的上下文,通常包含系统级指令、检索到的数据片段、引用信息、对话历史和检索编排所需的内容。因此,即使用户只输入 hello there,最终也可能产生数千个 prompt_tokens。
假设当前模型在对应区域的输入价格确实是 $0.0025 / 1,000 tokens,那么 4,000 个计费输入 token 的费用为:
4,000 ÷ 1,000 × $0.0025 = $0.01
这只是输入 token 的费用。输出 token、Azure AI Search 和其他关联服务可能单独计费。模型、区域和计价时间不同,价格也可能变化,请以实际部署对应的最新价格页和账单为准。
这些 prompt_tokens 从哪里来
On Your Data 一般使用检索增强生成,也就是 RAG。一次请求并不是把用户输入直接交给模型,而是大致经过以下流程:
用户问题
→ 查询理解或改写
→ 从数据源检索相关内容
→ 将检索结果、系统指令和用户问题组合成上下文
→ 调用模型生成带依据的回答
模型最终看到的输入可能类似下面的结构:
[检索上下文示例]
模型会依据检索到的数据生成带引用的回答……
[检索到的数据片段]
文档片段 1……
文档片段 2……
文档片段 3……
[对话历史]
此前的用户问题与助手回答……
[当前问题]
hello there
用户输入本身可能只有几个 token,但以下内容也会占用输入 token:
- On Your Data 注入的内部系统指令;
- 从数据源检索出的文档片段;
- 文档标题、路径、引用和其他元数据;
- 保留的对话历史;
- 角色标记、消息结构等协议开销;
- 某些检索模式使用的查询改写或编排上下文。
因此:
{"role": "system", "content": ""}
只能说明调用方没有填写自定义 system message,不能证明服务最终提交给模型的有效提示词为空。
长度相近的两个用户问题也可能产生差异很大的 prompt_tokens。影响 token 数量的往往不是问题多了几个单词,而是检索命中了多少内容、片段有多长,以及请求是否带有历史消息。
如何降低 token 使用量
1. 减少返回给模型的检索文档数量
如果当前 API 版本支持,可以适当降低数据源配置中的 top_n_documents。下面是示意配置,具体字段位置请以所用 API 版本的定义为准:
{
"data_sources": [
{
"type": "azure_search",
"parameters": {
"top_n_documents": 3,
"strictness": 4
}
}
]
}
不要一开始就把数值调得太低。减少检索片段可以降低 token 用量,但也可能让回答遗漏必要信息。
2. 优化文档切分
chunk 太大会把大量无关文字送入模型,太小则可能丢失上下文,需要检索更多片段才能完整回答问题。
可以从以下几方面调整:
- 按标题、段落或语义边界切分;
- 删除导航栏、页脚和重复模板等噪声;
- 避免同一内容在多个文档中重复出现;
- 保留必要的片段重叠,但不要设置过大的 overlap;
- 尽量让每个片段只覆盖一个相对完整的主题。
没有适用于所有数据集的固定切分大小,需要结合文档类型和实际问答效果进行测试。
3. 调整检索严格程度
提高 strictness 通常可以过滤相关性较低的结果,减少进入上下文的无关片段。但如果设置得太高,也可能检索不到足够的资料。
调整时可以同时观察:
prompt_tokens;- 检索结果数量;
- 回答是否遗漏信息;
- 引用是否确实支持回答。
4. 控制对话历史
多轮聊天如果每次都发送完整历史,旧消息同样会计入输入 token。可以只保留回答当前问题所需的消息:
messages = [
{
"role": "user",
"content": "I worked overtime what should I do?"
}
]
对于较长的会话,可以先把旧对话压缩成摘要,再发送摘要和最近几轮消息。不过,生成摘要本身也可能产生一次额外的模型调用费用。
5. 对简单问候绕过数据检索
hello there 通常不需要查询企业知识库。应用层可以识别问候、致谢或固定命令,直接返回预设内容,或者改用不带数据源的普通聊天请求。
例如:
def is_simple_greeting(text: str) -> bool:
normalized = text.strip().lower()
return normalized in {
"hello",
"hello there",
"hi",
"hey",
"thanks",
"thank you",
}
def handle_message(text: str):
if is_simple_greeting(text):
return "Hello! How can I help?"
return call_azure_openai_with_data(text)
这种处理比让 RAG 流程接收所有消息更直接,也能避免无意义的检索和上下文注入。
6. 限制输出长度
限制输出长度不会减少 prompt_tokens,但可以降低 completion_tokens。可以根据业务需要设置 max_tokens,或使用当前 API 版本对应的输出限制参数。
7. 使用真实请求做对照测试
可以分别测试以下场景:
- 普通模型请求,不配置数据源;
- 配置 On Your Data;
- 降低
top_n_documents; - 优化文档切分;
- 去掉对话历史。
记录每次请求返回的用量:
usage = response.usage
print({
"prompt_tokens": usage.prompt_tokens,
"completion_tokens": usage.completion_tokens,
"total_tokens": usage.total_tokens,
})
不同 SDK 版本可能以对象或字典形式返回 usage,请以实际响应结构为准。
费用应如何计算
模型的输入和输出通常需要分别计费:
prompt_tokens = 4000
completion_tokens = 200
input_price_per_1k = 0.0025
output_price_per_1k = 0.01 # 仅为演示值,不代表当前 Azure 价格
input_cost = prompt_tokens / 1000 * input_price_per_1k
output_cost = completion_tokens / 1000 * output_price_per_1k
total_model_cost = input_cost + output_cost
print(input_cost)
print(output_cost)
print(total_model_cost)
计算公式为:
模型费用 =
(prompt_tokens ÷ 1,000 × 输入单价)
+
(completion_tokens ÷ 1,000 × 输出单价)
当输入单价为 $0.0025 / 1,000 tokens 时:
4,000 个输入 token = $0.01
不能直接把 total_tokens 全部乘以输入单价,因为 completion_tokens 应按输出价格计算。此外,还要检查 Azure AI Search、向量化或 embedding 等相关资源是否产生独立费用。
注意事项
prompt_tokens是模型实际接收的输入规模,不只包括用户手写的 prompt。- 空的 system message 不会关闭 On Your Data 的内部指令和数据注入。
- On Your Data 改善的是回答的知识依据,并不以减少 token 数量为目标。
- 不同模型、区域、部署类型和计费时期的单价可能不同。
- 检索参数的名称和可用范围可能随 API 版本变化,修改前需要核对当前版本的接口定义。
- 减少 token 可能影响检索召回率和回答完整性,应使用实际问答集评估效果,不能只追求最低 token。
备注:内容仅供参考。
