Skip to content

Agent Harness 设计

Agent Harness 设计

目标

Agent Harness 是 AgentSurvey 的核心。它负责把研究配置、会话状态、LLM、工具、知识库和输出 schema 组织成一个可控、可审计、可扩展的访谈运行时。

不要把 Harness 简化为一个 prompt。它应该是显式状态机。

Harness 核心职责

  1. 加载 study config。
  2. 管理 session state。
  3. 判断当前研究 coverage。
  4. 决定下一步动作。
  5. 调用 LLM 和工具。
  6. 控制追问深度。
  7. 触发结构化抽取。
  8. 处理交互式 UI 结果。
  9. 判断结束条件。
  10. 记录 agent decision log。

状态机

START
-> LOAD_CONTEXT
-> CONSENT_OR_SCREENING
-> OPENING
-> ASK_OR_PROBE
-> OPTIONAL_INTERACTION
-> EXTRACT
-> EVALUATE_COVERAGE
-> NEXT_TOPIC_OR_PROBE
-> SUMMARY_CONFIRMATION
-> CONCLUDE
-> POST_SESSION_EXTRACTION
-> END

Agent Actions

export type AgentAction =
| { type: "send_message"; content: string }
| { type: "ask_question"; question: string; objective_id?: string }
| { type: "probe"; question: string; based_on_turn_id: string }
| { type: "render_interaction"; interaction: InteractionToolCall }
| { type: "retrieve_knowledge"; query: string }
| { type: "extract_fields"; fields?: string[] }
| { type: "summarize_and_confirm"; summary: string }
| { type: "conclude"; reason: string };

Session State

export type SessionState = {
session_id: string;
study_id: string;
participant_id?: string;
status: "created" | "active" | "waiting_for_user" | "waiting_for_tool" | "completed" | "abandoned";
current_phase: HarnessPhase;
current_objective_id?: string;
covered_objectives: Record<string, CoverageState>;
extracted_fields: Record<string, ExtractedFieldState>;
pending_interaction_id?: string;
turn_count: number;
started_at: string;
last_activity_at: string;
config_versions: ConfigVersionRefs;
};

Coverage State

export type CoverageState = {
objective_id: string;
status: "not_started" | "in_progress" | "covered" | "skipped" | "blocked";
confidence: number;
evidence_count: number;
last_turn_id?: string;
missing_info?: string[];
};

Study Objective

export type StudyObjective = {
id: string;
title: string;
description: string;
priority: "must" | "should" | "optional";
suggested_questions: string[];
success_criteria: string[];
related_output_fields: string[];
max_probe_count?: number;
interaction_tools?: string[];
};

Harness Decision Prompt 结构

LLM 不直接接收所有数据,而是接收结构化上下文:

System role:
You are an AI research interviewer...
Study brief:
- Goal
- Target participant
- Research constraints
Current objective:
- Objective title
- Success criteria
- Missing information
Session summary:
- Participant background
- Key known facts
- Covered objectives
- Extracted fields
Recent transcript:
- Last N turns
Available tools:
- render_interaction
- retrieve_knowledge
- extract_fields
- conclude
Decision instruction:
Choose exactly one next action.

Next Action Decision

建议让模型输出严格结构:

{
"action_type": "probe",
"rationale": "用户提到了配置复杂,但没有给出具体例子,需要追问场景。",
"objective_id": "obj_pain_point",
"content": {
"question": "你能举一个最近一次觉得配置复杂的具体例子吗?当时你想完成什么任务?"
}
}

追问策略

Agent 应遵循:

  1. 先开放,后结构化。
  2. 对泛泛回答追问具体例子。
  3. 对强情绪回答追问影响和原因。
  4. 对矛盾回答澄清。
  5. 对关键字段缺失进行 targeted probe。
  6. 每个 objective 限制最大 probe 次数。
  7. 不为了填满 schema 过度追问。
  8. 在用户疲劳时优先结束。

什么时候调用交互组件

适合调用:

  • 需要选择、排序、评分、确认;
  • 需要降低用户输入成本;
  • 需要把开放回答转成结构化变量;
  • 需要可比较数据;
  • 需要展示概念/选项/任务。

不适合调用:

  • 用户正在讲故事;
  • 需要建立信任;
  • 问题很敏感;
  • 追问可以更自然地完成;
  • 组件会打断思路。

Extraction 集成

Harness 可以在三类节点触发抽取:

After user message -> lightweight extraction
After objective covered -> checkpoint extraction
After session completed -> final extraction

轻量抽取用于更新 state,最终抽取用于结果页。

结束条件

可以结束的条件:

  1. 所有 must objectives 已覆盖。
  2. 关键 output fields 达到 confidence threshold。
  3. 用户表示没有更多补充。
  4. 达到最大轮次或最大时长。
  5. 用户要求结束。
  6. screening 不符合条件。
  7. safety/privacy policy 触发。

Decision Log

每次 Agent 决策都要记录:

export type AgentDecisionLog = {
id: string;
session_id: string;
turn_id?: string;
phase: HarnessPhase;
input_summary: string;
selected_action: AgentAction;
rationale?: string;
model: string;
prompt_version_id: string;
tool_candidates?: string[];
latency_ms: number;
token_usage?: TokenUsage;
created_at: string;
};

Harness MVP 实现建议

实现底座 = LangGraph(见 05_tech_stack_decision.md)。本文的 SessionState 映射到 LangGraph graph state;waiting_for_tool(等待受访者交互)由 interrupt() 实现;session 可重放 / audit / decision log 由 checkpointer(PostgresSaver)提供。下面的 HarnessRuntime 是 graph 节点编排的逻辑视图,而非另起炉灶的自研运行时。

第一版不必引入 multi-agent 或可视化 graph builder,用 LangGraph 实现固定状态机 + 配置驱动即可:

StudyConfig
-> Objectives[]
-> OutputSchema
-> EnabledTools
-> AgentPolicy
HarnessRuntime
-> choose_next_objective()
-> decide_next_action()
-> execute_action()
-> update_state()
-> maybe_extract()
-> maybe_conclude()

后续再逐步引入(其中 custom state graph / human handoff / time-travel debugging 多由 LangGraph 原生提供):

  • custom state graph;
  • multi-agent;
  • visual debugger(LangGraph Studio);
  • human handoff;
  • auto evaluation。