AI-Interview Skill 系统:Context-Aware 方法论加载机制
背景:多 Agent 架构下的方法论管理困境
AI-Interview 是一个基于 LangGraph + LangChain 构建的 AI 模拟面试官系统。系统采用多 Agent 架构,包含 orchestrator、resume_agent、question_agent、evaluate_agent、feedback_agent 和 review_agent 等多个角色。每个 Agent 在执行任务时都需要遵循特定的方法论——比如追问生成策略、评估打分规则、反馈纠错规范等。
随着系统功能不断丰富,方法论文档数量急剧增长。传统做法是将所有方法论文档一次性注入到 Prompt 中,导致 Prompt 变得冗长笨重,LLM 被淹没在不相关信息海洋里,调用延迟增加,成本浪费严重。
传统方案的局限性
在传统方案中,Prompt 的构建方式是这样的:
prompt = base_prompt + 大量_skill_文档 # 一次性全部注入这种方式存在三个核心问题:
信息过载。当 Agent 处理「生成追问」这样的具体动作时,Prompt 中可能包含 80% 与当前任务无关的方法论文档。LLM 需要在海量信息中筛选真正相关的内容,既增加了 token 消耗,又降低了响应质量。
维护困难。所有方法论混在一起,修改一个 skill 可能影响多个 Agent 的行为。测试也变得复杂,难以单独验证某个方法论的正确性。
缺乏灵活性。无法根据对话状态动态调整方法论。比如当对话处于 warmup 阶段时,不需要加载 followup 相关的 skill。
Skill 系统的核心设计
我们设计的 Skill 系统采用「按需加载」模式:
if ContextAwareSkillLoader 检测到需要 skill: prompt = base_prompt + 匹配的 skill(按需加载)else: prompt = base_prompt # 无额外开销核心是 ContextAwareSkillLoader 类,它负责检测当前上下文需要哪些 skill,并精确加载:
class ContextAwareSkillLoader:
def get_skills_for_context(self, agent, phase, action, state): matched_skills = []
for skill_dir in [common/, agent/]: for skill_file in skill_dir.glob("**/SKILL.md"): skill = self._parse_skill(skill_file)
# 关键:检测逻辑 if self._matches_triggers(skill, phase, action, state): matched_skills.append(skill)
return matched_skillsContext-Aware 加载机制详解
触发检测是整个机制的核心。我们设计了三种触发方式:
def _matches_triggers(self, skill, phase, action, state): for trigger in skill.triggers:
# 1. Phase 触发 - 当前阶段是否需要此 skill if "phase" in trigger and trigger["phase"] == phase: return True
# 2. Action 触发 - 当前动作是否需要此 skill if "action" in trigger and trigger["action"] == action: return True
# 3. Condition 触发 - 状态条件是否满足 if "condition" in trigger and self._eval_condition(trigger["condition"], state): return True
return FalsePhase 触发针对对话阶段,如 warmup、initial、followup、evaluation 等。当进入特定阶段时,自动加载对应方法论。
Action 触发针对具体动作,如 generate_question、evaluate_answer、generate_feedback 等。执行特定动作时,加载该动作的方法指南。
Condition 触发最为灵活,支持基于状态的动态判断。通过简单的表达式语法,可以在 state 满足某个条件时触发加载。
Skill 文件格式
每个 Skill 是一个独立的 Markdown 文件,采用 YAML frontmatter 定义元数据:
---name: 追问生成策略description: 根据偏差分数决定是否追问version: 1.0.0agent: questiontriggers: - action: generate_followup - phase: followup---
# 追问生成策略
## 追问决策
当 deviation_score >= 0.6 且 followup_depth < max_followup_depth 时生成追问
## 追问方向
- dev < 0.3: 深入技术细节,说明具体实践- 0.3 <= dev < 0.6: 引导扩展,补充项目背景- dev >= 0.6: 肯定方向,探索相关经验文件分为两部分:YAML frontmatter 定义名称、描述和触发条件;Markdown body 定义具体的方法论内容,会被注入到 Prompt 中供 LLM 参考。
目录结构与 Skill 分类
src/agent/skills/├── common/ # 通用技能(所有 Agent 共享)│ ├── retry/ # 重试策略│ ├── error-handling/ # 错误处理│ ├── llm-calling/ # LLM 调用规范│ └── state-management/ # 状态管理│├── orchestrator/ # 编排协调├── resume/ # 简历解析├── question/ # 问题生成│ ├── generation/ # 问题生成策略│ ├── followup/ # 追问生成│ └── deduplication/ # 去重检查├── evaluate/ # 评估├── feedback/ # 反馈│ ├── correction/ # 纠错反馈│ ├── guidance/ # 引导反馈│ └── comment/ # 点评反馈├── review/ # 审查└── knowledge/ # 知识管理目录设计遵循两个原则:层级组合和按职责分离。
common/ 目录下的 skill 会被所有 Agent 共享,比如重试策略、错误处理规范等。Agent 专属目录下的 skill 只在该 Agent 需要时加载。同一 Agent 内部按功能模块进一步划分,如 question Agent 下分为 generation、followup、deduplication 等子目录。
Agent 集成示例
在实际使用中,Agent 通过 skill_aware_prompt 函数构建增强 Prompt:
from dataclasses import asdictfrom src.agent.skill_loader import skill_aware_prompt
async def generate_followup(state: InterviewState, ...): prompt = f"问题: {question}\n回答: {answer}\n"
enhanced = skill_aware_prompt( agent="question", phase=state.phase, # warmup / initial / followup action="generate_followup", base_prompt=prompt, state=asdict(state), # 用于 condition 匹配 )
result = await invoke_llm(enhanced)当 phase=followup, action=generate_followup 时,系统会匹配到以下 skill:
common/retry/SKILL.md— 条件触发:当 error 包含 LLM_ERROR 时加载common/llm-calling/SKILL.md— 条件触发:当 llm_call 为 true 时加载question/followup/SKILL.md— phase 触发:当前 phase 为 followup 时加载
最终生成的增强 Prompt 结构如下:
原始 prompt: 请基于以下问题生成追问...
## 参考方法论(按需使用)
### [question] 追问生成策略# 追问生成策略
## 追问决策deviation_score >= 0.8 → 继续深入...
### [common] 重试策略# 重试策略...关键优势
| 传统方式 | Skill 系统 |
|---|---|
| 一次性注入所有 skill | 按需加载匹配的 skill |
| prompt 冗长 | prompt 精简高效 |
| LLM 被淹没在文档中 | 只接收当前相关的方法论 |
| 难以测试和维护 | 各 skill 独立可测试 |
在一次实际测试中,处理 generate_followup 动作时,Prompt token 消耗从原来的 3200 降至 1800,减少了 44%。
设计原则
零成本抽象。不使用 skill 时,系统不会有任何额外开销。get_skills_for_context 在没有匹配 skill 时直接返回空列表,后续的注入逻辑会跳过空列表。
精确匹配。三种触发条件确保只有在真正需要时才加载。Condition 触发支持表达式求值,可以根据 state 动态判断,避免了硬编码。
层级组合。Common skill 通用方法论 + Agent skill 专属方法论的组合模式,兼顾了复用性和专业性。修改 common skill 会影响所有 Agent,修改 Agent skill 只影响特定 Agent。
上下文感知。通过 phase、action、state 三个维度动态判断,skill 加载与业务逻辑解耦。增加新的 skill 只需要编写文件并定义触发条件,不需要修改业务代码。
总结
Context-Aware Skill 加载机制解决了多 Agent 系统中方法论管理的核心问题。通过精确的触发检测、灵活的目录结构和简洁的集成接口,实现了 Prompt 的按需增强。系统保持了对业务逻辑的透明性,开发者可以独立管理各个 skill 文件而不影响核心流程。
下一步我们将探索 skill 的版本管理和热更新机制,支持在运行时动态调整方法论行为。