feat(agent): persist production generation settings

This commit is contained in:
2026-07-16 16:07:11 +08:00
parent 245b6b3eca
commit 6c02662d3b
9 changed files with 353 additions and 56 deletions

View File

@@ -103,7 +103,7 @@ const modelForm = reactive({
topK: null as number | null,
presencePenalty: null as number | null,
frequencyPenalty: null as number | null,
maxToken: null as number | null,
maxToken: 8192 as number | null,
contextWindow: null as number | null,
streamEnabled: 1,
responseFormat: "",
@@ -471,18 +471,6 @@ function buildModelPayload() {
payload[field] = null;
}
});
Object.assign(payload, {
temperature: null,
topP: null,
topK: null,
presencePenalty: null,
frequencyPenalty: null,
maxToken: null,
contextWindow: null,
streamEnabled: 1,
responseFormat: null,
extraParams: null,
});
return payload;
}
@@ -513,7 +501,7 @@ async function quickAddModel() {
topK: null,
presencePenalty: null,
frequencyPenalty: null,
maxToken: null,
maxToken: 8192,
contextWindow: null,
streamEnabled: 1,
responseFormat: null,
@@ -594,13 +582,13 @@ function editModel(row: ModelItem) {
apiKey: "",
authType: row.authType,
apiVersion: row.apiVersion ?? "",
temperature: null,
topP: null,
topK: null,
presencePenalty: null,
frequencyPenalty: null,
maxToken: null,
contextWindow: null,
temperature: row.temperature ?? null,
topP: row.topP ?? null,
topK: row.topK ?? null,
presencePenalty: row.presencePenalty ?? null,
frequencyPenalty: row.frequencyPenalty ?? null,
maxToken: row.maxToken ?? 8192,
contextWindow: row.contextWindow ?? null,
streamEnabled: row.streamEnabled,
responseFormat: row.responseFormat ?? "",
extraParams: row.extraParams ?? "",
@@ -626,7 +614,7 @@ function resetModelForm() {
topK: null,
presencePenalty: null,
frequencyPenalty: null,
maxToken: null,
maxToken: 8192,
contextWindow: null,
streamEnabled: 1,
responseFormat: "",

View File

@@ -0,0 +1,49 @@
<script setup lang="ts">
defineProps<{
temperature: number | null;
topP: number | null;
topK: number | null;
presencePenalty: number | null;
frequencyPenalty: number | null;
maxToken: number | null;
disabled?: boolean;
}>();
defineEmits<{
"update:temperature": [value: number | null];
"update:topP": [value: number | null];
"update:topK": [value: number | null];
"update:presencePenalty": [value: number | null];
"update:frequencyPenalty": [value: number | null];
"update:maxToken": [value: number | null];
}>();
</script>
<template>
<div class="agent-config-grid">
<el-form-item>
<template #label><span class="agent-parameter-label">回答随机性<el-tooltip placement="top" :show-after="200" content="取值 02。数值越小回答越稳定、一致数值越大表达越多样但也更容易发散。答疑场景建议使用较低数值。"><button type="button" class="agent-parameter-help" aria-label="回答随机性说明">?</button></el-tooltip></span></template>
<el-input-number :model-value="temperature" :disabled="disabled" :min="0" :max="2" :step="0.1" @update:model-value="$emit('update:temperature', $event)" />
</el-form-item>
<el-form-item>
<template #label><span class="agent-parameter-label">核采样概率<el-tooltip placement="top" :show-after="200" content="取值 01。模型只从累计概率达到该数值的候选词中选择。数值越小越专注越大越多样。留空表示使用模型供应商默认值。"><button type="button" class="agent-parameter-help" aria-label="核采样概率说明">?</button></el-tooltip></span></template>
<el-input-number :model-value="topP" :disabled="disabled" :min="0" :max="1" :step="0.05" @update:model-value="$emit('update:topP', $event)" />
</el-form-item>
<el-form-item>
<template #label><span class="agent-parameter-label">候选词数量<el-tooltip placement="top" :show-after="200" content="取值 11000。每次生成只从概率最高的前 K 个候选词中选择。数值越小越保守,越大选择越多。留空表示使用供应商默认值,部分模型可能不支持。"><button type="button" class="agent-parameter-help" aria-label="候选词数量说明">?</button></el-tooltip></span></template>
<el-input-number :model-value="topK" :disabled="disabled" :min="1" :max="1000" @update:model-value="$emit('update:topK', $event)" />
</el-form-item>
<el-form-item>
<template #label><span class="agent-parameter-label">最大输出长度<el-tooltip placement="top" :show-after="200" content="限制模型本次最多生成的 Token 数,不等于字数。建议正式答疑使用 40968192数值越大允许回答越长也会增加耗时和费用最终仍受模型自身上限约束。"><button type="button" class="agent-parameter-help" aria-label="最大输出长度说明">?</button></el-tooltip></span></template>
<el-input-number :model-value="maxToken" :disabled="disabled" :min="256" :max="100000" :step="256" @update:model-value="$emit('update:maxToken', $event)" />
</el-form-item>
<el-form-item>
<template #label><span class="agent-parameter-label">主题重复惩罚<el-tooltip placement="top" :show-after="200" content="取值 -220 表示不调整。正数会降低已出现内容再次出现的概率,鼓励引入新主题;负数会更容易重复已出现内容。数值过高可能导致回答跳跃。"><button type="button" class="agent-parameter-help" aria-label="主题重复惩罚说明">?</button></el-tooltip></span></template>
<el-input-number :model-value="presencePenalty" :disabled="disabled" :min="-2" :max="2" :step="0.1" @update:model-value="$emit('update:presencePenalty', $event)" />
</el-form-item>
<el-form-item>
<template #label><span class="agent-parameter-label">高频重复惩罚<el-tooltip placement="top" :show-after="200" content="取值 -220 表示不调整。正数会根据词语已出现的次数降低其再次出现的概率,用于减少反复表达;负数会增加重复倾向。数值过高可能影响语句连贯性。"><button type="button" class="agent-parameter-help" aria-label="高频重复惩罚说明">?</button></el-tooltip></span></template>
<el-input-number :model-value="frequencyPenalty" :disabled="disabled" :min="-2" :max="2" :step="0.1" @update:model-value="$emit('update:frequencyPenalty', $event)" />
</el-form-item>
</div>
</template>

View File

@@ -3,7 +3,8 @@ import { ElMessage, ElMessageBox } from "element-plus";
import { computed, onMounted, reactive, ref, watch } from "vue";
import { api } from "../services/api";
import type { AgentDebugResult, KnowledgeItem, ModelItem, PromptDetail, PromptHistoryItem } from "../types/api";
import type { AgentDebugResult, AgentRuntimeConfig, KnowledgeItem, ModelItem, PromptDetail, PromptHistoryItem } from "../types/api";
import AgentGenerationParameters from "./AgentGenerationParameters.vue";
import AdminPagination from "./AdminPagination.vue";
const props = defineProps<{ previewKnowledgeId?: number | null }>();
@@ -11,6 +12,7 @@ const emit = defineEmits<{ consumedPreview: [] }>();
const loading = ref(false);
const promptSaving = ref(false);
const runtimeSaving = ref(false);
const historyLoading = ref(false);
const agentDebugging = ref(false);
const activeConfigTab = ref("prompt");
@@ -37,9 +39,18 @@ const agentForm = reactive({
topK: null as number | null,
presencePenalty: null as number | null,
frequencyPenalty: null as number | null,
maxToken: 1024 as number | null,
maxToken: 8192 as number | null,
question: "",
});
const runtimeConfig = ref<AgentRuntimeConfig | null>(null);
const runtimeForm = reactive({
temperature: null as number | null,
topP: null as number | null,
topK: null as number | null,
presencePenalty: null as number | null,
frequencyPenalty: null as number | null,
maxToken: 8192 as number | null,
});
const promptDirty = computed(() => promptContent.value !== savedPromptContent.value);
const selectedModelName = computed(() => {
@@ -63,13 +74,15 @@ watch(() => props.previewKnowledgeId, (knowledgeId) => {
async function load() {
loading.value = true;
try {
const [promptResult, modelRows, knowledgeRows] = await Promise.all([
api.prompt(), api.models(), api.knowledgeOptions(),
const [promptResult, modelRows, knowledgeRows, formalConfig] = await Promise.all([
api.prompt(), api.models(), api.knowledgeOptions(), api.agentRuntimeConfig(),
]);
applyPrompt(promptResult);
models.value = modelRows;
knowledge.value = knowledgeRows;
agentForm.modelId = modelRows.find((item) => item.enabled === 1)?.id ?? modelRows[0]?.id;
applyRuntimeConfig(formalConfig);
applyDebugModelDefaults(agentForm.modelId);
agentForm.knowledgeIds = knowledgeRows
.filter((item) => item.status === 1 && item.lifecycleStatus === "active")
.map((item) => item.id);
@@ -82,6 +95,56 @@ async function load() {
}
}
function applyRuntimeConfig(value: AgentRuntimeConfig) {
runtimeConfig.value = value;
Object.assign(runtimeForm, {
temperature: value.temperature,
topP: value.topP,
topK: value.topK,
presencePenalty: value.presencePenalty,
frequencyPenalty: value.frequencyPenalty,
maxToken: value.maxToken,
});
}
function applyDebugModelDefaults(modelId?: number) {
const model = models.value.find((item) => item.id === modelId);
if (!model) return;
Object.assign(agentForm, {
temperature: model.temperature ?? null,
topP: model.topP ?? null,
topK: model.topK ?? null,
presencePenalty: model.presencePenalty ?? null,
frequencyPenalty: model.frequencyPenalty ?? null,
maxToken: model.maxToken ?? (model.enabled === 1 ? runtimeConfig.value?.maxToken : null) ?? 8192,
});
}
async function saveRuntimeConfig() {
if (!runtimeConfig.value?.modelId) return ElMessage.error("请先在模型管理中启用一个正式模型");
if (!runtimeForm.maxToken) return ElMessage.warning("最大输出长度不能为空");
runtimeSaving.value = true;
try {
const saved = await api.saveAgentRuntimeConfig({
temperature: runtimeForm.temperature,
topP: runtimeForm.topP,
topK: runtimeForm.topK,
presencePenalty: runtimeForm.presencePenalty,
frequencyPenalty: runtimeForm.frequencyPenalty,
maxToken: runtimeForm.maxToken,
});
applyRuntimeConfig(saved);
const model = models.value.find((item) => item.id === saved.modelId);
if (model) Object.assign(model, runtimeForm);
if (agentForm.modelId === saved.modelId) applyDebugModelDefaults(saved.modelId ?? undefined);
ElMessage.success("正式运行参数已保存,将从用户端下一条消息开始生效");
} catch (error) {
ElMessage.error(errorMessage(error, "正式运行参数保存失败"));
} finally {
runtimeSaving.value = false;
}
}
function applyPreviewKnowledge(knowledgeId: number) {
if (knowledge.value.some((item) => item.id === knowledgeId)) {
agentForm.knowledgeIds = [knowledgeId];
@@ -262,7 +325,7 @@ function errorMessage(error: unknown, fallback: string) {
<div class="page-head agent-page-head">
<div>
<h2>Agent 管理</h2>
<p>维护主提示词及历史版本配置本次调试参数并验证真实检索与回答效果</p>
<p>维护主提示词用户端正式生成参数和历史版本并验证真实检索与回答效果</p>
</div>
<div class="agent-current-summary">
<el-tag type="success">当前版本 {{ prompt?.id ? `#${prompt.id}` : "系统默认" }}</el-tag>
@@ -286,11 +349,34 @@ function errorMessage(error: unknown, fallback: string) {
</div>
</el-tab-pane>
<el-tab-pane label="正式运行配置" name="runtime">
<div class="agent-section-intro">
<div><h3>用户端正式运行参数</h3><p>保存后从用户端下一条消息开始生效当前正式模型{{ runtimeConfig?.modelName || '未启用模型' }}</p></div>
<el-button type="primary" :loading="runtimeSaving" :disabled="!runtimeConfig?.modelId" @click="saveRuntimeConfig">保存正式参数</el-button>
</div>
<el-alert v-if="!runtimeConfig?.modelId" title="当前没有已启用模型,请先到模型管理中启用一个正式模型。" type="warning" :closable="false" show-icon />
<el-alert v-else title="最大输出长度默认提升为 8192 Token设置过低会导致长回答在完成前被模型截断。实际可用上限仍受模型供应商限制。" type="info" :closable="false" show-icon />
<el-form label-position="top" class="agent-runtime-form">
<section class="agent-advanced-settings">
<div class="agent-subsection-title"><h4>正式生成参数</h4><span>用户端正式对话使用</span></div>
<AgentGenerationParameters
v-model:temperature="runtimeForm.temperature"
v-model:top-p="runtimeForm.topP"
v-model:top-k="runtimeForm.topK"
v-model:presence-penalty="runtimeForm.presencePenalty"
v-model:frequency-penalty="runtimeForm.frequencyPenalty"
v-model:max-token="runtimeForm.maxToken"
:disabled="!runtimeConfig?.modelId"
/>
</section>
</el-form>
</el-tab-pane>
<el-tab-pane label="调试配置" name="debug">
<div class="agent-section-intro"><div><h3>本次调试配置</h3><p>配置只作用于后台预览不会修改模型和知识库的正式状态</p></div></div>
<el-form label-position="top">
<el-form-item label="调试模型">
<el-select v-model="agentForm.modelId" placeholder="选择已接入模型">
<el-select v-model="agentForm.modelId" placeholder="选择已接入模型" @change="applyDebugModelDefaults">
<el-option v-for="model in models" :key="model.id" :label="model.displayName || model.modelName" :value="model.id" />
</el-select>
</el-form-item>
@@ -301,32 +387,14 @@ function errorMessage(error: unknown, fallback: string) {
</el-form-item>
<section class="agent-advanced-settings">
<div class="agent-subsection-title"><h4>高级生成参数</h4><span>仅影响本次后台调试</span></div>
<div class="agent-config-grid">
<el-form-item>
<template #label><span class="agent-parameter-label">回答随机性<el-tooltip placement="top" :show-after="200" content="取值 02。数值越小回答越稳定、一致数值越大表达越多样但也更容易发散。答疑场景建议使用较低数值。"><button type="button" class="agent-parameter-help" aria-label="回答随机性说明">?</button></el-tooltip></span></template>
<el-input-number v-model="agentForm.temperature" :min="0" :max="2" :step="0.1" />
</el-form-item>
<el-form-item>
<template #label><span class="agent-parameter-label">核采样概率<el-tooltip placement="top" :show-after="200" content="取值 01。模型只从累计概率达到该数值的候选词中选择。数值越小越专注越大越多样。留空表示使用模型供应商默认值。"><button type="button" class="agent-parameter-help" aria-label="核采样概率说明">?</button></el-tooltip></span></template>
<el-input-number v-model="agentForm.topP" :min="0" :max="1" :step="0.05" />
</el-form-item>
<el-form-item>
<template #label><span class="agent-parameter-label">候选词数量<el-tooltip placement="top" :show-after="200" content="取值 11000。每次生成只从概率最高的前 K 个候选词中选择。数值越小越保守,越大选择越多。留空表示使用供应商默认值,部分模型可能不支持。"><button type="button" class="agent-parameter-help" aria-label="候选词数量说明">?</button></el-tooltip></span></template>
<el-input-number v-model="agentForm.topK" :min="1" :max="1000" />
</el-form-item>
<el-form-item>
<template #label><span class="agent-parameter-label">最大输出长度<el-tooltip placement="top" :show-after="200" content="限制模型本次最多生成的 Token 数,不等于字数,也不代表一定会生成到该长度。数值越大允许回答越长,同时可能增加耗时和费用,最终仍受模型上限约束。"><button type="button" class="agent-parameter-help" aria-label="最大输出长度说明">?</button></el-tooltip></span></template>
<el-input-number v-model="agentForm.maxToken" :min="1" :max="100000" />
</el-form-item>
<el-form-item>
<template #label><span class="agent-parameter-label">主题重复惩罚<el-tooltip placement="top" :show-after="200" content="取值 -220 表示不调整。正数会降低已出现内容再次出现的概率,鼓励引入新主题;负数会更容易重复已出现内容。数值过高可能导致回答跳跃。"><button type="button" class="agent-parameter-help" aria-label="主题重复惩罚说明">?</button></el-tooltip></span></template>
<el-input-number v-model="agentForm.presencePenalty" :min="-2" :max="2" :step="0.1" />
</el-form-item>
<el-form-item>
<template #label><span class="agent-parameter-label">高频重复惩罚<el-tooltip placement="top" :show-after="200" content="取值 -220 表示不调整。正数会根据词语已出现的次数降低其再次出现的概率,用于减少反复表达;负数会增加重复倾向。数值过高可能影响语句连贯性。"><button type="button" class="agent-parameter-help" aria-label="高频重复惩罚说明">?</button></el-tooltip></span></template>
<el-input-number v-model="agentForm.frequencyPenalty" :min="-2" :max="2" :step="0.1" />
</el-form-item>
</div>
<AgentGenerationParameters
v-model:temperature="agentForm.temperature"
v-model:top-p="agentForm.topP"
v-model:top-k="agentForm.topK"
v-model:presence-penalty="agentForm.presencePenalty"
v-model:frequency-penalty="agentForm.frequencyPenalty"
v-model:max-token="agentForm.maxToken"
/>
</section>
</el-form>
</el-tab-pane>

View File

@@ -2,6 +2,8 @@ import type {
AdminProfile,
AdminUser,
AgentDebugResult,
AgentGenerationConfig,
AgentRuntimeConfig,
AiLogRecord,
ApiResponse,
ChatDetail,
@@ -178,6 +180,9 @@ export const api = {
restorePrompt: (id: number) => request<PromptDetail>(`/admin/prompt/history/${id}/restore`, { method: "POST", body: "{}" }),
debugAgent: (payload: Record<string, unknown>) =>
request<AgentDebugResult>("/admin/agent/debug", { method: "POST", body: JSON.stringify(payload) }),
agentRuntimeConfig: () => request<AgentRuntimeConfig>("/admin/agent/runtime-config"),
saveAgentRuntimeConfig: (payload: AgentGenerationConfig) =>
request<AgentRuntimeConfig>("/admin/agent/runtime-config", { method: "PUT", body: JSON.stringify(payload) }),
models: () => request<ModelItem[]>("/admin/model/list"),
createModel: (payload: Record<string, unknown>) =>
request<ModelItem>("/admin/model", { method: "POST", body: JSON.stringify(payload) }),

View File

@@ -133,6 +133,20 @@ export interface ModelItem {
enabled: number;
}
export interface AgentGenerationConfig {
temperature: number | null;
topP: number | null;
topK: number | null;
presencePenalty: number | null;
frequencyPenalty: number | null;
maxToken: number;
}
export interface AgentRuntimeConfig extends AgentGenerationConfig {
modelId: number | null;
modelName: string | null;
}
export interface AgentDebugResult {
ok: boolean;
message: string;

View File

@@ -13,6 +13,7 @@ from app.models.ai_config import ModelConfig, Prompt, SystemConfig
from app.models.knowledge import Knowledge
from app.schemas.admin import (
AgentDebugRequest,
AgentRuntimeConfigSaveRequest,
EnableModelRequest,
ModelSaveRequest,
PromptSaveRequest,
@@ -184,6 +185,46 @@ async def debug_agent(
return api_success(result)
@router.get("/agent/runtime-config")
def get_agent_runtime_config(
db: Session = Depends(get_db),
current_admin: Admin = Depends(get_current_admin),
) -> dict:
model = _enabled_model(db)
return api_success(_agent_runtime_config_dict(model))
@router.put("/agent/runtime-config")
def save_agent_runtime_config(
payload: AgentRuntimeConfigSaveRequest,
db: Session = Depends(get_db),
current_admin: Admin = Depends(get_current_admin),
) -> dict:
model = _enabled_model(db)
if model is None:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="当前没有已启用模型,请先在模型管理中启用一个模型",
)
model.temperature = payload.temperature
model.top_p = payload.topP
model.top_k = payload.topK
model.presence_penalty = payload.presencePenalty
model.frequency_penalty = payload.frequencyPenalty
model.max_token = payload.maxToken
db.add(model)
OperationLogService.write(
db,
admin_id=current_admin.id,
module="agent",
action="save_runtime_config",
target_id=model.id,
)
db.commit()
db.refresh(model)
return api_success(_agent_runtime_config_dict(model))
@router.get("/model/list")
def list_models(db: Session = Depends(get_db), current_admin: Admin = Depends(get_current_admin)) -> dict:
models = db.scalars(select(ModelConfig).order_by(ModelConfig.id.desc())).all()
@@ -376,6 +417,28 @@ def _model_dict(model: ModelConfig) -> dict:
}
def _enabled_model(db: Session) -> ModelConfig | None:
return db.scalar(
select(ModelConfig)
.where(ModelConfig.enabled == 1)
.order_by(ModelConfig.id.desc())
.limit(1)
)
def _agent_runtime_config_dict(model: ModelConfig | None) -> dict:
return {
"modelId": model.id if model is not None else None,
"modelName": (model.display_name or model.model_name) if model is not None else None,
"temperature": float(model.temperature) if model is not None and model.temperature is not None else None,
"topP": float(model.top_p) if model is not None and model.top_p is not None else None,
"topK": model.top_k if model is not None else None,
"presencePenalty": float(model.presence_penalty) if model is not None and model.presence_penalty is not None else None,
"frequencyPenalty": float(model.frequency_penalty) if model is not None and model.frequency_penalty is not None else None,
"maxToken": model.max_token if model is not None and model.max_token is not None else 8192,
}
def _default_prompt_detail() -> dict:
return {
"id": None,

View File

@@ -89,7 +89,16 @@ class AgentDebugRequest(BaseModel):
topK: int | None = Field(default=None, ge=1, le=1000)
presencePenalty: float | None = Field(default=None, ge=-2, le=2)
frequencyPenalty: float | None = Field(default=None, ge=-2, le=2)
maxToken: int | None = Field(default=1024, ge=1, le=100000)
maxToken: int | None = Field(default=8192, ge=1, le=100000)
class AgentRuntimeConfigSaveRequest(BaseModel):
temperature: float | None = Field(default=None, ge=0, le=2)
topP: float | None = Field(default=None, ge=0, le=1)
topK: int | None = Field(default=None, ge=1, le=1000)
presencePenalty: float | None = Field(default=None, ge=-2, le=2)
frequencyPenalty: float | None = Field(default=None, ge=-2, le=2)
maxToken: int = Field(default=8192, ge=256, le=100000)
class ModelSaveRequest(BaseModel):

View File

@@ -494,7 +494,7 @@ def _agent_system_prompt() -> str:
def _max_output_tokens(model: ModelConfig) -> int:
configured = max(1, model.max_token or 1024)
configured = max(1, model.max_token or 8192)
if not model.context_window:
return configured
return min(configured, max(1, model.context_window // 3))

View File

@@ -0,0 +1,101 @@
from decimal import Decimal
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from sqlalchemy.pool import StaticPool
from app.api.admin_settings import get_agent_runtime_config, save_agent_runtime_config
from app.models import Base
from app.models.admin import Admin
from app.models.ai_config import ModelConfig
from app.schemas.admin import AgentRuntimeConfigSaveRequest
from app.services.model_stream_service import _openai_stream_payload
from app.services.model_service import _max_output_tokens
from app.services.rag_service import RagResult
def _database() -> Session:
engine = create_engine(
"sqlite:///:memory:",
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
Base.metadata.create_all(engine)
return Session(engine)
def _admin() -> Admin:
return Admin(id=1, username="admin", password="hash", name="系统管理员", status=1)
def _model() -> ModelConfig:
return ModelConfig(
id=1,
provider="openai-compatible",
display_name="正式模型",
api_type="openai_compatible",
model_name="production-model",
base_url="https://example.com/v1",
api_url="",
api_key="encrypted",
auth_type="bearer",
max_token=None,
stream_enabled=1,
timeout_second=30,
enabled=1,
)
def test_runtime_config_defaults_to_long_answer_safe_max_tokens():
with _database() as db:
admin = _admin()
model = _model()
db.add_all([admin, model])
db.commit()
result = get_agent_runtime_config(db=db, current_admin=admin)["data"]
assert result["modelId"] == model.id
assert result["modelName"] == "正式模型"
assert result["maxToken"] == 8192
assert _max_output_tokens(model) == 8192
def test_saved_runtime_config_is_persisted_on_enabled_model():
with _database() as db:
admin = _admin()
model = _model()
db.add_all([admin, model])
db.commit()
result = save_agent_runtime_config(
AgentRuntimeConfigSaveRequest(
temperature=0.3,
topP=0.9,
topK=40,
presencePenalty=0.2,
frequencyPenalty=0.4,
maxToken=12000,
),
db=db,
current_admin=admin,
)["data"]
db.refresh(model)
assert result["maxToken"] == 12000
assert model.max_token == 12000
assert model.temperature == Decimal("0.30")
assert model.top_p == Decimal("0.90")
assert model.top_k == 40
assert model.presence_penalty == Decimal("0.20")
assert model.frequency_penalty == Decimal("0.40")
payload = _openai_stream_payload(
model,
RagResult(question="测试", knowledge_scopes=[], chunks=[], prompt="测试", allow_general_knowledge=True),
)
assert payload["max_tokens"] == 12000
assert payload["temperature"] == 0.3
assert payload["top_p"] == 0.9
assert payload["presence_penalty"] == 0.2
assert payload["frequency_penalty"] == 0.4