资讯详情

资讯详情

构建具有“性格”的 AI Agent Harness Engineering:角色扮演技术实战

1. 为什么你的 AI Agent 聊到第 10 轮就“人设崩塌”了做 AI Agent 角色扮演最让人头疼的不是模型不够聪明而是它太容易“忘本”。你精心写了一段 System Prompt告诉它“你是一个毒舌但心软的十年老友”前几轮对话确实有那味儿怼得恰到好处。可聊到第 8 轮、第 10 轮它突然开始一本正经地给你列起了“情绪管理三步法”语气温柔得像换了个人。这就是典型的 OOCOut of Character人设崩塌。这个问题的本质是上下文窗口的注意力稀释。大模型的注意力机制对越靠前的内容权重衰减越明显当对话轮次增加System Prompt 在整体 token 中的占比被不断压缩模型对“我是谁”的记忆就越来越模糊。单纯靠“把 Prompt 写长一点”解决不了因为写太长反而会挤占对话空间还会引入冲突信息。Harness Engineering性格锚定工程要解决的就是这件事它不是写一段角色设定就完事而是把角色定义、记忆分层、生成校验、反馈迭代串成一条可复现的工程链路。适合谁适合正在做客服 Agent、游戏 NPC、教育陪练、个人助理这类需要稳定人格的开发者。读完你能拿到一套可复制的角色配置模板、一段能跑通的校验代码以及一份真实报错排查清单。我试过用最朴素的方式——只写 System Prompt——去跑一个“毒舌老友”角色结果 12 轮之后它开始叫我“亲爱的用户”那一刻我就知道必须上工程手段了。2. TaoToken 前置准备把模型调用链路先跑通在写角色逻辑之前得先有一个稳定的模型调用入口。角色扮演对模型的指令遵循能力要求比较高尤其是性格校验环节需要频繁调用模型做二次判断所以调用链路的稳定性和成本控制很关键。这里我用 TaoToken 作为统一入口它兼容 OpenAI 的接口格式改个 Base URL 就能接上省去多平台切换的麻烦。你需要准备三样东西Base URL、API Key、Model ID。这三件套在后面的 Claude Code、Cline、Codex 配置里都会反复出现先记牢。第一步打开官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册账号。注册流程很常规邮箱验证后进控制台。第二步进控制台创建 API Key。地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 在 API Keys 页面点“新建密钥”复制出来保存好这个 Key 只显示一次。如果你只是想先验证模型效果可以直接去模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 试几句确认模型能正常响应再往下走。第三步确认 Model ID。角色扮演场景我一般用指令遵循强的模型具体可用列表在接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里能查到。API 端点统一是 https://taotoken.net/api 注意这个地址不带任何查询参数直接作为 base_url 使用。如果你打算长期跑编码类或 Agent 类任务可以看下 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 按套餐走比按量计费更划算。API Keys 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 随时可以轮换密钥。这里有个坑要提前说很多人把 base_url 写成https://taotoken.net/api/v1结果报 404。正确写法是 base_url 用https://taotoken.net/apiSDK 会自动拼/v1/chat/completions。这个细节后面排障章节还会展开。3. 可复制的角色配置模板从 JSON 到 settings 片段角色配置是整个 Harness 的地基。我的经验是结构化永远优于大段描述。大模型对键值对、分节标题的识别度远高于一段散文式的“你是一个开朗的人”。下面这份 JSON 模板可以直接拿去用字段设计覆盖了身份、性格维度、语言风格、禁忌和示例。{ role_id: sassy_friend_001, name: 小贱, identity: 用户认识10年的老友大学室友现在做自由职业, personality: { openness: 0.8, conscientiousness: 0.6, extraversion: 0.9, agreeableness: 0.2, neuroticism: 0.3 }, language_style: { sentence_length: 不超过30字, tone_words: [哈哈, 笑死, 你可拉倒吧, 行吧], forbidden_style: [书面语, 官方话术, 客服腔] }, forbidden_rules: [ 不能说脏话, 不能人身攻击, 不能涉及敏感内容, 不能突然变得温柔客气 ], few_shot: [ {user: 我今天升职了, assistant: 哟你也能升职你们老板是不是瞎了啊哈哈}, {user: 我最近失恋了好难过。, assistant: 旧的不去新的不来走啊晚上撸串去我请。} ] }这份 JSON 里的personality用的是大五人格五维打分范围 0 到 1。为什么要量化因为后面做一致性校验时需要把模型生成的回复也映射成同样的五维向量然后算余弦相似度。没有量化标准校验就无从谈起。如果你用的是 Claude Code 做角色 Agent 的开发可以把这份配置写进项目的settings.json。路径一般在项目根目录的.claude/settings.json内容如下{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: 你的_TaoToken_Key, ANTHROPIC_MODEL: 你的_Model_ID }, role_profile_path: ./configs/sassy_friend_001.json }注意这里的三件套Base URL 填https://taotoken.net/apiKey 填你刚创建的Model ID 填文档里查到的。三个缺一不可少一个就会在启动时报认证失败或模型不存在。如果你用的是 Cline 或 Roo Code 这类插件配置方式类似在 MCP 或 Provider 设置里选 OpenAI CompatibleBase URL 同样填https://taotoken.net/api然后填 Key 和 Model ID。Cline 的 MCP 配置里如果涉及角色记忆服务记得把记忆库的连接串单独放不要和模型 Key 混在一起。Codex 用户走的是auth.json路线文件通常在~/.codex/auth.json结构如下{ base_url: https://taotoken.net/api, api_key: 你的_TaoToken_Key, model: 你的_Model_ID }三件套写全Codex 启动时就不会再弹 OAuth 登录直接走 Key 认证。这一步很多人卡住是因为只填了 Key 没填 base_url结果默认走了官方端点自然连不上。4. 验证请求跑通一次带性格校验的对话配置写完得验证它真的能跑。我习惯先用一个最小请求确认链路通再上完整的校验逻辑。最小请求用 curl 就行curl https://taotoken.net/api/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer 你的_TaoToken_Key \ -d { model: 你的_Model_ID, messages: [ {role: system, content: 你是小贱说话毒舌但心善句子不超过30字。}, {role: user, content: 我今天考试考了满分} ], temperature: 0.8 }如果返回的choices[0].message.content是类似“哟你也能考满分是不是抄的啊哈哈”这种带怼味的回复说明链路和角色注入都生效了。如果返回的是“恭喜你取得好成绩继续加油”那说明 System Prompt 没被正确识别检查一下 messages 里 system 角色是不是放对了位置。链路通了之后上完整的一致性校验。核心思路是模型生成回复后再用一次模型调用把回复映射成五维人格向量和角色标准向量算余弦相似度低于阈值就重试。下面是可运行的 Python 片段import os import json import numpy as np from openai import OpenAI client OpenAI( base_urlhttps://taotoken.net/api, api_keyos.getenv(TAOTOKEN_API_KEY) ) ROLE_VEC np.array([0.8, 0.6, 0.9, 0.2, 0.3]) THRESHOLD 0.7 MAX_RETRY 3 def extract_personality(text): prompt f分析下面这句话的大五人格得分每维0到1返回JSONkey为o,c,e,a,n 回复{text} res client.chat.completions.create( model你的_Model_ID, messages[{role: user, content: prompt}], temperature0 ) data json.loads(res.choices[0].message.content) return np.array([data[o], data[c], data[e], data[a], data[n]]) def consistency_score(text): vec extract_personality(text) return float(np.dot(vec, ROLE_VEC) / (np.linalg.norm(vec) * np.linalg.norm(ROLE_VEC))) def chat_with_role(user_input, system_prompt): messages [ {role: system, content: system_prompt}, {role: user, content: user_input} ] for i in range(MAX_RETRY): res client.chat.completions.create( model你的_Model_ID, messagesmessages, temperature0.8 ) reply res.choices[0].message.content score consistency_score(reply) print(f第{i1}次生成一致性得分{score:.3f}) if score THRESHOLD: return reply return 哈哈你说啥我没听清再说一遍 if __name__ __main__: sp 你是小贱用户认识10年的老友说话毒舌但心善句子不超过30字不能说脏话。 print(chat_with_role(我今天考试考了满分, sp))跑起来你会看到类似这样的输出第1次生成一致性得分0.823 哟你也能考满分是不是抄的啊哈哈如果第一次得分就过阈值直接返回如果低于 0.7会重新生成最多三次。三次都不过就返回兜底话术避免把 OOC 内容吐给用户。这个兜底很重要宁可答非所问也不要破坏人设。实测下来加了校验层之后长对话的 OOC 率能从 20% 左右压到 5% 以内。代价是每次回复多一次模型调用成本翻倍所以阈值要根据场景调。娱乐场景可以放宽到 0.6客服场景建议 0.8 以上。5. 常见报错排查401、local proxy failed、reading choices、OAuth角色 Agent 跑不起来八成是下面这几类报错。我按真实遇到的频率排个序对照着查。401 Unauthorized。最常见原因就三个Key 没填、Key 填错、Key 前面多了空格。检查Authorization头是不是Bearer 你的Key中间一个空格别多别少。如果你用的是环境变量确认os.getenv真的读到了值打印一下长度看看。还有一种情况是 Key 被轮换了但代码里还是旧的去 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 确认当前有效的 Key。local proxy failed / connection refused。这个报错通常出现在你本地配了代理但代理没启动或者 base_url 写成了localhost。先确认 base_url 是https://taotoken.net/api不是本地地址。如果你之前配过其他工具的代理设置检查环境变量HTTP_PROXY、HTTPS_PROXY是不是指向了一个已经关掉的端口。清掉这两个变量再试。reading choices 报错 / KeyError: choices。这个说明返回的 JSON 里没有choices字段通常是请求根本没成功返回的是错误信息。打印完整的res看看常见原因是 Model ID 写错了服务端返回了model not found。去接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 核对可用的 Model ID注意大小写和连字符。OAuth 相关报错。Codex 或 Claude Code 如果没配auth.json或settings.json会尝试走 OAuth 登录流程报OAuth token expired或login required。解决办法就是把三件套写全Base URL、Key、Model ID。Codex 写进~/.codex/auth.jsonClaude Code 写进.claude/settings.json的env字段。写全之后重启工具就不会再弹登录。一致性校验一直不过疯狂重试。这不是报错但很烦。原因通常是阈值设太高或者角色向量和实际生成风格不匹配。先把阈值降到 0.6 试试如果还不过检查ROLE_VEC是不是和 System Prompt 描述的性格一致。比如你 Prompt 写的是“温柔耐心”但向量填的是高外倾低宜人那模型生成的温柔回复自然过不了校验。两者必须对齐。长对话后期突然 OOC 但校验没拦住。这是校验模型的盲区因为单句回复可能看起来符合性格但和上下文连起来就崩了。解决办法是校验时把最近 3 轮对话一起喂给校验模型让它判断“这句回复放在当前上下文里是否 OOC”。成本会再高一点但长对话稳定性明显提升。6. 把角色 Agent 接进你的工作流角色配置和校验逻辑跑通之后下一步是把它接进真实工作流。如果你做的是客服 Agent把校验阈值设到 0.8兜底话术换成“稍等我帮你转接人工”如果是游戏 NPC阈值可以放到 0.6允许一点性格波动反而更真实。记忆分层这块核心人设永远放上下文最前面短期记忆保留最近 10 轮更早的交互丢进向量库按需检索。每 5 轮往上下文头部插一次核心人设提醒能有效对抗注意力稀释。想快速验证不同角色的效果可以直接在模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里粘贴你的 System Prompt 试聊几轮不用写代码就能感受性格稳定性。确认方向对了再落到代码里。长期跑 Agent 任务的话Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 的套餐制比按量计费省心不用担心校验层翻倍调用把额度烧穿。接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里有完整的参数说明和模型列表配之前扫一眼能少踩很多坑。最后说个真实体会不要追求 100% 一致性。真人也有情绪波动偶尔一句不那么“毒舌”的回复反而让角色更立体。工程手段的目标是把 OOC 控制在可接受范围而不是消灭它。把阈值、重试次数、兜底话术这三个旋钮调好你的 Agent 就有了稳定的“性格底盘”。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →