planning-user-interviews

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Planning user interviews

规划用户访谈

Use this skill when someone asks to set up a user interview — to talk to customers, check sentiment, or gather qualitative feedback through a voice conversation. The plan is captured as a
UserInterviewTopic
that a voice agent will later run through.
当有人要求设置用户访谈——与客户交流、了解用户情绪或通过语音对话收集定性反馈时,可使用本技能。访谈计划将被保存为
UserInterviewTopic
,后续由Voice Agent执行。

What a complete topic needs

完整主题所需内容

Before calling
user-interview-topics-create
, gather these:
  1. Who to interview — at least one of:
    • interviewee_cohort
      — an existing cohort ID
    • interviewee_emails
      — list of email addresses
    • interviewee_distinct_ids
      — list of PostHog distinct IDs
  2. What to ask about
    topic
    (required free text)
  3. How the agent should frame the conversation — optional
    agent_context
    (extra system prompt)
  4. The questions to work through — optional ordered
    questions
    list
The API rejects topics with no targeting, so at least one of the three audience fields must be set. They can be combined — a cohort plus a handful of extra emails is fine.
在调用
user-interview-topics-create
接口前,需收集以下信息:
  1. 访谈对象 — 至少包含以下一项:
    • interviewee_cohort
      — 现有cohort的ID
    • interviewee_emails
      — 邮箱地址列表
    • interviewee_distinct_ids
      — PostHog distinct IDs列表
  2. 访谈内容
    topic
    (必填自由文本)
  3. Agent对话框架 — 可选的
    agent_context
    (额外系统提示)
  4. 访谈问题清单 — 可选的有序
    questions
    列表
API会拒绝未设置目标对象的主题,因此至少需填写上述三类受众字段中的一项。也可组合使用——比如同时选择一个cohort和额外几个邮箱是允许的。

Step 1: Clarify intent

步骤1:明确需求意图

If the request is vague, ask:
  • Which feature or behavior? "checkout" might be the button click, the page view, or the payment submission — narrow it down to one event.
  • What do you want to learn? Why they bounced? What confused them? What alternatives they tried? The goal shapes both the audience and the questions.
  • Which kind of users? Heavy users (what works), drop-offs (what blocks adoption), at-risk users (what breaks retention), or a mix.
Skip these questions only when the user has already answered them.
若用户请求模糊,可询问以下问题:
  • 针对哪个功能或行为? “checkout”可能指按钮点击、页面浏览或支付提交——需将范围缩小至单一事件。
  • 您希望了解什么? 用户为何流失?什么让他们困惑?他们尝试过哪些替代方案?研究目标会影响受众选择和问题设计。
  • 针对哪类用户? 重度用户(了解现有功能优势)、流失用户(了解阻碍因素)、高风险用户(了解影响留存的问题),还是混合群体?
仅当用户已明确回答这些问题时,才可跳过。

Step 2: Pick the audience

步骤2:选择受众群体

Map what the user said to one of these paths:
  • They named a cohort ("our power users", "trial signups last week") — use
    cohorts-list
    filtered by name to find the cohort, confirm the match, and pass the cohort ID as
    interviewee_cohort
    .
  • They described the kind of person but no cohort exists — offer to either create the cohort first (
    cohorts-create
    ) or fall back to finding people by behavior (see below).
  • They gave email addresses or distinct IDs — accept them directly. Skip the cohort lookup.
  • They described a behavior, not a cohort ("users who tried checkout but didn't finish", "people who used to use dark mode and stopped") — find them by querying their events (see below).
  • They were vague ("a few customers", "some power users") — ask which they prefer:
    • Pick an existing cohort →
      cohorts-list
    • Look up specific persons by name or email →
      persons-list
      with a search query
    • Find users by behavior → see below
    • Paste a list of email addresses
