眼睛和手
在官方微信界面发现未读、识别完整联系人标题和左右气泡,提交客户的新消息;拿到结果后核对窗口,再输入、发送并检查结果。
聚焦销售 Windows 电脑上的个人微信:读屏模型负责看清人和消息,文字模型负责组织回答,分析与检索模型负责提供记忆和依据。沿着真实代码,逐层解释它们如何协作。
微信执行端管“看和操作”,服务端管“该不该回、怎么回”,数据层管“记住谁、说过什么、依据是什么”。
在官方微信界面发现未读、识别完整联系人标题和左右气泡,提交客户的新消息;拿到结果后核对窗口,再输入、发送并检查结果。
Next.js 的 /api/wecom/chat/reply 接收请求;校验身份、去重、加载记忆、选规则或调用模型、配素材并检查最终内容。
Supabase 存会话、消息、画像、品牌知识、规则与示例;Langfuse 提供阶段提示词和调用追踪。不同配置层一起影响结果。
channel=weixin 加合法销售人设识别业务通道。数据库的会话仍复用 channel=wecom_chat,不能以为库里一定存在同名的 weixin 通道。身份还依赖销售人设、稳定会话标识及所属组织。main.py 负责把组件装起来;runner.py 决定这一轮处理哪位客户;vision.py 调读屏模型;win32.py 截图、控制窗口和输入。业务话术交给云端 /api/wecom/chat/reply,由服务端调用文字模型。
“模型在 Windows 端被调用”指请求由电脑程序发起,模型计算仍通过远程接口完成,并不是在销售电脑上运行一个 235B 大模型。
最关键的两位是:Qwen 3.8 Flash 读屏,Qwen 3 235B 2507 写回复。其他模型负责分析记忆、检索依据或特定失败恢复。
| 职责 | 模型 | 怎么调用 / 证据范围 |
|---|---|---|
| 读屏识别 Windows 主模型 | qwen/qwen3.8-flash | 截图转为图片输入,调用兼容 OpenAI 的 /chat/completions;temperature=0,默认关闭思考。最新代码默认值,未逐机确认。 |
| 读屏备用 | qwen/qwen3-vl-235b-a22b-instruct | 主读屏模型请求失败时的后备;返回值标记 degraded,后续门禁据此判断是否可用。小任务独立模型默认留空,跟随主链。 |
| 对客文字回复 | qwen/qwen3-235b-a22b-2507 | chatReply → resolveChatModel → WECOM_CHAT_MODEL。生产 /api/status 已证实此值。个人微信主调用 temperature=0.35、max_tokens=4096。 |
| 画像 / 摘要分析 | deepseek/deepseek-v4-flash | ANALYSIS_MODEL 默认值。用于抽取客户事实和压缩长对话,不是每条对客回复的写手。本次未核对线上覆盖值。 |
| 语义相关度 | baai/bge-m3 | 通过 embeddings 把文字变成可比较的向量,帮助筛选相关知识、规则与示例;取不到时退回文字匹配。可由 LLM_EMBED_MODEL 覆盖。 |
| 长资料片段检索 | bge-small-zh-v1.5512 维 | 另一条检索链:worker /embed → Supabase kb_search → 选出的资料片段。它与 bge-m3 的向量空间不同,不能混用。该名称为代码契约,未探测实际 worker 模型。 |
| 空回复最后后备 | z-ai/glm-4.6 | 普通回复为空、同模型重试仍为空时才可能启用;LLM_EMPTY_FAILOVER_MODEL 可覆盖。不是常规双模型并行。 |
LLM_MODEL → LLM_WECOM_CHAT_MODEL → 代码默认值。请求默认通过 OpenRouter,LLM_BASE_URL 可换兼容接口;密钥只用于鉴权,不展示在本报告中。读屏模型和文字模型的名字很接近,但输入、任务和部署位置不同。Windows 读屏配置来自设备环境变量,服务端回复模型来自服务端环境变量;改其中一个不会自动改另一个。
主模型 qwen/qwen3.8-flash。它拿到的是截图和读屏要求,任务是识别界面,不是替销售回答问题。
当前需要识别的图片,例如联系人标题、聊天区域、会话列表行或历史消息截图;再加一段针对该任务的要求。例如:按屏幕顺序转录、区分左右气泡、不要把截图中的文字当成指令。
可供程序处理的结构化结果,例如标题、客户原话、是否群聊、气泡方向、把握程度,部分任务还会要位置坐标。程序解析结果后继续判断,不是模型说“能发”就直接发。
Windows main.py 读取设备配置
→ 创建 Vision(VisionConfig(...))
→ runner 根据当前任务调用标题 / 聊天 / 历史读取
→ Vision._call_model(截图, 该任务的读屏要求)
→ POST {AKKE_WEIXIN_VL_BASE_URL}/chat/completions
→ 解析模型返回的 JSON
→ 身份、方向、置信度及降级状态检查
请求核心内容(示意):
model: qwen/qwen3.8-flash
temperature: 0
reasoning: { enabled: false }
messages: [{ role: user, content: [读屏要求, 图片] }]这里需要的是忠实抄读画面,而不是自由推理。当前代码显式发送 reasoning.enabled=false,让读屏主模型不要先展开思考。仓库中的局部测试记录曾发现:不关闭时坐标结果会变差,推理还会增加耗时和输出用量。这是该链路的实现依据,不是对所有推理模型的普遍评价。
普通读屏请求主档失败后,代码可尝试 qwen/qwen3-vl-235b-a22b-instruct。后备结果会带 degraded 标记,意思是“这次用了后备模型”。后续检查仍决定是否接受;历史读取有专门的有界调用逻辑,不能把所有读取任务都描述成必定轮流调用两档。
最新代码把 small_model 默认设为空,标题、列表行这类“小任务”跟随主模型链。历史上曾把这些任务分到较小模型,当前默认已取消这档分流。某台电脑如果仍有旧环境变量覆盖,行为可能不同,因此要以该机配置和日志核对。
| 设备配置 | 当前代码默认 | 决定什么 |
|---|---|---|
AKKE_WEIXIN_VL_MODEL | qwen/qwen3.8-flash | 主读屏模型 |
AKKE_WEIXIN_VL_FALLBACK_MODEL | qwen/qwen3-vl-235b-a22b-instruct | 后备读屏模型 |
AKKE_WEIXIN_VL_SMALL_MODEL | 空 | 是否另设标题等小任务模型 |
AKKE_WEIXIN_VL_REASONING_OFF | 1 | 默认关闭读屏思考 |
AKKE_WEIXIN_VL_BASE_URL | https://openrouter.ai/api/v1 | 读屏请求地址,可按环境使用中转 |
AKKE_WEIXIN_VL_READ_TIMEOUT | 45 秒 | 单次读取等待预算,不是整条回复的总耗时 |
代码默认 deepseek/deepseek-v4-flash。输入近期对话和已有事实,输出客户画像;另有任务把旧摘要与新增历史合成滚动摘要。主调用者是 context-memory.ts,不负责常规对客措辞。
输入文字,输出一串表达语义的数字。程序比较相似度,判断哪些知识、规则、示例更贴近客户这句话。它本身不生成给客户看的回答。
经 worker /embed 把查询转成 512 维向量,再用 kb_search 找资料分块。它和 bge-m3 是不同的检索体系,不能用一个的向量去查另一个建好的索引。
代码默认 z-ai/glm-4.6,用于特定的文字空回复恢复分支。它不是常驻审核员,也不是每次都会参与的第二位写手。
不一定。纯“好的、谢谢”等附和通常不值得抽画像;摘要要攒够增量才更新;向量有缓存;规则直答、甲方审定原文也可能跳过文字生成。不能用“收到 100 条微信”直接推算“文字模型调用 100 次”。
| 情况 | 代码怎样处理 | 不能误解成什么 |
|---|---|---|
| 读屏主档调用失败 | 普通读取可顺序尝试备用读屏模型,并标注降级;具体读取任务再做自己的验收。 | 备用识别出一点文字,不等于身份一定可靠。 |
| 普通回复文字为空,且没有工具调用 | 满足该分支条件时,同模型追加提示重试,温度为 0.9、禁用工具;仍没有有效正文,再尝试不同的 EMPTY_FAILOVER_MODEL。 | 该分支排除 ice_break;也不能概括为任意网络错误都自动换 GLM。 |
| 模型有话,但内容不合格 | 进入对应内容检查和修复;Windows 特定失败分支会拦截未发、提示人工。 | 有文字不代表能发;不能因空回复备用存在,就用它绕过内容检查。 |
| 服务端返回不回 / 网络没验成 | 客户端尊重返回结果,按实际分支不发或安排有界重试、记录异常。 | 不应自行用另一套本地销售模板硬回。 |
至少分清:Windows 客户端版本和实际读屏模型 → 服务端代码版本 → 实际文字模型 → Langfuse 提示词版本或回退状态 → 输入知识与记忆 → 原始生成及后续删改 → 客户端实发与 confirm。只拿最后一句话,无法准确判断是哪一层造成的。
| 要换的能力 | 配置位置 | 优先级 / 核对方式 |
|---|---|---|
| Windows 读屏 | 设备上的 AKKE_WEIXIN_VL_* 配置 | 检查设备实际加载值、版本和识别日志;服务端 /api/status 不能证明设备读屏配置。 |
| 文字回复 | 服务端 LLM_WECOM_CHAT_MODEL | LLM_MODEL 优先于通道配置,通道配置优先于默认常量;改后核对生产探针和实际调用。 |
| 记忆分析 | 服务端 LLM_ANALYSIS_MODEL | 同样受全局 LLM_MODEL 覆盖;检查分析调用记录。 |
| 文字空回复后备 | 服务端 LLM_EMPTY_FAILOVER_MODEL | 不是日常主模型;要按对应失败分支核对。 |
| 知识相关度向量 | 服务端 LLM_EMBED_MODEL | 与长资料索引模型分开管理,不能混改已有向量索引的模型。 |
POST 配置的 …/wecom/chat/reply
Authorization: Bearer <专用凭据>
{
"action": "generate",
"channel": "weixin",
"persona": "<已绑定销售人设>",
"customerName": "<已核对联系人>",
"message": "<最新一条客户原文>",
"conversationIdentity": "<稳定身份>",
"clientContext": { "recentMessages": [] }
}
可发:reply / conversationId / replySource / posterUrls / posterIds
不发:skipped / reason 等(例如 needs_human)
发送验收成功 → action=confirm
提交 conversationId、实际正文 content、实际发送的 posterIds不要把整段历史拼成 message。message 是这轮新话;历史要走专门的上下文字段或服务端记忆,否则旧问题可能被当成新问题重新回答。
最终输入不是一段固定“销售提示词”。getSystemPrompt 先构建系统要求,chatReply 再加入压缩后的历史和本轮专用指令,交给模型。
getPrompt 默认缓存 30 秒;没有配置、取不到或发生静默回退时,使用代码里的 FALLBACK 模板。代码硬规则、数据库知识和客户端行为不跟着 Langfuse 一起变。
CHAT_TOOLS 包含 record_customer_info 和 request_handoff,模型可以返回结构化工具调用。它们由服务端解析处理,不会让模型直接操作微信窗口。
系统先识别这是尺寸报价,结合已有城市、尺寸和价格规则,由代码计算对应算式;命中直答条件时直接输出确定性明细,其他情况将计算结果作为约束交给模型表达。之后仍检查无出处的价格和承诺。具体金额取决于当轮有效业务规则,本页不写死价格口径。
| 材料 | 大白话解释 | 实际作用 |
|---|---|---|
| 品牌与知识文档 | 这家公司真实有什么、能做什么 | 给模型事实依据,例如产品、服务范围和门店信息。不是“聊天模板”。 |
| 决策规则 | 什么情况下应该怎么做 | 例如怎样推进、怎样处理顾虑、何时交给真人。内容与当前问题相关才有必要带入。 |
| 对话示例 | 类似问题以前有一种不错的答法 | 示范语气和组织方式。它影响生成,不等于每次逐字照抄。 |
| 甲方审定话术 | 业务方明确认可过的回答 | 命中较强且满足条件时可原文直答;另一档则作为约束交给模型表达;还可关闭此功能。 |
| 素材库片段 | 从较长资料中找与当前问题相关的一小段 | 经单独的向量检索链放进提示词。查不到时不给这一段,不代表整套知识都不存在。 |
| 可发图片与资料 | 真正能发给客户的附件 | 选择并返回具体 URL / ID,由客户端实发。用来帮助模型回答的文字知识,与发给客户的附件不是同一回事。 |
系统先看客户当下这句话,挑相关材料。客户只说“全屋”“是的”时,知识检索会带上紧邻的一问一答,让检索知道他到底在回答什么;对话示例的匹配则仍按客户原句处理,避免被上一句销售话带偏。
知识文档、规则与示例的一条路径用 bge-m3 算相关度;长资料的另一条路径用 bge-small-zh-v1.5 检索资料分块。后者代码默认取最多 4 段、同一份资料最多占 2 个名额,并限制注入文字量;这些是代码默认,环境变量可能覆盖。
所以 route 返回 generated,也不一定代表底下实际请求过文字模型:chatReply 内部还可能走审定原文或其他直答。要判断实际是否调模型,需要结合调用记录,而不能只看外层来源字段。
loadOrgContext 是统一装配点:把品牌、知识、示例、规则、审定话术,以及启用的工作台业务事实和规则合在一起。知识元素功能开启时,部分文档会用已启用的知识元素替代全文;没有可替换内容或查询失败的路径仍有原文处理机制。
服务端普通回复加载的历史窗口为最近 40 条消息,随后 chatReply 做压缩,默认保留最近 10 条原文。条数是消息条数,不是 40 轮或 10 轮。
把城市、面积、预算、风格、装修阶段、房屋类型和范围等整理成字段,下一轮直接使用。除了模型主动调用“记资料”工具,服务端还会在有信息量的消息后安排分析模型抽取。
把更早的对话增量合并成摘要,保留客户情况、报过的价格和承诺、顾虑、约定和待办。旧内容不是每轮全部重读,而是达到批量条件后更新摘要。
设备可能带来屏幕可见的历史、已读到的客户事实和更旧记录。服务端通过专门合并规则补入,而不是把屏幕内容无条件都算成新入站。
画像抽取和摘要更新通过响应后的后台任务处理,避免让客户一直等。但这也意味着:刚刚说出的事实,不能假设已经写入画像。当前轮仍要看客户原话;报价相关代码也会直接从本轮内容取信息。
有可靠身份关联时,系统还能补充抖音侧的结构化画像;个人微信同销售号的旧会话事实也有专门继承逻辑。这些都有身份匹配条件,不能仅靠“昵称相似”就宣称全平台记忆已打通。
普通回复只在 nurture(继续了解、解释问题)和 decision(出现更明确的决策信号)之间选择。它根据近期客户的话重新判断,信号消失时可以恢复培育口吻。数据库的阶段则保留客户曾到达过的进展,不一定一起回退。
例如客户前面问过到店,后来只是在问某种板材,系统不应该因为“历史上到过决策期”就每轮都强推到店。这是“本轮怎么接话”与“客户曾走到哪一步”分开记录的原因。
以下是解释代码路径的假设场景,不是真实客户对话,也不是本次在线调用模型得到的结果;不承诺实际回复逐字相同。
| 客户这一轮说什么 | 系统应读取哪些信息 | 代码路径如何变化 |
|---|---|---|
| “我在上海,准备做全屋柜子。” | 本轮城市和需求,已有会话身份、历史与组织知识。 | 消息去重后入站;准备普通回复;有信息量的内容可触发后台画像抽取,下一轮少问重复问题。 |
| “全屋。” 假设上一句问做全屋还是局部 | 必须连着上一句看,“全屋”是在回答问题。 | 知识检索用紧邻上下文补足含义;培育阶段有短答专项指令,避免连续盘问。 |
| “按这个尺寸大概多少钱?” | 当前/已知尺寸、城市、适用报价口径,以及已经说过的数字。 | 可能命中确定性报价;否则把代码算出的信息交给模型。不能让模型自己自由创造收费项目。 |
| “有参考图吗?” | 客户偏好、历史已发图片、客户端能发什么。 | 生成正文和选择附件相互配合,最终按真实附件校准描述。配了图片不等于图片已送达。 |
| “好的。” 假设上一句明确答应给图 | 这可能是在接受发图提议,不只是礼貌结束。 | 待兑现承诺规则会参与判断;确实选中附件后可用确定性承接语,避免刚答应发图就结束对话。 |
| “先不去店里了。” | 客户明确拒绝到店,而非从我方话术猜测客户意愿。 | 把拒绝事实放入上下文约束,减少继续邀约;有关拒绝的规则与更广义营销停止判定不能混为一谈。 |
核心 action=generate。围绕客户最新一轮发言生成;近期历史和记忆负责承接。不是因为定时到了就随便说一句。
有 opener 专用入口和首触内容逻辑,检查是否已打过招呼。Windows 首触还涉及资格和已发布内容;不能认定所有首触都实时调用同一条普通回复 prompt。
有独立的资格、任务认领、历史核对、话题、配图和回执路径。Windows 支持按列表标题认人、每日话题等配置;不是“重复调用 generate”就能等价实现。
| 位置 | 检查什么 | 为什么会影响客户看到的内容 |
|---|---|---|
| 模型调用前 | 身份、人设、消息新旧、重复入站、对话阶段、客户拒绝或交接信号 | 不需要回的轮次会提前退出;拿错身份或旧消息时不应继续出话。 |
| chatReply 内 | 工具调用解析、输出清理、短句和单气泡、空回复重试及特定内容修复 | 一次业务请求不一定只调用模型一次;空回复重试和检查重写会增加调用。 |
| 服务端返回前 | 不编门店、不乱许诺方案、价格与承诺有来源、图片实际有无、个人微信表达检查 | 可能删除某句话、修正文案,或返回不发。图片选出来后还要校准“发了几张”等描述。 |
| Windows 发送前后 | 联系人仍是同一位、窗口状态、内容是否变化、停止条件、发送后视觉证据 | 已生成的回复也可能被客户端拦下。需要结合客户端事件判断,不能只查模型是否成功。 |
| confirm 回写 | 实际发出的正文、实际成功的图片 ID | 用于下一轮记忆和图片去重;共享 Relay 有重试及待补记机制,不能把生成稿直接当发送历史。 |
salespc- Windows 设备的特定失败分支,采用“这一条不发,通知人工”策略:例如内容检查修不好、事实检查删空、最终检查只剩通用兜底。代码会记录拦截事件,而不是硬塞一句空话。它不等于所有人工交接场景都永久停用 AI。最终回复有两种主要来源:规则直接给出,或模型生成后再检查。route 用 replySource 标记来源,sanitizerActions 标记部分处理动作;删改和整条替换另有事件留痕。还原模型原文时,也要注意 chatReply 内部已经可能重写过。
| 想解决的问题 | 先看什么 |
|---|---|
| 认错人、读错左右、语音没识别 | 设备日志、截图证据、Vision 结果与设备上的实际读屏模型;入口在 vision.py / runner.py。 |
| 知识答错、报价或门店不对 | 本轮知识出处和客户城市等事实 → org-context / 知识库 → 确定性报价、门店规则 → 模型输入 → 后处理。 |
| 语气不自然、反复问已知信息 | 实际销售人设、历史与 confirm 是否完整、画像/摘要是否带入、Langfuse 版本及个微规则。不要只换模型。 |
| 模型答得对,客户收到另一句 | replySource、内容删改事件、sanitizerActions、route 后处理和客户端检查,比较生成稿与实发正文。 |
| 生成成功但客户没收到 | 客户端发前核对、发送验收、丢弃/重试事件和 confirm。Langfuse 成功只能证明对应模型调用完成。 |
| 想知道现在跑哪版 | 服务端看 /api/status;客户端看 wecom_loop_heartbeats 的版本与 last_seen_at。包发布记录不能证明电脑已安装。 |
conversations:会话身份、阶段、画像和摘要。messages:客户入站与确认后的我方消息。brand_profile / knowledge_documents / conversation_examples / decision_rules:品牌、事实、话术例子与业务规则。llm_call_provenance 和 Langfuse:模型、提示词来源、知识出处、工具及调用结果等。wecom_loop_heartbeats:机器是否有新鲜心跳、运行版本。wecom_client_events:异常、警告与拦截;不能拿异常条数当业务活跃度。
销售措辞和阶段引导 → Langfuse 提示词,并保持代码 fallback 同步。
业务事实与认可答法 → 对应知识、规则、示例数据及其发布路径。
个人微信共用约束、报价算法、事实检查 → 服务端 TypeScript。
读屏、认人、点击、发前复核 → Windows 执行端。
模型切换 → 对应服务端或设备环境变量;改完分别核对生效,不以本地 git 代替部署验证。
当前读到的主链路,是“给现成模型提供更合适的上下文”,包括记忆、知识、规则和示例;不能把写入客户画像或知识库,理解成模型参数已被自动训练。画像更新后是否真正影响下一轮,还要看是否被读取和带入。
没有固定次数。端上可能需要多次读标题、正文或复核;服务端可能要取语义向量、检索资料,再调用一次文字模型;遇到空回复或内容问题,还会有重试或修复。画像抽取和摘要又可能在后台调用分析模型。同一个客户轮次也可能因为发前复核而再次读屏。
耗时可以按“发现并点开 → 读屏 → 网络往返 → 查上下文与检索 → 生成及修复 → 发送前复核 → 发送验收”分段看。本次没有做真实客户压测,所以不编一个固定几秒的承诺。
生成过程中客户可能又说了一句,窗口也可能被人切走;生成结果还可能含错误承诺,或经过检查后已没有可发正文。因此生成只是中间结果。最后要同时满足“发给谁对了、现在仍该回、内容可用、设备能安全发送”。
Langfuse:管理提示词版本、记录模型调用过程的平台。
Relay:网络中转,把客户端请求转给服务端或模型接口,本身不等于话术大脑。
persona:本轮代谁说话的销售身份配置。
clientContext:设备附带的已看到的上下文。
confirm:客户端告诉服务端“这条确实发送成功,请记账”。
fallback:主要路径失败时的后备方案;提示词后备、模型后备、话术后备是不同层的事。
幂等:同一件事重复提交,也尽量只记或执行一次,用来减少重试造成的重复。
provenance:一条调用的出处账,帮助追溯它参考了什么、用什么配置生成。
确定性规则:代码按明确条件得出结果,例如计算金额或返回已确认门店信息,不让模型自由猜。
“已生成”“已尝试发送”“客户端确认成功”“已回写成功”是不同事实。“没查到发送记录”也可能是回写失败;“探针没连上”可能是网络核对失败。排查时要分清已确认成功、已确认失败、暂时没验成。
不要一遇到答得不好就换模型,也不要把所有要求都追加到 Langfuse。先还原“它看到了什么、参考了什么、生成了什么、最后发了什么”,再改真正造成问题的那一层。
| 现象 / 想改的内容 | 优先改哪里 | 为什么 / 改完看什么 |
|---|---|---|
| 事实正确,但太啰嗦、语气生硬、推进顺序不自然 | Langfuse 阶段提示词,同时排查代码拼入的风格约束 | 属于“怎么表达”。先确认实际用的 prompt 名称和版本;不要在模板里加一句与代码硬约束相反的话。 |
| 只想调整 Windows 个微,其他微信系业务不应受影响 | 先确认隔离方式,可能需要代码 | wecom.nurture.rules / decision.rules 是共用模板;channel=weixin 也不是 Windows 专属。若只对 Windows 生效,需要明确的设备条件、上下文标记或独立模板路由,不能直接改共用模板就声称只影响 Windows。 |
| 门店地址、产品参数、服务范围、认可话术本身变了 | 知识库 / 业务数据 | 事实应进入统一来源;把一份新价格偷偷写进 prompt,会与旧知识和代码价格规则冲突。若计算口径也变,相关算法一起改。 |
| 价格算错、条件判断错、明明已知城市仍走未知城市分支 | 代码的数据读取与计算逻辑 | 属于“依据或算法错了”。给模型加“请认真计算”不能修复错误输入、错误分支或漏字段。 |
| 客户说过的信息没带进去,取错历史、重复把旧消息当新消息 | 上下文、身份、去重与记忆代码 | 模型看不到事实,就无法可靠地遵守“不要重复问”。先查消息、画像、摘要和客户端补充是否正确进入这一轮。 |
| 模型原话不错,发给客户却被删坏或换成另一句 | 生成后的内容检查代码 | 比较模型稿、chatReply 返回稿、route 最终稿和实际发送记录。修复过宽规则,不能靠换模型掩盖删改问题。 |
| 绝不能编某类承诺、绝不能发错联系人 | 代码检查 + 提示词配合 | 提示词说明原则;可以明确判断的条件由代码落实。但拦截也会误伤,必须同时测试该拦和该放的样本。 |
| 标题读错、左右气泡弄反、坐标不准 | Windows 读屏要求、截图范围、解析与复核代码 | 这些要求在 vision.py 等代码中,不属于文字回复的 Langfuse 模板。先检查截图是否正确,再评估读屏模型。 |
| 文字生成能力确实不足,多个场景稳定失败 | 模型配置及必要的接口代码 | 先在相同输入下比较候选模型;更换服务端模型配置可能影响共用该配置的业务。推理参数、工具协议或输出结构不兼容时,还要改适配代码。 |
阶段模板放在 Langfuse,代码通过 getPrompt 读取并替换占位符;当读取失败时,代码里的 FALLBACK 模板顶上。与此同时,人设、个微附加要求、报价、门店清单、本轮动态指令等仍会由代码拼进去。
| 对象 | 建议固定的条件 | 重点指标 |
|---|---|---|
| Windows 读屏模型 | 相同截图、裁剪区域、任务要求、推理开关和解析方式;覆盖不同缩放、窗口大小、相似标题、重复数字、语音与系统提示。 | 完整标题准确率、左右方向、最新气泡识别、结构化输出可解析率、拒识与误识、耗时和每任务成本。认错人比少读到几个字更严重。 |
| 对客文字模型 | 相同历史、知识、prompt 版本、工具和后处理;比较整个会话,既测普通问题,也测更正、拒绝和多轮承诺。 | 当前问题有没有答、事实是否有来源、数字一致性、重复追问、语气自然度、空回复及工具调用表现、最终稿是否被检查删空。 |
| 记忆分析模型 | 同一组带已知正确事实的脱敏对话,包含客户纠正旧信息、数字和不同时间的约定。 | 字段抽对率、是否把销售的话误当客户事实、旧值是否被正确更新、摘要是否遗漏或改写价格与承诺。 |
| 检索模型 | 固定资料集和标准相关片段,覆盖同义问法、短答和无关问题;索引与查询模型要匹配。 | 相关片段能否找到、无关资料是否混入、同一本资料是否占满名额、时延与成本。不能只看向量接口返回成功。 |
建议统计方式:报告样本数和失败明细,耗时同时看中位数及较慢的一批;分别统计原始生成与最终可发结果。单次模型便宜,若导致频繁重试、人工接管或认错消息,整条业务链未必更便宜。
下面是后续实际修改时可用的命令参考,本次未执行付费评测。运行前需要有效的封顶评测密钥;生产调用路径的临时试跑应使用 AKKE_USE_EVAL_KEY=1,并设置 AKKE_RUN_BY 记录执行者。
# 在对应仓库的隔离工作区执行;先留改前基线,再测 staging AKKE_USE_EVAL_KEY=1 AKKE_RUN_BY=xiaxia \ pnpm tsx scripts/eval-wecom-talktrack.ts --channel=weixin --samples=5 AKKE_USE_EVAL_KEY=1 AKKE_RUN_BY=xiaxia AKKE_PROMPT_LABEL=staging \ pnpm tsx scripts/eval-wecom-talktrack.ts --channel=weixin --samples=5 # 只核对 production 提示词与仓库快照是否漂移,不写文件 pnpm tsx scripts/snapshot-langfuse-prompts.ts --check # 核对仓库快照与代码 fallback 的正文,以及占位符结构 pnpm tsx scripts/check-prompt-fallback-sync.ts pnpm tsx scripts/check-prompt-placeholders.ts
话术脚本走 chatReply 和真实组织上下文,适合验证生成层,但并非“完整 Windows GUI 测试”,也不覆盖 route 中所有后处理。长对话可参考 eval-wecom-longrun.ts 的画像与摘要测试,并核对测试通道是否符合本次改动;读屏与发送需要另外使用固定截图和受控会话。
快照 --check 只报告差异。正式修改 Langfuse 后,要按发布流程拉取更新后的快照、同步 fallback 并走代码评审;不能为了让检查变绿,盲目把较新的一边覆盖成较旧的一边。
每次记录:问题样本 → 原因所属层 → 具体改动 → 影响范围 → 改前结果 → 改后结果 → 实際生效版本 → 回退方法。例如“客户短答后连续追问”,先确认上一轮销售问题确实带入;若输入正确再改表达,若短答分支没触发就修代码。这样每次优化都有证据,而不是不停往提示词末尾追加禁令。
代码来源:Akke-AI/wecom-chat,已执行 fetch origin;分析固定在 5aa1ef4a6265f855958beba7f0132476bb41958f。HTML 写在以该版本建立的独立工作区,未切换或覆盖共享主目录。
生产核对:2026-09-29 11:07:52(北京时间),服务端健康探针 返回 production、commit=5aa1ef4、wecom_chat_model=qwen/qwen3-235b-a22b-2507,Langfuse 已配置;数据库和 OpenRouter 探针通过。
探针验证的是服务配置与连通性,不是实际发送测试。本次没有调用生成接口、没有向客户发消息。未逐机核验客户端安装版本和模型覆盖值,未拉取实时 Langfuse 模板正文及版本,未导出客户私密对话或在线知识库内容。因此这些部分说明的是当前代码机制,不声称每台机器都已按此运行。
以下链接固定到本次分析的提交,便于追溯;私有仓库需登录 GitHub 才能打开。