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
|
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 }
|
const body: any = { model: 'claude-haiku-4-5-20251001', max_tokens: MAX_TOKENS, system, messages }
|
||||||
if (tools.length > 0) body.tools = tools
|
if (tools.length > 0) body.tools = tools
|
||||||
const opts: any = {
|
const opts: any = {
|
||||||
@@ -137,6 +139,7 @@ async function buildLiveContext(): Promise<string> {
|
|||||||
const s = d.sensors || {}
|
const s = d.sensors || {}
|
||||||
const lines: string[] = []
|
const lines: string[] = []
|
||||||
for (const [id, st] of Object.entries<any>(states)) {
|
for (const [id, st] of Object.entries<any>(states)) {
|
||||||
|
if (st.state === 'unavailable' || st.state === 'unknown') continue
|
||||||
const name = st.attributes?.friendly_name || id
|
const name = st.attributes?.friendly_name || id
|
||||||
let extra = ''
|
let extra = ''
|
||||||
if (st.attributes?.preset_mode) extra += `, режим ${st.attributes.preset_mode}`
|
if (st.attributes?.preset_mode) extra += `, режим ${st.attributes.preset_mode}`
|
||||||
@@ -206,7 +209,8 @@ export async function POST(req: Request) {
|
|||||||
// Живой контекст (время + снимок устройств) — только для LLM-пути (fast-path
|
// Живой контекст (время + снимок устройств) — только для LLM-пути (fast-path
|
||||||
// выше уже вышел). Даёт модели понимание, что включено и что вообще есть в
|
// выше уже вышел). Даёт модели понимание, что включено и что вообще есть в
|
||||||
// доме, чтобы рассуждать про умный дом и не переспрашивать очевидное.
|
// доме, чтобы рассуждать про умный дом и не переспрашивать очевидное.
|
||||||
const fullSys = sysPrompt + (await buildLiveContext())
|
const liveCtx = await buildLiveContext()
|
||||||
|
const fullSys = sysPrompt + liveCtx
|
||||||
|
|
||||||
// ======== GROQ ========
|
// ======== GROQ ========
|
||||||
if (provider === 'groq') {
|
if (provider === 'groq') {
|
||||||
@@ -281,7 +285,7 @@ export async function POST(req: Request) {
|
|||||||
try {
|
try {
|
||||||
for (let round = 0; round < MAX_TOOL_ROUNDS; round++) {
|
for (let round = 0; round < MAX_TOOL_ROUNDS; round++) {
|
||||||
const t0 = Date.now()
|
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}`)
|
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 content: any[] = resp.content || []
|
||||||
const stopReason = resp.stop_reason || 'end_turn'
|
const stopReason = resp.stop_reason || 'end_turn'
|
||||||
|
|||||||
Reference in New Issue
Block a user