Each email passes through DRF email validation (display-name format
Paul D'Ambra <paul@x.com>
is accepted alongside plain
paul@x.com
).
根据用户描述匹配以下路径:
  • 用户指定了cohort(如“我们的核心用户”“上周注册的试用用户”)——使用
    cohorts-list
    按名称筛选找到对应cohort,确认匹配后,将cohort ID作为
    interviewee_cohort
    传入。
  • 用户描述了用户类型但无对应cohort——提供两种选择:先创建cohort(
    cohorts-create
    ),或通过用户行为查找(见下文)。
  • 用户提供了邮箱地址或distinct IDs——直接接收,跳过cohort查询。
  • 用户描述了行为而非cohort(如“尝试过checkout但未完成的用户”“曾经使用深色模式但现已停用的用户”)——通过查询用户事件找到对应人群(见下文)。
  • 用户描述模糊(如“几位客户”“一些核心用户”)——询问用户偏好:
    • 选择现有cohort →
      cohorts-list
    • 通过姓名或邮箱查找特定用户 → 使用搜索查询调用
      persons-list
    • 通过用户行为查找 → 见下文
    • 粘贴邮箱地址列表
每个邮箱需通过DRF邮箱验证(支持显示名称格式
Paul D'Ambra <paul@x.com>
,也支持纯邮箱格式
paul@x.com
)。

Finding users by behavior

通过用户行为查找受众

When the user describes who they want to talk to in behavioral terms, find them in the project's own data:
  1. Find the right event. Call
    read-data-schema
    to list events that actually exist in the project. Don't guess event names from training data — PostHog event taxonomies are bespoke. Match the user's description to one or two candidate events; if multiple plausible matches exist, list them and ask which behavior they care about.
  2. Query for users. Call
    execute-sql
    with HogQL. Filter by the chosen event over the last 60 days, group by person — prefer
    person.properties.email
    (directly usable as
    interviewee_emails
    ), fall back to
    distinct_id
    (for
    interviewee_distinct_ids
    ). Keep both kinds of rows. The aggregates in each template (
    event_count
    ,
    last_seen
    ,
    days_since_last_seen
    ) are what feed Step 5's per-interviewee context. Replace
    <event_name>
    with the chosen event, and
    <id>
    with
    person.properties.email
    or
    distinct_id
    :
    • Heavy users
      SELECT <id> AS id, count() AS event_count, max(timestamp) AS last_seen, dateDiff('day', max(timestamp), now()) AS days_since_last_seen FROM events WHERE event = '<event_name>' AND timestamp > now() - INTERVAL 60 DAY GROUP BY <id> HAVING count() >= 5 ORDER BY count() DESC LIMIT 20
    • Drop-offs (tried once or twice and never came back) —
      SELECT <id> AS id, count() AS event_count, max(timestamp) AS last_seen, dateDiff('day', max(timestamp), now()) AS days_since_last_seen FROM events WHERE event = '<event_name>' AND timestamp > now() - INTERVAL 60 DAY GROUP BY <id> HAVING count() <= 2 AND dateDiff('day', max(timestamp), now()) > 14 ORDER BY count() ASC LIMIT 20
    • At-risk (was active, now dormant) —
      SELECT <id> AS id, count() AS event_count, max(timestamp) AS last_seen, dateDiff('day', max(timestamp), now()) AS days_since_last_seen FROM events WHERE event = '<event_name>' AND timestamp > now() - INTERVAL 60 DAY GROUP BY <id> HAVING count() >= 3 AND dateDiff('day', max(timestamp), now()) > 14 ORDER BY days_since_last_seen DESC LIMIT 20
  3. Build a balanced sample. Unless the user asked for one specific segment, mixing 5 heavy users + 3 drop-offs + 2 at-risk users yields the most actionable interviews: you learn what works, what blocks adoption, and what breaks retention. Adjust counts to match what the user actually wants.
