跳转至

会话记录 2026-04-05 — Web UI 安全与架构修复

时间:2026-04-05 凌晨
版本:v0.15.0(基于 8d5d21e
主题:通过对话记录审计发现并修复 Web UI 的安全隐患和架构缺陷


一、发现过程

灵通老师要求查看 Web UI 的对话记录。通过直接查询 chat_messages 表(145条记录),在对话内容中发现了多个异常行为模式,进而追溯代码发现了深层的架构问题。

对话记录中的异常

时间段 异常行为 消息ID
01:17-01:19 灵依凭空编造"明天下午开会",用户反复追问后才承认日程中不存在 124-131
01:23-01:45 用户要求搜索AI伦理进展,搜索工具连续失败,灵依却说"我无法访问互联网" 134-145
00:47-00:50 对话中灵依行为正常,但底层代码存在会话泄露风险 108-118

二、发现的问题及根因分析

2.1 API Key 明文硬编码 — 安全问题

严重程度:高

DashScope API Key 直接写在 4 个源文件的代码中:

文件 写法 严重性
web_app.py:23 纯硬编码,无环境变量 fallback 最高
agent.py:21-23 os.environ.get(..., "sk-87b6...")
web.py:14-16 os.environ.get(..., "sk-87b6...")
voicecall.py:284-286 os.environ.get(..., "sk-87b6...")

web_app.py 最为严重——完全跳过环境变量,直接硬编码。其他 3 个文件虽然读了环境变量,但把 key 作为默认值写在了代码里,推到 GitHub 会直接泄露。

2.2 对话状态全局共享 — 隐私/架构问题

严重程度:高

_conversation 是进程级全局 list,所有 WebSocket 客户端共享同一段对话上下文。

后果: - 用户 A 发的消息会被包含在用户 B 的 LLM 上下文里(_conversation[-20:]) - 多个客户端连接时,互相能看到对方的对话历史(history 推送) - 单用户场景下暂时不严重,但多设备同时连接时会出现混乱

2.3 对话列表无限增长 — 资源问题

严重程度:中

_conversation 只追加不清理。启动时加载最近 40 条,之后只增不减。虽然发给 LLM 时只取后 20 条(_conversation[-20:]),但内存中的列表持续膨胀,长时间运行后会占用大量内存。

2.4 LLM 幻觉 — 模型层面问题(未修复)

严重程度:中(对话体验影响大,但无代码漏洞)

灵依在消息 124-131 中凭空编造了"明天下午开会"的安排。用户追问三次才勉强承认。

根因:系统提示词(agent.py:481-486)已有"绝对不许编造"规则,但 qwen-turbo 模型仍会在缺少数据时自行补全。这不是代码 bug,是模型能力边界。更强的模型(如 qwen-plus)或更严格的 prompt 约束可能改善。

2.5 搜索工具失败 — 工具链路问题(未修复)

严重程度:中

用户要求搜索AI伦理进展(消息134),连续4次失败。灵依在失败后回答"我无法直接访问互联网"(消息137),但实际上 search_web 工具是存在的。

根因search_web 通过抓取 DuckDuckGo HTML 实现(tools.py:369-391),可能被反爬机制拦截或网络不通。更深层的问题是 LLM 在工具调用失败后,没有正确回退为"搜索工具暂时不可用",反而否定了自身的能力——说明 LLM 对自己的工具集理解不够。


三、修复内容

已修复(4项)

修改 涉及文件 具体改动
API Key 安全 web_app.py, agent.py, web.py, voicecall.py 删除硬编码 key,统一改为 os.environ.get("DASHSCOPE_API_KEY", "")
对话隔离 web_app.py _conversation 全局变量取消;每个 WS 连接创建独立的 local_conv;bridge 连接使用独立的 _bridge_conv
对话限长 web_app.py 新增 _MAX_CONVERSATION = 60,每次对话后检查并截断
LLM 接口改造 web_app.py _chat_llm_with_context()_smart_reply() 新增 conv 参数,支持传入不同的对话上下文

变更文件统计

 src/lingyi/agent.py             |  4 +-
 src/lingyi/voicecall.py         |  4 +-
 src/lingyi/web.py               |  4 +-
 src/lingyi/web_app.py           | 50 +++++++++++++++++++++----------
 4 files changed, 40 insertions(+), 22 deletions(-)

部署注意

API Key 不再硬编码,启动前必须设置环境变量:

export DASHSCOPE_API_KEY="你的实际key"
lingyi web

测试结果

251 passed, 1 deselected(跳过的 test_today_schedules 是预存在的周日运行失败,与本次修改无关)。


四、未修复项与后续建议

优先级 项目 说明
P1 LLM 幻觉 需要更强的模型或更严格的 prompt 约束,属于调参范畴而非代码修复
P1 search_web 工具健壮性 DuckDuckGo HTML 抓取不可靠,考虑备用搜索引擎或 API 调用方式
P2 web_app.py 中的 ruff warnings 4 个 unused import(datetime)、1 个 unused variable(disc_id)、1 个空 f-string
P3 预存测试失败 test_today_schedules 周日运行时 assert 失败,测试应 mock date.today() 而非依赖实际星期

五、经验教训

  1. 对话记录是最好的审计材料 — 通过查看真实对话,发现了代码审查容易忽略的运行时问题(幻觉、工具失败)
  2. 安全不能靠约定 — API Key 硬编码在 4 个文件里,说明没有统一的密钥管理策略。今后应考虑集中的配置管理
  3. 全局状态是隐患_conversation 全局共享在设计时可能是"简单够用",但在多连接场景下是严重缺陷
  4. 模型能力 ≠ 工具能力 — LLM 拥有 search_web 工具却不"知道"自己能用,导致失败时给出错误解释。系统提示词需要更明确地列出可用工具