Files
ai-companion/deploy.sh
T
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

73 lines
2.7 KiB
Bash
Executable File
Raw 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.
#!/usr/bin/env bash
# 部署到服务器。
#
# **为什么要有这个脚本**:2026-09-16 我用一条 rsync 命令把服务器上的东西
# 删了一大片,教训有三条,都固化在这里:
#
# 1. **绝不用 `--delete`。** 服务器上还有本地没有的东西(.venv、models 软链、
# logs、数据库软链等)。`--delete` 会把它们全删掉。
# 实测后果:.venv/bin 与 100+ 个 *.dist-info 被删、services/ 被清空、
# README/部署说明被删、models 软链被删。
# 2. **一次只同步一个目录,不要多源。** 多源 rsync 不带 --relative 时,
# 会把 `app/` 的内容**平铺**到目标根目录,而不是放进 `app/` 下。
# 3. **排除清单要显式。** 即使不用 --delete,也别把 __pycache__ 之类带过去。
#
# 用法:
# ./deploy.sh # 同步代码
# ./deploy.sh --restart # 同步后重启两个服务
set -uo pipefail
HOST="${AI_DEPLOY_HOST:-yonglin@cadadmin-server.taild0f91d.ts.net}"
DEST="${AI_DEPLOY_DEST:-~/ai-companion}"
HERE="$(cd "$(dirname "$0")" && pwd)"
# 服务器上不该被本地覆盖的东西——保留在服务器上
EXCLUDES=(
--exclude '__pycache__'
--exclude '*.pyc'
--exclude '.baseline'
--exclude '.venv'
--exclude 'logs'
--exclude 'models'
--exclude 'out'
--exclude 'p0/stt_tts_bench/models'
)
sync_one() { # sync_one <本地目录> <远端子路径>
echo " → $2"
rsync -az "${EXCLUDES[@]}" -e "ssh -o BatchMode=yes" \
"$HERE/$1" "$HOST:$DEST/$2"
}
echo "部署到 $HOST:$DEST"
sync_one "app/" "app/"
sync_one "services/" "services/"
sync_one "client/" "client/"
sync_one "p1/" "p1/"
for f in README.md 部署说明.md requirements.txt; do
[ -f "$HERE/$f" ] && rsync -az -e "ssh -o BatchMode=yes" "$HERE/$f" "$HOST:$DEST/"
done
# 把 requirements 里没有、但运行需要的包装上(幂等)
ssh -o BatchMode=yes "$HOST" "cd $DEST && .venv/bin/pip -q install pipecat-ai-small-webrtc-prebuilt 2>&1 | tail -1"
if [ "${1:-}" = "--restart" ]; then
echo "重启服务"
ssh -o BatchMode=yes "$HOST" 'bash -s' <<REMOTE
cd ~/ai-companion
for p in \$(pgrep -f "services/bot_server|tts_server.py" 2>/dev/null); do kill "\$p" 2>/dev/null; done
sleep 3
cd ~/tts-qwen && setsid nohup .venv/bin/python tts_server.py --port 18040 > logs/tts_service.log 2>&1 < /dev/null &
sleep 1
cd ~/ai-companion && setsid nohup .venv/bin/python services/bot_server.py --host 0.0.0.0 --port 7860 > logs/bot_server.log 2>&1 < /dev/null &
for i in \$(seq 1 30); do
curl -sf -o /dev/null http://127.0.0.1:7860/health 2>/dev/null && { echo " bot ✅"; break; }
sleep 3
done
curl -sf http://127.0.0.1:18040/health 2>/dev/null | grep -q model_loaded && echo " tts ✅" || echo " tts ⚠️"
REMOTE
fi
echo "完成"