Pass the email rows as
interviewee_emails
and the distinct-ID rows as
interviewee_distinct_ids
— both can be set on the same topic. Keep
event_count
and
days_since_last_seen
per person so Step 5 can synthesise context like "used checkout 47 times in last 60 days; last seen 2 days ago".
当用户以行为描述目标访谈对象时,需从项目自身数据中查找:
  1. 找到对应事件——调用
    read-data-schema
    列出项目中实际存在的事件。不要根据训练数据猜测事件名称——PostHog的事件分类是定制化的。将用户描述匹配到1-2个候选事件;若存在多个合理匹配,列出所有选项并询问用户关注的具体行为。
  2. 查询用户——使用HogQL调用
    execute-sql
    。筛选过去60天内的目标事件,按用户分组——优先使用
    person.properties.email
    (可直接作为
    interviewee_emails
    ),其次是
    distinct_id
    (作为
    interviewee_distinct_ids
    )。保留两类数据。模板中的聚合字段(
    event_count
    last_seen
    days_since_last_seen
    )将用于步骤5的单用户上下文生成。将
    <event_name>
    替换为选定事件,
    <id>
    替换为
    person.properties.email
    distinct_id
    • 重度用户
      SELECT <id> AS id, count() AS event_count, max(timestamp) AS last_seen, dateDiff('day', max(timestamp), now()) AS days_since_last_seen FROM events WHERE event = '<event_name>' AND timestamp > now() - INTERVAL 60 DAY GROUP BY <id> HAVING count() >= 5 ORDER BY count() DESC LIMIT 20
    • 流失用户(尝试1-2次后未再使用) —
      SELECT <id> AS id, count() AS event_count, max(timestamp) AS last_seen, dateDiff('day', max(timestamp), now()) AS days_since_last_seen FROM events WHERE event = '<event_name>' AND timestamp > now() - INTERVAL 60 DAY GROUP BY <id> HAVING count() <= 2 AND dateDiff('day', max(timestamp), now()) > 14 ORDER BY count() ASC LIMIT 20
    • 高风险用户(曾活跃现已休眠) —
      SELECT <id> AS id, count() AS event_count, max(timestamp) AS last_seen, dateDiff('day', max(timestamp), now()) AS days_since_last_seen FROM events WHERE event = '<event_name>' AND timestamp > now() - INTERVAL 60 DAY GROUP BY <id> HAVING count() >= 3 AND dateDiff('day', max(timestamp), now()) > 14 ORDER BY days_since_last_seen DESC LIMIT 20
  3. 构建均衡样本——除非用户明确要求单一细分群体,否则混合5位重度用户+3位流失用户+2位高风险用户能获得最具价值的访谈结果:既了解现有优势,也能发现阻碍 adoption 和影响留存的问题。可根据用户实际需求调整数量。
将邮箱数据作为
interviewee_emails
传入,distinct ID数据作为
interviewee_distinct_ids
传入——同一主题可同时设置这两个字段。保留每位用户的
event_count
days_since_last_seen
,以便步骤5生成如“过去60天内使用checkout 47次;最后一次访问是2天前”的上下文信息。

Step 3: Capture the topic

步骤3:确定访谈主题

topic
is one or two sentences describing what the interview is about. Infer from context where possible — don't ask the user to repeat themselves.
Example: "ask trial users why they didn't convert" →
topic: "Why trial users didn't convert in the first 14 days"
.
topic
是1-2句话,描述访谈核心内容。尽可能从上下文推断——不要让用户重复说明。
示例:“询问试用用户为何未转化” →
topic: "为何试用用户在最初14天内未转化"

Step 4: Prepare the voice agent

步骤4:准备Voice Agent

Two fields shape what the agent actually does on the call. Always ask about both before creating the topic.
以下两个字段决定Agent在通话中的实际行为。创建主题前务必询问这两项内容。

Always ask: what questions do they want to ask?

必问:希望Agent提出哪些问题?

questions
is an ordered list the agent works through. Anchors, not a script — the agent will adapt phrasing. Keep them open-ended:
  • ✅ "What made you decide to try PostHog?"
  • ❌ "Did you like PostHog?"
