面试官:OpenCode Prompt 系统了解吗?

0 阅读7分钟

本系列文章皆基于开源 Vibecoding 工具 Opencode 源码进行详细拆解。
源码链接:github.com/anomalyco/o…


写在前面

上次咱们聊完了 Tool 工具系统,兄弟们是不是觉得 AI 终于能"动手"干活了?

!但是!光能动手也不行啊,兄弟们有没有想过这个问题:AI 是怎么"理解"自己是谁的?它怎么知道自己是 OpenCode 而不是 Claude?它怎么知道要在当前项目根目录工作而不是别的地方?

今天咱们就来看看,AI 背后的"灵魂"到底是咋构建的!这个 Prompt 系统,简直就是 OpenCode 的大脑中枢


一、什么是 Prompt 模块?

兄弟们,这个问题太关键了!Prompt 模块就是给 AI 灌输"世界观"的存在!

你跟 AI 说一句话,它不是直接就把那句话发出去了,它得先给自己"叠甲":

  • 我是谁?
  • 我在什么地方?
  • 我有什么能力?
  • 我要注意什么?

这些信息从哪来?就是 Prompt 模块给的!

Prompt 解决了什么问题?

问题Prompt 方案
AI 不知道自己是谁角色定义(你是 OpenCode)
不同模型需要不同调教模型特定 Prompt
项目需要自定义规则AGENTS.md 加载
指令散落各地不好找层级向上查找
团队需要共享指令远程 URL 支持

你说这些重要吗?简直不要太重要!没有 Prompt,AI 就是一个没有记忆、没有身份的"无头苍蝇"!


二、核心架构

看图!这四个东西就是 Prompt 模块的核心组件:

graph TB
    subgraph Prompt 模块
        S[system.ts<br/>模型特定提示]
        I[instruction.ts<br/>指令文件加载]
        P[prompt.ts<br/>主Prompt逻辑]
        SK[skill.ts<br/>技能系统]
    end
    
    S --> P
    I --> P
    SK --> P
    
    P -->|组装完成| AI[AI Model]

2.1 各组件职责

