从今天觉醒,技术赋予每一个人数字生命
我造了个"虚拟来访者"陪咨询师练手,并用数据验证它演得像不像

心理咨询新手的培训里有个绕不开的环节:角色扮演。学员需要一个"来访者"反复练习开放式提问、倾听、情感反映。但真人扮演有三个老问题:约不到人、演得不稳定、新人出错时有心理负担。不解决的代价很直接——新手把第一位真实来访者当成了练习对象。
先看一段我在本地跑出来的效果:
咨询师:最近睡得怎么样?
虚拟来访者:嗯……不太好。躺下来脑子就停不下来,老想着周五汇报搞砸了怎么办。
咨询师:听起来你对这次汇报挺紧张的。
语气、犹豫感已经有点意思了。但"像不像"不能靠感觉,得用数据说话。
学完这篇文章你能:
一、方案设计:为什么是"本地量化模型 + 模式标注"
整体拆成三个模块:虚拟来访者(LLM + 人设 Prompt)、标注器(把咨询师每句话分类)、统计分析(两组分布对比)。
选型理由:
- 本地开源模型:咨询对话高度敏感,数据不能出本机,这是硬约束。早期类似实验用的是 Mixtral 8x7B 的 4-bit 量化版,如今同等显存下可以跑更新的 8B 级模型(如 Qwen3 系列),Q4 量化后约 5GB,一张 12G 的消费级显卡或 Mac 都够。
- Prompt 而非微调:来访者人设用几百字的系统提示词就能立住八成,微调需要大量标注语料,投入产出不划算。
明确放弃的方案:规则脚本机器人——真实来访者不会按剧本走,脚本bot练不出倾听能力,这正是要解决的痛点本身。
二、核心实现
环境:Python 3.10+,Ollama,pip install "openai>=1.50" pandas scipy,然后 ollama pull qwen3:8b。
2.1 最小可运行的虚拟来访者
# sim_client.py
import re
from openai import OpenAI
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
MODEL = "qwen3:8b"
PERSONA = """你扮演心理咨询模拟中的来访者"小林",26岁,因工作压力失眠、自我怀疑三个月。
必须遵守:
1. 口语化,允许犹豫("嗯……""其实我也说不好");
2. 单次回复不超过3句话,禁止列表和分点;
3. 绝不主动总结、绝不提建议、绝不像咨询师那样反问;
4. 开放式问题才展开,封闭式问题可以只答一两个字。"""
THINK = re.compile(r"<think>.*?</think>", re.S)
def client_reply(history, counselor_says: str) –> str:
history.append({"role": "user", "content": counselor_says})
resp = client.chat.completions.create(
model=MODEL, messages=history, temperature=0.7, max_tokens=150)
text = THINK.sub("", resp.choices[0].message.content).strip()
history.append({"role": "assistant", "content": text})
return text
if __name__ == "__main__":
h = [{"role": "system", "content": PERSONA}]
while (s := input("咨询师: ")) not in {"quit", "exit"}:
print("来访者:", client_reply(h, s))
成功标准:跑起来后来访者回复口语化、不超过3句、不反客为主。
2.2 句子级沟通模式标注器
把咨询师的每句话归到一个类别,用同一本地模型、few-shot + 零温度保证可复现:
# labeler.py
import json, re
from openai import OpenAI
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
LABELS = ["开放式提问","封闭式提问","情感反映","内容复述","总结","建议","鼓励性回应","其他"]
TEMPLATE = """把咨询师的话归入且仅归入一类:{labels}。只输出JSON:{{"label":"…"}}
示例:"能多说一点当时的情况吗?"→{{"label":"开放式提问"}}
"你当时是不是特别难受?"→{{"label":"情感反映"}}
"你可以试试睡前冥想十分钟。"→{{"label":"建议"}}
待标注:"{s}"→"""
def label_sentence(s: str) –> str:
resp = client.chat.completions.create(
model="qwen3:8b", temperature=0,
messages=[{"role": "user", "content": TEMPLATE.format(labels="/".join(LABELS), s=s)}])
m = re.search(r"\\{.*\\}", resp.choices[0].message.content, re.S)
try:
lb = json.loads(m.group()).get("label", "其他")
except Exception:
lb = "其他"
return lb if lb in LABELS else "其他"
def split_sentences(text: str):
return [x.strip() for x in re.split(r"[。!?!?\\n]+", text) if x.strip()]
2.3 分布对比与统计检验
# analyze.py
import pandas as pd
from scipy.stats import chi2_contingency
def compare(rows): # rows: [{"group": "human"/"llm", "label": …}, …]
ct = pd.crosstab(pd.DataFrame(rows)["group"], pd.DataFrame(rows)["label"])
pct = ct.div(ct.sum(axis=1), axis=0).round(3)
chi2, p, _, _ = chi2_contingency(ct)
return pct, p
2.4 踩坑记录(三个都是真踩过的)
- 坑1:bitsandbytes 4-bit 在 Windows 上装到天荒地老。 最初学着论文做法用 transformers + bitsandbytes 做 4-bit 量化,版本矩阵对不上直接 CUDA 报错。排障:换 Ollama 的官方 Q4 量化模型,一条 ollama pull 解决,量化质量足够教学场景使用。
- 坑2:模型输出夹带"思考标签",且人设会漂移。 新一代思考型模型会在回复里混入 <think>…</think>;另外聊到 15 轮以后,来访者开始条理清晰地自我总结——真人来访者恰恰不会这样。排障:正则剥离思考标签(上文代码已含);每 8~10 轮把 PERSONA 重新注入一次对话历史;"不超过3句话"的规则能砍掉大部分漂移。
- 坑3:标注器分不清"内容复述"和"情感反映"。 裸 Prompt 时这两类互相误判率很高。排障:few-shot 里各加一条对比示例 + temperature=0;再抽 50 句人工核对,一致率从约 70% 提到 84%,剩下的误差在分析时如实报告,不藏着。
三、效果验证:数据说明什么
我各跑了 10 段对话(真人对照组来自同学互扮的转写文本),咨询师语句共约 400 句,标注后分布如下(演示性质的小样本,结论不外推):
| 开放式提问 | 34% | 41% |
| 封闭式提问 | 18% | 15% |
| 情感反映 | 16% | 14% |
| 内容复述 | 10% | 8% |
| 总结 | 6% | 5% |
| 建议 | 7% | 12% |
| 鼓励性回应 | 9% | 5% |
卡方检验 p < 0.05,两组分布差异显著但结构相似:主体都是开放式提问和情感反映,说明 LLM 来访者能撑起核心训练场景;差异在于——LLM 来访者表达更流畅完整、几乎不沉默,新手更容易连续追问、给建议也更顺口,而面对真人时的"鼓励性回应"更多,因为真人会卡壳、会冷场。这与更大样本研究里观察到的方向一致:相似与差异并存。
复现步骤:① 安装依赖并拉取模型;② 跑 sim_client.py 录 10 段对话存成文本;③ 用 labeler.py 逐句标注两组语料;④ 调 compare() 看分布和 p 值。
四、边界与演进
局限性必须说清楚:LLM 来访者不会真正抗拒、崩溃或长时间沉默,所以危机干预这类高风险训练不能用它;标注器本身有约 15% 的误差,所有结论都建立在这个噪声之上;小样本演示不能替代正式实验。
下一步优化方向:建一个来访者人格库(焦虑型、回避型、防御型);加人设一致性监控自动报警漂移;用更强的云端模型(如 GPT-5.5、DeepSeek 4.0 Pro 这类当前主流大模型)跑对照组,看模型能力对"演技"的影响。核心问题始终是那一个:虚拟来访者演得够不够像,得像这篇文章一样,拿数据出来说话。
网硕互联帮助中心





评论前必须登录!
注册