Files
eaiadminandClaude Code 81366ca273 fix(audio): 断连后能接着跑完 —— 失败消息上的重试 + 步骤编号统一
用户报「卡在步骤 3」,实际断在第 5 步 structure:请求发出 46ms 后浏览器
连接断开,Gin 的 Request.Context() 被取消,上游回 499,后端包成 400。
服务端与前端应用层都没有任何主动取消(全仓 grep cancel/AbortController
零命中),是一次客户端断连。

断连本身无法在代码里杜绝,但它暴露了三个真 bug:

1. 报错文案说「第 1 步」,右栏说第 5 步 —— 尾部两步按自己这一轮从 1 数。
   新增 STEP_NUMBERS,报错与右栏共用同一份编号(这就是「步骤 3」这个
   说法的来源:用户看到的第一个数字就对不上)。
2. 断连后界面上没有任何续跑入口,任务永远停在 4/6(右栏六步是只读的)。
   失败的那条助手消息上挂「🔁 重试」。
3. 无脑重跑会在同一任务里留第二份「结构化纪要」,两份差别用户看不出来。
   resumeAudioSkill 收 skipSteps,按 task_run.action_key 判「跑过没有」
   —— 不用产物类型判,document/checklist 别的技能也在用。

另修:待确认那条消息改用 reactive()。messages 是 ref([]),push 进去的对象
模板读时才被代理,而代码改的是那个变量,改普通对象不触发重渲染,
用户会一直看到「正在继续整理...」。

验证(临时任务 100,已删,先备份 db):CDP setBlockedURLs 掐掉 structure
复现同形断连 → 消息挂出重试按钮,文案与右栏同为第 5 步;后端补跑一次
structure(模拟响应丢失但已落库)→ 点重试只跑 minutes,落库 document 1 份、
checklist 1 份。反证:再手工跑一次 structure,同名产物立刻变 2 份。
详见 bugs_and_errors.md E14。

E15(未修,记录在案):DeleteMyTask 只删 task_record,run 与 artifact 全成
孤儿,产物 content_text 是完整逐字稿。删除语义务必先定硬删还是软删。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-27 00:04:19 +08:00