文件行数职责
system.ts72模型特定提示词选择
instruction.ts192指令文件加载
prompt.ts1968主 Prompt 构建逻辑
prompt/*.txt-各模型提示词模板

兄弟们,1968 行的 prompt.ts 是整个模块的大本营,里面逻辑那是相当的复杂!咱们后面会细讲!!


三、模型特定 Prompt 系统(面试重点!!!)

这个设计面试官特别喜欢问!!!问到你头皮发麻都有可能!!!

3.1 为什么需要区分模型?

兄弟们,这个设计太真实了。不同模型的"性格"完全不同!

  • Claude: 擅长思考,需要详细角色定义
  • GPT: 擅长执行,需要强调行动
  • Gemini: 有自己的特定优化方向
  • Qwen: 中文模型,不需要 TODO 功能

你说,你能让一个"思考型"模型去干"执行型"的活吗?能,但是效果不好。

所以 OpenCode 选择因材施教,给每个模型准备特定的提示词!这就是大厂的设计水平吗???简直离谱!!!

3.2 选择逻辑

// 源码位置: packages/opencode/src/session/system.ts:22
export function provider(model: Provider.Model) {
  // GPT 系列(包括 o1/o3)
  if (model.api.id.includes("gpt-") || model.api.id.includes("o1") || model.api.id.includes("o3"))
    return [PROMPT_BEAST]
  
  // Gemini
  if (model.api.id.includes("gemini-")) return [PROMPT_GEMINI]
  
  // Claude
  if (model.api.id.includes("claude")) return [PROMPT_ANTHROPIC]
  
  // Trinity
  if (model.api.id.toLowerCase().includes("trinity")) return [PROMPT_TRINITY]
  
  // 默认(Qwen 等)
  return [PROMPT_ANTHROPIC_WITHOUT_TODO]
}

面试官可能会问:如果我要添加一个新模型,比如 DeepSeek,怎么做?

答案简直不要太简单!在这个函数里加一个判断,然后提供一个对应的提示词模板文件就行!就这???对,就这!!!

3.3 各模型提示词模板

模型模板文件特点
Claudeanthropic.txt标准 OpenCode 角色定义,105 行
GPTbeast.txt强调高效执行
Geminigemini.txtGemini 特定优化
Qwenqwen.txt无 TODO 功能
Codexcodex_header.txt极简 header
Trinitytrinity.txt三合一模式

四、指令文件加载系统(必考!!!)

这个是面试重灾区,一定要搞懂!!!面试官问到你怀疑人生!!!

4.1 支持的指令文件

// 源码位置: packages/opencode/src/session/instruction.ts:14
const FILES = [
  "AGENTS.md",   // OpenCode 标准
  "CLAUDE.md",   // Claude Code 兼容
  "CONTEXT.md",  // 已废弃,别用了!
]

4.2 多层级查找(核心亮点!!!)

兄弟们,这个设计简直是太香了!!!香到爆!!!

想象一下这个场景:

project/
├── AGENTS.md           # 项目根目录的指令
├── packages/
│   └── common/
│       └── AGENTS.md   # 子包的指令

当你在 packages/common/ 目录下工作时,OpenCode 会自动向上查找所有 AGENTS.md!

这就是传说中的"继承"机制!太牛逼了!!!

graph TB
    subgraph 查找顺序
        A[当前目录<br/>packages/common]
        B[上级目录<br/>packages]
        C[项目根目录<br/>project]
        D[全局配置目录]
    end
    
    A -->|未找到| B
    B -->|未找到| C
    C -->|未找到| D

4.3 向上查找算法

// 源码位置: packages/opencode/src/session/instruction.ts:177
while (current.startsWith(root) && current !== root) {
  const found = await find(current)
  
  // 找到且不是目标文件、不是系统文件、未被加载过
  if (found && found !== target && !system.has(found) && !already.has(found)) {
    // 加载这个指令文件
    const content = await Filesystem.readText(found)
    results.push({ filepath: found, content })
  }
  current = path.dirname(current)  // 继续向上查找!!!
}

面试官可能会问:这个设计有什么好处?

  1. 子目录自动继承父目录指令:不用每个子项目都配一遍
  2. 就近优先:子目录的指令会覆盖父目录的
  3. 去重机制:不会重复加载同一个文件

就问你香不香???香爆了!!!

4.4 远程指令支持

// 源码位置: packages/opencode/src/session/instruction.ts:134
const fetches = urls.map((url) =>
  fetch(url, { signal: AbortSignal.timeout(5000) })
    .then((res) => (res.ok ? res.text() : ""))
    .catch(() => "")
)

在配置文件里可以这样用:

{
  "instructions": [
    "https://example.com/team-rules.md",
    "~/my-instructions/custom.md"
  ]
}

这样团队成员就能共享一份在线指令文档了!分布式团队开发,简直不要太爽!!!


五、技能(Skill)系统

这个是 OpenCode 的一个特色功能!让你的 AI 会"技能召唤"!!!

5.1 Skill 是什么?

兄弟们,Skill 就像是一个可插拔的能力包

// 源码位置: packages/opencode/src/session/system.ts:59
export async function skills(agent: Agent.Info) {
  // 检查权限
  if (PermissionNext.disabled(["skill"], agent.permission).has("skill")) return
  
  // 获取可用技能列表
  const list = await Skill.available(agent)
  
  return Skill.fmt(list, { verbose: true })
}

5.2 Skill 的好处

  1. 按需加载:AI 根据任务自己决定要不要加载
  2. 权限控制:可以禁用某些 Skill
  3. 可扩展:任何人都可以添加新的 Skill

这不就是程序员梦寐以求的"插件系统"吗???太香了!!!


六、环境信息注入

每次对话都会自动注入当前环境信息,AI 简直就是一个"环境感知大师"!

// 源码位置: packages/opencode/src/session/system.ts:32
export async function environment(model: Provider.Model) {
  return [
    `You are powered by the model named ${model.api.id}.`,
    `The exact model ID is ${model.providerID}/${model.api.id}`,
    `Here is some useful information about the environment you are running in:`,
    `<env>`,
    `  Working directory: ${Instance.directory}`,
    `  Workspace root folder: ${Instance.worktree}`,
    `  Is directory a git repo: ${project.vcs === "git" ? "yes" : "no"}`,
    `  Platform: ${process.platform}`,
    `  Today's date: ${new Date().toDateString()}`,
    `</env>`,
  ].join("\n")
}

这些信息帮助 AI 做出更准确的决策,比如:

  • 知道在哪个目录工作
  • 知道是什么平台(Windows/Linux/Mac)
  • 知道是不是 git 仓库

这不比某些 AI 连自己在哪都不知道强???甩它们十条街!!!


七、完整 Prompt 构建流程

sequenceDiagram
    participant U as 用户消息
    participant P as Prompt 模块
    participant S as SystemPrompt
    participant I as InstructionPrompt
    participant SK as Skill
    participant AI as AI Model
    
    U->>P: 用户发送消息
    
    P->>S: 获取模型特定提示
    S-->>P: 返回提示词模板
    
    P->>I: 加载指令文件
    I-->>P: 返回 AGENTS.md 内容
    
    P->>SK: 获取可用技能
    SK-->>P: 返回技能列表
    
    P->>P: 组装完整上下文
    
    P->>AI: 发送完整 Prompt
    AI-->>P: 返回响应

八、面试常见问题

Q1: Prompt 模块的核心职责是什么?

:负责构建 AI 每次对话的完整提示词,包括角色定义、模型特定指令、指令文件、Skill、环境信息等。这就是 AI 的"灵魂"!

Q2: 为什么需要模型特定的 Prompt?

:不同模型的"性格"和擅长领域不同。Claude 擅长思考,GPT 擅长执行,Gemini 有自己的优化方向。通过模型特定的 Prompt 可以最大化每个模型的效果。这就跟"因材施教"一个道理!!!

Q3: AGENTS.md 的向上查找机制是怎么工作的?

:从当前目录开始,逐层向上查找 AGENTS.md、CLAUDE.md 等指令文件,直到找到为止。所有找到的指令文件都会被加载,靠近当前目录的优先级更高。,简直就是"继承"机制的完美实现!

Q4: 如何添加对新模型的支持?

:在 system.tsprovider 函数中添加模型判断逻辑,然后创建一个对应的提示词模板文件(.txt)。简单到爆!!!

Q5: 远程指令是怎么实现的?

:通过 fetch API 加载配置中指定的 URL,5秒超时,返回内容作为指令追加到 Prompt 中。团队协作神器!!!


总结

兄弟们,今天咱们聊的 Prompt 模块,简直就是 OpenCode 的"大脑中枢"!它负责:

  1. 因材施教:为不同模型准备特定提示词
  2. 指令管理:自动加载和合并项目指令
  3. 技能扩展:支持动态加载 specialized 能力
  4. 环境感知:注入工作环境上下文

这个设计让 OpenCode 能够灵活适应不同模型和项目需求,是整个系统的核心基础设施。

兄弟们,这个设计你们觉得怎么样???是不是香到爆???


往期好文推荐


写在最后

兄弟们,如果文章对您有帮助麻烦亲点赞、收藏 + 关注和博主一起成长哟!!! 也欢迎在评论区留言讨论,说说你们觉得 Prompt 模块哪个设计最牛逼!!!

咱们下期再见!!!❤️❤️❤️