perf(voice): prompt-caching для Claude + отсев мёртвых сущностей
All checks were successful
Deploy / deploy (push) Successful in 1m28s
All checks were successful
Deploy / deploy (push) Successful in 1m28s
- claudeRequest: system разбит на кэшируемый базовый промпт (cache_control ephemeral) + волатильный живой контекст отдельным блоком. Схемы инструментов попадают в кэшируемый префикс (render order tools->system) и читаются за ~10%. - buildLiveContext: пропускаем entity в состоянии unavailable/unknown — меньше токенов и шума в снимке. - Цель: ~20k input/запрос на Haiku давал ~$0.02+/запрос; кэш стабильной части (инструменты+база) режет стоимость в разы, ответы не меняются. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UYsVrPyJ5phJeVsAGciS1v
This commit is contained in:
@@ -98,7 +98,9 @@ function historyToAnthropicMessages(history: HistoryMessage[]): any[] {
|
||||
return result
|
||||
}
|
||||
|
||||
async function claudeRequest(system: string, messages: any[], tools: any[]): Promise<any> {
|
||||
async function claudeRequest(baseSys: string, liveCtx: string, messages: any[], tools: any[]): Promise<any> {
|
||||
const system: any[] = [{ type: 'text', text: baseSys, cache_control: { type: 'ephemeral' } }]
|
||||
if (liveCtx) system.push({ type: 'text', text: liveCtx })
|
||||
const body: any = { model: 'claude-haiku-4-5-20251001', max_tokens: MAX_TOKENS, system, messages }
|
||||
if (tools.length > 0) body.tools = tools
|
||||
const opts: any = {
|
||||
@@ -137,6 +139,7 @@ async function buildLiveContext(): Promise<string> {
|
||||
const s = d.sensors || {}
|
||||
const lines: string[] = []
|
||||
for (const [id, st] of Object.entries<any>(states)) {
|
||||
if (st.state === 'unavailable' || st.state === 'unknown') continue
|
||||
const name = st.attributes?.friendly_name || id
|
||||
let extra = ''
|
||||
if (st.attributes?.preset_mode) extra += `, режим ${st.attributes.preset_mode}`
|
||||
@@ -206,7 +209,8 @@ export async function POST(req: Request) {
|
||||
// Живой контекст (время + снимок устройств) — только для LLM-пути (fast-path
|
||||
// выше уже вышел). Даёт модели понимание, что включено и что вообще есть в
|
||||
// доме, чтобы рассуждать про умный дом и не переспрашивать очевидное.
|
||||
const fullSys = sysPrompt + (await buildLiveContext())
|
||||
const liveCtx = await buildLiveContext()
|
||||
const fullSys = sysPrompt + liveCtx
|
||||
|
||||
// ======== GROQ ========
|
||||
if (provider === 'groq') {
|
||||
@@ -281,7 +285,7 @@ export async function POST(req: Request) {
|
||||
try {
|
||||
for (let round = 0; round < MAX_TOOL_ROUNDS; round++) {
|
||||
const t0 = Date.now()
|
||||
const resp = await claudeRequest(fullSys, messages, anthropicTools)
|
||||
const resp = await claudeRequest(sysPrompt, liveCtx, messages, anthropicTools)
|
||||
console.log(`[voice/chat] claude ${agent} r${round+1} ${Date.now()-t0}ms stop=${resp.stop_reason} in=${resp.usage?.input_tokens} out=${resp.usage?.output_tokens}`)
|
||||
const content: any[] = resp.content || []
|
||||
const stopReason = resp.stop_reason || 'end_turn'
|
||||
|
||||
Reference in New Issue
Block a user