249 lines
10 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"agent_routes": {
"embed_gen": "embed_route_llamacpp_nomic",
"image_gen": "image_route_openrouter_gpt_image_2",
"video_gen": "video_route_openrouter_veo_3",
"path_coach": "chat_route_lmuai_deepseek_v4_flash",
"title_gen": "chat_route_lmuai_deepseek_v4_flash",
"audio_transcribe": "audio_route_auto",
"audio_transcribe_llm": "chat_route_lmuai_deepseek_v4_flash_doc"
},
"audio_routes": {
"audio_route_local_whisper": {
"base_url": "http://127.0.0.1:8090/v1",
"description": "语音转写 · 本机 faster-whisper large-v3 + pyannote 3.1(音频不出本机)。由 deploy/eai_agentplatform-asr.service 常驻在 127.0.0.1:8090;服务不在时 audio_route_auto 会改走 fallback_routes 里的云端路由,并在转写产物里标注「音频已出本机」。timeout 定在 840s 而不是一小时:前端 api/audioSkill.js 给这一步的上限是 15 分钟,后端必须在它之前自己收手(否则用户看到的是 axios 超时,而后端还在跑),同时 840s 里还留得下云端那 600s 的回退预算",
"endpoint": "/audio/transcriptions",
"model": "large-v3",
"provider": "local_asr",
"short_model_name": "whisper large-v3",
"short_route_name": "本地",
"supports_speakers": true,
"timeout_seconds": 840
},
"audio_route_siliconflow_diarize": {
"description": "语音转写 · SiliconFlow / XingChen ASR Diarize(云端,音频会出本机;本地服务不可用时的回退,也可由管理员手动指定)",
"endpoint": "/audio/transcriptions",
"model": "XingChenAGI/XingChenASR-Diarize-V3.0",
"provider": "siliconflow",
"short_model_name": "XingChen ASR Diarize",
"short_route_name": "SiliconFlow",
"supports_speakers": true,
"timeout_seconds": 600
},
"audio_route_siliconflow_qwen3": {
"description": "语音转写 · SiliconFlow / Qwen3-ASR(云端,音频会出公网;无说话人分离)",
"endpoint": "/audio/transcriptions",
"model": "Qwen/Qwen3-ASR-1.7B",
"provider": "siliconflow",
"short_model_name": "Qwen3 ASR",
"short_route_name": "SiliconFlow",
"supports_speakers": false,
"timeout_seconds": 600
}
},
"chat_routes": {
"chat_route_lmuai_deepseek_v4_flash": {
"description": "LMUAI / DeepSeek Flash。max_tokens 从 4096 提到 32768(2026-09-26):4096 是当初只按「聊天」估的,但这条路由是 default_route,用户在对话框里选过模型后这个选择会被记进 localStorage 并**一路带到技能内部的加工步骤**(全仓库只有语音转写的第 3、4 步消费 ai_route_id,见 skills/api/audio_handlers.go 的 resolveAudioChatRoute)。于是它会顶掉技能自带的 _doc 路由,让「整理段落」在推理模型思考完之前就把预算耗光、正文 0 字。上限是天花板不是配额,模型写完就停,抬高不会让聊天变慢变贵(实测见 _doc 那条的说明)",
"endpoint": "/chat/completions",
"max_tokens": 32768,
"model": "deepseek-v4-flash",
"provider": "lmuai",
"short_model_name": "DeepSeek V4 Flash",
"short_route_name": "LMUAI",
"temperature": 0.7
},
"chat_route_lmuai_deepseek_v4_flash_doc": {
"description": "LMUAI / DeepSeek Flash(长文输出档,max_tokens=32768)· 供逐字稿整理这类要产出一整篇文档的技能使用。为什么不复用上面那条 4096 的:这是推理模型,思考与正文共用 max_tokens,而思考的长度跟输入几乎不成比例(实测 1200 字的输入,思考照样写到 7169 字)。4096 下正文一个字都写不出来(六次实测只有一次成功)。再说为什么是 32768 而不是 8192:纪要步骤最后要把各段结果**归并**成一份,那是全流程最长的一次输入(实测 8628 字),8192 下 finish_reason=length、正文 0 字,16384 才出稿、32768 又快又稳。上限提高**不会**让逐块调用变慢或变贵——上限是天花板不是配额,模型写完就停:实测同一批 11 段,8192 与 32768 两档的用时(18.6s / 19.2s)与 completion token(均 4928 / 5094)基本一致。调小这个值之前请先看 audio_transcribe/prompts.go 里的实测表",
"endpoint": "/chat/completions",
"max_tokens": 32768,
"model": "deepseek-v4-flash",
"provider": "lmuai",
"short_model_name": "DeepSeek V4 Flash(长文档)",
"short_route_name": "LMUAI",
"temperature": 0.7
},
"chat_route_ollama_qwen": {
"description": "本地对话 · llama.cpp / Qwen3.5 4B",
"endpoint": "/chat/completions",
"max_tokens": 512,
"model": "Qwen3.5-4B-Q4_K_M.gguf",
"provider": "llamacpp",
"short_model_name": "Qwen3.5 4B",
"short_route_name": "本地对话",
"temperature": 0.7,
"timeout_seconds": 90
},
"chat_route_ollama_qwen_fast": {
"description": "本地快聊 · llama.cpp / Qwen3.5 4B",
"endpoint": "/chat/completions",
"max_tokens": 512,
"model": "Qwen3.5-4B-Q4_K_M.gguf",
"provider": "llamacpp",
"short_model_name": "Qwen3.5 4B",
"short_route_name": "本地快聊",
"temperature": 0.3
},
"chat_route_openrouter_deepseek_v3": {
"description": "OpenRouter / DeepSeek V3.2",
"endpoint": "/chat/completions",
"max_tokens": 4096,
"model": "deepseek/deepseek-v3.2",
"provider": "openrouter",
"short_model_name": "DeepSeek V3.2",
"short_route_name": "OpenRouter",
"temperature": 0.6
},
"chat_route_openrouter_deepseek_v4_flash": {
"description": "OpenRouter / DeepSeek V4 Flash 0731",
"endpoint": "/chat/completions",
"max_tokens": 4096,
"model": "deepseek/deepseek-v4-flash-0731",
"provider": "openrouter",
"short_model_name": "DeepSeek V4 Flash 0731",
"short_route_name": "OpenRouter",
"temperature": 0.7
},
"chat_route_openrouter_gpt_5": {
"description": "OpenRouter / GPT 5.4",
"endpoint": "/chat/completions",
"max_tokens": 8192,
"model": "openai/gpt-5.4",
"provider": "openrouter",
"short_model_name": "GPT 5.4",
"short_route_name": "OpenRouter",
"temperature": 0.7
},
"chat_route_openrouter_grok_4": {
"description": "OpenRouter / Grok 4.20",
"endpoint": "/chat/completions",
"max_tokens": 4096,
"model": "x-ai/grok-4.20",
"provider": "openrouter",
"short_model_name": "Grok 4.20",
"short_route_name": "OpenRouter",
"temperature": 0.6
},
"chat_route_siliconflow_deepseek_v4_flash": {
"description": "SiliconFlow / DeepSeek V4 Flash",
"endpoint": "/chat/completions",
"max_tokens": 4096,
"model": "deepseek-ai/DeepSeek-V4-Flash",
"provider": "siliconflow",
"short_model_name": "DeepSeek V4 Flash",
"short_route_name": "SiliconFlow",
"temperature": 0.7
}
},
"default_audio_route": "audio_route_local_whisper",
"default_embed_route": "embed_route_llamacpp_nomic",
"default_route": "chat_route_lmuai_deepseek_v4_flash",
"description": "eai_agentplatform AI 路由配置 — 按场景分类定义多条路由,支持 provider/模型切换",
"embed_routes": {
"embed_route_llamacpp_nomic": {
"base_url": "http://127.0.0.1:8081/v1",
"description": "本地向量 · llama.cpp / Nomic Embed v1.5",
"endpoint": "/embeddings",
"model": "nomic-embed-text-v1.5.Q4_K_M.gguf",
"provider": "llamacpp",
"short_model_name": "Nomic Embed v1.5",
"short_route_name": "本地向量",
"timeout_seconds": 30
},
"embed_route_ollama_bge_m3": {
"description": "本地向量 · Ollama / BGE-M3",
"endpoint": "/embeddings",
"model": "bge-m3",
"provider": "ollama",
"short_model_name": "BGE-M3",
"short_route_name": "本地向量"
},
"embed_route_openrouter_text_v3": {
"description": "OpenRouter / text-embedding-3-small",
"endpoint": "/embeddings",
"model": "openai/text-embedding-3-small",
"provider": "openrouter",
"short_model_name": "text-embedding-3-small",
"short_route_name": "OpenRouter"
}
},
"fallback_routes": {
"chat_route_lmuai_deepseek_flash": [
"chat_route_ollama_qwen_fast",
"chat_route_ollama_qwen"
],
"chat_route_openrouter_deepseek_v3": [
"chat_route_openrouter_grok_4",
"chat_route_ollama_qwen"
],
"chat_route_openrouter_deepseek_v4_flash": [
"chat_route_openrouter_deepseek_v3",
"chat_route_openrouter_grok_4",
"chat_route_ollama_qwen"
],
"chat_route_openrouter_grok_4": [
"chat_route_ollama_qwen"
],
"chat_route_siliconflow_deepseek_v4_flash": [
"chat_route_ollama_qwen_fast",
"chat_route_ollama_qwen"
],
"audio_route_local_whisper": [
"audio_route_siliconflow_diarize"
],
"embed_route_llamacpp_nomic": [
"embed_route_openrouter_text_v3"
],
"embed_route_ollama_bge_m3": [
"embed_route_openrouter_text_v3"
],
"embed_route_openrouter_text_v3": [
"embed_route_ollama_bge_m3"
]
},
"image_routes": {
"image_route_ollama_llava": {
"description": "本地图像 · Ollama / LLaVA",
"endpoint": "/chat/completions",
"max_tokens": 2048,
"model": "llava",
"provider": "ollama",
"short_model_name": "LLaVA",
"short_route_name": "本地图像",
"temperature": 0.7
},
"image_route_openrouter_flux": {
"description": "OpenRouter / FLUX 1.1 Pro",
"endpoint": "/images/generations",
"max_tokens": 1024,
"model": "black-forest-labs/flux-1.1-pro",
"provider": "openrouter",
"short_model_name": "FLUX 1.1 Pro",
"short_route_name": "OpenRouter",
"temperature": 1
},
"image_route_openrouter_gpt_image_2": {
"description": "OpenRouter / GPT 5.4 Image 2",
"endpoint": "/images/generations",
"max_tokens": 4096,
"model": "openai/gpt-5.4-image-2",
"provider": "openrouter",
"short_model_name": "GPT 5.4 Image 2",
"short_route_name": "OpenRouter",
"temperature": 1
}
},
"video_routes": {
"video_route_openrouter_veo_3": {
"description": "OpenRouter / Google Veo 3",
"endpoint": "/videos/generations",
"model": "google/veo-3",
"max_tokens": 4096,
"provider": "openrouter",
"short_model_name": "Veo 3",
"short_route_name": "OpenRouter",
"temperature": 0.7
}
},
"version": "2.1.0"
}