43 KiB
43 KiB
Dev Changelog — Full
完整的开发改动记录,按时间倒序排列。作为主动 RAG 的数据源,用户手动唤醒时读取。
记录
[CL-20260413-2320] 2026-04-13 23:20 — 集成 Mem0 记忆系统:滑动窗口 + 跨会话长期记忆
- tags: Mem0, 记忆系统, 上下文管理, 长期记忆, Ollama, embedding, 滑动窗口
- affected_files:
- art-agent/backend/app/memory.py(新建)
- art-agent/backend/app/agent/loop.py
- art-agent/backend/app/config.py
- art-agent/backend/app/api/chat.py
- art-agent/backend/requirements.txt
- art-agent/backend/.env
- art-agent/frontend/src/lib/api.ts
- art-agent/frontend/src/app/page.tsx
- .gitignore
- what: 集成 Mem0 开源版作为统一记忆方案,一次性解决两个延期方案:上下文管理(滑动窗口截断)和跨会话长期记忆(事实提取+语义检索)
- why: 当前对话全量透传无截断,长对话会超 token 上限且费用线性增长;且每次会话从零开始无法记住用户偏好
- decisions:
- 选择 Mem0 OSS 自部署(非平台托管),完全本地化,数据在 ./data/qdrant
- DeepSeek 作为事实提取 LLM(复用现有 key,成本极低)
- Ollama nomic-embed-text 作为本地 embedding(免费,768维,性能足够)
- 不做静默降级:Ollama 不可用 → 阻止启动;search 失败 → SSE error 中断对话;add 失败 → SSE warning 告知用户
- 用 asyncio.run_in_executor 异步执行 memory.add(),不阻塞用户体验
- notes:
- 测试时创建了 data/qdrant 目录(含测试记忆数据),已加入 .gitignore
- Ollama 需要作为后台服务保持运行
- 首次 Mem0 初始化约需 5-8 秒(创建 Qdrant collection)
- 解决了延期方案 [context-window-management] 和 [mem0-long-term-memory]
- source_chat: Mem0 记忆系统集成
[CL-20260413-1130] 2026-04-13 11:30 — 修复 SDXL 模型 404 错误:补全 Replicate 版本 hash
- tags: bug修复, Replicate, SDXL, 模型配置, 404
- affected_files:
- art-agent/backend/app/config.py
- what: 修复 Stable Diffusion XL 模型调用 Replicate API 返回 404 的问题
- why: 与之前 Kolors IP-Adapter(CL-20260413-0440)完全相同的根因——Replicate 对非 Black Forest Labs 官方模型需要
owner/model:version_hash完整格式,短格式stability-ai/sdxl无法定位到具体版本 - decisions: 使用 Replicate 官方文档中的最新推荐版本 hash
39ed52f2...e08b - notes: Flux 系列(black-forest-labs/flux-schnell、flux-dev)不受此问题影响,Replicate 对其支持短格式。后续新增模型时应默认使用完整的
owner/model:version_hash格式
[CL-20260413-1100] 2026-04-13 11:00 — 修复切换模型后 LLM 仍声称使用旧模型名
- tags: Agent Loop, system prompt, 模型选择, LLM 幻觉, 模型名
- affected_files:
- art-agent/backend/app/agent/loop.py
- what: System Prompt 中动态注入当前生图模型名称,防止 LLM 从对话历史幻觉旧模型名
- why: 用户在同一会话内切换模型(如从 InstantStyle 切到 Kolors),LLM 在回复中仍声称使用旧模型。根因是 System Prompt 不包含模型信息,LLM 从对话历史中的工具返回结果/文字记录推断模型名,导致幻觉
- decisions: 在 system prompt 末尾动态拼接当前模型名 + 强调忽略旧记录。同时在假生成重试的纠正消息中也附带模型名
- notes: 通过 debug 日志验证:前端→后端→工具执行的模型传递链路完全正确(kolors-ipadapter 一路贯穿),问题仅在 LLM 文字输出层面。修复后验证通过
[CL-20260413-1030] 2026-04-13 10:30 — Agent Loop 假生成检测 + 自动重试机制
- tags: Agent Loop, DeepSeek, function calling, 防幻觉, 自动修复
- affected_files:
- art-agent/backend/app/agent/loop.py
- what: 当 LLM 返回纯文字(无 tool_calls)但内容包含"已生成"等模拟生图关键词时,自动注入纠正消息强制 LLM 重新调用工具
- why: DeepSeek 即使在 System Prompt 中明确禁止模拟工具调用(CL-0930),仍会在复杂多步任务中用文字"扮演"生图过程,导致前端收不到 image_result 事件。Prompt 约束对 DeepSeek 无效,必须在代码层面硬性拦截
- decisions: 用正则匹配"已生成"、"生成完成"、"图片已"等关键词,命中 2 次以上且文本 >= 50 字时判定为假生成。检测到后将 LLM 的回复保留在历史中,追加一条纠正消息"你没有调用工具,请立即调用",然后 continue 回到循环让 LLM 重试。重试消耗一次迭代配额,不影响正常对话
- notes: 此机制主要针对 DeepSeek 的 function calling 纪律问题。GPT-4o 等模型通常不会触发。如果 DeepSeek 重试后仍然不调用工具,会在 max_iterations 用尽后正常结束
[CL-20260413-1000] 2026-04-13 10:00 — 助手消息气泡添加复制文本按钮
- tags: 前端, UX, chat-messages, 复制
- affected_files:
- art-agent/frontend/src/components/chat/chat-messages.tsx
- what: 助手回复气泡下方新增复制文本按钮,hover 时显示,点击复制文本内容并显示对勾反馈
- why: LLM 生成的 prompt 思路、风格描述等文字内容用户经常需要复制,之前只能手动选中
- decisions: 按钮放在气泡下方左侧而非内部,避免干扰阅读。只对 assistant 消息显示(用户自己的消息不需要复制)。使用 navigator.clipboard API,hover 显示 + 1.5s 对勾反馈
- notes: 仅复制纯文本内容,不含图片信息
[CL-20260413-0930] 2026-04-13 09:30 — System Prompt 加入"禁止模拟工具调用"约束
- tags: prompt 工程, system prompt, DeepSeek, function calling, 防幻觉
- affected_files:
- art-agent/backend/app/agent/loop.py
- what: System Prompt 注意事项中新增"禁止模拟工具调用"硬性约束
- why: DeepSeek 在复杂多步任务(如一次生成 3 种不同建筑)中,有时不通过 function calling 调用 generate_image 工具,而是用文字"模拟"生成过程(如"已生成"),导致 Agent Loop 第一轮就因 tool_calls_data 为空而 yield done,前端收不到 image_result 事件,用户看不到图片
- decisions: 在 System Prompt 中加一条行为红线,告诉 LLM 必须实际调用工具。轻量级防御(检测文字中包含"已生成"但无工具调用时发警告)暂不实现,先观察 prompt 约束的效果
- notes: 这是 DeepSeek function calling 纪律问题,GPT-4o 等模型通常不会出现。如果 prompt 约束不够,后续可加检测机制
[CL-20260413-0900] 2026-04-13 09:00 — 非 vision + 参考图场景:尊重用户主动指定的风格意图
- tags: prompt 工程, IP-Adapter, 风格, system prompt, UX
- affected_files:
- art-agent/backend/app/agent/loop.py
- what: 将"绝对禁止风格关键词"改为"不自行猜测,但保留用户明确指定的风格"
- why: 之前的 system prompt 和非 vision hint 中对风格关键词的禁止是绝对性的("绝对不要"、"不要添加任何"),导致 LLM 在用户主动输入了风格描述(如"赛博朋克风"、"水彩风")时也会丢弃用户意图。系统不应替用户做决定
- decisions: 措辞从"绝对禁止"改为"不自行猜测,但用户明确指定则保留"。两处同步修改:SYSTEM_PROMPT 第 47 行 + 非 vision 模型的 hint 文本。IP-Adapter 风格迁移与用户文字风格描述可叠加不冲突
- notes: 这是对 CL-20260413-0540 策略的修正——当时为了防止 DeepSeek 脑补画风而加了绝对禁止,现在细化为区分 LLM 猜测 vs 用户意图
[CL-20260413-0800] 2026-04-13 08:00 — 修复 InstantStyle ReadTimeout + 多次生成丢失参考图
- tags: bug修复, Replicate, InstantStyle, timeout, 参考图, Agent Loop, wait, SDK
- affected_files:
- art-agent/backend/app/services/image_gen.py
- art-agent/backend/app/agent/loop.py
- what: 修复 InstantStyle 首次调用 ReadTimeout (61.4s) + 后续调用丢失参考图返回 "No input, Save money"
- why: 两个运行时日志证实的独立问题:(1)
wait=60时 SDK_create_prediction_timeout生成httpx.Timeout(5.0, read=60.5)作为 per-request timeout 传给httpx.AsyncClient.request(),优先级高于客户端级 300s timeout;(2) 成功生成后执行ref_image_url = None,但 LLM 可能在后续轮次继续调用工具,此时 InstantStyle 因没有style_image返回 "No input, Save money" - decisions: (1)
wait=60→wait=False:不发Prefer: waitheader,create 请求立即返回 prediction ID,SDK 自动进入prediction.async_wait()轮询路径。轮询请求不带 per-request timeout,使用客户端级read=300s。代价:比Prefer: wait模式多几秒轮询延迟,但绝不会 timeout。(2) 完全移除ref_image_url = None:消息构建(附加参考图到 LLM 消息)在外层循环前一次性完成,不受影响。ref_image_url 只在execute_tool()中使用,整个对话期间都应该传递 - notes: 迭代了 CL-0700 和 CL-0730 的方案。wait 参数完整语义:
True=Prefer: wait+ read=60.5s;int(n)=Prefer: wait={n}+ read={n+0.5}s(n 必须 1-60);False= 不等待、纯轮询。对慢模型(InstantStyle ~128s)配合大 payload(1.6MB base64),wait=False是唯一可靠选项
[CL-20260413-0730] 2026-04-13 07:30 — 修复生图失败后 LLM 重试丢失参考图
- tags: bug修复, Agent Loop, 参考图, InstantStyle, ref_image_url
- affected_files:
- art-agent/backend/app/agent/loop.py
- what: 修复 LLM 第一次生图工具调用失败后重试时参考图丢失,InstantStyle 返回 "No input, Save money"
- why:
loop.py在每轮工具调用循环结束后无条件执行ref_image_url = None。当第一次调用超时失败后,LLM 决定重试,但此时 ref_image_url 已被清空,第二次工具调用没有参考图。InstantStyle 模型必须有style_image才能工作 - decisions: 改为条件性清除:在工具调用循环中标记
tc_data["_had_images"] = True,循环结束后检查是否有任何成功产出,只有any_success时才清除 ref_image_url。失败时保留参考图供后续重试 - notes: 这个改动对所有参考图模型生效(Kolors、InstantStyle 等)。只要本轮所有工具调用都失败了,ref_image_url 会一直保留直到某次成功为止
[CL-20260413-0700] 2026-04-13 07:00 — 修复 InstantStyle 生图 422 + ReadTimeout:wait 参数超限与 SDK 内部 timeout 覆盖
- tags: bug修复, Replicate, InstantStyle, API参数, async_run, Prefer header, timeout
- affected_files:
- art-agent/backend/app/services/image_gen.py
- what: 修复 InstantStyle 生图 422(
Prefer: wait=x must be 1-60)和后续 ReadTimeout(61.4s 超时) - why: 上次修超时时将
async_run(wait=300)设为 300 秒。Replicate SDK 将 int 类型的 wait 值设为Prefer: wait=300header → API 返回 422。改为wait=True后 SDK 生成内部httpx.Timeout(read=60.5)作为请求级 timeout 覆盖了客户端级 300s timeout → 上传 1.6MB base64 style_image + 等待响应超过 60s → ReadTimeout - decisions: 最终改为
wait=60(API 允许的最大 int 值)。SDK 行为:(1)Prefer: wait=60header(合法);(2) 内部 timeoutread=60.5s用于初始 create prediction 请求;(3) 60s 内未完成自动 fallback 到prediction.async_wait()轮询;(4) 轮询请求用客户端级httpx.Timeout(read=300s) - notes: Replicate SDK wait 参数语义:
True=Prefer: wait+ read=60.5s;int(n)=Prefer: wait={n}+ read={n+0.5}s(n 必须 1-60);False= 不等待。对慢模型用wait=60+ 长客户端 timeout 是最优组合
[CL-20260413-0630] 2026-04-13 06:30 — 修复 Replicate SDK 不走代理 + 超时:自定义 Client 注入代理和长超时
- tags: bug修复, Replicate, InstantStyle, 代理, httpx, 超时, 图像生成
- affected_files:
- art-agent/backend/app/services/image_gen.py
- what: 修复 InstantStyle 调用时 ConnectTimeout / ReadTimeout + "URL missing protocol" 连环错误
- why: Replicate Python SDK 的
_build_httpx_client显式传入transport=AsyncHTTPTransport(),导致 httpx 跳过环境变量中的HTTPS_PROXY代理配置直连 Replicate API。网络不稳定时直连超时,SDK 内部状态异常导致后续请求报 "URL missing protocol"。同时默认 read timeout 30s 不够 InstantStyle 的 ~128s 生成时间 - decisions: 创建
_make_replicate_client()工厂函数,从环境变量读取代理并注入到AsyncHTTPTransport(proxy=...)中传给ReplicateClient。read timeout 300s、connect timeout 30s。_download_image也加了代理和 60s 超时 - notes: Replicate SDK 的代理绕过是个已知设计缺陷(显式 transport 覆盖了 httpx 的代理自动检测)。此修复对所有通过
_replicate_client的 Replicate API 调用生效。无代理环境下也兼容(proxy=None时 httpx 不走代理)
[CL-20260413-0600] 2026-04-13 06:00 — 新增 InstantStyle 模型:强风格迁移选项
- tags: 模型注册, InstantStyle, 风格迁移, IP-Adapter, 模型配置
- affected_files:
- art-agent/backend/app/config.py
- what: 在模型注册表中新增 InstantStyle(
jyoung105/instant-style),专门做风格分离迁移,与 Kolors IP-Adapter 并列为两个参考图模型选项 - why: Kolors IP-Adapter 的风格迁移弱(内容+风格+构图混合提取),经调研 InstantStyle 是 Replicate 上风格迁移能力最强的可用模型,能从参考图中分离出纯画风(线条、着色、色调)
- decisions: 利用现有
supports_ref_image+ref_image_param抽象机制,InstantStyle 的style_image参数名通过配置映射,无需修改_build_input逻辑。默认block_mode: "style-only"(只迁移风格不迁移构图),style_strength: 1.0 - notes: InstantStyle 较贵(~$0.12/次)且慢(~128s),适合风格定调阶段使用;Kolors 保留为低成本快速测试选项。社区模型需版本 hash
[CL-20260413-0540] 2026-04-13 05:40 — 非 vision LLM + 参考图时禁止猜测风格,避免 prompt 与参考图风格冲突
- tags: prompt 工程, IP-Adapter, 风格一致性, system prompt, 非vision模型
- affected_files:
- art-agent/backend/app/agent/loop.py
- what: 修改 system prompt 和非 vision 模型的参考图文字提示,明确要求 LLM 不要猜测/指定画风关键词,风格完全交给 IP-Adapter 从参考图提取
- why: DeepSeek 等非 vision LLM 看不到参考图内容,会根据"2D 游戏"等关键词脑补风格(如 pixel art),导致 prompt 中的风格描述与参考图实际风格严重冲突。IP-Adapter 优先服从 prompt 的显式风格指令,参考图的风格影响被稀释
- decisions: 双重约束——system prompt 中加入"看不到参考图时不猜风格"的通用指引 + 注入的文字提示中用编号列表明确三条规则。保留了 vision 模型路径不变(vision 模型能看图,可以写风格词)
- notes: 这是过渡方案,等切换到 vision LLM(如 GPT-4o)后,LLM 可直接看图描述风格,此约束自动失效(走 vision_capable 分支)
[CL-20260413-0520] 2026-04-13 05:20 — 多图生成改为单次 API 调用 + 修复空错误信息
- tags: 性能优化, Replicate, 速率限制, 错误处理, 模型配置
- affected_files:
- art-agent/backend/app/services/image_gen.py
- art-agent/backend/app/config.py
- what: 多图生成从 for 循环多次 API 调用改为单次调用(利用模型原生批量参数),同时修复异常 str() 为空时的错误信息丢失
- why: LLM 传 num_images=3 时会发 3 个独立 API 请求,在低余额账户的严格速率限制(burst=1)下后续请求会被 429 拦截。改为单次调用后只消耗 1 次请求配额。空错误信息(
[生成失败: ])导致用户无法诊断失败原因 - decisions: 新增
num_images_param配置字段(Flux 用num_outputs,Kolors 用number_of_images),由_build_input统一注入。从 kolors 的 default_params 中移除了硬编码的number_of_images: 1,改为动态设置 - notes: 空异常现在显示为
{TypeName}: {repr(e)},确保始终有诊断信息
[CL-20260413-0500] 2026-04-13 05:00 — 生成图片后显示使用的模型名称
- tags: 模型溯源, SSE, 图片生成, 前端展示
- affected_files:
- art-agent/backend/app/services/image_gen.py
- art-agent/backend/app/agent/tools.py
- art-agent/backend/app/agent/loop.py
- art-agent/frontend/src/lib/types.ts
- art-agent/frontend/src/app/page.tsx
- art-agent/frontend/src/components/chat/chat-messages.tsx
- what: 图片生成后在对话中显示实际使用的模型名称(如"由 Kolors IP-Adapter 生成"),失败时也附带模型名称
- why: 用户无法确认前端选择的模型是否真的被用于生图,特别是在多模型切换场景下需要明确溯源
- decisions:
generate_images返回值从list[str]改为GenerateResult数据类(包含 urls + model_name + model_id),模型名称通过 SSEimage_result和tool_error事件透传到前端。ChatMessage 类型新增modelName可选字段,消息归档后仍可查看模型来源 - notes: 模型名称来自 config.py 注册表中的
name字段,所以显示的是友好名称而非 Replicate 的 model_id
[CL-20260413-0440] 2026-04-13 04:40 — 修复 Kolors IP-Adapter 模型 404 错误:补全 Replicate 版本 hash
- tags: bug修复, Replicate, Kolors, IP-Adapter, 模型配置
- affected_files:
- art-agent/backend/app/config.py
- what: 在 kolors-ipadapter 的 model_id 中补全版本 hash,从
fofr/kolors-with-ipadapter改为fofr/kolors-with-ipadapter:5a1a92b2... - why: Replicate SDK
async_run对非 official 模型(社区模型)只用owner/model格式调用时,会尝试 official model predictions 端点,该端点返回 404。必须使用owner/model:version_hash格式才能正确创建 prediction - decisions: 只修复 kolors 模型(唯一报错的),其他三个模型(flux-schnell、flux-dev、sdxl)均为 official/热门模型,
owner/model格式能正常工作 - notes: 未来新增社区模型时,需确保 model_id 包含版本 hash。经实测加版本 hash 后生图成功
[CL-20260413-0430] 2026-04-13 04:30 — 图片生成失败时将具体错误信息透传到前端
- tags: 错误处理, Agent Loop, SSE, 调试体验
- affected_files:
- art-agent/backend/app/agent/loop.py
- art-agent/frontend/src/app/page.tsx
- art-agent/frontend/src/lib/api.ts
- what: 新增
tool_errorSSE 事件类型,将图片生成工具的具体错误信息(如 Replicate API 报错详情)直接透传到前端展示 - why: 之前工具调用失败时,错误信息只传回给 LLM,LLM 会自行"翻译"错误(如说成"速率限制"),用户无法看到真实报错,排查困难。典型场景:使用 Kolors IP-Adapter 生图失败,前端只看到 LLM 的模糊描述,无法定位是参数错误、超时还是 API 限制
- decisions: 错误信息同时发给前端展示和 LLM 继续对话,不互斥。前端用 ⚠️ 前缀醒目显示错误详情
- notes: 此改动不影响 LLM 的重试机制(工具结果仍然回传给 LLM),只是额外增加了一条面向用户的 SSE 事件
[CL-20260413-0330] 2026-04-13 03:30 — README 补充访问地址汇总 + 穿透管理文档
- tags: 文档, README, 穿透, Cloudflare, cloudflared
- affected_files:
- art-agent/README.md (新增"访问地址"章节 + 重写"远程访问"章节)
- what: README 新增三种访问场景(本机/局域网/外网)的地址汇总表,重写远程访问章节补充 cloudflared 安装指引、穿透管理操作表、代理配置排错
- why: 原 README 远程访问章节过于简略,缺少 cloudflared 安装方式、穿透的启动/停止/排错说明,用户实际操作时需要这些信息
- decisions:
- 访问地址章节放在"使用"之后、"配置说明"之前,让用户启动后立即看到访问方式
- cloudflared 安装提供 winget 和手动下载两种方式(winget 安装后可能不在 PATH 中)
- 穿透管理用表格呈现(启动/停止/查看状态/重启),简洁直观
- 代理排错放在注意事项中,因为国内环境常需代理才能连上 Cloudflare
- notes: 无
[CL-20260412-2345] 2026-04-12 23:45 — 参考图上传独立化:进度条 + 状态反馈 + 失败重试
- tags: 前端, 后端, 参考图, 上传, UX, 进度反馈
- affected_files:
- art-agent/backend/app/api/chat.py (新增 POST /api/upload-ref-image 独立上传端点,chat 端点新增 ref_image_url 字段)
- art-agent/frontend/src/lib/api.ts (新增 uploadRefImage 函数,XMLHttpRequest 实现进度回调;sendChat 参数从 File 改为服务端路径字符串)
- art-agent/frontend/src/components/chat/chat-input.tsx (重写上传流程:选图即上传、环形进度条、状态角标、失败重试、input value 重置)
- art-agent/frontend/src/app/page.tsx (handleSend 适配新签名:接收服务端路径而非 File;标注截图也走独立上传)
- what: 将参考图从"随消息一起提交"改为"选中后立即独立上传",全程有进度条、状态提示、失败重试入口
- why: 原方案图片上传绑定在发送消息时才执行,无任何进度反馈。大图或走 Cloudflare Tunnel 时用户完全无法判断上传是否开始、是否成功、是否卡住。多次上传参考图后 file input 不重置也导致交互异常
- decisions: 使用 XMLHttpRequest 而非 fetch(fetch 不支持 upload progress 事件);后端同时保留 ref_image 文件上传和 ref_image_url 路径两种方式,向后兼容
- notes: 上传超时设为 120 秒;支持 AbortController 取消;file input 每次选择后立即重置 value,确保同一文件可重复选择
[CL-20260412-2315] 2026-04-12 23:15 — 修复 Cloudflare Tunnel 跨域开发警告
- tags: 前端, 配置, Next.js, Cloudflare, 跨域
- affected_files:
- art-agent/frontend/next.config.ts (新增 allowedDevOrigins)
- what: 在 next.config.ts 中添加
allowedDevOrigins: ["*.trycloudflare.com"],消除 Cloudflare Tunnel 穿透时的跨域警告 - why: Next.js 检测到来自 trycloudflare.com 的跨域请求,发出警告提示未来版本将强制要求配置
- decisions: 使用通配符
*.trycloudflare.com覆盖所有 Quick Tunnel 随机域名 - notes: 仅影响开发模式,生产构建不受影响
[CL-20260412-2300] 2026-04-12 23:00 — 集成 Kolors IP-Adapter 模型,参考图可直接用于风格生成
- tags: 后端, 前端, IP-Adapter, 风格迁移, 参考图, 模型注册, Replicate, 架构
- affected_files:
- art-agent/backend/app/config.py (新增 kolors-ipadapter 模型注册 + supports_ref_image / ref_image_param 通用字段)
- art-agent/backend/app/services/image_gen.py (ReplicateProvider._build_input 支持参考图注入 + to_data_uri 公共工具函数)
- art-agent/backend/app/agent/loop.py (复用 to_data_uri 替代原 _to_vision_url,移除冗余 import)
- art-agent/frontend/src/lib/types.ts (ImageModelInfo 新增 supports_ref_image 字段)
- art-agent/frontend/src/components/chat/model-selector.tsx (模型列表中显示"参考图"标记)
- what: 集成 Kolors IP-Adapter 模型(fofr/kolors-with-ipadapter),参考图可真正参与图像生成的风格控制;架构上为后续切换其他 IP-Adapter 模型预留了通用扩展机制
- why: 之前参考图仅由 LLM 侧理解(且 DeepSeek 看不到图),生图工具侧完全忽略了参考图。用户希望参考图能真正影响生成结果的风格
- decisions:
- 模型注册表新增两个通用字段:supports_ref_image(布尔标记)和 ref_image_param(参考图参数名,不同模型可能不同)
- _build_input 根据 supports_ref_image 自动走不同构建逻辑,新增 IP-Adapter 模型只需加注册表配置
- 参考图通过 base64 data URI 传递给 Replicate(避免本地 URL 不可达的问题)
- to_data_uri 抽为 image_gen.py 中的公共函数,loop.py 复用(替代原 _to_vision_url)
- Kolors IP-Adapter 默认 ip_adapter_weight=0.8(非 1.0),给 prompt 文字留一些影响空间
- 前端模型列表中为支持参考图的模型显示绿色"参考图"徽章
- get_image_models_list 返回 supports_ref_image 字段,前端据此渲染标记
- notes:
- Kolors IP-Adapter 成本极低(~$0.004/次),速度快(~4s)
- 后续要换其他 IP-Adapter 模型(如 Flux IP-Adapter v2),只需在 IMAGE_MODELS 中新增配置
- 分层组合产线方案(IP-Adapter → LoRA → ControlNet)已记录为延期方案 [style-pipeline-layered]
[CL-20260412-2230] 2026-04-12 22:30 — 用户消息气泡中显示参考图缩略图
- tags: 前端, 参考图, UX, chat-messages
- affected_files:
- art-agent/frontend/src/lib/types.ts (ChatMessage 新增 refImageUrl 字段)
- art-agent/frontend/src/app/page.tsx (构造 userMessage 时保存参考图 Blob URL)
- art-agent/frontend/src/components/chat/chat-messages.tsx (用户消息气泡中渲染参考图缩略图)
- what: 用户上传参考图发送后,在聊天气泡中显示参考图缩略图,让用户确认图片确实被附带发送了
- why: 之前用户上传参考图后,发送消息后气泡中看不到参考图,无法确认是否上传成功,体验不好
- decisions:
- 使用 URL.createObjectURL 创建 Blob URL 用于当前会话内显示(轻量、即时)
- Blob URL 不持久化到 localStorage(刷新后失效),避免存储 base64 data URI 的空间开销
- 参考图缩略图显示在消息文本上方,最大尺寸 160×120px
- notes:
- Blob URL 仅在当前标签页有效,刷新页面后旧消息中的参考图缩略图不可见(MVP 可接受)
- 如需持久化,后续可改为存储后端上传路径(需要等后端返回 upload URL 后再构造 userMessage)
[CL-20260412-2200] 2026-04-12 22:00 — 修复 DeepSeek 不支持 image_url 导致参考图上传报错
- tags: bug修复, 后端, Agent Loop, vision, DeepSeek, 多模态
- affected_files:
- art-agent/backend/app/agent/loop.py (新增 vision 能力检测,非 vision 模型走文字提示)
- what: 修复使用 DeepSeek 作为 LLM 时,上传参考图后报 400 错误
unknown variant 'image_url', expected 'text' - why: 代码原本假设所有 LLM 都支持 OpenAI Vision API 的
image_urlcontent type,但 DeepSeek 的 Chat API 只支持text类型 - decisions:
- 通过模型名称关键词检测 vision 能力(gpt-4o / gpt-4-vision / claude 视为支持)
- 不支持 vision 的模型:用文字提示告知 LLM 有参考图存在,参考图仍由图像生成工具侧处理
- 支持 vision 的模型:保持原有 image_url 格式不变
- notes:
- 此方案确保参考图功能在任何 LLM 下都不会报错
- 非 vision 模型无法"看到"参考图,但生图工具仍会收到参考图用于 img2img 场景
- 如需更精确的 vision 能力检测,可后续改为在 config.py 中按模型注册 vision 标志
[CL-20260412-2130] 2026-04-12 21:30 — 修复图片生成失败时前端显示破碎图标
- tags: bug修复, 前端, 后端, 图像生成, 错误处理
- affected_files:
- art-agent/backend/app/agent/tools.py (分离有效 URL 和错误信息)
- art-agent/frontend/src/app/page.tsx (过滤无效 URL,空列表时不渲染图片网格)
- what: 修复 Replicate API 失败时前端出现 4 个破碎图标框的问题
- why: 用户在 Replicate 余额不足(402)时生图,错误字符串被当作图片 URL 传给
<img>标签 - decisions:
- 后端 tools.py:将 generate_images 返回值分为 images(有效 URL)和 errors(错误信息)两个字段
- 前端 page.tsx:过滤以
[开头的无效 URL,无有效图片时直接 break 不创建 ImageAsset
- notes:
- 根因是 Replicate 账户余额不足,需用户到 https://replicate.com/account/billing#billing 充值
- 此修复确保任何 API 错误场景下前端都不会显示破碎图标
[CL-20260412-2100] 2026-04-12 21:00 — 生图模型动态切换:Provider 抽象 + 前端模型选择器
- tags: 后端, 前端, 图像生成, 模型切换, Provider, 重构, Replicate
- affected_files:
- art-agent/backend/app/config.py (新增 IMAGE_MODELS 注册表 + get_image_model_config / get_image_models_list / get_default_image_model_id)
- art-agent/backend/app/services/image_gen.py (重构:ImageProvider 抽象基类 + ReplicateProvider 实现 + generate_images 接受 model_id)
- art-agent/backend/app/api/chat.py (新增 GET /api/models 端点 + POST /api/chat 增加 image_model 参数)
- art-agent/backend/app/agent/loop.py (run_agent_loop 增加 image_model 参数透传)
- art-agent/backend/app/agent/tools.py (execute_tool 增加 image_model 参数透传)
- art-agent/backend/.env (IMAGE_MODEL 改为短 ID 格式)
- art-agent/backend/.env.example (同步更新)
- art-agent/frontend/src/lib/types.ts (新增 ImageModelInfo 类型)
- art-agent/frontend/src/lib/api.ts (新增 fetchModels() + sendChat 增加 imageModel 参数)
- art-agent/frontend/src/components/chat/model-selector.tsx (新建:模型选择下拉组件)
- art-agent/frontend/src/components/chat/chat-input.tsx (集成 ModelSelector + onSend 签名扩展)
- art-agent/frontend/src/app/page.tsx (handleSend 透传 imageModel 到 sendChat)
- what: 将图像生成服务从 Replicate 硬绑定重构为 Provider 抽象架构,支持 Replicate 上多模型(flux-schnell / flux-dev / SDXL)按消息粒度切换
- why: 用户希望能在对话中随时切换生图模型来对比不同模型的效果
- decisions:
- Provider 模式:抽象基类 ImageProvider + 具体实现(当前只有 ReplicateProvider),预留 DalleProvider/ComfyUIProvider 等扩展点
- 模型注册表放在 config.py 中(Python dict),新增模型只需加一条配置
- 前端模型列表由后端 API 驱动(GET /api/models),不在前端硬编码
- 切换粒度为每条消息级(最灵活),通过 FormData 传递 image_model 参数
- 模型选择持久化到 localStorage,作为后续消息的默认值
- Flux 系列使用 aspect_ratio 参数,SDXL 使用 width/height 参数,由 ReplicateProvider._build_input 内部分流处理
- notes:
- 向后兼容:image_model 参数可选,不传时使用 .env 中的默认模型
- .env 中 IMAGE_MODEL 支持短 ID(flux-schnell)和完整 Replicate ID(black-forest-labs/flux-schnell),自动转换
[CL-20260412-1800] 2026-04-12 18:00 — 移动端适配 + Cloudflare Tunnel 内网穿透
- tags: 前端, 响应式, 移动端, 部署, Cloudflare, 穿透, 配置
- affected_files:
- art-agent/frontend/src/app/layout.tsx (viewport meta 配置)
- art-agent/frontend/src/app/globals.css (iOS bounce 防护、tap highlight、dvh 支持、遮罩动画)
- art-agent/frontend/src/app/page.tsx (桌面端展开按钮加 hidden md:flex)
- art-agent/frontend/src/app/gallery/page.tsx (网格 gap/列数适配、hover 操作移动端始终可见、选择框可见)
- art-agent/frontend/src/components/sidebar/sidebar.tsx (移动端固定定位抽屉 + 遮罩)
- art-agent/frontend/src/components/layout/top-nav.tsx (新增汉堡菜单按钮、间距微调)
- art-agent/frontend/src/components/detail/image-detail-panel.tsx (移动端全屏 overlay)
- art-agent/frontend/src/components/chat/chat-messages.tsx (气泡宽度 90%、间距收紧)
- art-agent/frontend/src/components/chat/chat-input.tsx (padding 收紧)
- art-agent/frontend/src/components/chat/image-grid.tsx (max-width 适配、操作栏移动端可见)
- art-agent/frontend/src/lib/app-context.tsx (小屏默认折叠侧边栏、切换会话自动收起)
- art-agent/frontend/next.config.ts (trycloudflare.com + replicate.delivery 白名单)
- art-agent/start-tunnel.ps1 (新建:一键穿透脚本)
- art-agent/README.md (新增远程访问章节、uvicorn 加 --host 0.0.0.0)
- what: 为实现手机浏览器远程访问,完成移动端响应式适配(9 个组件)和 Cloudflare Quick Tunnel 穿透方案
- why: 用户希望把项目发给自己和朋友在手机上通过浏览器使用
- decisions:
- 移动端断点统一用
md:(768px),与 Tailwind 默认保持一致 - 侧边栏移动端用 fixed + overlay 抽屉模式,桌面端保持原有 w-0/w-[280px] 切换
- 图片详情面板移动端全屏(fixed inset-0),不做半屏,因为手机屏幕空间有限
- 穿透方案选 Cloudflare Quick Tunnel(免费、免注册),不选 ngrok(有连接限制)
- 穿透脚本自动管理 .env.local 的更新和恢复,减少手动操作
- hover 操作在移动端始终显示(无 hover 事件),避免操作不可达
- 路线 B(云服务器正式部署)记录为延期方案,待后续实施
- 移动端断点统一用
- notes:
- 构建验证通过,无 lint 错误
- cloudflared 通过 winget 安装,版本 2025.8.1
- Quick Tunnel 每次启动分配随机域名(xxx.trycloudflare.com),非固定
- 穿透启动后需重启前端才能读取新的 NEXT_PUBLIC_API_URL
- project-launcher Skill 中的 uvicorn 命令也同步加了 --host 0.0.0.0
[CL-20260412-1530] 2026-04-12 15:30 — 修复 .env 配置加载时序问题
- tags: 后端, bug修复, 配置, dotenv, Python
- affected_files:
- art-agent/backend/app/main.py (load_dotenv 前置 + override=True)
- art-agent/backend/app/config.py (模块级常量 → 函数式懒读取)
- art-agent/backend/app/agent/loop.py (引用改为函数调用)
- art-agent/backend/app/services/image_gen.py (引用改为函数调用)
- art-agent/backend/.env (OPENAI_BASE_URL 去掉 /v1)
- what: 修复切换 DeepSeek API 后报 "Model Not Exist" 400 错误
- why: 用户修改 .env 切换到 DeepSeek,但实际发出的请求仍使用默认模型名 gpt-4o-mini
- decisions:
- load_dotenv(override=True) 放在 main.py 所有业务 import 之前,确保环境变量在任何模块读取前就位
- config.py 从模块级常量改为函数(get_llm_model() 等),避免 import 时求值被固化
- 不使用 lru_cache(避免首次调用在 load_dotenv 前就缓存了空值)
- notes:
- 根因有两层:import 时序(config.py 在 load_dotenv 前被 import)+ override 默认行为(不覆盖已有环境变量)
- 通过在 uvicorn 同环境中运行 Python 脚本成功复现了 API 调通,证明问题在进程内加载顺序而非 API 本身
- DeepSeek base_url 使用 https://api.deepseek.com(不带 /v1),与官方文档一致
[CL-20260412-1500] 2026-04-12 15:00 — 品牌重命名 EPEEKit + API 配置集中化
- tags: EPEEKit, 品牌, 配置, 后端, 前端, 重构
- affected_files:
- art-agent/frontend/src/app/layout.tsx (title/description)
- art-agent/frontend/src/components/layout/top-nav.tsx (Logo SVG + 品牌名)
- art-agent/frontend/src/app/page.tsx (欢迎文案)
- art-agent/frontend/src/lib/store.ts (localStorage 键名)
- art-agent/frontend/src/app/gallery/page.tsx (下载前缀)
- art-agent/frontend/src/components/detail/image-detail-panel.tsx (下载前缀)
- art-agent/frontend/src/components/chat/image-grid.tsx (下载前缀)
- art-agent/frontend/package.json (项目名)
- art-agent/frontend/package-lock.json (项目名)
- art-agent/backend/app/main.py (FastAPI title)
- art-agent/backend/app/config.py (新建:集中配置)
- art-agent/backend/app/agent/loop.py (引用集中配置)
- art-agent/backend/app/services/image_gen.py (引用集中配置 + 简化重复分支)
- art-agent/backend/.env (重组为分组结构 + 新增 LLM_MODEL/IMAGE_MODEL 等)
- art-agent/backend/.env.example (新建)
- art-agent/README.md (全文更新)
- what: 将应用从 "Art Agent" 正式命名为 "EPEEKit",同时将后端所有硬编码的 API/模型配置抽取到 .env 文件,通过 config.py 集中管理
- why: 用户要求正式命名应用并希望能方便地切换 LLM 和图像生成模型进行测试
- decisions:
- 品牌名全部统一为 "EPEEKit",包括页面标题、Logo、下载文件名、localStorage 键名
- Logo 采用内联 SVG 设计(主题色圆角方块 + A/i 组合),不引入外部图片资源
- API 配置走 .env + config.py 方案(非 settings.py 类模式),保持极简
- 切换 LLM 只需改 .env 中 3 个值:OPENAI_BASE_URL + OPENAI_API_KEY + LLM_MODEL
- image_gen.py 中去除了参考图分支的重复代码(两个分支逻辑完全相同)
- notes:
- localStorage 键名变更意味着旧数据不会自动迁移(MVP 阶段可接受)
- .env 文件中含真实密钥,需确认 .gitignore 覆盖
[CL-20260412-0300] 2026-04-12 03:00 — 完成交互原型全面重构
- tags: art-agent, 前端, 交互设计, 三栏布局, 标签系统, Canvas标注, 资源库, 后端
- affected_files:
- art-agent/frontend/src/app/page.tsx (重写)
- art-agent/frontend/src/app/layout.tsx (添加 AppProvider)
- art-agent/frontend/src/app/globals.css (增加样式)
- art-agent/frontend/src/app/gallery/page.tsx (新建)
- art-agent/frontend/src/lib/types.ts (新建:全局类型定义)
- art-agent/frontend/src/lib/store.ts (新建:localStorage 持久化存储)
- art-agent/frontend/src/lib/app-context.tsx (新建:全局状态 Context)
- art-agent/frontend/src/lib/api.ts (更新类型兼容)
- art-agent/frontend/src/components/layout/top-nav.tsx (新建)
- art-agent/frontend/src/components/sidebar/sidebar.tsx (新建)
- art-agent/frontend/src/components/sidebar/session-list.tsx (新建)
- art-agent/frontend/src/components/sidebar/tag-filter.tsx (新建)
- art-agent/frontend/src/components/chat/chat-messages.tsx (适配新类型)
- art-agent/frontend/src/components/chat/chat-input.tsx (增加拖拽上传)
- art-agent/frontend/src/components/chat/image-grid.tsx (增加操作栏)
- art-agent/frontend/src/components/detail/image-detail-panel.tsx (新建)
- art-agent/frontend/src/components/detail/annotation-canvas.tsx (新建)
- art-agent/backend/app/agent/loop.py (System Prompt + base64 转换)
- what: 从单页对话 MVP 全面重构为完整交互原型,三个 Phase 一次性完成
- why: 用户要求完整设计交互原型,通过规划讨论确定了三栏布局 + 标签系统 + 标注 + 资源库的完整方案
- decisions:
- 数据持久化使用 localStorage(MVP 阶段),后续可迁移到后端数据库
- 全局状态管理使用 React Context + useReducer 模式,不引入第三方状态库
- 标注功能使用原生 Canvas API,不引入第三方画板库(减少依赖)
- 标注坐标使用归一化比例(0-1),与图片实际分辨率解耦
- 资源库使用 Modal overlay 展示详情,而非独立路由页面
- 标注截图通过 base64 data URI 直接传给 OpenAI Vision,后端自动处理本地路径转换
- notes:
- 新增 12 个源文件,修改 6 个现有文件,无新依赖引入
- 内置标签 6 个:UI、Icon、原画、风格探索、立绘、概念图
- 标注工具 4 种:矩形框选、箭头、自由画笔、文字,含撤销/清除
- 构建验证通过,无 linter 错误
- 未来可优化:标签自动推荐逻辑(当前仅预留接口)、后端会话持久化、图片搜索索引
[CL-20260411-1500] 2026-04-11 15:00 — 完成美术 Agent 产品决策和技术选型
- tags: art-agent, 产品决策, 技术选型, 规划
- affected_files:
- docs/art-agent/DECISIONS.md
- docs/art-agent/TECH-STACK.md
- what: 通过 5 轮结构化讨论确定了美术 Agent 工具的产品决策(产品形态、交互模型、AI 架构、风格管理、资源 Pipeline),并完成全部 8 个维度的技术选型
- why: 项目从零开始,需要先把产品方向和技术基准定下来再动手写代码
- decisions:
- 产品形态选 Chat-first Web App(排除纯 Bot 和桌面应用)
- 前端 Next.js / 后端 Python FastAPI / 自建 Agent Loop(不用 LangChain)
- 数据库 PostgreSQL / 图像生成 Replicate / 部署 Vercel + Railway
- 对象存储 MVP 先用本地文件系统
- notes: 技术选型中图像生成 API、部署方案、异步任务三项用户未明确选定,采用了推荐方案
[CL-20260411-1600] 2026-04-11 16:00 — 搭建美术 Agent MVP 全部前后端代码
- tags: art-agent, MVP, 前端, 后端, FastAPI, Next.js, Agent Loop
- affected_files:
- art-agent/README.md
- art-agent/backend/requirements.txt
- art-agent/backend/.env.example
- art-agent/backend/app/main.py
- art-agent/backend/app/api/chat.py
- art-agent/backend/app/agent/loop.py
- art-agent/backend/app/agent/tools.py
- art-agent/backend/app/services/image_gen.py
- art-agent/frontend/package.json
- art-agent/frontend/src/app/page.tsx
- art-agent/frontend/src/app/layout.tsx
- art-agent/frontend/src/app/globals.css
- art-agent/frontend/src/components/chat/chat-messages.tsx
- art-agent/frontend/src/components/chat/chat-input.tsx
- art-agent/frontend/src/components/chat/image-grid.tsx
- art-agent/frontend/src/lib/api.ts
- docs/art-agent/MVP-PLAN.md
- what: 从零创建了完整的 MVP 前后端代码,包括 FastAPI 后端(Agent Loop + Replicate 图像生成 + SSE 流式推送)和 Next.js 前端(Chat UI + 参考图上传 + 图片下载),后端已验证可正常启动
- why: 以最小流程跑通端到端闭环(对话 → 生图 → 迭代 → 保存),快速暴露集成问题
- decisions:
- MVP 范围刻意砍掉:数据库/持久化、Skill/Rules 机制、风格库、用户认证、云端部署
- Agent Loop 硬编码 system prompt,不走 Skill 扩展(最简化)
- 图像模型选 flux-schnell(快速版),优先验证流程通畅
- OpenAI 客户端延迟初始化,避免无 Key 时模块加载失败
- notes:
- 前端使用 Tailwind CSS v4 + PostCSS 配置方式(非 tailwind.config.ts)
- 参考图在 MVP 阶段仅通过 GPT vision 理解风格后融入 prompt,未直接传给图像模型做 img2img
[CL-20260411-1630] 2026-04-11 16:30 — 完成开发环境搭建和依赖安装
- tags: art-agent, 环境搭建, Node.js, Python
- affected_files:
- art-agent/backend/venv/
- art-agent/frontend/node_modules/
- what: 通过 winget 安装 Node.js v24.14.1,创建 Python 虚拟环境并安装后端依赖(9 个包),安装前端 npm 依赖(46 个包),后端启动验证通过
- why: 代码写好后需要实际运行环境来验证
- decisions:
- Node.js 用 winget 安装 LTS 版本
- Python 虚拟环境放在 backend/venv/ 下
- notes:
- 遇到 3 个环境问题已解决:OpenAI 延迟初始化、PowerShell 不支持 &&、脚本执行策略限制
- 端到端完整测试待用户配置 API Key 后进行