ylhan
|
98bbba93d0
|
Phase 4:补齐通用记忆闭环(验收 9/9 通过)
按 P1-Pipecat Flows Agent化与记忆改造交接.md 的 Phase 4 完成。
新增 p1/phase4_acceptance.py:跑真实服务端验 7 条,每条之间查数据库。
实测结果(2026-09-16)
1. "记住我不吃香菜" → confirmed 落库 ✅
2. **新连接** "我不吃什么?" → "你不吃香菜。" ✅ 连接开始时加载档案生效
3. "我今天吃了香菜" → 不新增 confirmed,模型还追问了是否口味变了 ✅
4. "其实我现在吃香菜了" → 同键仍只一条 confirmed,值已更新 ✅
5. "忘掉我的饮食偏好" → 已删除 ✅
6/7. 访客与跨用户隔离 → 由单测覆盖(客户端不支持切身份)
实现:会话开始时加载稳定档案
- load_stable_memories():取已确认、未过期记忆(身份未确认返回空)
- _conversation_node 改用 build_system_prompt,与 legacy 共用同一套
人格与记忆注入格式;记忆进**同一条** system 消息,仍不用 role_message
修掉一个真实缺陷:Flows 路径误用了语音的 max_tokens
- 症状:一句"忘掉我的饮食偏好",服务端日志
"Failed to parse function call arguments: {"query": "饮食"(JSON 被截断),
回复为空、记忆没删掉,且**没有任何报错**
- 根因:Flows 路径沿用了语音的 max_tokens=200(为"回复要短"而设)。
原始 API 对照实测:max_tokens=200 时模型 finish=stop、根本不调工具;
600 时正常产生 tool_calls 且参数 JSON 完整
- 修法:新增 AgentConfig.max_tokens(AI_AGENT_MAX_TOKENS,默认 600),
Flows 路径用它,语音路径仍用 200
新增 client/test_client.py 能力(为验收所需)
- RTVIReplies:收服务端 RTVI 文本消息(bot-output / bot-transcription)
- 打印 BOT_REPLY 供验收脚本断言
回归:test_agent_tools 45/45、test_flows_runtime 24/24、
test_memory 30/30、test_identity 19/19
服务器已改回 AI_AGENT_RUNTIME=legacy(改默认是 Phase 7 的事)
|
2026-09-16 14:54:42 +08:00 |
|
ylhan
|
4f621dc95b
|
Phase 3:Flows 接管网页文字路径(默认仍 legacy)
按 P1-Pipecat Flows Agent化与记忆改造交接.md 的 Phase 3 完成。
**语音路径保持 legacy**,文字路径可由 AI_AGENT_RUNTIME=flows 切换。
服务器实测通过工具、姓名、记忆三项验收,随后按文档要求改回 legacy。
新增 app/agent/flows_runtime.py
- FlowsBridge:LLM 文本帧 → RTVI 消息 + 分句 TTS,产出与 legacy 的
_run_turn 一致(bot-llm-started → 逐 token bot-llm-text → stopped
→ bot-transcription / bot-output)
- UserTextRecorder:截下用户原话供策略层判定语义等级
- build_flows_parts / make_flow_manager:拆成两段,解决
"FlowManager 要 worker、worker 要等管线" 的先后依赖
- 节点只用 task_messages,**不用 role_message**(避免两条 system 消息)
- respond_immediately=False(不自动开口)
- handler 用闭包捕获 ctx_factory,不用模块级全局(并发会话会串身份)
新增 app/agent/llm_service.py
- 固化 Phase 1 spike 的选型:复用 DeepSeekLLMService,显式覆盖模型名
(Pipecat 默认的 deepseek-v4-flash 不存在)
配置 app/config.py
- 新增 AgentConfig + AI_AGENT_RUNTIME,**默认 legacy**
改造 services/bot_server.py
- EngineProcessor 加 owns_text:flows 模式下语音仍归它,文字帧往下传
- runtime_deps() 暴露 memory/identity/session/tts,两条路径共用同一份资源
(避免各建一份 SQLite 连接或各加载一次 TTS)
- **_run_task 改用 PipelineRunner**:直接 task.run() 时 runner 没挂上,
Flows 的工具执行会失败("runner is not set; call attach() first"),
异常被转成给 LLM 的通用错误串,默认日志看不到。这正是 Phase 1 spike
记录的坑 2,集成时又踩了一次。
新增 app/tests/test_flows_runtime.py(22 项,不依赖网络)
新增 deploy.sh
- **不用 --delete**、一次只同步一个目录、显式排除清单。
起因见下。
客户端 client/test_client.py 加 --text 模式(RTVI send-text)
- 信封字段实测校正两次:**是 id 不是 msg_id**,**data.content 不是 text**;
写错会被服务端以 "Invalid RTVI transport message" 拒掉且客户端无感知
- 等待条件改为"等到非静音音频",不能数音频块——WebRTC 空闲时也在推静音
服务器实测(2026-09-16)
- legacy 文字:11.2s 音频 / 25 个有声段
- flows 文字:9.3s 音频 / 18 个有声段,首音约 2.8s
- flows 记忆闭环:只说"记住我不吃香菜" → 工具写入 confirmed 记忆
→ 数据库确认 #4 [confirmed] preference 饮食偏好=不吃香菜
- 称呼"林"从档案恢复
已知问题(留给 Phase 4/7)
- Pipecat 报 "Both system_instruction and an initial system message in
context are set" 警告。来源未查明(我只用了 task_messages)。
切回本地 vLLM 时可能 400,因为该后端拒绝多条 system 消息。
- Flows 路径暂不暴露 web_search(交接文档要求分阶段,搜索仍走 legacy)
|
2026-09-16 14:13:32 +08:00 |
|
ylhan
|
20cfaa6ef7
|
基线:姓名档案修复、疑问句防误写、搜索与传输测试
这是进入 Pipecat Flows 改造前的回滚点。
提交时已核对本地与线上代码 md5 一致(engine.py 7e97bad8、
bot_server.py 1cf543ae),所以这个提交就是当前线上状态。
内容(此前一直在线上运行但未提交的改动):
- 姓名档案:用户自报"我叫林"同步写 confirmed 姓名,重连后恢复
- 疑问句防误写:"谁吗"之类的疑问句不再被覆盖成姓名
- 新增 test_profile_memory.py(姓名档案专项回归)
- 新增 test_profile_live.py(需要真实 LLM 的现场测试)
- 搜索、身份、记忆测试的相应补充
背景:下一步要按 P1-Pipecat Flows Agent化与记忆改造交接.md
渐进引入 Pipecat Flows,交接文档明确要求先保护基线、不得
reset/checkout/覆盖现有改动。此提交即该基线。
|
2026-09-16 12:48:18 +08:00 |
|
ylhan
|
719fc13e48
|
修复网页对话并接入 SearXNG 搜索
|
2026-09-16 11:17:41 +08:00 |
|
ylhan
|
35e107c290
|
助手本体:会话引擎、LLM 路由、记忆、身份、语音适配
从 Obsidian 笔记库剥离为独立仓库。规划文档与 P0 报告留在笔记库,
代码(助手本体、TTS 服务、P0 基准脚本、ESP32 固件)在此。
架构:服务器是助手,本地是客户端
- 助手本体跑在 cadadmin-server,N5095 只做 USB 外设桥与网络桥接
- 起因:实测 N5095 无 AVX2,跑不动可用的语音模型
当前技术栈
- LLM:DeepSeek deepseek-flash(云端,必须关思考)
- TTS:Qwen3-TTS 1.7B(服务器 3090,独立 HTTP 服务)
- STT:Zipformer 中英双语 int8(CPU,中文识别率未测)
实测:端到端 16/16 通过,首音延迟 1545ms
(对比:本地 LLM + vits-zh-ll 是 179ms,但音色不满意——音质与延迟
在此硬件上此消彼长)
设计要点
- MemoryStore 接口按"可能远程"设计(全 async、可超时、可失败)
- user_id / session_id / track_id 三者分开,人脸只作候选不自动切身份
- 记忆查询强制带 owner_user_id,无按 id 单独取的口子
- 自动抽取的记忆是"候选",默认不参与检索
- 异步写记忆绑定创建时的身份,不读"当前用户"
- 引擎与传输解耦,只用文件音频即可端到端测试
模型与音频产物不进版本管理(1.1GB),由 download_models.sh 恢复
|
2026-09-15 11:05:09 +08:00 |
|