fix(chat): 流式问答中文乱码 + 问答模型链换成专用文字大模型
## 乱码修复 Gemini 流式接口 resp.iter_lines(decode_unicode=True) 没有显式设置 resp.encoding,requests 自己猜编码猜错了(Gemini 的 SSE 响应 Content-Type 不带 charset 参数),导致中文变成典型的 UTF-8 被当 Latin-1 解码的乱码。 fam-core 转发这一跳的 requests.iter_lines 调用有同样的坑,一并修了。 两处响应的 Content-Type 都补上 charset=utf-8,减少下游再犯同样错误的机会。 顺手用 latin-1/utf-8 往返把 NAS chat_history 里已经存了乱码的 3 条历史记录 恢复成正常文字。 ## 问答模型链重新设计(跟视频分析完全独立) 用户要求问答不再用 flash/omni,优先用 NVIDIA 免费文字模型里上下文最大的几个, 不行再退 Gemini 非 flash 文字模型,最后本地 Ollama 兜底。 - base_adapter 新增 usage 字段(纯标记,不影响行为) - qa.py 的 QAOrchestrator 只挑 role='text' 的适配器参与问答(按 config 出现 顺序决定降级顺序),role='vision' 的视频分析适配器(gemini-flash-latest / nvidia omni)不再参与问答,两条链路彻底解耦 - 新增问答专用 NVIDIA 文字模型链(同一适配器内部 model_chain 降级): nemotron-3-ultra-550b-a55b(1M上下文/561B) -> nemotron-3-super-120b-a12b (1M上下文/124B) -> openai/gpt-oss-120b(131K上下文/117B)。三个都用真实 API 调用验证过当前账号可访问;同时验证过 llama-3.1-70b-instruct 和 nemotron-super-49b-v1.5 都收到"08/25/2026 起弃用"通知,排除; nemotron-ultra-253b/mistral-large-2/nemotron-4-340b/kimi-k2.6 在目录里 能看到但实测调用返回 404"账号无权限",排除 - 新增问答专用 Gemini 非 flash 文字模型:gemini-pro-latest -> gemini-2.5-pro (1M 上下文,复用视频分析同一批多 key 轮换) - /api/edge/chat/ask(/stream) 默认 max_tokens 从 1024 提到 3072:新链路 优先用的都是"推理"模型,回答前会先吐一段思考过程,1024 经常在思考阶段 就被截断,用户永远看不到真正答案 新增 test_qa.py::test_init_only_keeps_text_role_adapters_in_config_order 验证角色过滤+顺序正确。 本地检查过 Ollama 服务本身:systemd enabled+running(8h 正常运行, qwen2.5:7b 已加载),并非没启动——用户观察到的现象另有原因。
This commit is contained in:
@@ -1,6 +1,34 @@
|
||||
from fam_edge.qa import QAOrchestrator
|
||||
|
||||
|
||||
class _FakeRoleAdapter:
|
||||
"""用于 __init__ 过滤逻辑测试,只需要 get_role(),不需要真的能 chat。"""
|
||||
def __init__(self, provider_name, role):
|
||||
self.provider_name = provider_name
|
||||
self.role = role
|
||||
|
||||
def get_role(self):
|
||||
return self.role
|
||||
|
||||
|
||||
def test_init_only_keeps_text_role_adapters_in_config_order(monkeypatch):
|
||||
"""核心诉求: 问答链路只用 role='text' 的适配器(跟视频分析用的
|
||||
role='vision' 完全隔离),且顺序沿用 config.yaml 里 models 数组的出现
|
||||
顺序,不需要额外的 qa_order 配置。"""
|
||||
fake_adapters = [
|
||||
_FakeRoleAdapter("gemini", "vision"), # 视频分析用的 gemini-flash,不该出现
|
||||
_FakeRoleAdapter("nvidia", "vision"), # 视频分析用的 nvidia omni,不该出现
|
||||
_FakeRoleAdapter("nvidia", "text"), # 新的问答专用 nvidia 文字模型链
|
||||
_FakeRoleAdapter("gemini", "text"), # 新的问答专用 gemini 非 flash 文字模型
|
||||
_FakeRoleAdapter("ollama", "text"), # 本地兜底
|
||||
]
|
||||
monkeypatch.setattr("fam_edge.qa.load_config", lambda: {"models": []})
|
||||
monkeypatch.setattr("fam_edge.qa.build_adapters", lambda models: fake_adapters)
|
||||
qa = QAOrchestrator()
|
||||
assert [a.role for a in qa.adapters] == ["text", "text", "text"]
|
||||
assert len(qa.adapters) == 3
|
||||
|
||||
|
||||
class _FakeAdapter:
|
||||
def __init__(self, provider_name, chunks=None, raises=False):
|
||||
self.provider_name = provider_name
|
||||
|
||||
Reference in New Issue
Block a user