469 lines
41 KiB
Markdown
469 lines
41 KiB
Markdown
# Dev Changelog — Full
|
||
|
||
完整的开发改动记录,按时间倒序排列。作为主动 RAG 的数据源,用户手动唤醒时读取。
|
||
|
||
## 记录
|
||
|
||
### [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: wait` header,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=300` header → 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=60` header(合法);(2) 内部 timeout `read=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),模型名称通过 SSE `image_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_error` SSE 事件类型,将图片生成工具的具体错误信息(如 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_url` content 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 后进行
|