If the user already listed questions in their original request, use those and confirm. Otherwise, ask explicitly: "What questions do you want the agent to ask?"
If the user can't think of any, suggest 3–5 open-ended questions drawn from the
topic
and offer them for review before creating.
The field is technically optional in the API, but don't skip it silently — an interview with no questions is rarely useful.
Question templates by research goal:
  • Why users dropped off / churned:
    • "Tell me about the last time you tried [feature] — what were you trying to do?"
    • "Walk me through what happened step-by-step."
    • "What did you expect vs what actually happened?"
    • "What made you stop or decide not to continue?"
    • "What would need to change for you to use [feature] regularly?"
  • Why heavy users love a feature:
    • "Tell me about how you use [feature] — what problem does it solve for you?"
    • "Walk me through your typical workflow."
    • "What would you do if [feature] didn't exist?"
    • "What almost made you not use it when you first tried?"
    • "What's one thing you wish it did differently?"
  • Why someone hasn't tried a feature yet:
    • "Have you noticed [feature] in the product?"
    • "What's stopped you from trying it?"
    • "What would have to be true for it to be worth trying?"
questions
是Agent将按顺序提问的列表。这是引导而非脚本——Agent会调整提问措辞。问题需保持开放式:
  • ✅ “是什么让您决定尝试PostHog?”
  • ❌ “您喜欢PostHog吗?”
若用户在初始请求中已列出问题,直接使用并确认。否则,明确询问:“您希望Agent提出哪些问题?”
若用户无法想出问题,根据
topic
建议3-5个开放式问题,供用户审核确认后再创建主题。
该字段在API中是可选的,但请勿跳过——没有问题的访谈几乎毫无价值。
按研究目标分类的问题模板:
  • 用户为何流失/ churned
    • “请告诉我您最后一次尝试[功能]的经历——您当时想完成什么操作?”
    • “请一步步告诉我发生了什么。”
    • “您的预期与实际情况有何不同?”
    • “是什么让您停止使用或决定不再继续?”
    • “需要做出哪些改变才能让您定期使用[功能]?”
  • 重度用户为何喜爱某功能
    • “请告诉我您如何使用[功能]——它为您解决了什么问题?”
    • “请描述您的典型工作流程。”
    • “如果[功能]不存在,您会怎么做?”
    • “您初次尝试时,是什么差点让您放弃使用它?”
    • “您希望它在哪些方面有所改进?”
  • 用户为何尚未尝试某功能
    • “您注意到产品中的[功能]了吗?”
    • “是什么阻止您尝试它?”
    • “满足什么条件才值得您尝试?”

Always offer: extra context to guide the interview

必选:提供引导访谈的额外上下文

agent_context
is optional, but a few sentences here make the conversation dramatically better. Always offer the user the chance to provide it, e.g.:
"Want to give the agent any extra context? Things like tone, what to avoid, or background on the interviewee help guide the conversation. It's optional."
Useful kinds of context:
  • Tone: "warm and conversational", "skip pleasantries — this is a 10-minute call"
  • Constraints: "don't promise feature delivery", "do not discuss pricing"
  • Background the agent should know: "the user just churned from the Scale plan; be empathetic", "this person tried PostHog 6 months ago and bounced"
  • Persona: "you are Sam, a PostHog product researcher"
If the user declines, that's fine — leave
agent_context
empty and continue.
agent_context
是可选字段,但简短的几句话就能大幅提升对话质量。务必为用户提供填写该字段的机会,例如:
“是否需要为Agent提供额外上下文?诸如语气、需避免的内容或访谈对象背景等信息,有助于引导对话。该字段为可选。”
有用的上下文类型:
  • 语气:“热情且口语化”“跳过寒暄——这是10分钟的通话”
  • 约束:“不要承诺功能上线”“请勿讨论定价”
  • Agent需了解的背景:“用户刚从Scale套餐流失;需保持同理心”“该用户6个月前尝试过PostHog后就不再使用”
  • 角色设定:“您是Sam,PostHog的产品研究员”
