feat(character): 创建角色时用 LLM 从描述补名称 - #329
Conversation
POST /characters 在 name 为空时,经 ai_engine 的 LangChain 起名器从 description 生成不超过 20 字的名称。用户填写的名称优先;LLM 失败则截断描述,都空则用「未命名角色」。 Refs 1024XEngineer#188 Co-authored-by: Cursor <cursoragent@cursor.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
审查结论
自动命名的分层与请求级失败兜底方向合理,但当前装配和配置会使默认环境无法启动,或让 LLM 起名路径持续退化为描述截断;现有 workflow_run_id 幂等重试还会新增无效的付费调用。已按固定 base/head SHA 核对完整 diff 与 #188 契约。仓库环境没有可执行的 uv,因此未运行 pytest;使用 langchain-openai==1.4.0 单独复现了无凭据构造异常以及空模型名被保留的行为。
| # 起名器在 composition root 注入,避免 web→character.service 碰到 ai_engine。 | ||
| # 测试若已注入假 namer,不要覆盖。 | ||
| if character_service._namer is None: | ||
| character_service._namer = LangChainCharacterNamer() |
There was a problem hiding this comment.
[P1] 避免在应用启动时强制创建 ChatOpenAI
create_app() 现在无条件构造 LangChainCharacterNamer,其构造函数会立即调用 ChatOpenAI;当本地、测试或仅使用非聊天 AI 能力的部署没有设置 AI_API_KEY 时,langchain-openai==1.4.0 会在这里直接抛出 OpenAIError: Missing credentials。这样应用连健康检查都无法启动,请求内 resolve_character_name 的异常兜底也没有机会执行。请延迟到实际起名调用时再创建模型(让该异常落入现有兜底),或在 bootstrap 中容忍未配置聊天 provider。
| """``CharacterNamerPort`` 的 LangChain 实现。""" | ||
|
|
||
| def __init__(self, chat_model: Any | None = None) -> None: | ||
| self._model = chat_model if chat_model is not None else create_chat_model() |
There was a problem hiding this comment.
[P1] 为起名调用配置非空的聊天模型
这里使用通用 create_chat_model(),它读取 AIProviderSettings.model;该字段默认值是空字符串,而仓库 .env.example 只配置了 AI_IMAGE_MODEL 和 AI_VIDEO_MODEL,没有 AI_MODEL。因此按仓库示例部署时会得到 ChatOpenAI(model=""),每次空名称请求都会因无效模型失败并静默退化为描述截断,PR 宣称的 LLM 起名路径实际上不会工作。请为起名器提供明确的非空模型配置/默认值,并把对应环境变量加入部署契约。
| fields = dict(fields) | ||
| name = fields.get("name") | ||
| namer = None if (name or "").strip() else self._namer | ||
| fields["name"] = resolve_character_name(name, fields.get("description"), namer) |
There was a problem hiding this comment.
[P2] 在付费起名前先处理 workflow_run 幂等
POST /characters 的幂等语义是先插入,再在唯一约束冲突时返回已有角色;但这行现在会在 session.flush() 之前调用起名器。于是同一个 workflow_run_id 的正常重试只要 name 为空,就会先执行一次最长 120 秒且可能付费的 LLM 调用,随后才触发 IntegrityError 并丢弃生成结果。请在通常的重试路径上先查询已有角色/建立唯一性,再解析名称;并保留唯一约束处理并发竞态。
CI 没有 AI_API_KEY 时,装配期创建 ChatOpenAI 会让所有走 create_app 的测试在 setup 失败。LangChain 客户端推迟到第一次起名再构建。 Co-authored-by: Cursor <cursoragent@cursor.com>
create_chat_model 在空 key/空型号时先拒绝,避免 ChatOpenAI(model="")。 同 workflow_run_id 先查已有角色再起名。装配期仍不创建 ChatOpenAI。 Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
POST /characters在name为空或纯空白时,用description经 ai_engine 的 LangChain 起名器生成不超过 20 字的名称再入库。bootstrap注入,避免web → character.service碰到ai_engine。Refs #188
Close #188
本次只做后端。Quick Start / Workflow Editor 的选填名称留给后续 PR。
变更
CharacterNamerPort+LangChainCharacterNamer(create_chat_model(),不是 Agent)resolve_character_name在create_character落库前解析最终名称Test plan
POST /characters不带 name 时写入生成名AI_*配置后,用一段角色描述创建角色,确认名称非空且 ≤20 字