若用户拒绝填写,无需处理——保持
agent_context
为空即可继续。

Calling user-interview-topics-create

调用user-interview-topics-create接口

Once you have the pieces:
json
{
  "topic": "Why trial users churned in week 2",
  "interviewee_cohort": 42,
  "interviewee_emails": ["paul@acme.com"],
  "agent_context": "Be warm. The interviewee just churned — don't pitch.",
  "questions": [
    "What were you hoping PostHog would help with?",
    "Where did you get stuck?",
    "What would have made you stay?"
  ]
}
After creation, capture the returned topic ID — you'll need it for Step 5 and for handing off to the voice agent.
收集完所有信息后:
json
{
  "topic": "Why trial users churned in week 2",
  "interviewee_cohort": 42,
  "interviewee_emails": ["paul@acme.com"],
  "agent_context": "Be warm. The interviewee just churned — don't pitch.",
  "questions": [
    "What were you hoping PostHog would help with?",
    "Where did you get stuck?",
    "What would have made you stay?"
  ]
}
创建完成后,记录返回的主题ID——步骤5及交接给Voice Agent时会用到。

Step 5: Optionally attach per-interviewee context

步骤5:可选添加单用户上下文

The topic-level
agent_context
applies to every interviewee. If the user knows something specific about individual interviewees that should shape that one conversation, attach it as a per-interviewee row via
user-interview-topics-interviewees-create
. This is optional — most topics won't need it.
Each row pairs an
interviewee_identifier
(must match one of the emails or distinct IDs in the parent topic's targeting) with an
agent_context
string. At most one row per (topic, interviewee). A user can have zero rows.
Good per-interviewee context looks like:
  • "uses the replay product but has never used summarization"
  • "churned from Scale plan last month — be empathetic, don't pitch"
  • "founder, very technical, skip basic product explanations"
After Step 4 succeeds, ask the user: "Want to add per-interviewee context? Useful when individual people have very different backgrounds. You can either dictate the rows or paste a CSV."
If you found the audience via behavioral query in Step 2, you already have per-person context (usage counts, dormancy windows). Use it: e.g.
"used checkout 47 times in last 60 days; last seen 2 days ago"
for heavy users,
"tried checkout once 18 days ago, never returned"
for drop-offs.
主题级别的
agent_context
适用于所有访谈对象。若用户了解个别访谈对象的特定信息,且这些信息会影响对应对话,可通过
user-interview-topics-interviewees-create
接口为单个访谈对象添加上下文。这是可选操作——大多数主题无需此步骤。
每条记录将
interviewee_identifier
(必须与父主题目标对象中的邮箱或distinct ID匹配)与
agent_context
字符串配对。每个(主题,访谈对象)最多对应一条记录,用户也可无对应记录。
优质的单用户上下文示例:
  • “使用replay产品但从未使用summarization功能”
  • “上月从Scale套餐流失——保持同理心,不要推销”
  • “创始人,技术背景深厚,跳过基础产品讲解”
步骤4完成后,询问用户:“是否需要添加单用户上下文?当个别用户背景差异较大时非常有用。您可以口述记录内容或粘贴CSV文件。”
若步骤2中通过行为查询找到受众,您已拥有单用户上下文(使用次数、休眠时长)。可直接使用:例如,重度用户的上下文为“过去60天内使用checkout 47次;最后一次访问是2天前”,流失用户的上下文为“18天前尝试过一次checkout,之后未再返回”。

Accepting CSV input

接收CSV输入

If the user pastes a CSV, expect two columns:
identifier,context
. Either with or without a header row. Examples:
csv
paul@acme.com,uses replay but never summarization
steve@apple.com,founder; very technical; skip product basics
Or with a header:
csv
identifier,context
abc-distinct-id-1,churned from Scale last month — be empathetic
Parse the CSV, then call
user-interview-topics-interviewees-create
once per row with the captured
topic_id
. Skip blank lines. Quote-escape commas inside the context cell — standard CSV rules.
If a row's identifier isn't present in the parent topic's
interviewee_emails
or
interviewee_distinct_ids
, warn the user before creating — the voice agent looks up context by exact string match, so a mismatched identifier just gets ignored at runtime.
若用户粘贴CSV文件,预期包含两列:
identifier,context
。可包含或不包含表头行。示例:
csv
paul@acme.com,uses replay but never summarization
steve@apple.com,founder; very technical; skip product basics
或带表头:
csv
identifier,context
abc-distinct-id-1,churned from Scale last month — be empathetic
解析CSV文件后,针对每一行调用
user-interview-topics-interviewees-create
接口,传入已记录的
topic_id
。跳过空行。上下文单元格中的逗号需使用引号转义——遵循标准CSV规则。
若某行的identifier未出现在父主题的
interviewee_emails
interviewee_distinct_ids
中,创建前需提醒用户——Voice Agent会通过精确字符串匹配查找上下文,不匹配的identifier在运行时会被忽略。

Edge cases

边缘情况

  • No users match the behavioral query. Possible reasons: the event isn't firing, the date range is too narrow, or no users have email addresses captured as person properties. Offer to widen the date range, try a different event, or fall back to cohorts / explicit emails.
  • Users matched but few have emails. PostHog stores whatever the SDK captures. If only a handful of matching users have email addresses on their person profile, surface the count and ask: take the smaller sample, fall back to
    interviewee_distinct_ids
    (the agent can still reach them via in-app delivery), or skip the behavioral query and let the user paste emails directly.
  • Ambiguous event name. If
    read-data-schema
    returns multiple candidates (e.g.
    checkout_started
    ,
    checkout_completed
    ,
    checkout_abandoned
    ), list them with counts and let the user pick the behavior they want to understand. Don't pick silently.
  • User asks to interview only drop-offs (or only one segment). That works, but flag the tradeoff: interviewing only drop-offs tells you what's broken without telling you what works. Recommend including 2–3 successful users for contrast unless the user has a reason for the narrower sample.
  • 行为查询未匹配到用户:可能原因包括事件未触发、日期范围过窄或无用户的person属性中包含邮箱地址。建议扩大日期范围、尝试其他事件,或改用cohort/明确邮箱。
  • 匹配到用户但少数有邮箱:PostHog存储SDK捕获的所有数据。若仅少数匹配用户的person资料中包含邮箱地址,需告知用户数量并询问:选择较小样本、改用
    interviewee_distinct_ids
    (Agent仍可通过应用内推送联系用户),或跳过行为查询让用户直接粘贴邮箱。
  • 事件名称模糊:若
    read-data-schema
    返回多个候选事件(如
    checkout_started
    checkout_completed
    checkout_abandoned
    ),列出所有选项及对应数量,让用户选择需了解的行为。请勿自行选择。
  • 用户要求仅访谈流失用户(或单一细分群体):这是允许的,但需告知用户利弊:仅访谈流失用户只能了解问题所在,无法了解现有优势。建议加入2-3位成功用户作为对比,除非用户有明确理由选择更窄的样本。

What this skill is not for

本技能不适用场景

  • Uploading a recorded interview — that's the separate
    UserInterview
    model (
    user_interviews_create
    with an audio file). Different flow, different model.
  • Listing existing topics
    user-interview-topics-list
    handles that directly with
    search
    ,
    limit
    , and
    offset
    . No skill needed.
  • Analyzing transcripts after the interview — out of scope here; that lives with the recorded
    UserInterview
    flow.
  • 上传已录制的访谈音频——属于独立的
    UserInterview
    模型(通过
    user_interviews_create
    接口上传音频文件)。流程不同,模型不同。
  • 列出现有主题——
    user-interview-topics-list
    可直接通过
    search
    limit
    offset
    参数处理,无需使用本技能。
  • 访谈后分析转录文本——超出本技能范围;属于已录制的
    UserInterview
    流程的功能。",